@cyanheads/openfec-mcp-server 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CLAUDE.md +59 -24
  2. package/README.md +2 -2
  3. package/dist/mcp-server/resources/definitions/candidate.resource.d.ts +7 -1
  4. package/dist/mcp-server/resources/definitions/candidate.resource.d.ts.map +1 -1
  5. package/dist/mcp-server/resources/definitions/candidate.resource.js +15 -2
  6. package/dist/mcp-server/resources/definitions/candidate.resource.js.map +1 -1
  7. package/dist/mcp-server/resources/definitions/committee.resource.d.ts +7 -1
  8. package/dist/mcp-server/resources/definitions/committee.resource.d.ts.map +1 -1
  9. package/dist/mcp-server/resources/definitions/committee.resource.js +17 -2
  10. package/dist/mcp-server/resources/definitions/committee.resource.js.map +1 -1
  11. package/dist/mcp-server/resources/definitions/election.resource.d.ts +3 -3
  12. package/dist/mcp-server/resources/definitions/election.resource.d.ts.map +1 -1
  13. package/dist/mcp-server/resources/definitions/index.d.ts +13 -3
  14. package/dist/mcp-server/resources/definitions/index.d.ts.map +1 -1
  15. package/dist/mcp-server/tools/definitions/index.d.ts +59 -9
  16. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  17. package/dist/mcp-server/tools/definitions/lookup-calendar.tool.d.ts +1 -1
  18. package/dist/mcp-server/tools/definitions/lookup-calendar.tool.d.ts.map +1 -1
  19. package/dist/mcp-server/tools/definitions/lookup-elections.tool.d.ts +22 -1
  20. package/dist/mcp-server/tools/definitions/lookup-elections.tool.d.ts.map +1 -1
  21. package/dist/mcp-server/tools/definitions/lookup-elections.tool.js +43 -5
  22. package/dist/mcp-server/tools/definitions/lookup-elections.tool.js.map +1 -1
  23. package/dist/mcp-server/tools/definitions/search-candidates.tool.d.ts +7 -1
  24. package/dist/mcp-server/tools/definitions/search-candidates.tool.d.ts.map +1 -1
  25. package/dist/mcp-server/tools/definitions/search-candidates.tool.js +11 -2
  26. package/dist/mcp-server/tools/definitions/search-candidates.tool.js.map +1 -1
  27. package/dist/mcp-server/tools/definitions/search-committees.tool.d.ts +7 -1
  28. package/dist/mcp-server/tools/definitions/search-committees.tool.d.ts.map +1 -1
  29. package/dist/mcp-server/tools/definitions/search-committees.tool.js +11 -2
  30. package/dist/mcp-server/tools/definitions/search-committees.tool.js.map +1 -1
  31. package/dist/mcp-server/tools/definitions/search-contributions.tool.d.ts +12 -1
  32. package/dist/mcp-server/tools/definitions/search-contributions.tool.d.ts.map +1 -1
  33. package/dist/mcp-server/tools/definitions/search-contributions.tool.js +19 -3
  34. package/dist/mcp-server/tools/definitions/search-contributions.tool.js.map +1 -1
  35. package/dist/mcp-server/tools/definitions/search-disbursements.tool.d.ts +1 -1
  36. package/dist/mcp-server/tools/definitions/search-disbursements.tool.d.ts.map +1 -1
  37. package/dist/mcp-server/tools/definitions/search-expenditures.tool.d.ts +7 -1
  38. package/dist/mcp-server/tools/definitions/search-expenditures.tool.d.ts.map +1 -1
  39. package/dist/mcp-server/tools/definitions/search-expenditures.tool.js +13 -2
  40. package/dist/mcp-server/tools/definitions/search-expenditures.tool.js.map +1 -1
  41. package/dist/mcp-server/tools/definitions/search-filings.tool.d.ts +1 -1
  42. package/dist/mcp-server/tools/definitions/search-filings.tool.d.ts.map +1 -1
  43. package/dist/mcp-server/tools/definitions/search-legal.tool.d.ts +7 -1
  44. package/dist/mcp-server/tools/definitions/search-legal.tool.d.ts.map +1 -1
  45. package/dist/mcp-server/tools/definitions/search-legal.tool.js +10 -2
  46. package/dist/mcp-server/tools/definitions/search-legal.tool.js.map +1 -1
  47. package/dist/mcp-server/tools/definitions/utils/id-validators.d.ts +2 -2
  48. package/dist/mcp-server/tools/definitions/utils/id-validators.d.ts.map +1 -1
  49. package/dist/mcp-server/tools/definitions/utils/id-validators.js +5 -5
  50. package/dist/mcp-server/tools/definitions/utils/id-validators.js.map +1 -1
  51. package/package.json +8 -9
  52. package/server.json +3 -3
package/CLAUDE.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Agent Protocol
2
2
 
3
3
  **Server:** openfec-mcp-server
