@aifinpay/mcp 1.5.3 → 2.0.0-rc.13

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.
Files changed (47) hide show
  1. package/README.md +116 -69
  2. package/bin/aifinpay-mcp.js +119 -49
  3. package/dist/api.d.ts +2 -0
  4. package/dist/api.d.ts.map +1 -0
  5. package/dist/api.js +6 -0
  6. package/dist/api.js.map +1 -0
  7. package/dist/config.d.ts +35 -2
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +63 -0
  10. package/dist/config.js.map +1 -1
  11. package/dist/identity.d.ts +9 -0
  12. package/dist/identity.d.ts.map +1 -0
  13. package/dist/identity.js +75 -0
  14. package/dist/identity.js.map +1 -0
  15. package/dist/index.d.ts +3 -6
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +3 -6
  18. package/dist/index.js.map +1 -1
  19. package/dist/safe-fetch.d.ts +2 -0
  20. package/dist/safe-fetch.d.ts.map +1 -1
  21. package/dist/safe-fetch.js +76 -17
  22. package/dist/safe-fetch.js.map +1 -1
  23. package/dist/server.d.ts +11 -8
  24. package/dist/server.d.ts.map +1 -1
  25. package/dist/server.js +106 -102
  26. package/dist/server.js.map +1 -1
  27. package/dist/tools/agent-address.d.ts.map +1 -1
  28. package/dist/tools/agent-address.js +6 -27
  29. package/dist/tools/agent-address.js.map +1 -1
  30. package/dist/tools/agent-history.d.ts +58 -0
  31. package/dist/tools/agent-history.d.ts.map +1 -0
  32. package/dist/tools/agent-history.js +73 -0
  33. package/dist/tools/agent-history.js.map +1 -0
  34. package/dist/tools/agent-quota.d.ts +40 -0
  35. package/dist/tools/agent-quota.d.ts.map +1 -0
  36. package/dist/tools/agent-quota.js +95 -0
  37. package/dist/tools/agent-quota.js.map +1 -0
  38. package/dist/tools/dev-payment-quote.d.ts +39 -0
  39. package/dist/tools/dev-payment-quote.d.ts.map +1 -0
  40. package/dist/tools/dev-payment-quote.js +52 -0
  41. package/dist/tools/dev-payment-quote.js.map +1 -0
  42. package/dist/tools/production-control.d.ts +108 -0
  43. package/dist/tools/production-control.d.ts.map +1 -0
  44. package/dist/tools/production-control.js +132 -0
  45. package/dist/tools/production-control.js.map +1 -0
  46. package/package.json +8 -22
  47. package/skills/SKILL.md +143 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAcvF,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,cAAc,GAAG,IAAI,CA0C3E"}
