@forgemeshlabs/gov-transparency-mcp 0.1.6 → 0.1.7
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/index.js +5 -1
- package/package.json +1 -1
- package/x402-guard.js +20 -2
package/index.js
CHANGED
|
@@ -98,7 +98,7 @@ const TOOLS = [
|
|
|
98
98
|
openWorldHint: true,
|
|
99
99
|
},
|
|
100
100
|
description:
|
|
101
|
-
"PAID ($0.02) — Congress stock trades 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.
|
|
101
|
+
"PAID ($0.02) — Congress stock trades 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. House only, no Senate; disclosures lag trades by up to 45 days by law. Requires WALLET_PRIVATE_KEY.",
|
|
102
102
|
inputSchema: {
|
|
103
103
|
type: "object",
|
|
104
104
|
properties: {
|
|
@@ -348,6 +348,10 @@ async function main() {
|
|
|
348
348
|
}
|
|
349
349
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
350
350
|
} catch (e) {
|
|
351
|
+
if (e && e.status !== undefined) {
|
|
352
|
+
// Service refusal: structured data, the upstream body is untrusted and never interpolated into prose.
|
|
353
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: e.message, status: e.status, charged: e.charged, upstream: e.upstream, untrusted: true }, null, 2) }], isError: true };
|
|
354
|
+
}
|
|
351
355
|
return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
|
|
352
356
|
}
|
|
353
357
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgemeshlabs/gov-transparency-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
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
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
package/x402-guard.js
CHANGED
|
@@ -99,6 +99,24 @@ function createGuard(opts) {
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
// Keep the service's refusal as data, never as prose: the message is fixed (status plus a short error
|
|
103
|
+
// code if the service sent one); the parsed body is carried in err.upstream, capped at 1500 chars.
|
|
104
|
+
function httpError(res, prefix, charged) {
|
|
105
|
+
let upstream;
|
|
106
|
+
try { upstream = JSON.parse(res.text); } catch { upstream = res.text.slice(0, 1500); }
|
|
107
|
+
if (upstream && typeof upstream === "object") {
|
|
108
|
+
const json = JSON.stringify(upstream);
|
|
109
|
+
if (json.length > 1500) upstream = json.slice(0, 1500);
|
|
110
|
+
}
|
|
111
|
+
const code = upstream && typeof upstream === "object" && typeof upstream.error === "string" && /^[A-Za-z0-9_.-]{1,64}$/.test(upstream.error) ? upstream.error : null;
|
|
112
|
+
const err = new Error(`${prefix}HTTP ${res.status}${code ? ` (${code})` : ""}`);
|
|
113
|
+
err.status = res.status;
|
|
114
|
+
err.upstream = upstream;
|
|
115
|
+
if (charged !== undefined) err.charged = charged;
|
|
116
|
+
else if (upstream && typeof upstream === "object" && typeof upstream.charged === "boolean") err.charged = upstream.charged;
|
|
117
|
+
return err;
|
|
118
|
+
}
|
|
119
|
+
|
|
102
120
|
function parseJson(res) {
|
|
103
121
|
try { return JSON.parse(res.text); } catch { throw new Error(`HTTP ${res.status}: non-JSON response`); }
|
|
104
122
|
}
|
|
@@ -111,7 +129,7 @@ function createGuard(opts) {
|
|
|
111
129
|
const init = { method, headers: { ...headers, ...(body ? { "content-type": "application/json" } : {}) }, ...(body ? { body: JSON.stringify(body) } : {}) };
|
|
112
130
|
const res = await fetchBounded(url, init);
|
|
113
131
|
if (res.status !== 402) {
|
|
114
|
-
if (!res.ok) throw
|
|
132
|
+
if (!res.ok) throw httpError(res, "", false); // nothing was signed, so nothing was charged
|
|
115
133
|
return parseJson(res);
|
|
116
134
|
}
|
|
117
135
|
let challenge;
|
|
@@ -119,7 +137,7 @@ function createGuard(opts) {
|
|
|
119
137
|
const paymentRequired = httpClient.getPaymentRequiredResponse((n) => res.headers.get(n), challenge);
|
|
120
138
|
const payload = await httpClient.createPaymentPayload(paymentRequired); // policy runs (and reserves budget) inside
|
|
121
139
|
const paid = await fetchBounded(url, { ...init, headers: { ...init.headers, ...httpClient.encodePaymentSignatureHeader(payload) } });
|
|
122
|
-
if (!paid.ok) throw
|
|
140
|
+
if (!paid.ok) throw httpError(paid, "Payment failed — ");
|
|
123
141
|
let settle = null;
|
|
124
142
|
try { settle = httpClient.getPaymentSettleResponse((n) => paid.headers.get(n)) || null; } catch { settle = null; }
|
|
125
143
|
const contentType = paid.headers.get("content-type") || "";
|