4
- **Version:** 0.4.1
5
- **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)
4
+ **Version:** 0.4.2
5
+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.8.19`
6
+ **Engines:** Bun ≥1.3.0, Node ≥24.0.0
6
7
 
7
8
  > **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
8
9
 
@@ -35,7 +36,7 @@ The OpenFEC OpenAPI spec (Swagger 2.0) is at `docs/openapi-spec.json` — 100 pa
35
36
 
36
37
  ## Core Rules
37
38
 
38
- - **Logic throws, framework catches.** Tool/resource handlers are pure — throw on failure, no `try/catch`. Plain `Error` is fine; the framework catches, classifies, and formats. Use error factories (`notFound()`, `validationError()`, etc.) when the error code matters.
39
+ - **Logic throws, framework catches.** Tool/resource handlers are pure — throw on failure, no `try/catch`. Prefer typed contracts (`errors[]` + `ctx.fail(reason)`) when the failure is part of the public surface; fall back to error factories (`notFound()`, `validationError()`) or plain `Error` otherwise. The framework catches, classifies, and formats.
39
40
  - **Use `ctx.log`** for request-scoped logging. No `console` calls.
40
41
  - **Use `ctx.state`** for tenant-scoped storage. Never access persistence directly.
41
42
  - **Check `ctx.elicit` / `ctx.sample`** for presence before calling.
@@ -49,12 +50,24 @@ The OpenFEC OpenAPI spec (Swagger 2.0) is at `docs/openapi-spec.json` — 100 pa
49
50
 
50
51
  ```ts
51
52
  import { tool, z } from '@cyanheads/mcp-ts-core';
52
- import { invalidParams } from '@cyanheads/mcp-ts-core/errors';
53
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
53
54
  import { getOpenFecService } from '@/services/openfec/openfec-service.js';
55
+ import { validateCandidateId } from './utils/id-validators.js';
54
56
 