@@ -0,0 +1,75 @@
1
+ import { readFileSync, existsSync, statSync } from "node:fs";
2
+ import { resolve, join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import { scryptSync, createDecipheriv } from "node:crypto";
5
+ function seed(value) {
6
+ if (typeof value !== "string" || !/^(0x)?[0-9a-fA-F]{64}$/.test(value)) {
7
+ throw new Error("SEED_HASH must contain a 32-byte hex seed (64 hex characters); no mnemonic or double hashing");
8
+ }
9
+ return value.replace(/^0x/, "");
10
+ }
11
+ function readJson(path) {
12
+ try {
13
+ return JSON.parse(readFileSync(path, "utf8"));
14
+ }
15
+ catch {
16
+ throw new Error(`Cannot read wallet JSON at ${path}; refusing to generate a replacement wallet`);
17
+ }
18
+ }
19
+ /** Local inputs only. Never put the returned secrets in an MCP response/log. */
20
+ export function loadWalletIdentity(config) {
21
+ if (config.seedHash !== undefined)
22
+ return { source: "SEED_HASH", seedHash: seed(config.seedHash) };
23
+ const path = resolve(config.agentsFile || "./aifinpay/agents.json");
24
+ if (existsSync(path)) {
25
+ const document = readJson(path);
26
+ const agents = document?.agents;
27
+ if (!Array.isArray(agents) || agents.length === 0)
28
+ throw new Error("agents.json requires a non-empty agents array");
29
+ const matches = config.agentId
30
+ ? agents.filter((a) => a?.id === config.agentId)
31
+ : agents;
32
+ if (matches.length !== 1)
33
+ throw new Error("Select exactly one agents.json record with AIFINPAY_AGENT_ID; refusing an ambiguous wallet");
34
+ return { source: "agents.json", seedHash: seed(matches[0]?.seed_hash) };
35
+ }
36
+ if (config.agentsFile)
37
+ throw new Error("Configured AIFINPAY_AGENTS_FILE does not exist");
38
+ if (config.agentSecretB58)
39
+ return { source: "AIFINPAY_AGENT_SECRET", secretB58: config.agentSecretB58 };
40
+ const legacyPath = join(config.walletHome || join(homedir(), ".aifinpay"), "agent.json");
41
+ if (!existsSync(legacyPath))
42
+ return null;
43
+ const legacy = readJson(legacyPath);
44
+ try {
45
+ const mode = statSync(legacyPath).mode & 0o777;
46
+ if (mode & 0o077) {
47
+ const message = `[aifinpay-mcp] ${legacyPath} is mode ${mode.toString(8)} — readable beyond your user. Run: chmod 600 ${legacyPath}`;
48
+ if (config.logFn)
49
+ config.logFn("warn", message);
50
+ else
51
+ process.stderr.write(`[warn] ${message}\n`);
52
+ }
53
+ }
54
+ catch { /* A stat failure does not change which wallet was selected. */ }
55
+ if (legacy.enc) {
56
+ if (legacy.enc !== "scrypt-aes-256-gcm" || !config.walletPassphrase) {
57
+ throw new Error("Encrypted keystore requires AIFINPAY_WALLET_PASSPHRASE and the supported encryption format");
58
+ }
59
+ try {
60
+ const key = scryptSync(config.walletPassphrase, Buffer.from(legacy.salt, "base64"), 32, { N: 1 << 15, r: 8, p: 1, maxmem: 64 * 1024 * 1024 });
61
+ const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(legacy.iv, "base64"));
62
+ decipher.setAuthTag(Buffer.from(legacy.tag, "base64"));
63
+ return { source: "legacy-keystore", secretB58: Buffer.concat([
64
+ decipher.update(Buffer.from(legacy.ct, "base64")), decipher.final(),
65
+ ]).toString("utf8") };
66
+ }
67
+ catch {
68
+ throw new Error("Cannot decrypt keystore; refusing to generate a replacement wallet");
69
+ }
70
+ }
71
+ if (typeof legacy.secretB58 !== "string" || !legacy.secretB58)
72
+ throw new Error("Invalid legacy keystore");
73
+ return { source: "legacy-keystore", secretB58: legacy.secretB58 };
74
+ }
75
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,12 +2,9 @@
2
2
  * @aifinpay/mcp — MCP server exposing AiFinPay's autonomous x402 payment
3
3
  * loop as agent-callable tools.
4
4
  *
5
- * Tools:
6
- * - agent_address() — return Solana + EVM addresses to fund
7
- * - agent_call(provider, body) — registry-resolved paid call (Polygon settle)
8
- * - payable_fetch(url, opts?) — raw-URL paid fetch (legacy Solana path)
9
- * - agent_quote(url) — inspect 402 cost before paying
10
- * - pay_with_split / quote_split — direct B2BSplitter invoice (advanced)
5
+ * Tools: public addresses, history, quotas, passport resolution, non-signing
6
+ * settlement invoices, local wallet reload, and opt-in dev batch quoting.
7
+ * Signing tools are not registered in this RC.
11
8
  *
12
9
  * Quick start (stdio transport for Claude Desktop / MCP-aware runtimes):
13
10
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -2,12 +2,9 @@
2
2
  * @aifinpay/mcp — MCP server exposing AiFinPay's autonomous x402 payment
3
3
  * loop as agent-callable tools.
4
4
  *
5
- * Tools:
6
- * - agent_address() — return Solana + EVM addresses to fund
7
- * - agent_call(provider, body) — registry-resolved paid call (Polygon settle)
8
- * - payable_fetch(url, opts?) — raw-URL paid fetch (legacy Solana path)
9
- * - agent_quote(url) — inspect 402 cost before paying
10
- * - pay_with_split / quote_split — direct B2BSplitter invoice (advanced)
5
+ * Tools: public addresses, history, quotas, passport resolution, non-signing
6
+ * settlement invoices, local wallet reload, and opt-in dev batch quoting.
7
+ * Signing tools are not registered in this RC.
11
8
  *
