coinopai-mcp 2.2.4 → 2.2.6
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/package.json +1 -1
- package/server.json +2 -2
- package/x402-guard.js +16 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coinopai-mcp",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.6",
|
|
4
4
|
"mcpName": "io.github.forgemeshlabs/coinopai-mcp",
|
|
5
5
|
"description": "Auditable market intelligence MCP with x402 payments, calibrated forecast ranges, anomaly review, risk context, and outcome audits. The hosted MCP at https://x402.coinopai.com/mcp has a free handshake (initialize, ping, tools/list); only tool calls are charged",
|
|
6
6
|
"main": "index.js",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/forgemeshlabs/coinopai-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "2.2.
|
|
9
|
+
"version": "2.2.6",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "coinopai-mcp",
|
|
14
|
-
"version": "2.2.
|
|
14
|
+
"version": "2.2.6",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|
package/x402-guard.js
CHANGED
|
@@ -99,6 +99,20 @@ function createGuard(opts) {
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
// Keep the service's refusal intact: HTTP status, body (JSON when parseable) and the charged flag.
|
|
103
|
+
function httpError(res, prefix, charged) {
|
|
104
|
+
let upstream;
|
|
105
|
+
try { upstream = JSON.parse(res.text); } catch { upstream = res.text.slice(0, 500); }
|
|
106
|
+
// The message stays short and fixed; the service body travels only as structured, capped data.
|
|
107
|
+
const code = upstream && typeof upstream === "object" && typeof upstream.error === "string" && /^[a-z0-9_-]{1,64}$/i.test(upstream.error) ? ` ${upstream.error}` : "";
|
|
108
|
+
const err = new Error(`${prefix}HTTP ${res.status}${code}`);
|
|
109
|
+
err.status = res.status;
|
|
110
|
+
err.upstream = typeof upstream === "string" ? upstream.slice(0, 1500) : (JSON.stringify(upstream).length > 1500 ? JSON.stringify(upstream).slice(0, 1500) : upstream);
|
|
111
|
+
if (charged !== undefined) err.charged = charged;
|
|
112
|
+
else if (upstream && typeof upstream === "object" && typeof upstream.charged === "boolean") err.charged = upstream.charged;
|
|
113
|
+
return err;
|
|
114
|
+
}
|
|
115
|
+
|
|
102
116
|
function parseJson(res) {
|
|
103
117
|
try { return JSON.parse(res.text); } catch { throw new Error(`HTTP ${res.status}: non-JSON response`); }
|
|
104
118
|
}
|
|
@@ -111,7 +125,7 @@ function createGuard(opts) {
|
|
|
111
125
|
const init = { method, headers: { ...headers, ...(body ? { "content-type": "application/json" } : {}) }, ...(body ? { body: JSON.stringify(body) } : {}) };
|
|
112
126
|
const res = await fetchBounded(url, init);
|
|
113
127
|
if (res.status !== 402) {
|
|
114
|
-
if (!res.ok) throw
|
|
128
|
+
if (!res.ok) throw httpError(res, "", false); // nothing was signed, so nothing was charged
|
|
115
129
|
return parseJson(res);
|
|
116
130
|
}
|
|
117
131
|
let challenge;
|
|
@@ -119,7 +133,7 @@ function createGuard(opts) {
|
|
|
119
133
|
const paymentRequired = httpClient.getPaymentRequiredResponse((n) => res.headers.get(n), challenge);
|
|
120
134
|
const payload = await httpClient.createPaymentPayload(paymentRequired); // policy runs (and reserves budget) inside
|
|
121
135
|
const paid = await fetchBounded(url, { ...init, headers: { ...init.headers, ...httpClient.encodePaymentSignatureHeader(payload) } });
|
|
122
|
-
if (!paid.ok) throw
|
|
136
|
+
if (!paid.ok) throw httpError(paid, "Payment failed — ");
|
|
123
137
|
let settle = null;
|
|
124
138
|
try { settle = httpClient.getPaymentSettleResponse((n) => paid.headers.get(n)) || null; } catch { settle = null; }
|
|
125
139
|
const contentType = paid.headers.get("content-type") || "";
|