usaspending-mcp 0.1.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 ADDED
@@ -0,0 +1,164 @@
1
+ # usaspending-mcp
2
+
3
+ MCP server for the [USASpending.gov API](https://api.usaspending.gov/) — 25 tools for querying federal spending data, tracking government contracts, and researching award recipients.
4
+
5
+ No API key required. Works with Claude Code, Claude Desktop, Claude.ai, and any MCP-compatible client.
6
+
7
+ ## Quick Start
8
+
9
+ ### Claude Code (npx)
10
+
11
+ ```json
12
+ {
13
+ "mcpServers": {
14
+ "usaspending": {
15
+ "type": "stdio",
16
+ "command": "npx",
17
+ "args": ["-y", "usaspending-mcp"]
18
+ }
19
+ }
20
+ }
21
+ ```
22
+
23
+ ### Claude Code (local)
24
+
25
+ ```json
26
+ {
27
+ "mcpServers": {
28
+ "usaspending": {
29
+ "type": "stdio",
30
+ "command": "node",
31
+ "args": ["/path/to/usaspending-mcp/dist/index.js"]
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ ### Remote (Streamable HTTP)
38
+
39
+ Run on a server:
40
+
41
+ ```bash
42
+ npx usaspending-mcp --transport http --port 3001
43
+ ```
44
+
45
+ Connect from Claude Desktop or Claude.ai via your reverse proxy URL.
46
+
47
+ ## Tools
48
+
49
+ ### Search & Discovery (8 tools)
50
+
51
+ | Tool | Description |
52
+ |------|-------------|
53
+ | `search_awards` | Search federal awards with filters (agency, NAICS, PSC, keywords, date range, award type). Supports pagination. |
54
+ | `search_awards_count` | Get result counts by award type before running a full search. |
55
+ | `search_subawards` | Search subaward/subcontract records across all prime awards. |
56
+ | `search_by_category` | Aggregate spending by dimension (NAICS, PSC, recipient, agency, geography, etc.). |
57
+ | `search_new_awards_over_time` | Track new award volume over time by month, quarter, or fiscal year. |
58
+ | `search_spending_over_time` | Track spending amounts over time. |
59
+ | `search_spending_by_geography` | Break down spending by state, county, or congressional district. |
60
+ | `search_by_transaction` | Transaction-level search across all awards. |
61
+
62
+ ### Award & IDV Detail (8 tools)
63
+
64
+ | Tool | Description |
65
+ |------|-------------|
66
+ | `get_award` | Full details for a specific award (recipient, amounts, dates, NAICS/PSC, agency). |
67
+ | `get_award_funding` | Funding sources — which federal accounts and agencies fund an award. |
68
+ | `get_award_subawards` | Subawards under a prime award. Key for mapping supply chains. |
69
+ | `get_award_transactions` | Transaction/modification history for an award. |
70
+ | `get_idv_amounts` | Funding summary for an IDV (IDIQ, GWAC, BPA, BOA, FSS). |
71
+ | `get_idv_awards` | Task orders under an IDV. Identifies all awardees on a contract vehicle. |
72
+ | `get_idv_activity` | Modification and activity history for an IDV. |
73
+ | `get_idv_funding` | IDV funding breakdown by federal account. |
74
+
75
+ ### Recipient Intelligence (5 tools)
76
+
77
+ | Tool | Description |
78
+ |------|-------------|
79
+ | `autocomplete_recipient` | Quick recipient name search. First step in finding a company. |
80
+ | `list_recipients` | Search and filter recipients with award totals. |
81
+ | `get_recipient` | Full company profile — DUNS/UEI, parent company, award history by type. |
82
+ | `get_recipient_children` | Child/subsidiary organizations under a parent company. |
83
+ | `get_spending_by_recipient_for_agency` | Recipients ranked by award amount from a specific agency. |
84
+
85
+ ### Reference Data (4 tools)
86
+
87
+ | Tool | Description |
88
+ |------|-------------|
89
+ | `list_agencies` | All top-tier federal agencies with codes and metadata. |
90
+ | `search_naics` | Search NAICS industry codes by keyword. |
91
+ | `search_psc` | Search Product/Service Classification codes by keyword. |
92
+ | `get_naics_hierarchy` | Browse the NAICS code tree. |
93
+
94
+ ## Filtering
95
+
96
+ Search tools accept a shared filter object:
97
+
98
+ ```json
99
+ {
100
+ "keywords": ["cybersecurity"],
101
+ "award_type_codes": ["D"],
102
+ "time_period": [{ "start_date": "2025-01-01", "end_date": "2025-12-31" }],
103
+ "agencies": [{ "type": "awarding", "tier": "toptier", "name": "Department of Defense" }],
104
+ "naics_codes": ["541512"],
105
+ "psc_codes": ["D399"],
106
+ "recipient_search_text": ["Lockheed"],
107
+ "page": 1,
108
+ "limit": 20,
109
+ "sort": "Award Amount",
110
+ "order": "desc"
111
+ }
112
+ ```
113
+
114
+ All filter fields are optional — compose what you need.
115
+
116
+ ### Award Type Codes
117
+
118
+ | Code | Type |
119
+ |------|------|
120
+ | `A` | BPA Call |
121
+ | `B` | Purchase Order |
122
+ | `C` | Delivery Order |
123
+ | `D` | Definitive Contract |
124
+ | `IDV_A` | GWAC |
125
+ | `IDV_B_A` | IDC / IDIQ |
126
+ | `IDV_B_B` | IDC / Indefinite |
127
+ | `IDV_B_C` | IDC / Definitive |
128
+ | `IDV_C` | FSS |
129
+ | `IDV_D` | BOA |
130
+ | `IDV_E` | BPA |
131
+
132
+ ## Example Workflows
133
+
134
+ **Find DOD cybersecurity contracts:**
135
+ 1. `search_naics` — find relevant codes (541512, 541519)
136
+ 2. `search_awards` — filter by DOD + NAICS codes + award type "D" + date range
137
+ 3. `get_award` — deep dive on a specific contract
138
+ 4. `get_recipient` — profile the winning company
139
+
140
+ **Map a contractor's supply chain:**
141
+ 1. `autocomplete_recipient` — find the prime by name
142
+ 2. `get_recipient` — get their profile
143
+ 3. `search_awards` — find their contracts
144
+ 4. `get_award_subawards` — find subcontractors on each contract
145
+
146
+ **Explore an IDIQ/GWAC:**
147
+ 1. `search_awards` — filter for IDV award types
148
+ 2. `get_idv_awards` — list all task order holders
149
+ 3. `get_idv_activity` — see recent activity
150
+ 4. `get_recipient` — profile each awardee
151
+
152
+ ## Development
153
+
154
+ ```bash
155
+ git clone https://github.com/boejucci/usa-spending-mcp.git
156
+ cd usa-spending-mcp
157
+ npm install
158
+ npm run build
159
+ npm run dev # watch mode
160
+ ```
161
+
162
+ ## License
163
+
164
+ MIT
@@ -0,0 +1,45 @@
1
+ /**
2
+ * USASpending API Client
3
+ *
4
+ * HTTP layer for all communication with the USASpending.gov API.
5
+ * Every MCP tool in this server routes through this client.
6
+ */
7
+ export declare class USASpendingApiError extends Error {
8
+ readonly statusCode: number;
9
+ readonly statusText: string;
10
+ readonly body: string;
11
+ readonly url: string;
12
+ constructor(message: string, statusCode: number, statusText: string, body: string, url: string);
13
+ }
14
+ export interface PageMetadata {
15
+ page: number;
16
+ hasNext: boolean;
17
+ total?: number;
18
+ limit?: number;
19
+ }
20
+ export declare class USASpendingClient {
21
+ private readonly baseUrl;
22
+ private readonly timeoutMs;
23
+ constructor(baseUrl?: string, timeoutMs?: number);
24
+ get<T>(path: string): Promise<T>;
25
+ post<T>(path: string, body: Record<string, unknown>): Promise<T>;
26
+ /**
27
+ * Injects a human-readable `_summary` field into a paginated API response.
28
+ *
29
+ * Only modifies the response if `page_metadata` is present.
30
+ *
31
+ * Format:
32
+ * "Page X of Y (Z total results). Showing N items. [context] [More pages available.]"
33
+ */
34
+ addSummary<T extends Record<string, unknown>>(response: T, context?: string): T & {
35
+ _summary?: string;
36
+ };
37
+ private request;
38
+ /**
39
+ * Counts the number of result items in a response by looking for the first
40
+ * top-level array field (excluding metadata-like keys).
41
+ */
42
+ private countItems;
43
+ }
44
+ export declare const client: USASpendingClient;
45
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,qBAAa,mBAAoB,SAAQ,KAAK;aAG1B,UAAU,EAAE,MAAM;aAClB,UAAU,EAAE,MAAM;aAClB,IAAI,EAAE,MAAM;aACZ,GAAG,EAAE,MAAM;gBAJ3B,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM;CAK9B;AAMD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,OAAO,GAAE,MAAiB,EAAE,SAAS,GAAE,MAAmB;IAShE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAKhC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAYtE;;;;;;;OAOG;IACH,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1C,QAAQ,EAAE,CAAC,EACX,OAAO,CAAC,EAAE,MAAM,GACf,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE;YA4Cd,OAAO;IA4CrB;;;OAGG;IACH,OAAO,CAAC,UAAU;CASnB;AAMD,eAAO,MAAM,MAAM,mBAA0B,CAAC"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * USASpending API Client
3
+ *
4
+ * HTTP layer for all communication with the USASpending.gov API.
5
+ * Every MCP tool in this server routes through this client.
6
+ */
7
+ const BASE_URL = "https://api.usaspending.gov/api/v2";
8
+ const TIMEOUT_MS = 30_000;
9
+ // ---------------------------------------------------------------------------
10
+ // Error class
11
+ // ---------------------------------------------------------------------------
12
+ export class USASpendingApiError extends Error {
13
+ statusCode;
14
+ statusText;
15
+ body;
16
+ url;
17
+ constructor(message, statusCode, statusText, body, url) {
18
+ super(message);
19
+ this.statusCode = statusCode;
20
+ this.statusText = statusText;
21
+ this.body = body;
22
+ this.url = url;
23
+ this.name = "USASpendingApiError";
24
+ }
25
+ }
26
+ // ---------------------------------------------------------------------------
27
+ // Client
28
+ // ---------------------------------------------------------------------------
29
+ export class USASpendingClient {
30
+ baseUrl;
31
+ timeoutMs;
32
+ constructor(baseUrl = BASE_URL, timeoutMs = TIMEOUT_MS) {
33
+ this.baseUrl = baseUrl;
34
+ this.timeoutMs = timeoutMs;
35
+ }
36
+ // -------------------------------------------------------------------------
37
+ // Public HTTP methods
38
+ // -------------------------------------------------------------------------
39
+ async get(path) {
40
+ const url = `${this.baseUrl}${path}`;
41
+ return this.request(url, { method: "GET" });
42
+ }
43
+ async post(path, body) {
44
+ const url = `${this.baseUrl}${path}`;
45
+ return this.request(url, {
46
+ method: "POST",
47
+ body: JSON.stringify(body),
48
+ });
49
+ }
50
+ // -------------------------------------------------------------------------
51
+ // Pagination summary injection
52
+ // -------------------------------------------------------------------------
53
+ /**
54
+ * Injects a human-readable `_summary` field into a paginated API response.
55
+ *
56
+ * Only modifies the response if `page_metadata` is present.
57
+ *
58
+ * Format:
59
+ * "Page X of Y (Z total results). Showing N items. [context] [More pages available.]"
60
+ */
61
+ addSummary(response, context) {
62
+ const metadata = response.page_metadata;
63
+ if (!metadata) {
64
+ return response;
65
+ }
66
+ const { page, hasNext } = metadata;
67
+ // Some endpoints put total/limit in page_metadata, others at the top level
68
+ const total = metadata.total ?? response.total;
69
+ const limit = metadata.limit ?? response.limit;
70
+ // Determine how many items are on the current page.
71
+ const itemCount = this.countItems(response);
72
+ const parts = [];
73
+ if (total != null && limit != null) {
74
+ const totalPages = Math.max(1, Math.ceil(total / limit));
75
+ parts.push(`Page ${page} of ${totalPages} (${total.toLocaleString()} total results).`);
76
+ }
77
+ else {
78
+ parts.push(`Page ${page}.`);
79
+ }
80
+ parts.push(`Showing ${itemCount} items.`);
81
+ if (context) {
82
+ parts.push(context);
83
+ }
84
+ if (hasNext) {
85
+ parts.push("More pages available.");
86
+ }
87
+ return {
88
+ ...response,
89
+ _summary: parts.join(" "),
90
+ };
91
+ }
92
+ // -------------------------------------------------------------------------
93
+ // Internal helpers
94
+ // -------------------------------------------------------------------------
95
+ async request(url, init) {
96
+ const controller = new AbortController();
97
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
98
+ try {
99
+ const response = await fetch(url, {
100
+ ...init,
101
+ signal: controller.signal,
102
+ headers: {
103
+ "Content-Type": "application/json",
104
+ ...init.headers,
105
+ },
106
+ });
107
+ if (!response.ok) {
108
+ const body = await response.text();
109
+ throw new USASpendingApiError(`USASpending API error: ${response.status} ${response.statusText} for ${url}`, response.status, response.statusText, body, url);
110
+ }
111
+ return (await response.json());
112
+ }
113
+ catch (error) {
114
+ if (error instanceof USASpendingApiError) {
115
+ throw error;
116
+ }
117
+ if (error instanceof DOMException ||
118
+ (error instanceof Error && error.name === "AbortError")) {
119
+ throw new Error(`USASpending API request timed out after ${this.timeoutMs}ms: ${url}`);
120
+ }
121
+ throw error;
122
+ }
123
+ finally {
124
+ clearTimeout(timer);
125
+ }
126
+ }
127
+ /**
128
+ * Counts the number of result items in a response by looking for the first
129
+ * top-level array field (excluding metadata-like keys).
130
+ */
131
+ countItems(response) {
132
+ const skipKeys = new Set(["page_metadata", "_summary", "messages"]);
133
+ for (const [key, value] of Object.entries(response)) {
134
+ if (!skipKeys.has(key) && Array.isArray(value)) {
135
+ return value.length;
136
+ }
137
+ }
138
+ return 0;
139
+ }
140
+ }
141
+ // ---------------------------------------------------------------------------
142
+ // Singleton export
143
+ // ---------------------------------------------------------------------------
144
+ export const client = new USASpendingClient();
145
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
+ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
5
+ import express from "express";
6
+ import { randomUUID } from "node:crypto";
7
+ import { createServer } from "./server.js";
8
+ const args = process.argv.slice(2);
9
+ const transportFlag = args.includes("--transport")
10
+ ? args[args.indexOf("--transport") + 1]
11
+ : "stdio";
12
+ const portFlag = args.includes("--port")
13
+ ? parseInt(args[args.indexOf("--port") + 1], 10)
14
+ : 3001;
15
+ async function main() {
16
+ if (transportFlag === "stdio") {
17
+ const server = createServer();
18
+ const transport = new StdioServerTransport();
19
+ await server.connect(transport);
20
+ console.error("USASpending MCP server running on stdio");
21
+ }
22
+ else if (transportFlag === "http") {
23
+ const app = express();
24
+ app.use(express.json());
25
+ const transports = new Map();
26
+ app.post("/mcp", async (req, res) => {
27
+ const sessionId = req.headers["mcp-session-id"];
28
+ if (sessionId && transports.has(sessionId)) {
29
+ const transport = transports.get(sessionId);
30
+ await transport.handleRequest(req, res, req.body);
31
+ return;
32
+ }
33
+ if (!sessionId && isInitializeRequest(req.body)) {
34
+ const transport = new StreamableHTTPServerTransport({
35
+ sessionIdGenerator: () => randomUUID(),
36
+ onsessioninitialized: (sid) => {
37
+ transports.set(sid, transport);
38
+ },
39
+ });
40
+ transport.onclose = () => {
41
+ const sid = [...transports.entries()].find(([, t]) => t === transport)?.[0];
42
+ if (sid)
43
+ transports.delete(sid);
44
+ };
45
+ const server = createServer();
46
+ await server.connect(transport);
47
+ await transport.handleRequest(req, res, req.body);
48
+ return;
49
+ }
50
+ res.status(400).json({ error: "Invalid request" });
51
+ });
52
+ app.get("/mcp", async (req, res) => {
53
+ const sessionId = req.headers["mcp-session-id"];
54
+ if (sessionId && transports.has(sessionId)) {
55
+ const transport = transports.get(sessionId);
56
+ await transport.handleRequest(req, res);
57
+ return;
58
+ }
59
+ res.status(400).json({ error: "Invalid request - no session" });
60
+ });
61
+ app.delete("/mcp", async (req, res) => {
62
+ const sessionId = req.headers["mcp-session-id"];
63
+ if (sessionId && transports.has(sessionId)) {
64
+ const transport = transports.get(sessionId);
65
+ await transport.handleRequest(req, res);
66
+ transports.delete(sessionId);
67
+ return;
68
+ }
69
+ res.status(400).json({ error: "Invalid request - no session" });
70
+ });
71
+ app.listen(portFlag, () => {
72
+ console.error(`USASpending MCP server running on http://localhost:${portFlag}/mcp`);
73
+ });
74
+ }
75
+ else {
76
+ console.error(`Unknown transport: ${transportFlag}. Use "stdio" or "http".`);
77
+ process.exit(1);
78
+ }
79
+ }
80
+ main().catch((error) => {
81
+ console.error("Fatal error:", error);
82
+ process.exit(1);
83
+ });
84
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function createServer(): McpServer;
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,wBAAgB,YAAY,IAAI,SAAS,CAYxC"}
package/dist/server.js ADDED
@@ -0,0 +1,17 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { registerReferenceTools } from "./tools/references.js";
3
+ import { registerRecipientTools } from "./tools/recipients.js";
4
+ import { registerSearchTools } from "./tools/search.js";
5
+ import { registerAwardTools } from "./tools/awards.js";
6
+ export function createServer() {
7
+ const server = new McpServer({
8
+ name: "usaspending-mcp",
9
+ version: "0.1.0",
10
+ });
11
+ registerReferenceTools(server);
12
+ registerRecipientTools(server);
13
+ registerSearchTools(server);
14
+ registerAwardTools(server);
15
+ return server;
16
+ }
17
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE3B,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Award & IDV Detail Tools
3
+ *
4
+ * Tools for drilling into specific awards and Indefinite Delivery Vehicles (IDVs).
5
+ * Once a user finds an award via search, these tools provide full details,
6
+ * funding breakdowns, subaward chains, transaction histories, and IDV structure.
7
+ */
8
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
9
+ export declare function registerAwardTools(server: McpServer): void;
10
+ //# sourceMappingURL=awards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"awards.d.ts","sourceRoot":"","sources":["../../src/tools/awards.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0W1D"}