12
9
  * Quick start (stdio transport for Claude Desktop / MCP-aware runtimes):
13
10
  *
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
@@ -12,6 +12,7 @@ export declare class BlockedRequestError extends Error {
12
12
  */
13
13
  export declare function assertRequestAllowed(rawUrl: string, opts?: {
14
14
  allowPrivate?: boolean;
15
+ trustedHosts?: string[];
15
16
  }): Promise<URL>;
16
17
  /**
17
18
  * A `fetch` that validates the target, and every redirect target, before going.
@@ -21,5 +22,6 @@ export declare function assertRequestAllowed(rawUrl: string, opts?: {
21
22
  */
22
23
  export declare function makeSafeFetch(opts?: {
23
24
  allowPrivate?: boolean;
25
+ trustedHosts?: string[];
24
26
  }): typeof fetch;
25
27
  //# sourceMappingURL=safe-fetch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"safe-fetch.d.ts","sourceRoot":"","sources":["../src/safe-fetch.ts"],"names":[],"mappings":"AA4DA,oDAAoD;AACpD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAmBtD;AAED,qBAAa,mBAAoB,SAAQ,KAAK;CAAG;AAEjD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GACpC,OAAO,CAAC,GAAG,CAAC,CAkDd;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,KAAK,CA4BjF"}
1
+ {"version":3,"file":"safe-fetch.d.ts","sourceRoot":"","sources":["../src/safe-fetch.ts"],"names":[],"mappings":"AA4DA,oDAAoD;AACpD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CA0BtD;AAED,qBAAa,mBAAoB,SAAQ,KAAK;CAAG;AAEjD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,GAC7D,OAAO,CAAC,GAAG,CAAC,CAyEd;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,GAAG,OAAO,KAAK,CAkD1G"}
@@ -65,12 +65,22 @@ export function isBlockedAddress(addr) {
65
65
  return BLOCKED_V4.some(([lo, hi]) => n >= lo && n <= hi);
66
66
  }
67
67
  if (family === 6) {
68
- const lower = addr.toLowerCase().replace(/^\[|\]$/g, "");
68
+ // URL canonicalization collapses expanded zeros AND rewrites mapped dotted
69
+ // IPv4 into hex, e.g. ::ffff:127.0.0.1 becomes ::ffff:7f00:1.
70
+ let lower;
71
+ try {
72
+ lower = new URL(`https://[${addr}]/`).hostname.replace(/^\[|\]$/g, "");
73
+ }
74
+ catch {
75
+ return true;
76
+ }
69
77
  // An IPv4-mapped address is an IPv4 address wearing a hat. Unwrap it, or
70
78
  // ::ffff:127.0.0.1 walks straight through an IPv6-only check.
71
- const mapped = lower.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);
72
- if (mapped)
73
- return isBlockedAddress(mapped[1]);
79
+ const mapped = lower.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
80
+ if (mapped) {
81
+ const n = (parseInt(mapped[1], 16) * 65536 + parseInt(mapped[2], 16)) >>> 0;
82
+ return BLOCKED_V4.some(([lo, hi]) => n >= lo && n <= hi);
83
+ }
74
84
  if (lower === "::1" || lower === "::")
75
85
  return true;
76
86
  if (/^f[cd][0-9a-f]{2}:/.test(lower))
@@ -116,12 +126,32 @@ export async function assertRequestAllowed(rawUrl, opts = {}) {
116
126
  }
117
127
  return url;
118
128
  }
