@forgemeshlabs/gov-transparency-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/LICENSE +21 -0
- package/README.md +52 -0
- package/index.js +332 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ForgeMesh Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# gov-transparency-mcp
|
|
2
|
+
|
|
3
|
+
**Watch the watchers.** Congressional stock trades, federal contract awards, campaign finance, lobbying filings, and new regulations — nine MCP tools over official US government data, paid per call with [x402](https://x402.org) USDC on Base. No account, no API key, no subscription.
|
|
4
|
+
|
|
5
|
+
Commercial trackers sell congressional-trading data behind monthly subscriptions. Here it is per-call, in structured JSON, for agents: $0.005–$0.02 a query.
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
| Tool | Price | What it returns |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `get_congress_trades` | $0.02 | US House member stock trades parsed from official STOCK Act filings — member, ticker, buy/sell, date, amount range. Filter by member, ticker, type, state, date window. |
|
|
12
|
+
| `get_trade_filings` | $0.01 | The disclosure filing index — who filed trade reports and when, with official PDF links. |
|
|
13
|
+
| `search_federal_contracts` | $0.01 | Federal contract awards won by any company — amounts, agencies, dates, descriptions. |
|
|
14
|
+
| `get_contractor_profile` | $0.01 | Company → official federal recipient records with UEI and recent award totals. |
|
|
15
|
+
| `get_candidate_money` | $0.01 | Campaign finance totals per candidate — receipts, spending, cash on hand, debts. |
|
|
16
|
+
| `find_candidate` | $0.005 | Candidate name → official ids, party, office, committees. |
|
|
17
|
+
| `search_lobbying` | $0.01 | Lobbying filings by client or firm — money, issues, named lobbyists. |
|
|
18
|
+
| `watch_federal_register` | $0.005 | Newest regulations and notices matching any topic. |
|
|
19
|
+
| `lookup_bill` | $0.005 | Official status of any bill in Congress. |
|
|
20
|
+
| `get_endpoint_spec` | free | Live schemas and worked examples for all nine routes. |
|
|
21
|
+
|
|
22
|
+
## Data sources
|
|
23
|
+
|
|
24
|
+
All official, all public domain: US House Clerk financial disclosures (parsed from the source PTR PDFs), USAspending.gov, the Federal Election Commission, the Senate Lobbying Disclosure Act database, the Federal Register, and Congress.gov. Trade disclosures lag transactions by up to 45 days — that is the law's reporting window, not a data delay. Current trade coverage: US House (Senate planned); paper-filed disclosures are indexed with PDF links but not parsed into rows.
|
|
25
|
+
|
|
26
|
+
## Setup
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"gov-transparency": {
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["-y", "@forgemeshlabs/gov-transparency-mcp"],
|
|
34
|
+
"env": {
|
|
35
|
+
"WALLET_PRIVATE_KEY": "0x..."
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`WALLET_PRIVATE_KEY` must be a **dedicated low-balance wallet** holding a small amount of USDC on Base mainnet — never your primary wallet. `get_endpoint_spec` works without one.
|
|
43
|
+
|
|
44
|
+
Optional env: `GOV_TRANSPARENCY_BASE_URL` (default `https://x402.forgemesh.io`), `BASE_RPC_URL` (default `https://mainnet.base.org`).
|
|
45
|
+
|
|
46
|
+
## How payment works
|
|
47
|
+
|
|
48
|
+
Each call makes a normal HTTP request; the server answers `402 Payment Required` with exact terms, the client signs a USDC transfer authorization (EIP-3009) and retries, and the settlement transaction hash comes back in the response under `_payment`. Atomic: no data without payment, no payment without data.
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
MIT — code only. The underlying government data is public domain.
|
package/index.js
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { Server } = require("@modelcontextprotocol/sdk/server/index.js");
|
|
5
|
+
const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
|
+
const { CallToolRequestSchema, ListToolsRequestSchema } = require("@modelcontextprotocol/sdk/types.js");
|
|
7
|
+
const { x402Client, x402HTTPClient } = require("@x402/core/client");
|
|
8
|
+
const { ExactEvmScheme } = require("@x402/evm/exact/client");
|
|
9
|
+
const { toClientEvmSigner } = require("@x402/evm");
|
|
10
|
+
const { privateKeyToAccount } = require("viem/accounts");
|
|
11
|
+
const { createPublicClient, http } = require("viem");
|
|
12
|
+
const { base } = require("viem/chains");
|
|
13
|
+
|
|
14
|
+
const VERSION = "0.1.0";
|
|
15
|
+
const BASE_URL = (process.env.GOV_TRANSPARENCY_BASE_URL || "https://x402.forgemesh.io").replace(/\/$/, "");
|
|
16
|
+
const BASE_RPC_URL = process.env.BASE_RPC_URL || "https://mainnet.base.org";
|
|
17
|
+
|
|
18
|
+
// Every tool maps to one paid route on the ForgeMesh Utility Grid's
|
|
19
|
+
// gov-transparency shelf. All underlying data is official US government
|
|
20
|
+
// data (public domain): House Clerk financial disclosures, USAspending,
|
|
21
|
+
// FEC, the Senate lobbying registry, the Federal Register, and Congress.gov.
|
|
22
|
+
|
|
23
|
+
// --- payment client ---------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
function buildBaseHttpClient() {
|
|
26
|
+
const key = process.env.WALLET_PRIVATE_KEY;
|
|
27
|
+
if (!key) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
"WALLET_PRIVATE_KEY is not set. Calls cost $0.005-$0.02 via x402 — set a dedicated low-balance Base wallet private key (never your primary wallet) holding a small amount of USDC on Base mainnet. The get_endpoint_spec tool works without one."
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
const pk = key.startsWith("0x") ? key : "0x" + key;
|
|
33
|
+
const account = privateKeyToAccount(pk);
|
|
34
|
+
const coreClient = new x402Client().register("eip155:*", new ExactEvmScheme(toClientEvmSigner(account)));
|
|
35
|
+
return { httpClient: new x402HTTPClient(coreClient), account };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// x402 derives EIP-3009 validity windows from Date.now; choose a timestamp
|
|
39
|
+
// valid for both Base block time and facilitator wall-clock checks (clock-skew fix).
|
|
40
|
+
async function createChainTimedPaymentPayload(httpClient, paymentRequired) {
|
|
41
|
+
try {
|
|
42
|
+
const publicClient = createPublicClient({ chain: base, transport: http(BASE_RPC_URL) });
|
|
43
|
+
const block = await publicClient.getBlock();
|
|
44
|
+
const chainNow = Number(block.timestamp);
|
|
45
|
+
const originalNow = Date.now;
|
|
46
|
+
const localNow = Math.floor(originalNow() / 1000);
|
|
47
|
+
const timeout = Number(paymentRequired.accepts?.[0]?.maxTimeoutSeconds || 300);
|
|
48
|
+
const lowerBound = localNow + 30 - timeout;
|
|
49
|
+
const upperBound = chainNow + 600;
|
|
50
|
+
const signingNow = Math.min(Math.max(chainNow, lowerBound), upperBound);
|
|
51
|
+
Date.now = () => signingNow * 1000;
|
|
52
|
+
try {
|
|
53
|
+
return await httpClient.createPaymentPayload(paymentRequired);
|
|
54
|
+
} finally {
|
|
55
|
+
Date.now = originalNow;
|
|
56
|
+
}
|
|
57
|
+
} catch (_) {
|
|
58
|
+
return httpClient.createPaymentPayload(paymentRequired);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function paidPost(ctx, path, body) {
|
|
63
|
+
const { httpClient } = ctx;
|
|
64
|
+
const url = BASE_URL + path;
|
|
65
|
+
const init = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body || {}) };
|
|
66
|
+
const res = await fetch(url, init);
|
|
67
|
+
|
|
68
|
+
if (res.status === 402) {
|
|
69
|
+
let challengeBody;
|
|
70
|
+
try {
|
|
71
|
+
challengeBody = await res.clone().json();
|
|
72
|
+
} catch (_) {}
|
|
73
|
+
const paymentRequired = httpClient.getPaymentRequiredResponse((name) => res.headers.get(name), challengeBody);
|
|
74
|
+
const paymentPayload = await createChainTimedPaymentPayload(httpClient, paymentRequired);
|
|
75
|
+
const paidRes = await fetch(url, {
|
|
76
|
+
...init,
|
|
77
|
+
headers: { ...init.headers, ...httpClient.encodePaymentSignatureHeader(paymentPayload) },
|
|
78
|
+
});
|
|
79
|
+
if (!paidRes.ok) {
|
|
80
|
+
const errBody = await paidRes.text().catch(() => paidRes.statusText);
|
|
81
|
+
throw new Error(`HTTP ${paidRes.status}: ${errBody.slice(0, 300)}`);
|
|
82
|
+
}
|
|
83
|
+
const data = await paidRes.json();
|
|
84
|
+
try {
|
|
85
|
+
const settleResponse = httpClient.getPaymentSettleResponse((name) => paidRes.headers.get(name));
|
|
86
|
+
if (settleResponse && data && typeof data === "object" && !Array.isArray(data)) {
|
|
87
|
+
return { ...data, _payment: settleResponse };
|
|
88
|
+
}
|
|
89
|
+
} catch (_) {}
|
|
90
|
+
return data;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!res.ok) {
|
|
94
|
+
const errBody = await res.text().catch(() => res.statusText);
|
|
95
|
+
throw new Error(`HTTP ${res.status}: ${errBody.slice(0, 300)}`);
|
|
96
|
+
}
|
|
97
|
+
return res.json();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// --- free discovery ---------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
const GOV_PATHS = [
|
|
103
|
+
"/congress-stock-trades",
|
|
104
|
+
"/congress-trade-filings",
|
|
105
|
+
"/federal-contracts-search",
|
|
106
|
+
"/federal-contractor-profile",
|
|
107
|
+
"/fec-candidate-money",
|
|
108
|
+
"/fec-candidate-lookup",
|
|
109
|
+
"/lobbying-filings",
|
|
110
|
+
"/federal-register-watch",
|
|
111
|
+
"/congress-bill-lookup",
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
async function getEndpointSpec(args) {
|
|
115
|
+
const res = await fetch(`${BASE_URL}/openapi.json`);
|
|
116
|
+
if (!res.ok) throw new Error(`Failed to fetch discovery doc: HTTP ${res.status}`);
|
|
117
|
+
const spec = await res.json();
|
|
118
|
+
let p = String(args.path || "").trim();
|
|
119
|
+
if (p && !p.startsWith("/")) p = "/" + p;
|
|
120
|
+
if (!p) {
|
|
121
|
+
return {
|
|
122
|
+
routes: GOV_PATHS.map((gp) => {
|
|
123
|
+
const post = spec.paths?.[gp]?.post || {};
|
|
124
|
+
return { path: gp, price: post["x-payment-info"]?.price?.amount ? `$${post["x-payment-info"].price.amount}` : undefined, summary: post.summary || "" };
|
|
125
|
+
}),
|
|
126
|
+
hint: "Pass a path for its full input schema and worked examples.",
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
const post = spec.paths?.[p]?.post;
|
|
130
|
+
if (!post) throw new Error(`No gov route "${args.path}". Routes: ${GOV_PATHS.join(", ")}`);
|
|
131
|
+
return {
|
|
132
|
+
path: p,
|
|
133
|
+
price: post["x-payment-info"]?.price?.amount ? `$${post["x-payment-info"].price.amount}` : undefined,
|
|
134
|
+
description: post.description || post.summary,
|
|
135
|
+
input_schema: post.requestBody?.content?.["application/json"]?.schema,
|
|
136
|
+
request_example: post.requestBody?.content?.["application/json"]?.example,
|
|
137
|
+
response_example: post.responses?.["200"]?.content?.["application/json"]?.example,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// --- tools ------------------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
const TOOLS = [
|
|
144
|
+
{
|
|
145
|
+
name: "get_congress_trades",
|
|
146
|
+
description:
|
|
147
|
+
"PAID ($0.02) — Congressional stock trades parsed from official STOCK Act disclosures: US House member trades with ticker, asset, buy/sell, transaction date, and disclosed amount range. Filter by member name, ticker, trade type (purchase/sale/sale_partial/exchange), state, or date window. Disclosures lag trades by up to 45 days by law. Requires WALLET_PRIVATE_KEY.",
|
|
148
|
+
inputSchema: {
|
|
149
|
+
type: "object",
|
|
150
|
+
properties: {
|
|
151
|
+
member: { type: "string", description: "Member name substring, e.g. 'wittman'" },
|
|
152
|
+
ticker: { type: "string", description: "Exact ticker, e.g. 'NVDA'" },
|
|
153
|
+
type: { type: "string", enum: ["purchase", "sale", "sale_partial", "exchange"] },
|
|
154
|
+
state: { type: "string", description: "State or district prefix, e.g. 'VA' or 'VA01'" },
|
|
155
|
+
since: { type: "string", description: "ISO date lower bound on transaction date" },
|
|
156
|
+
until: { type: "string", description: "ISO date upper bound on transaction date" },
|
|
157
|
+
limit: { type: "integer", description: "Max rows (default 25, max 100)" },
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: "get_trade_filings",
|
|
163
|
+
description:
|
|
164
|
+
"PAID ($0.01) — US House financial-disclosure filing index: who filed periodic transaction reports, annual reports, amendments, and more — filer, district, type, date, and official PDF link. Poll filing_type 'P' to catch fresh trade disclosures early. Requires WALLET_PRIVATE_KEY.",
|
|
165
|
+
inputSchema: {
|
|
166
|
+
type: "object",
|
|
167
|
+
properties: {
|
|
168
|
+
member: { type: "string", description: "Member name substring" },
|
|
169
|
+
state: { type: "string", description: "State or district prefix" },
|
|
170
|
+
filing_type: { type: "string", description: "Filing type code, e.g. 'P' for trade reports" },
|
|
171
|
+
year: { type: "integer", description: "Filing year, e.g. 2026" },
|
|
172
|
+
limit: { type: "integer", description: "Max rows (default 25, max 100)" },
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: "search_federal_contracts",
|
|
178
|
+
description:
|
|
179
|
+
"PAID ($0.01) — Federal contract awards won by any company: award id, dollar amount, awarding agency, dates, description, and record link, sorted largest first. Optional agency and date-window filters. Requires WALLET_PRIVATE_KEY.",
|
|
180
|
+
inputSchema: {
|
|
181
|
+
type: "object",
|
|
182
|
+
properties: {
|
|
183
|
+
recipient: { type: "string", description: "Company name, min 3 chars (required)" },
|
|
184
|
+
agency: { type: "string", description: "Awarding top-tier agency, e.g. 'Department of Defense'" },
|
|
185
|
+
since: { type: "string", description: "ISO start date (default: 2 years back)" },
|
|
186
|
+
until: { type: "string", description: "ISO end date (default: today)" },
|
|
187
|
+
limit: { type: "integer", description: "Max awards (default 10, max 50)" },
|
|
188
|
+
},
|
|
189
|
+
required: ["recipient"],
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: "get_contractor_profile",
|
|
194
|
+
description:
|
|
195
|
+
"PAID ($0.01) — Resolve a company name to its official federal recipient records: legal name, UEI, parent/child level, recent federal award totals, profile link. Use before search_federal_contracts to disambiguate entities. Requires WALLET_PRIVATE_KEY.",
|
|
196
|
+
inputSchema: {
|
|
197
|
+
type: "object",
|
|
198
|
+
properties: {
|
|
199
|
+
company: { type: "string", description: "Company name, min 3 chars (required)" },
|
|
200
|
+
limit: { type: "integer", description: "Max entities (default 5, max 20)" },
|
|
201
|
+
},
|
|
202
|
+
required: ["company"],
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
name: "get_candidate_money",
|
|
207
|
+
description:
|
|
208
|
+
"PAID ($0.01) — Campaign finance totals for a US federal candidate: receipts, spending, cash on hand, debts, individual vs PAC split, per recent cycle. Pass a name (fuzzy) or exact candidate_id; optional office preference. Requires WALLET_PRIVATE_KEY.",
|
|
209
|
+
inputSchema: {
|
|
210
|
+
type: "object",
|
|
211
|
+
properties: {
|
|
212
|
+
candidate: { type: "string", description: "Candidate name, min 3 chars" },
|
|
213
|
+
candidate_id: { type: "string", description: "Exact FEC candidate id (alternative to name)" },
|
|
214
|
+
office: { type: "string", enum: ["president", "senate", "house"] },
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
name: "find_candidate",
|
|
220
|
+
description:
|
|
221
|
+
"PAID ($0.005) — Search US federal candidates by name: candidate ids, party, office, state, district, and principal campaign committees. The cheap resolver before get_candidate_money. Requires WALLET_PRIVATE_KEY.",
|
|
222
|
+
inputSchema: {
|
|
223
|
+
type: "object",
|
|
224
|
+
properties: {
|
|
225
|
+
candidate: { type: "string", description: "Candidate name, min 3 chars (required)" },
|
|
226
|
+
},
|
|
227
|
+
required: ["candidate"],
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: "search_lobbying",
|
|
232
|
+
description:
|
|
233
|
+
"PAID ($0.01) — US federal lobbying filings by client company or lobbying firm: reported income, issue areas, specific-issue text, and named lobbyists per filing. Optional year filter. Requires WALLET_PRIVATE_KEY.",
|
|
234
|
+
inputSchema: {
|
|
235
|
+
type: "object",
|
|
236
|
+
properties: {
|
|
237
|
+
client: { type: "string", description: "Client organization name, e.g. 'coinbase'" },
|
|
238
|
+
registrant: { type: "string", description: "Lobbying firm name" },
|
|
239
|
+
year: { type: "string", description: "Filing year, e.g. '2025'" },
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: "watch_federal_register",
|
|
245
|
+
description:
|
|
246
|
+
"PAID ($0.005) — Newest US regulations and official notices matching a topic: proposed and final rules, executive orders, and notices with agency, date, abstract, and links, newest first. Empty query returns the latest government-wide. Requires WALLET_PRIVATE_KEY.",
|
|
247
|
+
inputSchema: {
|
|
248
|
+
type: "object",
|
|
249
|
+
properties: {
|
|
250
|
+
q: { type: "string", description: "Search term, e.g. 'stablecoin'" },
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
name: "lookup_bill",
|
|
256
|
+
description:
|
|
257
|
+
"PAID ($0.005) — Official status of a bill in the US Congress: title, sponsor, latest action, policy area, committees, and counts of actions/cosponsors/amendments. Address by congress number, type (hr, s, hjres, sjres...), and bill number. Requires WALLET_PRIVATE_KEY.",
|
|
258
|
+
inputSchema: {
|
|
259
|
+
type: "object",
|
|
260
|
+
properties: {
|
|
261
|
+
congress: { type: "string", description: "Congress number, e.g. '119'" },
|
|
262
|
+
type: { type: "string", description: "Bill type: hr, s, hjres, sjres, hconres, sconres, hres, sres" },
|
|
263
|
+
number: { type: "string", description: "Bill number, e.g. '1'" },
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: "get_endpoint_spec",
|
|
269
|
+
description:
|
|
270
|
+
"FREE — no wallet needed. Live call spec for the gov-transparency routes: price, input JSON schema, and worked request/response examples from the service's OpenAPI doc. Call with no arguments to list all nine routes, or pass a path for full detail.",
|
|
271
|
+
inputSchema: {
|
|
272
|
+
type: "object",
|
|
273
|
+
properties: {
|
|
274
|
+
path: { type: "string", description: "Route path, e.g. 'congress-stock-trades'" },
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
];
|
|
279
|
+
|
|
280
|
+
const TOOL_ROUTES = {
|
|
281
|
+
get_congress_trades: "/congress-stock-trades",
|
|
282
|
+
get_trade_filings: "/congress-trade-filings",
|
|
283
|
+
search_federal_contracts: "/federal-contracts-search",
|
|
284
|
+
get_contractor_profile: "/federal-contractor-profile",
|
|
285
|
+
get_candidate_money: "/fec-candidate-money",
|
|
286
|
+
find_candidate: "/fec-candidate-lookup",
|
|
287
|
+
search_lobbying: "/lobbying-filings",
|
|
288
|
+
watch_federal_register: "/federal-register-watch",
|
|
289
|
+
lookup_bill: "/congress-bill-lookup",
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
async function main() {
|
|
293
|
+
let ctxPromise;
|
|
294
|
+
async function getPaymentContext() {
|
|
295
|
+
if (!ctxPromise) ctxPromise = Promise.resolve().then(buildBaseHttpClient);
|
|
296
|
+
return ctxPromise;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const server = new Server({ name: "gov-transparency-mcp", version: VERSION }, { capabilities: { tools: {} } });
|
|
300
|
+
|
|
301
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
302
|
+
|
|
303
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
304
|
+
const { name, arguments: args = {} } = req.params;
|
|
305
|
+
try {
|
|
306
|
+
let data;
|
|
307
|
+
if (name === "get_endpoint_spec") {
|
|
308
|
+
data = await getEndpointSpec(args);
|
|
309
|
+
} else if (TOOL_ROUTES[name]) {
|
|
310
|
+
data = await paidPost(await getPaymentContext(), TOOL_ROUTES[name], args);
|
|
311
|
+
} else {
|
|
312
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
313
|
+
}
|
|
314
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
315
|
+
} catch (e) {
|
|
316
|
+
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
const transport = new StdioServerTransport();
|
|
321
|
+
await server.connect(transport);
|
|
322
|
+
console.error(`gov-transparency-mcp v${VERSION} ready — ${BASE_URL}`);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (require.main === module) {
|
|
326
|
+
main().catch((e) => {
|
|
327
|
+
console.error("Fatal:", e.message);
|
|
328
|
+
process.exit(1);
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
module.exports = { TOOLS, TOOL_ROUTES, getEndpointSpec, buildBaseHttpClient };
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@forgemeshlabs/gov-transparency-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Watch the watchers: congressional stock trades, federal contracts, campaign finance, lobbying, and new regulations as nine MCP tools. All official US government data, paid per call with x402 USDC on Base — no account or API key.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"gov-transparency-mcp": "index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"mcpName": "io.github.forgemeshlabs/gov-transparency-mcp",
|
|
15
|
+
"scripts": {
|
|
16
|
+
"start": "node index.js",
|
|
17
|
+
"test": "node --test test/*.test.js"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"model-context-protocol",
|
|
22
|
+
"x402",
|
|
23
|
+
"congress",
|
|
24
|
+
"stock-act",
|
|
25
|
+
"congressional-trading",
|
|
26
|
+
"campaign-finance",
|
|
27
|
+
"lobbying",
|
|
28
|
+
"federal-contracts",
|
|
29
|
+
"government-transparency",
|
|
30
|
+
"open-data",
|
|
31
|
+
"usdc",
|
|
32
|
+
"base"
|
|
33
|
+
],
|
|
34
|
+
"author": "ForgeMesh Labs (https://forgemesh.io)",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/forgemeshlabs/gov-transparency-mcp.git"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
42
|
+
"@x402/core": "^2.17.0",
|
|
43
|
+
"@x402/evm": "^2.17.0",
|
|
44
|
+
"viem": "^2.0.0"
|
|
45
|
+
}
|
|
46
|
+
}
|