@cliwant/mcp-sam-gov 0.2.1 → 0.3.0

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.
package/README.md CHANGED
@@ -1,11 +1,61 @@
1
+ <div align="center">
2
+
1
3
  # @cliwant/mcp-sam-gov
2
4
 
3
- > **The most comprehensive keyless federal-data MCP server.**
4
- > 36 tools for SAM.gov + USAspending + Federal Register + eCFR + Grants.gov.
5
- > No API key, no registration, no signup. Works in Claude Desktop, Claude Code,
6
- > Codex CLI, Cursor, Continue, Gemini CLI, and any MCP-aware host.
5
+ ### **$4 trillion of public federal data, one `npm install` away.**
6
+
7
+ The most comprehensive **keyless** MCP server for US federal contracting + spending + regulation. **36 tools** that work today, in any AI agent.
8
+
9
+ [![npm](https://img.shields.io/npm/v/@cliwant/mcp-sam-gov?color=cb3837&label=%40cliwant%2Fmcp-sam-gov&logo=npm)](https://www.npmjs.com/package/@cliwant/mcp-sam-gov)
10
+ [![mcp-registry](https://img.shields.io/badge/MCP%20Registry-active-2ea44f?logo=anthropic)](https://registry.modelcontextprotocol.io/v0/servers?search=cliwant)
11
+ [![Glama score](https://glama.ai/mcp/servers/cliwant/mcp-sam-gov/badges/score.svg)](https://glama.ai/mcp/servers/cliwant/mcp-sam-gov)
12
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
13
+ [![Daily smoke](https://github.com/cliwant/mcp-sam-gov/actions/workflows/daily-smoke.yml/badge.svg)](https://github.com/cliwant/mcp-sam-gov/actions/workflows/daily-smoke.yml)
14
+
15
+ [English](./README.md) · [한국어](./README.ko.md) · [日本語](./README.ja.md)
16
+
17
+ </div>
18
+
19
+ ---
20
+
21
+ ## See it in action
22
+
23
+ ```text
24
+ 👤 user Find active SAM.gov solicitations under NAICS 541512 closing this month
25
+
26
+ 🤖 Claude → sam_search_opportunities { ncode: "541512", limit: 5 }
27
+ ✓ 47,478 active opportunities indexed
28
+
29
+ • 5ef3db5d… VA Bulk Oxygen Tank Rental closes 2026-05-15 ($1.05M)
30
+ • a000339c… Articulating Boom Lifts closes 2026-05-30 ($310K)
31
+ • be9c24ef… CMOP Hazardous Waste Removal closes 2026-06-12 ($2.7M)
32
+
33
+ 👤 user Pull the SOW + contracting officer for the first one
34
+
35
+ 🤖 Claude → sam_get_opportunity { noticeId: "5ef3db5d…" }
36
+ ✓ Department of Veterans Affairs · Combined Synopsis/Solicitation
37
+ POC: Rebecca Gobble <rebecca.gobble@va.gov> +1-410-642-2411
38
+ Set-aside: Total Small Business
39
+ Attachments: 1 ↓ 36C24526Q0460_1.docx (172 KB)
40
+ SOW preview: "RFQ# 36C24526Q0460 — Bulk Oxygen Tank Rental, Fill, Telemetry…"
41
+ ```
42
+
43
+ **Zero API key. Zero registration. Zero signup.** Just plug it in and ask.
7
44
 
8
- [한국어 README](./README.ko.md) · [日本語 README](./README.ja.md)
45
+ ---
46
+
47
+ ## Why this exists
48
+
49
+ | Status quo | With this MCP |
50
+ |---|---|
51
+ | GovWin: $30K-$100K/yr per seat | Free, MIT license |
52
+ | API key registration → wait 24h → quota tier shopping | `npm install` → working in 60s |
53
+ | 5 separate vendor APIs / scrapers | 1 unified surface, 36 tools |
54
+ | LLMs hallucinate NAICS codes / agency names | Anti-hallucination autocomplete guards built-in |
55
+ | Brittle scraping breaks weekly | Daily live smoke test ([badge above](#)) |
56
+ | Procurement officer → IT ticket → 3-week wait | Claude Desktop double-click install |
57
+
58
+ The federal data this wraps is **public domain**. There is no good reason it should cost a five-figure subscription to query.
9
59
 
10
60
  ---
11
61
 
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Tiny in-memory TTL cache for hot, idempotent reads.
3
+ *
4
+ * Why this exists
5
+ * ----------------
6
+ * Some calls are extremely repeat-prone within a single agent
7
+ * conversation: `usas_lookup_agency("VA")`, `ecfr_list_titles()`,
8
+ * `fed_register_list_agencies()`, `usas_autocomplete_naics(...)`.
9
+ * The agent will call them five times in a row across different
10
+ * tool sequences. Each is a 250-700ms federal API hit.
11
+ *
12
+ * This cache is per-process (no Redis, no disk). Lives for the
13
+ * lifetime of the MCP server stdio session — typically minutes
14
+ * to hours. TTL is short enough that schema drift gets noticed
15
+ * within an hour.
16
+ *
17
+ * What we cache
18
+ * --------------
19
+ * - Reference lookups (agencies, NAICS hierarchy, glossary)
20
+ * - Autocomplete (idempotent for same query string)
21
+ * What we DON'T cache
22
+ * --------------------
23
+ * - Search results (volume changes; user expects freshness)
24
+ * - Per-opportunity / per-award detail (stale = wrong)
25
+ * - Anything with a date filter
26
+ */
27
+ /**
28
+ * Wrap an idempotent async producer in a TTL cache.
29
+ *
30
+ * const result = await memoize("usas:agency:VA", () => lookupAgency("VA"));
31
+ *
32
+ * Returns the cached value if fresh; otherwise computes + stores.
33
+ */
34
+ export declare function memoize<T>(key: string, producer: () => Promise<T>, ttlMs?: number): Promise<T>;
35
+ /** For tests / debug. */
36
+ export declare function _cacheStats(): {
37
+ size: number;
38
+ entries: string[];
39
+ };
40
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAQH;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,CAAC,EAC7B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC1B,KAAK,GAAE,MAAuB,GAC7B,OAAO,CAAC,CAAC,CAAC,CAWZ;AASD,yBAAyB;AACzB,wBAAgB,WAAW;;;EAE1B"}
package/dist/cache.js ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Tiny in-memory TTL cache for hot, idempotent reads.
3
+ *
4
+ * Why this exists
5
+ * ----------------
6
+ * Some calls are extremely repeat-prone within a single agent
7
+ * conversation: `usas_lookup_agency("VA")`, `ecfr_list_titles()`,
8
+ * `fed_register_list_agencies()`, `usas_autocomplete_naics(...)`.
9
+ * The agent will call them five times in a row across different
10
+ * tool sequences. Each is a 250-700ms federal API hit.
11
+ *
12
+ * This cache is per-process (no Redis, no disk). Lives for the
13
+ * lifetime of the MCP server stdio session — typically minutes
14
+ * to hours. TTL is short enough that schema drift gets noticed
15
+ * within an hour.
16
+ *
17
+ * What we cache
18
+ * --------------
19
+ * - Reference lookups (agencies, NAICS hierarchy, glossary)
20
+ * - Autocomplete (idempotent for same query string)
21
+ * What we DON'T cache
22
+ * --------------------
23
+ * - Search results (volume changes; user expects freshness)
24
+ * - Per-opportunity / per-award detail (stale = wrong)
25
+ * - Anything with a date filter
26
+ */
27
+ const store = new Map();
28
+ const DEFAULT_TTL_MS = 5 * 60 * 1000; // 5 minutes
29
+ /**
30
+ * Wrap an idempotent async producer in a TTL cache.
31
+ *
32
+ * const result = await memoize("usas:agency:VA", () => lookupAgency("VA"));
33
+ *
34
+ * Returns the cached value if fresh; otherwise computes + stores.
35
+ */
36
+ export async function memoize(key, producer, ttlMs = DEFAULT_TTL_MS) {
37
+ const now = Date.now();
38
+ const hit = store.get(key);
39
+ if (hit && hit.expiresAt > now) {
40
+ return hit.value;
41
+ }
42
+ const value = await producer();
43
+ store.set(key, { value, expiresAt: now + ttlMs });
44
+ // Light-touch GC: every 100 sets, sweep expired entries.
45
+ if (store.size % 100 === 0)
46
+ sweepExpired();
47
+ return value;
48
+ }
49
+ function sweepExpired() {
50
+ const now = Date.now();
51
+ for (const [k, v] of store) {
52
+ if (v.expiresAt <= now)
53
+ store.delete(k);
54
+ }
55
+ }
56
+ /** For tests / debug. */
57
+ export function _cacheStats() {
58
+ return { size: store.size, entries: [...store.keys()] };
59
+ }
60
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;AAEhD,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;AAElD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAW,EACX,QAA0B,EAC1B,QAAgB,cAAc;IAE9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC;QAC/B,OAAO,GAAG,CAAC,KAAU,CAAC;IACxB,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC/B,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC;IAClD,yDAAyD;IACzD,IAAI,KAAK,CAAC,IAAI,GAAG,GAAG,KAAK,CAAC;QAAE,YAAY,EAAE,CAAC;IAC3C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG;YAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,yBAAyB;AACzB,MAAM,UAAU,WAAW;IACzB,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;AAC1D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ecfr.d.ts","sourceRoot":"","sources":["../src/ecfr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAeH,wBAAsB,UAAU;;;;;;;;;GAsB/B;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;;;;;;;;;;;;;;GAkDA"}
1
+ {"version":3,"file":"ecfr.d.ts","sourceRoot":"","sources":["../src/ecfr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAmBH,wBAAsB,UAAU;;;;;;;;;GAyB/B;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;;;;;;;;;;;;;;GAkDA"}
package/dist/ecfr.js CHANGED
@@ -12,29 +12,31 @@
12
12
  *
13
13
  * Both keyless. Documented at https://www.ecfr.gov/developers/.
14
14
  */
15
+ import { fetchWithRetry } from "./errors.js";
16
+ import { memoize } from "./cache.js";
15
17
  const ECFR = "https://www.ecfr.gov/api";
16
18
  async function fetchJson(url) {
17
- const r = await fetch(url, {
19
+ const r = await fetchWithRetry(url, {
18
20
  headers: { Accept: "application/json" },
19
21
  signal: AbortSignal.timeout(15_000),
20
- });
21
- if (!r.ok) {
22
- throw new Error(`eCFR ${url} returned ${r.status}`);
23
- }
22
+ }, `ecfr:${url.split("/api/")[1] ?? url}`);
24
23
  return (await r.json());
25
24
  }
26
25
  export async function listTitles() {
27
- const json = await fetchJson(`${ECFR}/versioner/v1/titles.json`);
28
- return {
29
- titles: (json.titles ?? []).map((t) => ({
30
- number: t.number ?? 0,
31
- name: t.name ?? "",
32
- latestAmendedOn: t.latest_amended_on,
33
- latestIssueDate: t.latest_issue_date,
34
- upToDateAsOf: t.up_to_date_as_of,
35
- reserved: !!t.reserved,
36
- })),
37
- };
26
+ // 50 CFR titles change very infrequently. Cache aggressively (5 min).
27
+ return memoize("ecfr:titles", async () => {
28
+ const json = await fetchJson(`${ECFR}/versioner/v1/titles.json`);
29
+ return {
30
+ titles: (json.titles ?? []).map((t) => ({
31
+ number: t.number ?? 0,
32
+ name: t.name ?? "",
33
+ latestAmendedOn: t.latest_amended_on,
34
+ latestIssueDate: t.latest_issue_date,
35
+ upToDateAsOf: t.up_to_date_as_of,
36
+ reserved: !!t.reserved,
37
+ })),
38
+ };
39
+ });
38
40
  }
39
41
  export async function search(args) {
40
42
  const url = new URL(`${ECFR}/search/v1/results`);
package/dist/ecfr.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ecfr.js","sourceRoot":"","sources":["../src/ecfr.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ecfr.js","sourceRoot":"","sources":["../src/ecfr.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Structured error envelope for every tool response.
3
+ *
4
+ * Why this exists
5
+ * ----------------
6
+ * Federal APIs fail in 5 distinct ways: rate-limited (429), down
7
+ * (5xx), schema-drift (200 with unexpected shape), notice-not-found
8
+ * (404), and transient network. Each has a different retry strategy.
9
+ * If we just throw, the LLM sees "Tool error: TypeError: x is
10
+ * undefined" and gives up.
11
+ *
12
+ * Every tool should return either:
13
+ * { ok: true, data: ... }
14
+ * { ok: false, error: { kind, message, retryable, retryAfterSeconds? } }
15
+ *
16
+ * The MCP server layer surfaces this as JSON to the calling agent.
17
+ * The agent can then decide: retry now, retry later, or surface
18
+ * the error to the user with appropriate framing.
19
+ */
20
+ export type ErrorKind =
21
+ /** HTTP 429. Retry after `retryAfterSeconds`. */
22
+ "rate_limited"
23
+ /** HTTP 5xx or network error. Likely transient. */
24
+ | "upstream_unavailable"
25
+ /** HTTP 404 / empty results. Don't retry. */
26
+ | "not_found"
27
+ /** Caller passed bad input (e.g. malformed noticeId). Don't retry. */
28
+ | "invalid_input"
29
+ /** API returned 200 but we couldn't parse / shape doesn't match. */
30
+ | "schema_drift"
31
+ /** Anything else. Don't retry. */
32
+ | "unknown";
33
+ export type ToolError = {
34
+ kind: ErrorKind;
35
+ message: string;
36
+ /** Whether the agent should retry. Pairs with retryAfterSeconds. */
37
+ retryable: boolean;
38
+ /** If rate-limited, advisory wait time. Honors `Retry-After` header. */
39
+ retryAfterSeconds?: number;
40
+ /** Echo upstream HTTP status when available — helps debug. */
41
+ upstreamStatus?: number;
42
+ /** Endpoint that failed — for ops. */
43
+ upstreamEndpoint?: string;
44
+ };
45
+ export type ToolResult<T> = {
46
+ ok: true;
47
+ data: T;
48
+ } | {
49
+ ok: false;
50
+ error: ToolError;
51
+ };
52
+ export declare class ToolErrorCarrier extends Error {
53
+ readonly toolError: ToolError;
54
+ constructor(toolError: ToolError);
55
+ }
56
+ /**
57
+ * Convert a fetch Response into a structured tool error.
58
+ *
59
+ * Honors `Retry-After` (both seconds-int and HTTP-date forms).
60
+ */
61
+ export declare function errorFromResponse(r: Response, endpoint: string): ToolError;
62
+ /**
63
+ * Wrap a fetch + json call in retry-with-backoff for transient errors.
64
+ *
65
+ * Strategy: up to 3 attempts. On 429: respect Retry-After up to 60s.
66
+ * On 5xx: 1s, 2s, 4s exponential. On parse error: no retry (schema
67
+ * drift — needs human investigation).
68
+ */
69
+ export declare function fetchWithRetry(url: string, init: RequestInit, endpointLabel: string): Promise<Response>;
70
+ /**
71
+ * Convert any thrown error into a serializable ToolError envelope.
72
+ * Used at the dispatcher boundary — server.ts catches everything
73
+ * and wraps before returning to the MCP client.
74
+ */
75
+ export declare function toToolError(e: unknown, endpointLabel?: string): ToolError;
76
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,SAAS;AACnB,iDAAiD;AAC/C,cAAc;AAChB,mDAAmD;GACjD,sBAAsB;AACxB,6CAA6C;GAC3C,WAAW;AACb,sEAAsE;GACpE,eAAe;AACjB,oEAAoE;GAClE,cAAc;AAChB,kCAAkC;GAChC,SAAS,CAAC;AAEd,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,SAAS,EAAE,OAAO,CAAC;IACnB,wEAAwE;IACxE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,8DAA8D;IAC9D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sCAAsC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,CAAC,IACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GACrB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAIpC,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;gBAClB,SAAS,EAAE,SAAS;CAKjC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,QAAQ,EACX,QAAQ,EAAE,MAAM,GACf,SAAS,CAgDX;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,QAAQ,CAAC,CA0CnB;AAcD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CA2BzE"}
package/dist/errors.js ADDED
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Structured error envelope for every tool response.
3
+ *
4
+ * Why this exists
5
+ * ----------------
6
+ * Federal APIs fail in 5 distinct ways: rate-limited (429), down
7
+ * (5xx), schema-drift (200 with unexpected shape), notice-not-found
8
+ * (404), and transient network. Each has a different retry strategy.
9
+ * If we just throw, the LLM sees "Tool error: TypeError: x is
10
+ * undefined" and gives up.
11
+ *
12
+ * Every tool should return either:
13
+ * { ok: true, data: ... }
14
+ * { ok: false, error: { kind, message, retryable, retryAfterSeconds? } }
15
+ *
16
+ * The MCP server layer surfaces this as JSON to the calling agent.
17
+ * The agent can then decide: retry now, retry later, or surface
18
+ * the error to the user with appropriate framing.
19
+ */
20
+ const RATE_LIMIT_DEFAULT_SECONDS = 30;
21
+ export class ToolErrorCarrier extends Error {
22
+ toolError;
23
+ constructor(toolError) {
24
+ super(toolError.message);
25
+ this.toolError = toolError;
26
+ this.name = "ToolErrorCarrier";
27
+ }
28
+ }
29
+ /**
30
+ * Convert a fetch Response into a structured tool error.
31
+ *
32
+ * Honors `Retry-After` (both seconds-int and HTTP-date forms).
33
+ */
34
+ export function errorFromResponse(r, endpoint) {
35
+ const upstreamStatus = r.status;
36
+ if (r.status === 429) {
37
+ const retryAfter = parseRetryAfter(r.headers.get("Retry-After"));
38
+ return {
39
+ kind: "rate_limited",
40
+ message: `Upstream rate-limited (HTTP 429) at ${endpoint}. Retry after ${retryAfter}s.`,
41
+ retryable: true,
42
+ retryAfterSeconds: retryAfter,
43
+ upstreamStatus,
44
+ upstreamEndpoint: endpoint,
45
+ };
46
+ }
47
+ if (r.status === 404) {
48
+ return {
49
+ kind: "not_found",
50
+ message: `Resource not found at ${endpoint} (HTTP 404).`,
51
+ retryable: false,
52
+ upstreamStatus,
53
+ upstreamEndpoint: endpoint,
54
+ };
55
+ }
56
+ if (r.status >= 500) {
57
+ return {
58
+ kind: "upstream_unavailable",
59
+ message: `Upstream server error (HTTP ${r.status}) at ${endpoint}. Try again later.`,
60
+ retryable: true,
61
+ retryAfterSeconds: 60,
62
+ upstreamStatus,
63
+ upstreamEndpoint: endpoint,
64
+ };
65
+ }
66
+ if (r.status >= 400) {
67
+ return {
68
+ kind: "invalid_input",
69
+ message: `Bad request (HTTP ${r.status}) at ${endpoint}.`,
70
+ retryable: false,
71
+ upstreamStatus,
72
+ upstreamEndpoint: endpoint,
73
+ };
74
+ }
75
+ return {
76
+ kind: "unknown",
77
+ message: `Unexpected status ${r.status} at ${endpoint}.`,
78
+ retryable: false,
79
+ upstreamStatus,
80
+ upstreamEndpoint: endpoint,
81
+ };
82
+ }
83
+ /**
84
+ * Wrap a fetch + json call in retry-with-backoff for transient errors.
85
+ *
86
+ * Strategy: up to 3 attempts. On 429: respect Retry-After up to 60s.
87
+ * On 5xx: 1s, 2s, 4s exponential. On parse error: no retry (schema
88
+ * drift — needs human investigation).
89
+ */
90
+ export async function fetchWithRetry(url, init, endpointLabel) {
91
+ const maxAttempts = 3;
92
+ let lastErr;
93
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
94
+ try {
95
+ const r = await fetch(url, init);
96
+ if (r.ok)
97
+ return r;
98
+ const err = errorFromResponse(r, endpointLabel);
99
+ if (!err.retryable || attempt === maxAttempts) {
100
+ throw new ToolErrorCarrier(err);
101
+ }
102
+ lastErr = err;
103
+ const wait = err.retryAfterSeconds
104
+ ? Math.min(err.retryAfterSeconds, 60)
105
+ : Math.pow(2, attempt - 1);
106
+ await new Promise((res) => setTimeout(res, wait * 1000));
107
+ }
108
+ catch (e) {
109
+ if (e instanceof ToolErrorCarrier)
110
+ throw e;
111
+ // Network-level error
112
+ lastErr = {
113
+ kind: "upstream_unavailable",
114
+ message: `Network error reaching ${endpointLabel}: ${e.message}`,
115
+ retryable: true,
116
+ retryAfterSeconds: 30,
117
+ upstreamEndpoint: endpointLabel,
118
+ };
119
+ if (attempt === maxAttempts) {
120
+ throw new ToolErrorCarrier(lastErr);
121
+ }
122
+ await new Promise((res) => setTimeout(res, Math.pow(2, attempt - 1) * 1000));
123
+ }
124
+ }
125
+ throw new ToolErrorCarrier(lastErr ?? {
126
+ kind: "unknown",
127
+ message: `${endpointLabel} failed after ${maxAttempts} attempts.`,
128
+ retryable: false,
129
+ upstreamEndpoint: endpointLabel,
130
+ });
131
+ }
132
+ function parseRetryAfter(value) {
133
+ if (!value)
134
+ return RATE_LIMIT_DEFAULT_SECONDS;
135
+ const asInt = Number.parseInt(value, 10);
136
+ if (Number.isFinite(asInt))
137
+ return asInt;
138
+ // HTTP-date form
139
+ const date = Date.parse(value);
140
+ if (!Number.isNaN(date)) {
141
+ return Math.max(1, Math.ceil((date - Date.now()) / 1000));
142
+ }
143
+ return RATE_LIMIT_DEFAULT_SECONDS;
144
+ }
145
+ /**
146
+ * Convert any thrown error into a serializable ToolError envelope.
147
+ * Used at the dispatcher boundary — server.ts catches everything
148
+ * and wraps before returning to the MCP client.
149
+ */
150
+ export function toToolError(e, endpointLabel) {
151
+ if (e instanceof ToolErrorCarrier)
152
+ return e.toolError;
153
+ if (e instanceof Error) {
154
+ const msg = e.message;
155
+ // Common fetch timeout signature
156
+ if (e.name === "TimeoutError" || /timeout|aborted/i.test(msg)) {
157
+ return {
158
+ kind: "upstream_unavailable",
159
+ message: `${endpointLabel ?? "upstream"} timed out: ${msg}`,
160
+ retryable: true,
161
+ retryAfterSeconds: 30,
162
+ upstreamEndpoint: endpointLabel,
163
+ };
164
+ }
165
+ return {
166
+ kind: "unknown",
167
+ message: msg,
168
+ retryable: false,
169
+ upstreamEndpoint: endpointLabel,
170
+ };
171
+ }
172
+ return {
173
+ kind: "unknown",
174
+ message: String(e),
175
+ retryable: false,
176
+ upstreamEndpoint: endpointLabel,
177
+ };
178
+ }
179
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"federal-register.d.ts","sourceRoot":"","sources":["../src/federal-register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAeH,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GACN,SAAS,GACT,QAAQ,GACR,UAAU,GACV,SAAS,CAAC;AASd,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IAClD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;;;;;;;;;;;;;;;;;;GAkEA;AAED,wBAAsB,WAAW,CAAC,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;GA2CvD;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;GAuB5D"}
1
+ {"version":3,"file":"federal-register.d.ts","sourceRoot":"","sources":["../src/federal-register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAmBH,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GACN,SAAS,GACT,QAAQ,GACR,UAAU,GACV,SAAS,CAAC;AASd,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IAClD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;;;;;;;;;;;;;;;;;;GAkEA;AAED,wBAAsB,WAAW,CAAC,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;GA2CvD;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;GAyB5D"}
@@ -16,15 +16,14 @@
16
16
  * All endpoints are public + keyless (no API key, no registration).
17
17
  * Rate-limit: documented as ~1000 req/hour per IP (informal).
18
18
  */
19
+ import { fetchWithRetry } from "./errors.js";
20
+ import { memoize } from "./cache.js";
19
21
  const FED_REG = "https://www.federalregister.gov/api/v1";
20
22
  async function fetchJson(url) {
21
- const r = await fetch(url, {
23
+ const r = await fetchWithRetry(url, {
22
24
  headers: { Accept: "application/json" },
23
25
  signal: AbortSignal.timeout(15_000),
24
- });
25
- if (!r.ok) {
26
- throw new Error(`Federal Register ${url} returned ${r.status}`);
27
- }
26
+ }, `federal-register:${url.split("/api/v1/")[1] ?? url}`);
28
27
  return (await r.json());
29
28
  }
30
29
  const TYPE_MAP = {
@@ -102,16 +101,18 @@ export async function getDocument(documentNumber) {
102
101
  };
103
102
  }
104
103
  export async function listAgencies(args) {
105
- const json = await fetchJson(`${FED_REG}/agencies.json?per_page=${args.perPage ?? 100}`);
106
- return {
107
- agencies: (json ?? []).map((a) => ({
108
- id: a.id ?? 0,
109
- name: a.name ?? "",
110
- shortName: a.short_name,
111
- slug: a.slug ?? "",
112
- description: a.description ?? "",
113
- parentId: a.parent_id,
114
- })),
115
- };
104
+ return memoize(`fedreg:agencies:${args.perPage ?? 100}`, async () => {
105
+ const json = await fetchJson(`${FED_REG}/agencies.json?per_page=${args.perPage ?? 100}`);
106
+ return {
107
+ agencies: (json ?? []).map((a) => ({
108
+ id: a.id ?? 0,
109
+ name: a.name ?? "",
110
+ shortName: a.short_name,
111
+ slug: a.slug ?? "",
112
+ description: a.description ?? "",
113
+ parentId: a.parent_id,
114
+ })),
115
+ };
116
+ });
116
117
  }
117
118
  //# sourceMappingURL=federal-register.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"federal-register.js","sourceRoot":"","sources":["../src/federal-register.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"federal-register.js","sourceRoot":"","sources":["../src/federal-register.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE1E,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;;;;;;;;;;;;;;GA+CA;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;oBAoDpC,MAAM,EAAE;wBAGR,MAAM,EAAE;uBAGR,MAAM,EAAE;;;;;GAMjC"}
1
+ {"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAuBH,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE1E,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;;;;;;;;;;;;;;GA+CA;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;oBAoDpC,MAAM,EAAE;wBAGR,MAAM,EAAE;uBAGR,MAAM,EAAE;;;;;GAMjC"}
package/dist/grants.js CHANGED
@@ -11,17 +11,15 @@
11
11
  *
12
12
  * Documented at https://grants.gov/web/grants/s2s/grantor/schemas/grants-search-2-soap.html
13
13
  */
14
+ import { fetchWithRetry } from "./errors.js";
14
15
  const GRANTS = "https://api.grants.gov/v1/api";
15
16
  async function postJson(endpoint, body) {
16
- const r = await fetch(`${GRANTS}/${endpoint}`, {
17
+ const r = await fetchWithRetry(`${GRANTS}/${endpoint}`, {
17
18
  method: "POST",
18
19
  headers: { "Content-Type": "application/json" },
19
20
  body: JSON.stringify(body),
20
21
  signal: AbortSignal.timeout(15_000),
21
- });
22
- if (!r.ok) {
23
- throw new Error(`Grants.gov ${endpoint} returned ${r.status}`);
24
- }
22
+ }, `grants.gov:${endpoint}`);
25
23
  return (await r.json());
26
24
  }
27
25
  export async function searchGrants(args) {
@@ -1 +1 @@
1
- {"version":3,"file":"grants.js","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"grants.js","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"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"}