Skip to content

feat(mcp): restore merchant_summary tool#1843

Closed
canalesb93 wants to merge 8 commits into
mainfrom
agents/merchant-summary-tool
Closed

feat(mcp): restore merchant_summary tool#1843
canalesb93 wants to merge 8 commits into
mainfrom
agents/merchant-summary-tool

Conversation

@canalesb93

Copy link
Copy Markdown
Owner

Follow-up to #1841. Restores the merchant_summary MCP tool.

While auditing the Routine Reviewer's prompts I found merchant_summary referenced as a tool in six agent prompts and in docs/mcp-tools-reference.md, but it was not registered in the MCP server — agents told to "use merchant_summary" hit an unknown tool and improvised. The building blocks already existed:

  • Service method GetMerchantSummary (internal/service/transaction_summary.go) — production-grade, fully parameterized.
  • REST endpoint GET /transactions/merchants already exposes it.
  • docs/mcp-tools-reference.md already documents it, and the admin tool-label map already lists it.

Only the MCP wiring was missing. This re-registers it.

What it does

Per-merchant aggregation over a window (default last 90 days) — the merchant-grouped companion to transaction_summary (which groups by category/time, not merchant). Each row: merchant, transaction_count, total_amount, avg_amount, first_date, last_date, iso_currency_code (never summed across currencies; capped at 500).

Filters: min_count (2 = recurring, 3+ = subscriptions), spending_only, category_slug, account_id, user_id, min_amount/max_amount, search (+ search_mode incl. fuzzy for bank-feed name variants), exclude_search.

This makes the six prompts that already reference it correct, no prompt edits needed.

Tests

  • New MCP handler test: merchants array + totals shape, per-row keys, and min_count exclusion.
  • go build / go vet clean; full unit suite + mcp/admin integration green.

Stack

Stacked on #1841 (agents/rule-query-and-agent-shell) since both touch server.go / server_test.go / tools.go / the docs reference — basing here keeps this diff to just the merchant change. Once #1841 squash-merges, GitHub retargets this to main cleanly.

🤖 Generated with Claude Code

canalesb93 and others added 8 commits June 4, 2026 22:36
…actions

Agents rarely set the optional fields param, so query_transactions returned
all ~22 fields per row by default — most unused. Make the MCP default a compact
projection (core,category); pass fields=all for the full struct. This is
MCP-only: the REST API shares service.ParseFields and keeps returning full
objects when ?fields= is omitted.

Also hoist iso_currency_code to a single top-level field when every returned
row shares one currency (the common single-currency household case), with a
safe per-row fallback the moment a response mixes currencies.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…transaction_rules

Extend the field-projection mechanism (previously transaction-only) to two
heavy read tools. fields.go's parser is generalized into parseFieldsWith so
each entity supplies its own valid-field/alias maps; ParseFields stays a stable
wrapper so the REST API is untouched.

- list_series: lean "overview" default (identity + renewal prediction) drops
  the verbose detection_signals blob; fields=all or get_series for full detail.
- list_transaction_rules: lean "summary" default drops the conditions/actions
  trees; fields=all restores the full definition.

Both are MCP-tool-only; the breadbox://rules resource still returns full, and
the tool<->resource parity test now asserts that invariant via fields=all.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a safety ceiling on any single MCP tool response, enforced at the
jsonResult chokepoint on the post-compaction wire bytes. Over the cap, the tool
returns an actionable RESPONSE_TOO_LARGE error (narrow filters / lower limit /
paginate / use fields) instead of dumping a context-blowing payload — the
pattern GitHub's MCP server uses.

Default 100 KB (~25K tokens). Override via BREADBOX_MCP_MAX_RESPONSE_BYTES
(env, consistent with config precedence); set to 0 to disable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…esponse cap

Keep the canonical MCP tools reference in sync with the token-optimization
changes: query_transactions / list_series / list_transaction_rules lean
defaults + fields=all, top-level currency hoisting, and the per-response byte
cap with its BREADBOX_MCP_MAX_RESPONSE_BYTES override.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds query_transaction_rules — the filterable/sortable analogue of
query_transactions for the rule set — and fixes the agent sidecar so its
Bash/Grep analysis tools actually work inside the container.

query_transaction_rules: filter by category_slug / enabled / trigger /
creator_type / search / min_hit_count / only_unused; sort by priority
(default) | hit_count | last_hit_at | created_at | name. Lean-by-default
summary projection + response cap, shared with list_transaction_rules.
Cursor pagination is emitted only for the default priority sort; an
explicit sort_by returns a single top-N page. Lets a reviewer audit
coverage and prune dead rules without dumping the whole roster (which
overflowed the tool-result cap in prod).

Sidecar shell: the Alpine runtime image shipped no bash and no ripgrep
and left SHELL unset, so an agent that tried to grep a large saved
tool-result hit "No suitable shell found" / vendored-rg ENOENT and was
left unable to do file-level analysis. Install bash + ripgrep, set
SHELL=/bin/bash and USE_BUILTIN_RIPGREP=0 (the SDK's bundled rg isn't
embedded in the Bun --compile output), with defensive defaults in the
sidecar itself for non-Docker (per-user worktree) installs.

Also fixes the routine-review prompt's reference to the phantom
merchant_summary tool (no merchant grouping exists; the small queue is
already in context) and points rule-coverage analysis at the new tool.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Six agent prompts (merchant-analysis, strategy-spending-report,
strategy-rule-foundation, strategy-anomaly-detection,
strategy-large-charge-sentinel, review-depth-thorough) and
docs/mcp-tools-reference.md all reference a merchant_summary MCP tool
that wasn't registered. The service method (GetMerchantSummary) and the
REST endpoint (/transactions/merchants) already exist — only the MCP
wiring was missing — so every prompt that told an agent to "use
merchant_summary" hit an unknown tool and the agent improvised.

Re-register the tool: per-merchant aggregation (count, total, avg,
first/last date) over a window, with min_count / spending_only /
category_slug / account_id / user_id / amount-range / search (fuzzy)
filters. It's the merchant-grouped companion to transaction_summary
(which groups by category/time, not merchant), backed by the same
service method the REST endpoint uses. The admin tool-label map already
listed merchant_summary; docs already documented it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@canalesb93 canalesb93 added stacked Part of a Graphite stacked PR (filter-friendly) stack/agents-tooling PRs in the agents-tooling stack labels Jun 13, 2026
Base automatically changed from agents/rule-query-and-agent-shell to main June 14, 2026 00:13
@canalesb93

Copy link
Copy Markdown
Owner Author

Closing — the decision changed: we want merchant_summary removed and scrubbed, not restored. A better merchant-data offering is planned for the future, so the phantom references are being cleaned up instead (separate PR off main). See follow-up.

@canalesb93 canalesb93 closed this Jun 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stack/agents-tooling PRs in the agents-tooling stack stacked Part of a Graphite stacked PR (filter-friendly)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant