coinopai-mcp 1.2.9 → 1.2.10
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 +37 -7
- package/package.json +3 -3
- package/server.json +2 -2
package/index.js
CHANGED
|
@@ -5,7 +5,7 @@ const { Server } = require("@modelcontextprotocol/sdk/server/index.js");
|
|
|
5
5
|
const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
6
|
const { CallToolRequestSchema, ListToolsRequestSchema } = require("@modelcontextprotocol/sdk/types.js");
|
|
7
7
|
const { x402Client, x402HTTPClient } = require("@x402/core/client");
|
|
8
|
-
const {
|
|
8
|
+
const { ExactEvmScheme } = require("@x402/evm/exact/client");
|
|
9
9
|
const { toClientEvmSigner } = require("@x402/evm");
|
|
10
10
|
const { privateKeyToAccount } = require("viem/accounts");
|
|
11
11
|
const { createPublicClient, createWalletClient, http, parseAbi } = require("viem");
|
|
@@ -36,6 +36,7 @@ const IMAGEGEN_URL = "https://imagegen.coinopai.com";
|
|
|
36
36
|
const PYRIMID_PRODUCTS_IMAGEGEN = {
|
|
37
37
|
"/generate": { productId: 3n, priceUsdc: 100000n },
|
|
38
38
|
};
|
|
39
|
+
const BASE_RPC_URL = process.env.BASE_RPC_URL || "https://mainnet.base.org";
|
|
39
40
|
|
|
40
41
|
const TOOLS = [
|
|
41
42
|
{
|
|
@@ -163,20 +164,42 @@ function buildHttpClient() {
|
|
|
163
164
|
if (!key) throw new Error("WALLET_PRIVATE_KEY required — set a Base wallet private key with USDC funded");
|
|
164
165
|
const pk = key.startsWith("0x") ? key : "0x" + key;
|
|
165
166
|
const account = privateKeyToAccount(pk);
|
|
166
|
-
const
|
|
167
|
-
const coreClient = registerExactEvmScheme(new x402Client(), { signer });
|
|
167
|
+
const coreClient = new x402Client().register("eip155:*", new ExactEvmScheme(toClientEvmSigner(account)));
|
|
168
168
|
return { httpClient: new x402HTTPClient(coreClient), account };
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
172
172
|
|
|
173
|
+
async function createChainTimedPaymentPayload(httpClient, paymentRequired) {
|
|
174
|
+
try {
|
|
175
|
+
const publicClient = createPublicClient({ chain: base, transport: http(BASE_RPC_URL) });
|
|
176
|
+
const block = await publicClient.getBlock();
|
|
177
|
+
const chainNow = Number(block.timestamp);
|
|
178
|
+
const originalNow = Date.now;
|
|
179
|
+
const localNow = Math.floor(originalNow() / 1000);
|
|
180
|
+
const timeout = Number(paymentRequired.accepts?.[0]?.maxTimeoutSeconds || 300);
|
|
181
|
+
const lowerBound = localNow + 30 - timeout;
|
|
182
|
+
const upperBound = chainNow + 600;
|
|
183
|
+
const signingNow = Math.min(Math.max(chainNow, lowerBound), upperBound);
|
|
184
|
+
// x402 derives EIP-3009 validity windows from Date.now; choose a timestamp valid for both Base block time and facilitator wall-clock checks.
|
|
185
|
+
Date.now = () => signingNow * 1000;
|
|
186
|
+
try {
|
|
187
|
+
return await httpClient.createPaymentPayload(paymentRequired);
|
|
188
|
+
} finally {
|
|
189
|
+
Date.now = originalNow;
|
|
190
|
+
}
|
|
191
|
+
} catch (_) {
|
|
192
|
+
return httpClient.createPaymentPayload(paymentRequired);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
173
196
|
// Pyrimid affiliate flow — approve + routePayment on-chain, then retry with tx hash
|
|
174
197
|
async function callPyrimid(account, path, affiliateId, baseUrl, products) {
|
|
175
198
|
const pathname = new URL(path, baseUrl).pathname;
|
|
176
199
|
const product = products[pathname];
|
|
177
200
|
if (!product) throw new Error(`No Pyrimid product registered for ${pathname}`);
|
|
178
201
|
const url = baseUrl + path;
|
|
179
|
-
const transport = http();
|
|
202
|
+
const transport = http(BASE_RPC_URL);
|
|
180
203
|
const publicClient = createPublicClient({ chain: base, transport });
|
|
181
204
|
const walletClient = createWalletClient({ account, chain: base, transport });
|
|
182
205
|
|
|
@@ -234,7 +257,7 @@ async function callPaid(ctx, path, affiliateId, opts = {}) {
|
|
|
234
257
|
const paymentRequired = httpClient.getPaymentRequiredResponse(
|
|
235
258
|
(name) => res.headers.get(name), body
|
|
236
259
|
);
|
|
237
|
-
const paymentPayload = await httpClient
|
|
260
|
+
const paymentPayload = await createChainTimedPaymentPayload(httpClient, paymentRequired);
|
|
238
261
|
const paidRes = await fetch(url, {
|
|
239
262
|
method,
|
|
240
263
|
headers: { ...bodyHeaders, ...httpClient.encodePaymentSignatureHeader(paymentPayload), ...extraHeaders },
|
|
@@ -244,7 +267,14 @@ async function callPaid(ctx, path, affiliateId, opts = {}) {
|
|
|
244
267
|
const errBody = await paidRes.text().catch(() => paidRes.statusText);
|
|
245
268
|
throw new Error(`HTTP ${paidRes.status}: ${errBody.slice(0, 200)}`);
|
|
246
269
|
}
|
|
247
|
-
|
|
270
|
+
const data = await paidRes.json();
|
|
271
|
+
try {
|
|
272
|
+
const settleResponse = httpClient.getPaymentSettleResponse((name) => paidRes.headers.get(name));
|
|
273
|
+
if (settleResponse && data && typeof data === "object" && !Array.isArray(data)) {
|
|
274
|
+
return { ...data, _payment: settleResponse };
|
|
275
|
+
}
|
|
276
|
+
} catch (_) {}
|
|
277
|
+
return data;
|
|
248
278
|
}
|
|
249
279
|
|
|
250
280
|
if (!res.ok) {
|
|
@@ -262,7 +292,7 @@ async function main() {
|
|
|
262
292
|
}
|
|
263
293
|
|
|
264
294
|
const server = new Server(
|
|
265
|
-
{ name: "coinopai-mcp", version: "1.2.
|
|
295
|
+
{ name: "coinopai-mcp", version: "1.2.10" },
|
|
266
296
|
{ capabilities: { tools: {} } }
|
|
267
297
|
);
|
|
268
298
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coinopai-mcp",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.10",
|
|
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",
|
|
6
6
|
"main": "index.js",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@modelcontextprotocol/sdk": "^1.10.1",
|
|
51
|
-
"@x402/core": "
|
|
52
|
-
"@x402/evm": "
|
|
51
|
+
"@x402/core": "2.11.0",
|
|
52
|
+
"@x402/evm": "2.11.0",
|
|
53
53
|
"viem": "^2.0.0"
|
|
54
54
|
}
|
|
55
55
|
}
|
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": "1.2.
|
|
9
|
+
"version": "1.2.10",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "coinopai-mcp",
|
|
14
|
-
"version": "1.2.
|
|
14
|
+
"version": "1.2.10",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|