129
+ // An operator naming this exact host has vouched for it, so the resolution
130
+ // step is skipped for it and only for it.
131
+ //
132
+ // Why this exists: behind an HTTP proxy the client does not resolve at all —
133
+ // the proxy does — so lookup() fails with getaddrinfo EAI_AGAIN and every
134
+ // host is refused as "cannot resolve". That is the guard misfiring on the
135
+ // environment rather than on a threat, and it made the MCP server unusable in
136
+ // proxied setups (external E2E, 2026-08-27).
137
+ //
138
+ // Deliberately per-host and not a proxy-detection switch. "We seem to be
139
+ // behind a proxy, disable the SSRF check" turns one environment quirk into a
140
+ // blanket bypass, which is the shape of the vulnerability this file exists to
141
+ // prevent. Exact hostnames only — no suffix matching, because "example.com"
142
+ // trusting "evil-example.com" is the classic way an allowlist stops meaning
143
+ // anything.
144
+ if (opts.trustedHosts?.some((h) => h.toLowerCase() === host.toLowerCase())) {
145
+ return url;
146
+ }
119
147
  let addresses;
120
148
  try {
121
149
  addresses = await lookup(host, { all: true });
122
150
  }
123
151
  catch (e) {
124
- throw new BlockedRequestError(`cannot resolve ${host}: ${e.message}`);
152
+ throw new BlockedRequestError(`cannot resolve ${host}: ${e.message}. `
153
+ + `If this host is reachable only through a proxy, name it in `
154
+ + `AIFINPAY_TRUSTED_HOSTS to skip the DNS pre-check for it alone.`);
125
155
  }