55
57
  export const searchCandidates = tool('openfec_search_candidates', {
56
58
  description: 'Find federal candidates by name, state, office, party, or cycle.',
57
59
  annotations: { readOnlyHint: true, idempotentHint: true },
60
+
61
+ errors: [
62
+ {
63
+ reason: 'candidate_not_found',
64
+ code: JsonRpcErrorCode.NotFound,
65
+ when: 'Single-candidate lookup by candidate_id returned no record',
66
+ recovery:
67
+ 'Verify the candidate_id format (H/S/P + digits) or drop it and search by name, state, or cycle.',
68
+ },
69
+ ],
70
+
58
71
  input: z.object({
59
72
  query: z.string().optional().describe('Full-text candidate name search.'),
60
73
  candidate_id: z.string().optional().describe('FEC candidate ID (e.g., P00003392).'),
@@ -68,10 +81,14 @@ export const searchCandidates = tool('openfec_search_candidates', {
68
81
  }),
69
82
  async handler(input, ctx) {
70
83
  const fec = getOpenFecService();
71
- if (input.candidate_id && !/^[HSP]\d+$/i.test(input.candidate_id)) {
72
- throw invalidParams('Invalid candidate ID format', { candidate_id: input.candidate_id });
73
- }
84
+ if (input.candidate_id) validateCandidateId(input.candidate_id);
74
85
  const result = await fec.searchCandidates(input, ctx);
86
+ if (input.candidate_id && result.candidates.length === 0) {
87
+ throw ctx.fail('candidate_not_found', `Candidate ${input.candidate_id} not found.`, {
88
+ candidate_id: input.candidate_id,
89
+ ...ctx.recoveryFor('candidate_not_found'),
90
+ });
91
+ }
75
92
  ctx.log.info('Candidate search completed', { count: result.pagination.count });
76
93
  return result;
77
94
  },
@@ -169,24 +186,38 @@ Handlers receive a unified `ctx` object. Key properties:
169
186
 
170
187
  ## Errors
171
188
 
172
- Handlers throw — the framework catches, classifies, and formats. Three escalation levels:
189
+ Handlers throw — the framework catches, classifies, and formats.
190
+
191
+ **Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()`. The handler then receives `ctx.fail(reason, msg?, data?)` keyed against the contract reason union — `ctx.fail('typo')` is a TypeScript error. The framework auto-populates `data.reason`, the linter enforces conformance, and the `recovery` string (≥5 words) is the source of truth for the recovery hint that flows to the wire. Spread `ctx.recoveryFor('reason')` into `data` to opt the contract recovery onto the wire payload.
173
192
 
174
193
  ```ts
175
- // 1. Plain Error — framework auto-classifies from message patterns
176
- throw new Error('Item not found'); // NotFound
177
- throw new Error('Invalid query format'); // ValidationError
194
+ errors: [
195
+ { reason: 'candidate_not_found', code: JsonRpcErrorCode.NotFound,
196
+ when: 'Single-candidate lookup returned no record',
197
+ recovery: 'Verify the candidate_id (H/S/P + digits) or drop it and search by name.' },
198
+ ],
199
+ async handler(input, ctx) {
200
+ if (!found) {
201
+ throw ctx.fail('candidate_not_found', `Candidate ${id} not found.`, {
202
+ candidate_id: id,
203
+ ...ctx.recoveryFor('candidate_not_found'),
204
+ });
205
+ }
206
+ }
207
+ ```
178
208
 
179
- // 2. Error factoriesexplicit code, concise
180
- import { notFound, validationError, forbidden, serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
181
- throw notFound('Item not found', { itemId });
182
- throw serviceUnavailable('API unavailable', { url }, { cause: err });
209
+ **Declare contracts inline on each tool**, even when reasons look similar across tools per-tool repetition is the intended cost of locality.
183
210
 
184
- // 3. McpError full control over code and data
185
- import { McpError, JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
186
- throw new McpError(JsonRpcErrorCode.DatabaseError, 'Connection failed', { pool: 'primary' });
211
+ **Fallback (no contract entry fits):** error factories or plain `Error`. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`) bubble freely without contract entries.
212
+
213
+ ```ts
214
+ import { notFound, validationError, serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
215
+ throw validationError('Invalid query format', { field: 'query' }); // baseline — fine
216
+ throw serviceUnavailable('API unavailable', { url }, { cause: err });
217
+ throw new Error('Item not found'); // auto-classifies → NotFound
187
218
  ```
188
219
 
189
- Plain `Error` is fine for most cases. Use factories when the error code matters. See framework CLAUDE.md for the full auto-classification table and all available factories.
220
+ Note: `invalidParams` is for malformed JSON-RPC params (rare post-Zod). For semantic post-shape validation, use `validationError`. See the framework `api-errors` skill for the full reference.
190
221
 
191
222
  ---
192
223
 
@@ -253,6 +284,7 @@ Available skills:
253
284
  | `add-service` | Scaffold a new service integration |
254
285
  | `add-test` | Scaffold test file for a tool, resource, or service |
255
286
  | `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
287
+ | `tool-defs-analysis` | Read-only audit of definition language across the surface (10 categories: voice, leaks, defaults, recovery, structure, …) |
256
288
  | `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
257
289
  | `devcheck` | Lint, format, typecheck, audit |
258
290
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
@@ -262,13 +294,15 @@ Available skills:
262
294
  | `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
263
295
  | `report-issue-local` | File a bug or feature request against this server's own repo via `gh` CLI |
264
296
  | `api-auth` | Auth modes, scopes, JWT/OAuth |
297
+ | `api-canvas` | DataCanvas: register tabular data, run SQL, export, plus the `spillover()` helper for big result sets — Tier 3 opt-in |
265
298
  | `api-config` | AppConfig, parseConfig, env vars |
266
- | `api-context` | Context interface, logger, state, progress |
267
- | `api-errors` | McpError, JsonRpcErrorCode, error patterns |
299
+ | `api-context` | Context interface, logger, state, progress, sessionId, recoveryFor |
300
+ | `api-errors` | McpError, JsonRpcErrorCode, typed error contracts, factories |
268
301
  | `api-linter` | MCP definition lint rules reference — look here when devcheck flags `format-parity`, `schema-*`, `name-*`, `server-json-*`, etc. |
269
302
  | `api-services` | LLM, Speech, Graph services |
303
+ | `api-telemetry` | OTel catalog: spans, metrics, completion logs, env config, cardinality rules |
270
304
  | `api-testing` | createMockContext, test patterns |
271
- | `api-utils` | Formatting, parsing, security, pagination, scheduling |
305
+ | `api-utils` | Formatting, parsing, security, pagination, scheduling, telemetry helpers |
272
306
  | `api-workers` | Cloudflare Workers runtime |
273
307
 
274
308
  When you complete a skill's checklist, check the boxes and add a completion timestamp at the end (e.g., `Completed: 2026-03-11`).
@@ -287,11 +321,12 @@ When you complete a skill's checklist, check the boxes and add a completion time
287
321
  | `bun run format` | Auto-fix formatting |
288
322
  | `bun run lint:mcp` | Validate MCP tool/resource/prompt definitions |
289
323
  | `bun run test` | Run tests |
290
- | `bun run dev:stdio` | Dev mode (stdio) |
291
- | `bun run dev:http` | Dev mode (HTTP) |
324
+ | `bun run start` | Production mode (transport from `MCP_TRANSPORT_TYPE`) |
292
325
  | `bun run start:stdio` | Production mode (stdio) |
293
326
  | `bun run start:http` | Production mode (HTTP) |
294
327
 
328
+ For dev / smoke-testing, use `bun run rebuild && bun run start:stdio` (or `start:http`) — production-shape execution against the built `dist/`.
329
+
295
330
  ---
296
331
 
297
332
  ## Publishing
package/README.md CHANGED
@@ -6,9 +6,9 @@
6
6
 
7
7
  <div align="center">
8
8
 
9
- [![npm](https://img.shields.io/npm/v/@cyanheads/openfec-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/openfec-mcp-server) [![Version](https://img.shields.io/badge/Version-0.4.1-blue.svg?style=flat-square)](./CHANGELOG.md) [![Framework](https://img.shields.io/badge/Built%20on-@cyanheads/mcp--ts--core-259?style=flat-square)](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.29.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/)
9
+ [![npm](https://img.shields.io/npm/v/@cyanheads/openfec-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/openfec-mcp-server) [![Version](https://img.shields.io/badge/Version-0.4.2-blue.svg?style=flat-square)](./CHANGELOG.md) [![Framework](https://img.shields.io/badge/Built%20on-@cyanheads/mcp--ts--core-259?style=flat-square)](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.29.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/)
10
10
 
11
- [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![TypeScript](https://img.shields.io/badge/TypeScript-^6.0.3-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-^1.2.0-f9f1e1.svg?style=flat-square)](https://bun.sh/)
11
+ [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![TypeScript](https://img.shields.io/badge/TypeScript-^6.0.3-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-^1.3.0-f9f1e1.svg?style=flat-square)](https://bun.sh/)
12
12
 
13
13
  </div>
14
14
 
@@ -4,7 +4,13 @@
4
4
  * @module src/mcp-server/resources/definitions/candidate.resource
5
5
  */
6
6
  import { z } from '@cyanheads/mcp-ts-core';
7
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
8
  export declare const candidateResource: import("@cyanheads/mcp-ts-core").ResourceDefinition<z.ZodObject<{
8
9
  candidate_id: z.ZodString;
9
- }, z.core.$strip>, undefined>;
10
+ }, z.core.$strip>, undefined, readonly [{
11
+ readonly reason: "candidate_not_found";
12
+ readonly code: JsonRpcErrorCode.NotFound;
13
+ readonly when: "No candidate exists for the supplied candidate_id";
14
+ readonly recovery: "Verify the candidate_id format (H/S/P + digits) or look up the candidate by name via openfec_search_candidates.";
15
+ }]>;
10
16
  //# sourceMappingURL=candidate.resource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"candidate.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/candidate.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAIrD,eAAO,MAAM,iBAAiB;;6BAuB5B,CAAC"}
1
+ {"version":3,"file":"candidate.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/candidate.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,iBAAiB;;;;;;;GAsC5B,CAAC"}
@@ -4,6 +4,7 @@
4
4
  * @module src/mcp-server/resources/definitions/candidate.resource
5
5
  */
6
6
  import { resource, z } from '@cyanheads/mcp-ts-core';
7
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
8
  import { validateCandidateId } from '../../../mcp-server/tools/definitions/utils/id-validators.js';
8
9
  import { getOpenFecService } from '../../../services/openfec/openfec-service.js';
9
10
  export const candidateResource = resource('openfec://candidate/{candidate_id}', {
@@ -13,13 +14,25 @@ export const candidateResource = resource('openfec://candidate/{candidate_id}',
13
14
  params: z.object({
14
15
  candidate_id: z.string().describe('FEC candidate ID (e.g., P00003392, H2CO07170, S4AZ00345)'),
15
16
  }),
17
+ errors: [
18
+ {
19
+ reason: 'candidate_not_found',
20
+ code: JsonRpcErrorCode.NotFound,
21
+ when: 'No candidate exists for the supplied candidate_id',
22
+ recovery: 'Verify the candidate_id format (H/S/P + digits) or look up the candidate by name via openfec_search_candidates.',
23
+ },
24
+ ],
16
25
  async handler(params, ctx) {
17
26
  validateCandidateId(params.candidate_id);
18
27
  const fec = getOpenFecService();
19
28
  const candidateResult = await fec.getCandidate(params.candidate_id, ctx);
20
29
  const candidate = candidateResult.results[0];
21
- if (!candidate)
22
- throw new Error(`Candidate ${params.candidate_id} not found`);
30
+ if (!candidate) {
31
+ throw ctx.fail('candidate_not_found', `Candidate ${params.candidate_id} not found.`, {
32
+ candidate_id: params.candidate_id,
33
+ ...ctx.recoveryFor('candidate_not_found'),
34
+ });
35
+ }
23
36
  const totalsResult = await fec.getCandidateTotals({ candidate_id: params.candidate_id }, ctx);
24
37
  const totals = totalsResult.results[0];
25
38
  ctx.log.info('Candidate resource fetched', { candidate_id: params.candidate_id });
@@ -1 +1 @@
1
- {"version":3,"file":"candidate.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/candidate.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uDAAuD,CAAC;AAC5F,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAE1E,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,oCAAoC,EAAE;IAC9E,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACT,uJAAuJ;IACzJ,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0DAA0D,CAAC;KAC9F,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG;QACvB,mBAAmB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAEzC,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;QAChC,MAAM,eAAe,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QACzE,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,MAAM,CAAC,YAAY,YAAY,CAAC,CAAC;QAE9E,MAAM,YAAY,GAAG,MAAM,GAAG,CAAC,kBAAkB,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9F,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAEvC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QAClF,OAAO,EAAE,GAAG,SAAS,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;IAC7C,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"candidate.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/candidate.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uDAAuD,CAAC;AAC5F,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAE1E,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,oCAAoC,EAAE;IAC9E,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACT,uJAAuJ;IACzJ,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0DAA0D,CAAC;KAC9F,CAAC;IAEF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,qBAAqB;YAC7B,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,mDAAmD;YACzD,QAAQ,EACN,iHAAiH;SACpH;KACF;IAED,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG;QACvB,mBAAmB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAEzC,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;QAChC,MAAM,eAAe,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QACzE,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,GAAG,CAAC,IAAI,CAAC,qBAAqB,EAAE,aAAa,MAAM,CAAC,YAAY,aAAa,EAAE;gBACnF,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,GAAG,GAAG,CAAC,WAAW,CAAC,qBAAqB,CAAC;aAC1C,CAAC,CAAC;QACL,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,GAAG,CAAC,kBAAkB,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9F,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAEvC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QAClF,OAAO,EAAE,GAAG,SAAS,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;IAC7C,CAAC;CACF,CAAC,CAAC"}
@@ -4,7 +4,13 @@
4
4
  * @module src/mcp-server/resources/definitions/committee.resource
5
5
  */
6
6
  import { z } from '@cyanheads/mcp-ts-core';
7
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
8
  export declare const committeeResource: import("@cyanheads/mcp-ts-core").ResourceDefinition<z.ZodObject<{
8
9
  committee_id: z.ZodString;
9
- }, z.core.$strip>, undefined>;
10
+ }, z.core.$strip>, undefined, readonly [{
11
+ readonly reason: "committee_not_found";
12
+ readonly code: JsonRpcErrorCode.NotFound;
13
+ readonly when: "No committee exists for the supplied committee_id";
14
+ readonly recovery: "Verify the committee_id format (C + digits) or look up the committee by name via openfec_search_committees.";
15
+ }]>;
10
16
  //# sourceMappingURL=committee.resource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"committee.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/committee.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAGrD,eAAO,MAAM,iBAAiB;;6BAkB5B,CAAC"}
1
+ {"version":3,"file":"committee.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/committee.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,iBAAiB;;;;;;;GAmC5B,CAAC"}
@@ -4,6 +4,8 @@
4
4
  * @module src/mcp-server/resources/definitions/committee.resource
5
5
  */
6
6
  import { resource, z } from '@cyanheads/mcp-ts-core';
7
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
8
+ import { validateCommitteeId } from '../../../mcp-server/tools/definitions/utils/id-validators.js';
7
9
  import { getOpenFecService } from '../../../services/openfec/openfec-service.js';
8
10
  export const committeeResource = resource('openfec://committee/{committee_id}', {
9
11
  name: 'FEC Committee Profile',
@@ -12,12 +14,25 @@ export const committeeResource = resource('openfec://committee/{committee_id}',
12
14
  params: z.object({
13
15
  committee_id: z.string().describe('FEC committee ID (e.g., C00358796)'),
14
16
  }),
17
+ errors: [
18
+ {
19
+ reason: 'committee_not_found',
20
+ code: JsonRpcErrorCode.NotFound,
21
+ when: 'No committee exists for the supplied committee_id',
22
+ recovery: 'Verify the committee_id format (C + digits) or look up the committee by name via openfec_search_committees.',
23
+ },
24
+ ],
15
25
  async handler(params, ctx) {
26
+ validateCommitteeId(params.committee_id);
16
27
  const fec = getOpenFecService();
17
28
  const result = await fec.getCommittee(params.committee_id, ctx);
18
29
  const committee = result.results[0];
19
- if (!committee)
20
- throw new Error(`Committee ${params.committee_id} not found`);
30
+ if (!committee) {
31
+ throw ctx.fail('committee_not_found', `Committee ${params.committee_id} not found.`, {
32
+ committee_id: params.committee_id,
33
+ ...ctx.recoveryFor('committee_not_found'),
34
+ });
35
+ }
21
36
  ctx.log.info('Committee resource fetched', { committee_id: params.committee_id });
22
37
  return committee;
23
38
  },
@@ -1 +1 @@
1
- {"version":3,"file":"committee.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/committee.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAE1E,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,oCAAoC,EAAE;IAC9E,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACT,qJAAqJ;IACvJ,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;KACxE,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG;QACvB,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QAChE,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,MAAM,CAAC,YAAY,YAAY,CAAC,CAAC;QAE9E,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QAClF,OAAO,SAAS,CAAC;IACnB,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"committee.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/committee.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uDAAuD,CAAC;AAC5F,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAE1E,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,oCAAoC,EAAE;IAC9E,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACT,qJAAqJ;IACvJ,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;KACxE,CAAC;IAEF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,qBAAqB;YAC7B,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,mDAAmD;YACzD,QAAQ,EACN,6GAA6G;SAChH;KACF;IAED,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG;QACvB,mBAAmB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAEzC,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QAChE,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,GAAG,CAAC,IAAI,CAAC,qBAAqB,EAAE,aAAa,MAAM,CAAC,YAAY,aAAa,EAAE;gBACnF,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,GAAG,GAAG,CAAC,WAAW,CAAC,qBAAqB,CAAC;aAC1C,CAAC,CAAC;QACL,CAAC;QAED,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QAClF,OAAO,SAAS,CAAC;IACnB,CAAC;CACF,CAAC,CAAC"}
@@ -8,18 +8,18 @@ import { z } from '@cyanheads/mcp-ts-core';
8
8
  export declare const electionResource: import("@cyanheads/mcp-ts-core").ResourceDefinition<z.ZodObject<{
9
9
  cycle: z.ZodString;
10
10
  office: z.ZodString;
11
- }, z.core.$strip>, undefined>;
11
+ }, z.core.$strip>, undefined, undefined>;
12
12
  /** Senate races: openfec://election/2024/senate/AZ */
13
13
  export declare const electionStateResource: import("@cyanheads/mcp-ts-core").ResourceDefinition<z.ZodObject<{
14
14
  cycle: z.ZodString;
15
15
  office: z.ZodString;
16
16
  state: z.ZodString;
17
- }, z.core.$strip>, undefined>;
17
+ }, z.core.$strip>, undefined, undefined>;
18
18
  /** House races: openfec://election/2024/house/CA/12 */
19
19
  export declare const electionDistrictResource: import("@cyanheads/mcp-ts-core").ResourceDefinition<z.ZodObject<{
20
20
  cycle: z.ZodString;
21
21
  office: z.ZodString;
22
22
  state: z.ZodString;
23
23
  district: z.ZodString;
24
- }, z.core.$strip>, undefined>;
24
+ }, z.core.$strip>, undefined, undefined>;
25
25
  //# sourceMappingURL=election.resource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"election.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/election.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAmCrD,yEAAyE;AACzE,eAAO,MAAM,gBAAgB;;;6BAU3B,CAAC;AAEH,sDAAsD;AACtD,eAAO,MAAM,qBAAqB;;;;6BAUhC,CAAC;AAEH,uDAAuD;AACvD,eAAO,MAAM,wBAAwB;;;;;6BAcpC,CAAC"}
1
+ {"version":3,"file":"election.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/election.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAmCrD,yEAAyE;AACzE,eAAO,MAAM,gBAAgB;;;wCAU3B,CAAC;AAEH,sDAAsD;AACtD,eAAO,MAAM,qBAAqB;;;;wCAUhC,CAAC;AAEH,uDAAuD;AACvD,eAAO,MAAM,wBAAwB;;;;;wCAcpC,CAAC"}
@@ -7,10 +7,20 @@ export { committeeResource } from './committee.resource.js';
7
7
  export { electionDistrictResource, electionResource, electionStateResource, } from './election.resource.js';
8
8
  export declare const allResourceDefinitions: (import("@cyanheads/mcp-ts-core").ResourceDefinition<import("zod").ZodObject<{
9
9
  candidate_id: import("zod").ZodString;
10
- }, import("zod/v4/core").$strip>, undefined> | import("@cyanheads/mcp-ts-core").ResourceDefinition<import("zod").ZodObject<{
10
+ }, import("zod/v4/core").$strip>, undefined, readonly [{
11
+ readonly reason: "candidate_not_found";
12
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
13
+ readonly when: "No candidate exists for the supplied candidate_id";
14
+ readonly recovery: "Verify the candidate_id format (H/S/P + digits) or look up the candidate by name via openfec_search_candidates.";
15
+ }]> | import("@cyanheads/mcp-ts-core").ResourceDefinition<import("zod").ZodObject<{
11
16
  committee_id: import("zod").ZodString;
12
- }, import("zod/v4/core").$strip>, undefined> | import("@cyanheads/mcp-ts-core").ResourceDefinition<import("zod").ZodObject<{
17
+ }, import("zod/v4/core").$strip>, undefined, readonly [{
18
+ readonly reason: "committee_not_found";
19
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
20
+ readonly when: "No committee exists for the supplied committee_id";
21
+ readonly recovery: "Verify the committee_id format (C + digits) or look up the committee by name via openfec_search_committees.";
22
+ }]> | import("@cyanheads/mcp-ts-core").ResourceDefinition<import("zod").ZodObject<{
13
23
  cycle: import("zod").ZodString;
14
24
  office: import("zod").ZodString;
15
- }, import("zod/v4/core").$strip>, undefined>)[];
25
+ }, import("zod/v4/core").$strip>, undefined, undefined>)[];
16
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAUhC,eAAO,MAAM,sBAAsB;;;;;;;+CAMlC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAUhC,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;0DAMlC,CAAC"}
@@ -41,7 +41,7 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
41
41
  per_page: import("zod").ZodNumber;
42
42
  }, import("zod/v4/core").$strip>;
43
43
  search_criteria: import("zod").ZodOptional<import("zod").ZodObject<{}, import("zod/v4/core").$loose>>;
44
- }, import("zod/v4/core").$strip>> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
44
+ }, import("zod/v4/core").$strip>, undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
45
45
  mode: import("zod").ZodDefault<import("zod").ZodEnum<{
46
46
  summary: "summary";
47
47
  search: "search";
@@ -65,7 +65,27 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
65
65
  per_page: import("zod").ZodNumber;
66
66
  }, import("zod/v4/core").$strip>;
67
67
  search_criteria: import("zod").ZodOptional<import("zod").ZodObject<{}, import("zod/v4/core").$loose>>;
68
- }, import("zod/v4/core").$strip>> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
68
+ }, import("zod/v4/core").$strip>, readonly [{
69
+ readonly reason: "cycle_must_be_even";
70
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
71
+ readonly when: "Cycle is an odd year";
72
+ readonly recovery: "Federal election cycles are two-year periods ending in even years (e.g., 2024, 2026).";
73
+ }, {
74
+ readonly reason: "missing_state_for_office";
75
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
76
+ readonly when: "Senate or House office without a state and without a zip";
77
+ readonly recovery: "Provide a two-letter state code (e.g., AZ) or a zip code to scope the senate or house race.";
78
+ }, {
79
+ readonly reason: "missing_district_for_house";
80
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
81
+ readonly when: "House office without a district number and without a zip";
82
+ readonly recovery: "Provide a two-digit district number (e.g., \"07\") or a zip code to identify the House race.";
83
+ }, {
84
+ readonly reason: "summary_does_not_support_zip";
85
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
86
+ readonly when: "Summary mode invoked with a zip parameter";
87
+ readonly recovery: "Use mode \"search\" for ZIP-based lookups, or remove zip and use state and district for summary mode.";
88
+ }]> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
69
89
  query: import("zod").ZodOptional<import("zod").ZodString>;
70
90
  candidate_id: import("zod").ZodOptional<import("zod").ZodString>;
71
91
  state: import("zod").ZodOptional<import("zod").ZodString>;
@@ -103,7 +123,12 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
103
123
  per_page: import("zod").ZodNumber;
104
124
  }, import("zod/v4/core").$strip>;
105
125
  search_criteria: import("zod").ZodOptional<import("zod").ZodObject<{}, import("zod/v4/core").$loose>>;
106
- }, import("zod/v4/core").$strip>> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
126
+ }, import("zod/v4/core").$strip>, readonly [{
127
+ readonly reason: "candidate_not_found";
128
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
129
+ readonly when: "Single-candidate lookup by candidate_id returned no record";
130
+ readonly recovery: "Verify the candidate_id format (H/S/P + digits) or drop it and search by name, state, or cycle.";
131
+ }]> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
107
132
  query: import("zod").ZodOptional<import("zod").ZodString>;
108
133
  committee_id: import("zod").ZodOptional<import("zod").ZodString>;
109
134
  candidate_id: import("zod").ZodOptional<import("zod").ZodString>;
@@ -124,7 +149,12 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
124
149
  per_page: import("zod").ZodNumber;
125
150
  }, import("zod/v4/core").$strip>;
126
151
  search_criteria: import("zod").ZodOptional<import("zod").ZodObject<{}, import("zod/v4/core").$loose>>;
127
- }, import("zod/v4/core").$strip>> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
152
+ }, import("zod/v4/core").$strip>, readonly [{
153
+ readonly reason: "committee_not_found";
154
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
155
+ readonly when: "Single-committee lookup by committee_id returned no record";
156
+ readonly recovery: "Verify the committee_id format (C + digits) or drop it and search by name, candidate_id, or type.";
157
+ }]> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
128
158
  mode: import("zod").ZodDefault<import("zod").ZodEnum<{
129
159
  by_size: "by_size";
130
160
  by_state: "by_state";
@@ -163,7 +193,17 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
163
193
  per_page: import("zod").ZodNumber;
164
194
  }, import("zod/v4/core").$strip>>;
165
195
  search_criteria: import("zod").ZodOptional<import("zod").ZodObject<{}, import("zod/v4/core").$loose>>;
166
- }, import("zod/v4/core").$strip>> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
196
+ }, import("zod/v4/core").$strip>, readonly [{
197
+ readonly reason: "itemized_requires_committee_id";
198
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
199
+ readonly when: "Itemized mode invoked without a committee_id";
200
+ readonly recovery: "Provide a committee_id, switch to a by_size or by_state aggregate mode with candidate_id, or look up the candidate's committee with openfec_search_committees.";
201
+ }, {
202
+ readonly reason: "aggregate_requires_committee_id";
203
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
204
+ readonly when: "by_employer or by_occupation aggregate without a committee_id";
205
+ readonly recovery: "These aggregates roll up to a single committee — provide a committee_id for the spending committee.";
206
+ }]> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
167
207
  mode: import("zod").ZodDefault<import("zod").ZodEnum<{
168
208
  by_purpose: "by_purpose";
169
209
  by_recipient: "by_recipient";
@@ -199,7 +239,7 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
199
239
  per_page: import("zod").ZodNumber;
200
240
  }, import("zod/v4/core").$strip>>;
201
241
  search_criteria: import("zod").ZodOptional<import("zod").ZodObject<{}, import("zod/v4/core").$loose>>;
202
- }, import("zod/v4/core").$strip>> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
242
+ }, import("zod/v4/core").$strip>, undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
203
243
  mode: import("zod").ZodDefault<import("zod").ZodEnum<{
204
244
  itemized: "itemized";
205
245
  by_candidate: "by_candidate";
@@ -243,7 +283,12 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
243
283
  per_page: import("zod").ZodNumber;
244
284
  }, import("zod/v4/core").$strip>>;
245
285
  search_criteria: import("zod").ZodOptional<import("zod").ZodObject<{}, import("zod/v4/core").$loose>>;
246
- }, import("zod/v4/core").$strip>> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
286
+ }, import("zod/v4/core").$strip>, readonly [{
287
+ readonly reason: "by_candidate_requires_candidate_id";
288
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
289
+ readonly when: "by_candidate mode invoked without a candidate_id";
290
+ readonly recovery: "Find the candidate ID via openfec_search_candidates, then pass it here to see independent expenditures supporting or opposing that candidate.";
291
+ }]> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
247
292
  committee_id: import("zod").ZodOptional<import("zod").ZodString>;
248
293
  candidate_id: import("zod").ZodOptional<import("zod").ZodString>;
249
294
  filer_name: import("zod").ZodOptional<import("zod").ZodString>;
@@ -266,7 +311,7 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
266
311
  per_page: import("zod").ZodNumber;
267
312
  }, import("zod/v4/core").$strip>;
268
313
  search_criteria: import("zod").ZodOptional<import("zod").ZodObject<{}, import("zod/v4/core").$loose>>;
269
- }, import("zod/v4/core").$strip>> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
314
+ }, import("zod/v4/core").$strip>, undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
270
315
  query: import("zod").ZodOptional<import("zod").ZodString>;
271
316
  type: import("zod").ZodOptional<import("zod").ZodEnum<{
272
317
  advisory_opinions: "advisory_opinions";
@@ -290,5 +335,10 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
290
335
  results: import("zod").ZodArray<import("zod").ZodObject<{}, import("zod/v4/core").$loose>>;
291
336
  total_count: import("zod").ZodNumber;
292
337
  search_criteria: import("zod").ZodOptional<import("zod").ZodObject<{}, import("zod/v4/core").$loose>>;
293
- }, import("zod/v4/core").$strip>>)[];
338
+ }, import("zod/v4/core").$strip>, readonly [{
339
+ readonly reason: "missing_filter";
340
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
341
+ readonly when: "Called without query, type, or a specific identifier (ao_number / case_number)";
342
+ readonly recovery: "Provide at least a search query, document type, or specific identifier (ao_number, case_number) to scope the legal search.";
343
+ }]>)[];
294
344
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAYrD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAU9B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAYrD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAU9B,CAAC"}
@@ -34,5 +34,5 @@ export declare const lookupCalendar: import("@cyanheads/mcp-ts-core").ToolDefini
34
34
  per_page: z.ZodNumber;
35
35
  }, z.core.$strip>;
36
36
  search_criteria: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
37
- }, z.core.$strip>>;
37
+ }, z.core.$strip>, undefined>;
38
38
  //# sourceMappingURL=lookup-calendar.tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lookup-calendar.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/lookup-calendar.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAUjD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAuJzB,CAAC"}
1
+ {"version":3,"file":"lookup-calendar.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/lookup-calendar.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAUjD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAuJzB,CAAC"}
@@ -4,6 +4,7 @@
4
4
  * @module mcp-server/tools/definitions/lookup-elections.tool
5
5
  */
6
6
  import { z } from '@cyanheads/mcp-ts-core';
7
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
8
  export declare const lookupElections: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
9
  mode: z.ZodDefault<z.ZodEnum<{
9
10
  summary: "summary";
@@ -28,5 +29,25 @@ export declare const lookupElections: import("@cyanheads/mcp-ts-core").ToolDefin
28
29
  per_page: z.ZodNumber;
29
30
  }, z.core.$strip>;
30
31
  search_criteria: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
31
- }, z.core.$strip>>;
32
+ }, z.core.$strip>, readonly [{
33
+ readonly reason: "cycle_must_be_even";
34
+ readonly code: JsonRpcErrorCode.ValidationError;
35
+ readonly when: "Cycle is an odd year";
36
+ readonly recovery: "Federal election cycles are two-year periods ending in even years (e.g., 2024, 2026).";
37
+ }, {
38
+ readonly reason: "missing_state_for_office";
39
+ readonly code: JsonRpcErrorCode.ValidationError;
40
+ readonly when: "Senate or House office without a state and without a zip";
41
+ readonly recovery: "Provide a two-letter state code (e.g., AZ) or a zip code to scope the senate or house race.";
42
+ }, {
43
+ readonly reason: "missing_district_for_house";
44
+ readonly code: JsonRpcErrorCode.ValidationError;
45
+ readonly when: "House office without a district number and without a zip";
46
+ readonly recovery: "Provide a two-digit district number (e.g., \"07\") or a zip code to identify the House race.";
47
+ }, {
48
+ readonly reason: "summary_does_not_support_zip";
49
+ readonly code: JsonRpcErrorCode.ValidationError;
50
+ readonly when: "Summary mode invoked with a zip parameter";
51
+ readonly recovery: "Use mode \"search\" for ZIP-based lookups, or remove zip and use state and district for summary mode.";
52
+ }]>;
32
53
  //# sourceMappingURL=lookup-elections.tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lookup-elections.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/lookup-elections.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAWjD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;kBA2J1B,CAAC"}
1
+ {"version":3,"file":"lookup-elections.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/lookup-elections.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAUjE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoM1B,CAAC"}