coinopai-mcp 1.2.9 → 2.0.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 CHANGED
@@ -59,6 +59,10 @@ Trust the process less. Verify the record more.
59
59
 
60
60
  The agent calls a tool → the MCP server receives an `HTTP 402` → automatically signs a USDC micropayment → retries with the payment header → data returned. Configure once, pay automatically from the configured low-balance wallet.
61
61
 
62
+ Current package: `coinopai-mcp@1.2.10`.
63
+
64
+ Settlement note: the MCP pins `@x402/core` and `@x402/evm` to `2.11.0` and signs EIP-3009 authorizations with a chain-aware timestamp. This avoids the Base RPC/facilitator clock-skew failure mode where a payment can be rejected as "authorization is not yet valid" or "valid before expired". Successful object responses include x402 settlement metadata under `_payment`, including the on-chain transaction hash when available.
65
+
62
66
  ---
63
67
 
64
68
  ## The Auditable Loop ($0.27/cycle)
@@ -147,6 +151,8 @@ Directional values are supporting context, not guarantees, human recommendations
147
151
 
148
152
  Audit verdicts include `GOOD_DECISION`, `BAD_DIRECTION`, `NOISE`, `NO_ACTION_TAKEN`, and `PENDING`. Kronos gets some right, gets some wrong, and exposes both through the same record.
149
153
 
154
+ Fresh audits can return `pending_window` until the evaluation window matures.
155
+
150
156
  ---
151
157
 
152
158
  ## Tools
@@ -213,6 +219,10 @@ Add to your Claude Desktop config (`claude_desktop_config.json`):
213
219
 
214
220
  Not currently listed on Smithery. Use the `npx` install flow shown above until a verified public listing is live.
215
221
 
222
+ ### Developer smoke-test note
223
+
224
+ When testing the published package with an MCP stdio harness, do not launch `npx coinopai-mcp@...` from inside the `coinopai-mcp` source checkout. npm can prefer the local package context and fail before the temporary bin is available. Test from another directory, or install into a temp project and launch `./node_modules/.bin/coinopai-mcp`.
225
+
216
226
  ### Registry status
217
227
 
218
228
  Prepared MCP Registry identity: `io.github.forgemeshlabs/coinopai-mcp`. Refresh the public directory submission after publishing this package so old `clawdbotworker` entries stop being canonical.
@@ -289,6 +299,8 @@ Route to an available symbol or wait 15 minutes for the next cycle.
289
299
  | Network | Base mainnet (`eip155:8453`) |
290
300
  | Token | USDC (`0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`) |
291
301
  | Facilitator | Coinbase |
302
+ | Client SDK pins | `@x402/core@2.11.0`, `@x402/evm@2.11.0` |
303
+ | Receipt metadata | Successful object responses include `_payment` |
292
304
 
293
305
  ---
294
306
 
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 { registerExactEvmScheme } = require("@x402/evm/exact/client");
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 signer = toClientEvmSigner(account);
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.createPaymentPayload(paymentRequired);
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
- return paidRes.json();
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.9" },
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.9",
3
+ "version": "2.0.0",
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",
@@ -16,7 +16,7 @@
16
16
  "start": "node index.js"
17
17
  },
18
18
  "engines": {
19
- "node": ">=18"
19
+ "node": ">=20"
20
20
  },
21
21
  "keywords": [
22
22
  "mcp",
@@ -47,9 +47,9 @@
47
47
  "url": "https://github.com/forgemeshlabs/coinopai-mcp/issues"
48
48
  },
49
49
  "dependencies": {
50
- "@modelcontextprotocol/sdk": "^1.10.1",
51
- "@x402/core": "^2.12.0",
52
- "@x402/evm": "^2.12.0",
50
+ "@modelcontextprotocol/sdk": "^1.30.0",
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",
9
+ "version": "1.2.10",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "coinopai-mcp",
14
- "version": "1.2.9",
14
+ "version": "1.2.10",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },