All nine tool handlers set search_criteria only when results are empty (results.length === 0 ? buildSearchCriteria(input) : undefined). Multi-mode tools (search-contributions, search-disbursements, search-expenditures) do not echo the resolved mode back in their response.
Without a query echo on non-empty responses, an agent cannot verify that its filters were applied as intended — e.g., a cycle defaulted from 2023 to 2024, or an aggregate mode silently resolved to a _candidate variant. Without a mode echo, an agent receiving a contributions response cannot confirm whether it got itemized records or an aggregate bucket, leading to misinterpretation of the result shape.
Proposal
Two related output schema changes that bring response surfaces inline with what agents need to self-verify.
Proposed behavior
1. Always populate search_criteria in every tool handler return statement, unconditionally:
// Current — only on empty
search_criteria: results.length === 0 ? buildSearchCriteria(input) : undefined,
// Proposed — always
search_criteria: buildSearchCriteria(input),
Applies to: search-candidates, search-committees, search-contributions, search-disbursements, search-expenditures, search-filings, lookup-elections, search-legal, lookup-calendar.
2. Echo resolved mode in multi-mode tool responses:
// search-contributions — aggregateMode already has the resolved variant ('by_size_candidate' etc.)
return {
results: result.results,
mode: aggregateMode, // or 'itemized'
pagination: result.pagination,
search_criteria: buildSearchCriteria(input),
};
// search-disbursements — mode variable available in handler scope
return {
results: result.results,
mode: mode, // 'itemized' | 'by_purpose' | 'by_recipient' | 'by_recipient_id'
...
};
// search-expenditures — mode variable available
return {
results: result.results,
mode: mode, // 'itemized' | 'by_candidate'
...
};
The mode field should be added to the output Zod schema of each affected tool (string literal or enum, with .describe()).
Scope
src/mcp-server/tools/definitions/search-candidates.tool.ts
src/mcp-server/tools/definitions/search-committees.tool.ts
src/mcp-server/tools/definitions/search-contributions.tool.ts (+ mode field)
src/mcp-server/tools/definitions/search-disbursements.tool.ts (+ mode field)
src/mcp-server/tools/definitions/search-expenditures.tool.ts (+ mode field)
src/mcp-server/tools/definitions/search-filings.tool.ts
src/mcp-server/tools/definitions/lookup-elections.tool.ts
src/mcp-server/tools/definitions/search-legal.tool.ts
src/mcp-server/tools/definitions/lookup-calendar.tool.ts
Out of scope
- Changing the
buildSearchCriteria implementation itself
- Adding mode echo to single-mode tools (they have no ambiguity)
Alternatives considered
Keeping search_criteria conditional preserves a slight payload reduction on non-empty responses, but the cost — agents being unable to verify applied filters — outweighs it. The field is already in the schema as optional; changing it to always-populated is non-breaking for consumers that handle the optional shape.
All nine tool handlers set
search_criteriaonly when results are empty (results.length === 0 ? buildSearchCriteria(input) : undefined). Multi-mode tools (search-contributions, search-disbursements, search-expenditures) do not echo the resolvedmodeback in their response.Without a query echo on non-empty responses, an agent cannot verify that its filters were applied as intended — e.g., a cycle defaulted from 2023 to 2024, or an aggregate mode silently resolved to a
_candidatevariant. Without a mode echo, an agent receiving a contributions response cannot confirm whether it got itemized records or an aggregate bucket, leading to misinterpretation of the result shape.Proposal
Two related output schema changes that bring response surfaces inline with what agents need to self-verify.
Proposed behavior
1. Always populate
search_criteriain every tool handler return statement, unconditionally:Applies to: search-candidates, search-committees, search-contributions, search-disbursements, search-expenditures, search-filings, lookup-elections, search-legal, lookup-calendar.
2. Echo resolved
modein multi-mode tool responses:The
modefield should be added to the output Zod schema of each affected tool (string literal or enum, with.describe()).Scope
src/mcp-server/tools/definitions/search-candidates.tool.tssrc/mcp-server/tools/definitions/search-committees.tool.tssrc/mcp-server/tools/definitions/search-contributions.tool.ts(+ mode field)src/mcp-server/tools/definitions/search-disbursements.tool.ts(+ mode field)src/mcp-server/tools/definitions/search-expenditures.tool.ts(+ mode field)src/mcp-server/tools/definitions/search-filings.tool.tssrc/mcp-server/tools/definitions/lookup-elections.tool.tssrc/mcp-server/tools/definitions/search-legal.tool.tssrc/mcp-server/tools/definitions/lookup-calendar.tool.tsOut of scope
buildSearchCriteriaimplementation itselfAlternatives considered
Keeping
search_criteriaconditional preserves a slight payload reduction on non-empty responses, but the cost — agents being unable to verify applied filters — outweighs it. The field is already in the schema as optional; changing it to always-populated is non-breaking for consumers that handle the optional shape.