126
156
  if (!addresses.length) {
127
157
  throw new BlockedRequestError(`${host} resolved to nothing`);
@@ -143,22 +173,51 @@ export async function assertRequestAllowed(rawUrl, opts = {}) {
143
173
  */
144
174
  export function makeSafeFetch(opts = {}) {
145
175
  const safeFetch = async (input, init) => {
146
- let target = typeof input === "string" ? input
147
- : input instanceof URL ? input.toString()
148
- : input.url;
149
- let request = init;
176
+ let request = new Request(input, init);
177
+ const redirect = request.redirect;
150
178
  for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {
151
- await assertRequestAllowed(target, opts);
152
- const res = await globalThis.fetch(target, { ...request, redirect: "manual" });
153
- const location = res.status >= 300 && res.status < 400 ? res.headers.get("location") : null;
179
+ await assertRequestAllowed(request.url, opts);
180
+ const res = await globalThis.fetch(request.clone(), { redirect: "manual" });
181
+ const location = [301, 302, 303, 307, 308].includes(res.status) ? res.headers.get("location") : null;
154
182
  if (!location)
155
183
  return res;
156
- target = new URL(location, target).toString();
157
- // 303, and 301/302 in practice, turn the follow-up into a GET with no
158
- // body. Mirroring that keeps behaviour the same as a normal fetch.
159
- if (res.status === 303 || res.status === 301 || res.status === 302) {
160
- request = { ...request, method: "GET", body: undefined };
184
+ if (redirect === "manual")
185
+ return res;
186
+ await res.body?.cancel();
187
+ if (redirect === "error")
188
+ throw new BlockedRequestError("redirect forbidden by request policy");
189
+ if (hop === MAX_REDIRECTS)
190
+ break;
191
+ const next = new URL(location, request.url);
192
+ const crossOrigin = next.origin !== new URL(request.url).origin;
193
+ const dropBody = (res.status === 303 && !["GET", "HEAD"].includes(request.method))
194
+ || ([301, 302].includes(res.status) && request.method === "POST");
195
+ if (crossOrigin && request.body && !dropBody) {
196
+ throw new BlockedRequestError("refusing cross-origin redirect with a request body");
197
+ }
198
+ const headers = new Headers(request.headers);
199
+ if (crossOrigin) {
200
+ // Only explicitly public negotiation headers may leave the original
201
+ // origin. A denylist cannot anticipate every merchant's secret header.
202
+ const publicHeaders = new Set(["accept", "accept-language", "cache-control", "pragma"]);
203
+ for (const key of Array.from(headers.keys()))
204
+ if (!publicHeaders.has(key))
205
+ headers.delete(key);
206
+ }
207
+ if (dropBody) {
208
+ for (const key of ["content-type", "content-length", "content-encoding", "content-language", "content-location"])
209
+ headers.delete(key);
161
210
  }
211
+ const redirectInit = dropBody ? {
212
+ method: "GET", signal: request.signal, credentials: request.credentials,
213
+ cache: request.cache, mode: request.mode, redirect, referrer: request.referrer,
214
+ referrerPolicy: request.referrerPolicy, integrity: request.integrity, keepalive: request.keepalive,
215
+ } : request;
216
+ const redirected = new Request(next, redirectInit);
217
+ request = new Request(redirected, {
218
+ headers,
219
+ ...(crossOrigin ? { credentials: "omit", referrer: "", referrerPolicy: "no-referrer" } : {}),
220
+ });
162
221
  }
163
222
  throw new BlockedRequestError(`too many redirects (more than ${MAX_REDIRECTS})`);
164
223
  };
@@ -1 +1 @@
1
- {"version":3,"file":"safe-fetch.js","sourceRoot":"","sources":["../src/safe-fetch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"safe-fetch.js","sourceRoot":"","sources":["../src/safe-fetch.ts"],"names":[],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -2,15 +2,18 @@ import { AiFinPayAgent } from "@aifinpay/agent";
2
2
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import type { McpConfig } from "./config.js";
4
4
  /**
5
- * Build an MCP server that wraps the AiFinPay agent SDK as MCP tools.
5
+ * Production-RC MCP surface.
6
6
  *
7
- * Returned server is unstarted — caller wires up a transport (stdio, SSE,
8
- * etc.) via the official `@modelcontextprotocol/sdk` package.
7
+ * IMPORTANT: the old agent_call, payable_fetch, pay_with_split, quote_split,
8
+ * agent_claim_self and agent_quote tools are deliberately NOT registered.
9
+ * They depend on @aifinpay/agent 1.x legacy splitter/x402 semantics and must not
10
+ * be available to a model after the 0% AIFP-2 / gross-inclusive AIFP-1 change.
9
11
  *
10
- * As of 0.1.0-alpha.3 the wrapped identity is `AiFinPayAgent` — dual-chain
11
- * (Solana base58 pubkey AND Polygon EVM address from one secret). Tools
12
- * that previously called legacy `Agent` methods now reach them via
13
- * `agent.inner.*`.
12
+ * This server remains useful before the SDK 2.0 package is published: it can
13
+ * expose the wallet address, resolve Agent Passport identity, read verified
14
+ * v1.3 routes, and construct a non-signing settlement invoice. Signing/moving
15
+ * value returns only after MCP depends on the published v2 executor and its E2E
16
+ * release gate has passed.
14
17
  */
15
18
  export declare function createServer(config?: McpConfig): Promise<{
16
19
  server: Server<{
@@ -47,7 +50,7 @@ export declare function createServer(config?: McpConfig): Promise<{
47
50
  } | undefined;
48
51
  } | undefined;
49
52
  }>;
50
- agent: AiFinPayAgent;
53
+ readonly agent: AiFinPayAgent;
51
54
  }>;
52
55
  export interface ToolContext {
53
56
  agent: AiFinPayAgent;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAS,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAKnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AA4B7C;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAAC,MAAM,GAAE,SAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiHxD;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,SAAS,CAAC;IAClB,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9D"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAQnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AA2B7C;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAAC,MAAM,GAAE,SAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+GxD;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,SAAS,CAAC;IAClB,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9D"}
package/dist/server.js CHANGED
@@ -1,139 +1,143 @@
1
1
  import { AiFinPayAgent } from "@aifinpay/agent";
2
2
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
- import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
- import { payableFetchTool, runPayableFetch } from "./tools/payable-fetch.js";
3
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
+ import { readFileSync } from "node:fs";
5
+ import { loadWalletIdentity } from "./identity.js";
6
+ import { agentHistoryTool, runAgentHistory } from "./tools/agent-history.js";
7
+ import { devPaymentQuoteTool, runDevPaymentQuote } from "./tools/dev-payment-quote.js";
5
8
  import { agentAddressTool, runAgentAddress } from "./tools/agent-address.js";
6
- import { agentQuoteTool, runAgentQuote } from "./tools/agent-quote.js";
7
- import { agentCallTool, runAgentCall } from "./tools/agent-call.js";
8
- import { agentClaimSelfTool, runAgentClaimSelf } from "./tools/agent-claim-self.js";
9
+ import { agentQuotaTool, runAgentQuota } from "./tools/agent-quota.js";
9
10
  import { makeSafeFetch } from "./safe-fetch.js";
10
- import { payWithSplitTool, runPayWithSplit, quoteSplitTool, runQuoteSplit, } from "./tools/pay-with-split.js";
11
- // Every request the agent makes goes through this, including redirects.
12
- //
13
- // payable_fetch hands a caller-supplied URL to the agent, which requests it
14
- // and, on a 402, pays and requests it again. Nothing checked the URL, so a
15
- // caller — or a prompt injection reaching the tool — could name
16
- // http://127.0.0.1:4001 or http://169.254.169.254/latest/meta-data/ and read
17
- // the answer. It is the tool exposed over HTTP today.
18
- //
19
- // Set AIFINPAY_ALLOW_PRIVATE_FETCH=1 to lift it, which is what a local bridge
20
- // on localhost needs and what a public deployment must never have.
11
+ import { loadConfigFromEnv } from "./config.js";
12
+ import { agentPassportResolveTool, runAgentPassportResolve, settlementRoutesTool, runSettlementRoutes, settlementInvoiceTool, runSettlementInvoice, } from "./tools/production-control.js";
13
+ // Every backend/public request made by this server goes through safeFetch.
14
+ // Public deployments never lift private-network protection; local development
15
+ // may explicitly use AIFINPAY_ALLOW_PRIVATE_FETCH=1.
21
16
  const safeFetch = makeSafeFetch({
22
17
  allowPrivate: process.env.AIFINPAY_ALLOW_PRIVATE_FETCH === "1",
18
+ // Exact hosts an operator vouches for. Skips only the DNS pre-check, and only
19
+ // for those names — see safe-fetch.ts for why this is not a proxy switch.
20
+ trustedHosts: loadConfigFromEnv().trustedHosts,
23
21
  });
24
22
  /**
25
- * Build an MCP server that wraps the AiFinPay agent SDK as MCP tools.
23
+ * Production-RC MCP surface.
26
24
  *
27
- * Returned server is unstarted — caller wires up a transport (stdio, SSE,
28
- * etc.) via the official `@modelcontextprotocol/sdk` package.
25
+ * IMPORTANT: the old agent_call, payable_fetch, pay_with_split, quote_split,
26
+ * agent_claim_self and agent_quote tools are deliberately NOT registered.
27
+ * They depend on @aifinpay/agent 1.x legacy splitter/x402 semantics and must not
28
+ * be available to a model after the 0% AIFP-2 / gross-inclusive AIFP-1 change.
29
29
  *
30
- * As of 0.1.0-alpha.3 the wrapped identity is `AiFinPayAgent` — dual-chain
31
- * (Solana base58 pubkey AND Polygon EVM address from one secret). Tools
32
- * that previously called legacy `Agent` methods now reach them via
33
- * `agent.inner.*`.
30
+ * This server remains useful before the SDK 2.0 package is published: it can
31
+ * expose the wallet address, resolve Agent Passport identity, read verified
32
+ * v1.3 routes, and construct a non-signing settlement invoice. Signing/moving
33
+ * value returns only after MCP depends on the published v2 executor and its E2E
34
+ * release gate has passed.
34
35
  */
35
36
  export async function createServer(config = {}) {
36
37
  const log = config.logFn ?? defaultLog;
37
- // Agent identity: load from env secret if provided, else generate one
38
- // and print to stderr so the human knows what to fund.
39
- const agent = config.agentSecretB58
40
- ? await AiFinPayAgent.fromSolanaSecret(config.agentSecretB58, {
41
- fetchImpl: safeFetch,
42
- baseUrl: config.baseUrl,
43
- timeoutMs: config.timeoutMs,
44
- })
45
- : await (async () => {
46
- const a = await AiFinPayAgent.new({
47
- fetchImpl: safeFetch,
48
- baseUrl: config.baseUrl,
49
- timeoutMs: config.timeoutMs,
50
- });
51
- // NEVER log private key material. stderr is captured by Docker,
52
- // journald, CI logs, support bundles and monitoring, so printing the
53
- // secret here leaked it into all of them.
54
- //
55
- // The warning below stays, but not for the reason it once gave. That
56
- // reason — that new() produced an EVM key independent of the Solana
57
- // one, so no backup could restore both — was fixed: everything now
58
- // derives from a single random seed. What makes this identity
59
- // ephemeral is narrower and still true: the seed is never printed and
60
- // never written anywhere, deliberately, because stderr ends up in
61
- // Docker, journald, CI logs and support bundles. Recoverable in
62
- // principle, unrecoverable in practice, so still not an address to
63
- // fund.
64
- log("warn", `[aifinpay-mcp] no AIFINPAY_AGENT_SECRET set — generated an EPHEMERAL, NON-RECOVERABLE agent.\n` +
65
- ` solana_address: ${a.solanaAddress}\n` +
66
- ` evm_address: ${a.evmAddress}\n` +
67
- ` >> DO NOT FUND these addresses. This identity is lost when the process exits.\n` +
68
- ` >> For a persistent wallet, create one from a seed you back up\n` +
69
- ` (AiFinPayAgent.fromSeed / \`aifinpay init\`) and set AIFINPAY_AGENT_SECRET.`);
70
- return a;
71
- })();
72
- // AIFINPAY_MAX_USD is the documented "hard cap on a single payment".
73
- // payable_fetch enforces it via PayOptions, but agent_call settles through
74
- // AiFinPayAgent.call() which only honours the agent's budget caps — wire
75
- // the cap there too, otherwise the primary tool has NO runaway protection.
38
+ let identitySource = "ephemeral";
39
+ async function configuredAgent() {
40
+ const identity = loadWalletIdentity(config);
41
+ if (!identity)
42
+ return null;
43
+ const options = { fetchImpl: safeFetch, baseUrl: config.baseUrl, timeoutMs: config.timeoutMs };
44
+ const loaded = identity.seedHash
45
+ ? await AiFinPayAgent.fromSeed(identity.seedHash, options)
46
+ : await AiFinPayAgent.fromSolanaSecret(identity.secretB58, options);
47
+ return { loaded, source: identity.source };
48
+ }
49
+ const configured = await configuredAgent();
50
+ let agent = configured?.loaded ?? await AiFinPayAgent.new({
51
+ fetchImpl: safeFetch, baseUrl: config.baseUrl, timeoutMs: config.timeoutMs,
52
+ });
53
+ identitySource = configured?.source ?? "ephemeral";
54
+ if (!configured)
55
+ log("warn", "[aifinpay-mcp] EPHEMERAL wallet — DO NOT FUND. Run `npx @aifinpay/mcp init`, then agent_reload in this connection.");
56
+ // Keep the legacy agent budget configured even though this RC exposes no
57
+ // signing tool. It remains an additional defence for downstream/private code
58
+ // and for the subsequent v2 MCP executor integration.
76
59
  if (config.maxAmountUsd !== undefined && Number.isFinite(config.maxAmountUsd)) {
77
60
  agent.setBudget({ per_call_usd: config.maxAmountUsd });
78
61
  log("info", `[aifinpay-mcp] per-call cap: $${config.maxAmountUsd} (AIFINPAY_MAX_USD)`);
79
62
  }
80
- else {
81
- log("warn", "[aifinpay-mcp] AIFINPAY_MAX_USD not set — agent_call/payable_fetch have NO per-payment cap. Strongly recommended.");
82
- }
83
- log("info", `[aifinpay-mcp] solana: ${agent.solanaAddress} · evm: ${agent.evmAddress}`);
63
+ log("info", `[aifinpay-mcp] production RC safe surface · solana: ${agent.solanaAddress} · evm: ${agent.evmAddress}`);
84
64
  const server = new Server({
85
65
  name: "@aifinpay/mcp",
86
- version: "1.0.0",
87
- }, {
88
- capabilities: {
89
- tools: {},
90
- },
91
- });
92
- server.setRequestHandler(ListToolsRequestSchema, async () => {
93
- return {
94
- tools: [
95
- agentAddressTool(),
96
- agentCallTool(),
97
- agentClaimSelfTool(),
98
- payableFetchTool(),
99
- agentQuoteTool(),
100
- payWithSplitTool(),
101
- quoteSplitTool(),
102
- ],
103
- };
66
+ version: JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version,
67
+ }, { capabilities: { tools: {}, resources: {} } });
68
+ server.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: [{
69
+ uri: "aifinpay://skill", name: "AiFinPay skill", mimeType: "text/markdown",
70
+ description: "Wallet source priority, payment history routes, reconnect behavior and dev testing limits",
71
+ }] }));
72
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
73
+ if (request.params.uri !== "aifinpay://skill")
74
+ throw new Error("Unknown resource");
75
+ return { contents: [{ uri: "aifinpay://skill", mimeType: "text/markdown",
76
+ text: readFileSync(new URL("../skills/SKILL.md", import.meta.url), "utf8") }] };
104
77
  });
78
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
79
+ tools: [
80
+ agentAddressTool(),
81
+ {
82
+ name: "agent_reload",
83
+ description: "Reload the configured local wallet files after init or a file update, without starting a new conversation. Returns public addresses only. Shell environment changes still require reconnecting the MCP process.",
84
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
85
+ annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
86
+ },
87
+ agentQuotaTool(),
88
+ agentHistoryTool(),
89
+ ...(config.devMode ? [devPaymentQuoteTool()] : []),
90
+ agentPassportResolveTool(),
91
+ settlementRoutesTool(),
92
+ settlementInvoiceTool(),
93
+ ],
94
+ }));
105
95
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
106
96
  const { name, arguments: args } = request.params;
