feat(mcp-server): tags & tax-category lookup tools (MCP Prompt 14)#4015
feat(mcp-server): tags & tax-category lookup tools (MCP Prompt 14)#4015gilgardosh wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces two new read-only lookup tools, accounter_list_tags and accounter_list_tax_categories, along with their corresponding unit tests. The feedback focuses on improving type safety in the test suite, utilizing localeCompare for more robust sorting, simplifying redundant object mapping, and polishing user-facing pluralization strings.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| function byNameThenId(a: { name: string; id: string }, b: { name: string; id: string }): number { | ||
| const an = a.name.toLowerCase(); | ||
| const bn = b.name.toLowerCase(); | ||
| if (an < bn) return -1; | ||
| if (an > bn) return 1; | ||
| return a.id < b.id ? -1 : a.id > b.id ? 1 : 0; | ||
| } |
There was a problem hiding this comment.
The byNameThenId comparison logic can be simplified and made more robust, especially for international characters, by using String.prototype.localeCompare.
function byNameThenId(a: { name: string; id: string }, b: { name: string; id: string }): number {
return (
a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }) || a.id.localeCompare(b.id)
);
}b165a5a to
0e6e0f0
Compare
Add two read-only reference lookups (docs/mcp/spec.md §8.2). - src/tools/lookups.ts: accounter_list_tags (allTags) and accounter_list_tax_categories (taxCategories) with minimal input (nameContains, limit, activeOnly), deterministic sort (name then id), and a 500-row output cap with a `truncated` flag; response fields limited to the lookup use case - both gated on business membership (scope enforcement) and registered in the process-wide registry - integration tests: sorted lookups, name filter, active filter, cap/truncation, scope enforcement, and unknown-field rejection Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo
Address review: - byNameThenId uses localeCompare (locale-aware, robust for i18n names) - tax-category handler returns the already-shaped rows directly (drop redundant identity map) - natural-language pluralization for tag/tax-category summaries - lookup tests: union type for the runTool helper; assert the full rows array Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPMszz9gdZFhNjobRm6Ndo
0929ded to
57e3d25
Compare
Summary
Implements Prompt 14 – Tool 2: tags and tax-category lookup (read-only) (see
docs/mcp/spec.md§8.2). Two reference-datalookup tools.
Changes
src/tools/lookups.tsaccounter_list_tags(allTags) →{ id, name, namePath }.accounter_list_tax_categories(taxCategories) →{ id, name, irsCode, isActive }, with anactiveOnlyfilter.nameContains,limit); output is deterministically sorted (name case-insensitive, then id) and size-capped at 500 with atruncatedflag. Response fields are limited to the lookup use case.src/tools/registry-instance.ts— both tools registered.Validation
yarn workspace @accounter/mcp-server test→ 160 passedyarn workspace @accounter/mcp-server lint/typecheck/build→ passNotes / open decisions
allTags/taxCategoriesare org-wide (not business-filtered upstream), but I setrequiresBusinessScope: trueso a caller with no business membership is denied — that's the "scope enforcement" the prompt asks tests to cover, and it's a sensible gate (you browse tags because you belong to a business). The scope itself isn't used to filter the query. Easy to relax tofalseif reference lookups should be open to any authenticated user.allTags/taxCategoriestake no arguments upstream, sonameContains/limit/sort are applied in the tool. Fine at reference-data sizes; if these grow large, a server-side filtered query would be better.🤖 Generated with Claude Code
Generated by Claude Code