107
97
  const ctx = { agent, config, log };
108
98
  switch (name) {
99
+ case "agent_reload":
100
+ try {
101
+ const replacement = await configuredAgent();
102
+ if (!replacement)
103
+ throw new Error("No persistent wallet configured; run init or configure the project wallet first");
104
+ if (config.maxAmountUsd !== undefined && Number.isFinite(config.maxAmountUsd)) {
105
+ replacement.loaded.setBudget({ per_call_usd: config.maxAmountUsd });
106
+ }
107
+ agent = replacement.loaded;
108
+ identitySource = replacement.source;
109
+ return { content: [{ type: "text", text: JSON.stringify({
110
+ source: identitySource, solana: agent.solanaAddress, evm: agent.evmAddress,
111
+ casper: agent.casperAddress, reloaded: true,
112
+ }) }] };
113
+ }
114
+ catch (error) {
115
+ return { isError: true, content: [{ type: "text", text: `Wallet reload failed: ${error.message}` }] };
116
+ }
109
117
  case "agent_address":
110
118
  return runAgentAddress(ctx, args ?? {});
111
- case "agent_call":
112
- return runAgentCall(ctx, args ?? {});
113
- case "agent_claim_self":
114
- return runAgentClaimSelf(ctx, args ?? {});
115
- case "payable_fetch":
116
- return runPayableFetch(ctx, args ?? {});
117
- case "agent_quote":
118
- return runAgentQuote(ctx, args ?? {});
119
- case "pay_with_split":
120
- return runPayWithSplit(ctx, args ?? {});
121
- case "quote_split":
122
- return runQuoteSplit(ctx, args ?? {});
119
+ case "agent_quota":
120
+ return runAgentQuota(ctx, args ?? {});
121
+ case "agent_history":
122
+ return runAgentHistory(ctx, args ?? {});
123
+ case "dev_payment_quote":
124
+ return runDevPaymentQuote(ctx, args ?? {});
125
+ case "agent_passport_resolve":
126
+ return runAgentPassportResolve(ctx, args ?? {});
127
+ case "settlement_routes":
128
+ return runSettlementRoutes(ctx, args ?? {});
129
+ case "settlement_invoice":
130
+ return runSettlementInvoice(ctx, args ?? {});
123
131
  default:
124
132
  return {
125
133
  isError: true,
126
- content: [
127
- { type: "text", text: `unknown tool: ${name}` },
128
- ],
134
+ content: [{ type: "text", text: `unknown or retired tool: ${name}` }],
129
135
  };
130
136
  }
131
137
  });
132
- return { server, agent };
138
+ return { server, get agent() { return agent; } };
133
139
  }
134
140
  function defaultLog(level, msg) {
135
- // MCP stdio servers MUST NOT write to stdout — the transport owns it.
136
- // stderr is safe.
137
141
  process.stderr.write(`[${level}] ${msg}\n`);
138
142
  }
139
143
  //# sourceMappingURL=server.js.map