@aifinpay/mcp 2.11.4 → 2.12.2
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 +117 -93
- package/bin/aifinpay-mcp.js +44 -36
- package/dist/config.d.ts +38 -13
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +51 -19
- package/dist/config.js.map +1 -1
- package/dist/dashboard-policy.d.ts +47 -0
- package/dist/dashboard-policy.d.ts.map +1 -0
- package/dist/dashboard-policy.js +124 -0
- package/dist/dashboard-policy.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/merchant-site.d.ts +32 -0
- package/dist/merchant-site.d.ts.map +1 -0
- package/dist/merchant-site.js +58 -0
- package/dist/merchant-site.js.map +1 -0
- package/dist/server.d.ts +4 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +37 -10
- package/dist/server.js.map +1 -1
- package/dist/tools/agent-claim-self.d.ts +14 -7
- package/dist/tools/agent-claim-self.d.ts.map +1 -1
- package/dist/tools/agent-claim-self.js +76 -25
- package/dist/tools/agent-claim-self.js.map +1 -1
- package/dist/tools/payable-fetch.d.ts.map +1 -1
- package/dist/tools/payable-fetch.js +40 -12
- package/dist/tools/payable-fetch.js.map +1 -1
- package/dist/tools/payment-setup-status.d.ts +16 -9
- package/dist/tools/payment-setup-status.d.ts.map +1 -1
- package/dist/tools/payment-setup-status.js +83 -63
- package/dist/tools/payment-setup-status.js.map +1 -1
- package/package.json +3 -3
- package/skills/SKILL.md +99 -82
- package/smithery.yaml +7 -8
package/dist/config.js
CHANGED
|
@@ -8,8 +8,13 @@ export function loadConfigFromEnv() {
|
|
|
8
8
|
throw new Error("AIFINPAY_PAYMENTS_ENABLED must be 0 or 1");
|
|
9
9
|
}
|
|
10
10
|
return {
|
|
11
|
-
paymentsEnabled: process.env.AIFINPAY_PAYMENTS_ENABLED
|
|
12
|
-
|
|
11
|
+
paymentsEnabled: process.env.AIFINPAY_PAYMENTS_ENABLED !== "0",
|
|
12
|
+
paymentsByDefault: !process.env.AIFINPAY_PAYMENTS_ENABLED,
|
|
13
|
+
ownerOverrides: [
|
|
14
|
+
...(process.env.AIFINPAY_MAX_USD ? ["AIFINPAY_MAX_USD"] : []),
|
|
15
|
+
...(process.env.AIFINPAY_DAILY_USD ? ["AIFINPAY_DAILY_USD"] : []),
|
|
16
|
+
],
|
|
17
|
+
dailyAmountUsd: ownerCeiling("AIFINPAY_DAILY_USD", process.env.AIFINPAY_DAILY_USD, DEFAULT_DAILY_USD),
|
|
13
18
|
payChain: process.env.AIFINPAY_PAY_CHAIN || undefined,
|
|
14
19
|
rpcUrl: process.env.AIFINPAY_RPC_URL || undefined,
|
|
15
20
|
maxGas: process.env.AIFINPAY_MAX_GAS || undefined,
|
|
@@ -27,7 +32,7 @@ export function loadConfigFromEnv() {
|
|
|
27
32
|
agentSecretB58: process.env.AIFINPAY_AGENT_SECRET || undefined,
|
|
28
33
|
baseUrl: process.env.AIFINPAY_BASE_URL || undefined,
|
|
29
34
|
timeoutMs: process.env.AIFINPAY_TIMEOUT_MS ? Number(process.env.AIFINPAY_TIMEOUT_MS) : undefined,
|
|
30
|
-
maxAmountUsd:
|
|
35
|
+
maxAmountUsd: ownerCeiling("AIFINPAY_MAX_USD", process.env.AIFINPAY_MAX_USD, DEFAULT_MAX_USD),
|
|
31
36
|
gatewayOrigins: splitOrigins(process.env.AIFINPAY_GATEWAY_ORIGINS),
|
|
32
37
|
gatewayPathMode: parseGatewayPathMode(process.env.AIFINPAY_GATEWAY_PATH_MODE),
|
|
33
38
|
trustedHosts: splitList(process.env.AIFINPAY_TRUSTED_HOSTS),
|
|
@@ -54,7 +59,7 @@ function parseSolanaNetwork(raw) {
|
|
|
54
59
|
}
|
|
55
60
|
function parseGatewayPathMode(raw) {
|
|
56
61
|
if (raw === undefined || raw.trim() === "")
|
|
57
|
-
return
|
|
62
|
+
return undefined;
|
|
58
63
|
if (raw === "gateway" || raw === "direct")
|
|
59
64
|
return raw;
|
|
60
65
|
throw new Error("AIFINPAY_GATEWAY_PATH_MODE must be either gateway or direct");
|
|
@@ -106,10 +111,33 @@ function splitOrigins(raw) {
|
|
|
106
111
|
}
|
|
107
112
|
return list;
|
|
108
113
|
}
|
|
109
|
-
/**
|
|
114
|
+
/** Built-in spending ceiling (owner decision 2026-10-20): $5 per payment, $20 per
|
|
115
|
+
* 24 h. The env values can only lower it; a higher value is refused so a
|
|
116
|
+
* pasted config cannot raise the ceiling above what the dashboard Controls
|
|
117
|
+
* are meant to manage. */
|
|
118
|
+
export const DEFAULT_MAX_USD = 5;
|
|
119
|
+
export const DEFAULT_DAILY_USD = 20;
|
|
120
|
+
/** Gas cap per payment on Polygon when the owner sets none: the worst case at
|
|
121
|
+
* ~280 gwei is ~0.10 POL paying in POL and ~0.21 POL in USDC, so 0.3 POL
|
|
122
|
+
* (~$0.06) leaves room without being a budget. Another chain still needs
|
|
123
|
+
* AIFINPAY_MAX_GAS in its own currency: choosing the chain is explicit anyway. */
|
|
124
|
+
export const DEFAULT_MAX_GAS_POL = "0.3";
|
|
125
|
+
function ownerCeiling(name, raw, ceiling) {
|
|
126
|
+
if (raw === undefined || raw === "")
|
|
127
|
+
return ceiling;
|
|
128
|
+
const value = Number(raw);
|
|
129
|
+
if (!Number.isFinite(value) || value <= 0)
|
|
130
|
+
throw new Error(`${name} must be a positive finite owner limit`);
|
|
131
|
+
if (value > ceiling)
|
|
132
|
+
throw new Error(`${name} can only lower the built-in ceiling of ${ceiling}; set the working limits in the dashboard`);
|
|
133
|
+
return value;
|
|
134
|
+
}
|
|
135
|
+
/** Signing is available only while payments are on and every spending boundary is set:
|
|
136
|
+
* the per-payment and daily USD ceiling, a gas cap, and an exact https allowlist when
|
|
137
|
+
* the owner chose to set one. */
|
|
110
138
|
export function validatePaymentConfig(config) {
|
|
111
139
|
if (!config.paymentsEnabled)
|
|
112
|
-
throw new Error("Payments disabled
|
|
140
|
+
throw new Error("Payments disabled by the owner (AIFINPAY_PAYMENTS_ENABLED=0)");
|
|
113
141
|
const chain = payChain(config.payChain);
|
|
114
142
|
if (config.devMode && chain.name !== "solana")
|
|
115
143
|
throw new Error("MCP receipt payments support live mode only");
|
|
@@ -131,17 +159,21 @@ export function validatePaymentConfig(config) {
|
|
|
131
159
|
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0)
|
|
132
160
|
throw new Error(`${name} must be a positive finite owner limit`);
|
|
133
161
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
162
|
+
// Unset means "the origin of the URL being fetched" (see McpConfig). An empty
|
|
163
|
+
// list is a config bug's shape, not a request for that default, and a
|
|
164
|
+
// malformed entry would read as allowed while matching nothing.
|
|
165
|
+
if (config.gatewayOrigins !== undefined &&
|
|
166
|
+
(!config.gatewayOrigins.length ||
|
|
167
|
+
config.gatewayOrigins.some((origin) => {
|
|
168
|
+
try {
|
|
169
|
+
const u = new URL(origin);
|
|
170
|
+
return (u.protocol !== "https:" || u.origin !== origin || !!u.username || !!u.password || u.hostname.includes("*"));
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
})))
|
|
176
|
+
throw new Error("AIFINPAY_GATEWAY_ORIGINS must list exact HTTPS origins; unset it to accept the origin of each URL");
|
|
145
177
|
if (chain.name === "solana") {
|
|
146
178
|
const expectedNetwork = config.devMode ? "devnet" : "mainnet";
|
|
147
179
|
if (config.solanaNetwork !== expectedNetwork)
|
|
@@ -175,8 +207,8 @@ export function validatePaymentConfig(config) {
|
|
|
175
207
|
throw new Error(`AIFINPAY_MAX_GAS_POL caps POL gas and does not apply on ${chain.name}; set AIFINPAY_MAX_GAS in ${chain.native}`);
|
|
176
208
|
if (config.maxGas !== undefined && config.maxGasPol !== undefined && config.maxGas !== config.maxGasPol)
|
|
177
209
|
throw new Error("AIFINPAY_MAX_GAS and AIFINPAY_MAX_GAS_POL disagree; set one");
|
|
178
|
-
const name = config.maxGas !== undefined ? "AIFINPAY_MAX_GAS" : "AIFINPAY_MAX_GAS_POL";
|
|
179
|
-
const gas = config.maxGas ?? config.maxGasPol;
|
|
210
|
+
const name = config.maxGas !== undefined || chain.name !== "polygon" ? "AIFINPAY_MAX_GAS" : "AIFINPAY_MAX_GAS_POL";
|
|
211
|
+
const gas = config.maxGas ?? config.maxGasPol ?? (chain.name === "polygon" ? DEFAULT_MAX_GAS_POL : undefined);
|
|
180
212
|
if (typeof gas !== "string" || !/^(?:0|[1-9][0-9]*)(?:\.[0-9]{1,18})?$/.test(gas))
|
|
181
213
|
throw new Error(`${name} must be a positive decimal with at most 18 places: the gas cap per payment in ${chain.native}`);
|
|
182
214
|
const [whole, fraction = ""] = gas.split(".");
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEvE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ToolContext } from "./server.js";
|
|
2
|
+
/**
|
|
3
|
+
* The owner's dashboard Controls for this agent, read by the agent itself.
|
|
4
|
+
*
|
|
5
|
+
* The backend enforces the policy an owner sets under My Agents → Controls on
|
|
6
|
+
* every /v1/quote and /v1/pay for a claimed agent, but until
|
|
7
|
+
* GET /v1/agents/:address/policy existed the agent could not read it: a 403
|
|
8
|
+
* agent_policy at quote time had no explanation, and payment_setup_status
|
|
9
|
+
* could only talk about env. This reads the same view the owner sees.
|
|
10
|
+
*
|
|
11
|
+
* The request is proven by the agent's own key — EIP-191 over the statement
|
|
12
|
+
* below, with the lowercase address, which is what the backend verifies
|
|
13
|
+
* against — and is read-only: nothing in the response grants anything, and
|
|
14
|
+
* nothing here can change a limit. A failure to read is reported as unknown,
|
|
15
|
+
* never treated as "no limits": the backend applies the policy whether or not
|
|
16
|
+
* this read succeeded.
|
|
17
|
+
*/
|
|
18
|
+
export declare const CONTROLS_URL = "https://dash.aifinpay.io";
|
|
19
|
+
export interface DashboardPolicy {
|
|
20
|
+
per_tx_cap_usd: number | null;
|
|
21
|
+
daily_cap_usd: number | null;
|
|
22
|
+
merchant_allowlist: string[] | null;
|
|
23
|
+
expires_at: number | null;
|
|
24
|
+
paused: boolean;
|
|
25
|
+
}
|
|
26
|
+
export type DashboardStatus = {
|
|
27
|
+
linked: true;
|
|
28
|
+
policy: DashboardPolicy;
|
|
29
|
+
controls: string;
|
|
30
|
+
} | {
|
|
31
|
+
linked: false;
|
|
32
|
+
controls: string;
|
|
33
|
+
} | {
|
|
34
|
+
linked: "unknown";
|
|
35
|
+
reason: string;
|
|
36
|
+
controls: string;
|
|
37
|
+
};
|
|
38
|
+
/** The exact bytes the backend verifies: aifinpay-web routes/me-agents.js policyReadMessage. */
|
|
39
|
+
export declare function policyReadStatement(issuer: string, address: string, expiresAt: number): string;
|
|
40
|
+
/** The API this server quotes and pays through, which is also the statement's issuer. */
|
|
41
|
+
export declare function policyIssuer(baseUrl: string | undefined): string;
|
|
42
|
+
export declare function readDashboardPolicy(ctx: ToolContext): Promise<DashboardStatus>;
|
|
43
|
+
/** Why the backend will refuse every quote for this agent right now, if it will. */
|
|
44
|
+
export declare function dashboardRefusal(status: DashboardStatus, now?: Date): string | undefined;
|
|
45
|
+
/** One sentence for next_step about the dashboard, given what was read. */
|
|
46
|
+
export declare function dashboardSentence(status: DashboardStatus): string;
|
|
47
|
+
//# sourceMappingURL=dashboard-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-policy.d.ts","sourceRoot":"","sources":["../src/dashboard-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,YAAY,6BAA6B,CAAC;AAKvD,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,kBAAkB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D,gGAAgG;AAChG,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE9F;AAED,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAEhE;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CA6BpF;AAuCD,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,GAAG,SAAS,CAOpG;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAkBjE"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The owner's dashboard Controls for this agent, read by the agent itself.
|
|
3
|
+
*
|
|
4
|
+
* The backend enforces the policy an owner sets under My Agents → Controls on
|
|
5
|
+
* every /v1/quote and /v1/pay for a claimed agent, but until
|
|
6
|
+
* GET /v1/agents/:address/policy existed the agent could not read it: a 403
|
|
7
|
+
* agent_policy at quote time had no explanation, and payment_setup_status
|
|
8
|
+
* could only talk about env. This reads the same view the owner sees.
|
|
9
|
+
*
|
|
10
|
+
* The request is proven by the agent's own key — EIP-191 over the statement
|
|
11
|
+
* below, with the lowercase address, which is what the backend verifies
|
|
12
|
+
* against — and is read-only: nothing in the response grants anything, and
|
|
13
|
+
* nothing here can change a limit. A failure to read is reported as unknown,
|
|
14
|
+
* never treated as "no limits": the backend applies the policy whether or not
|
|
15
|
+
* this read succeeded.
|
|
16
|
+
*/
|
|
17
|
+
export const CONTROLS_URL = "https://dash.aifinpay.io";
|
|
18
|
+
const DEFAULT_ISSUER = "https://api.aifinpay.io";
|
|
19
|
+
/** How long the signed statement is valid; the backend accepts at most 300 s. */
|
|
20
|
+
const STATEMENT_LIFETIME_S = 60;
|
|
21
|
+
/** The exact bytes the backend verifies: aifinpay-web routes/me-agents.js policyReadMessage. */
|
|
22
|
+
export function policyReadStatement(issuer, address, expiresAt) {
|
|
23
|
+
return JSON.stringify(["AiFinPay agent policy read v1", issuer, address, expiresAt]);
|
|
24
|
+
}
|
|
25
|
+
/** The API this server quotes and pays through, which is also the statement's issuer. */
|
|
26
|
+
export function policyIssuer(baseUrl) {
|
|
27
|
+
return (baseUrl ?? DEFAULT_ISSUER).replace(/\/+$/, "");
|
|
28
|
+
}
|
|
29
|
+
export async function readDashboardPolicy(ctx) {
|
|
30
|
+
const controls = CONTROLS_URL;
|
|
31
|
+
const issuer = policyIssuer(ctx.config.baseUrl);
|
|
32
|
+
const address = ctx.agent.evmAddress.toLowerCase();
|
|
33
|
+
const expiresAt = Math.floor(Date.now() / 1000) + STATEMENT_LIFETIME_S;
|
|
34
|
+
try {
|
|
35
|
+
const signature = await ctx.agent.evmAccount.signMessage({
|
|
36
|
+
message: policyReadStatement(issuer, address, expiresAt),
|
|
37
|
+
});
|
|
38
|
+
const response = await ctx.agent.inner.fetchImpl(`${issuer}/v1/agents/${address}/policy`, {
|
|
39
|
+
method: "GET",
|
|
40
|
+
headers: {
|
|
41
|
+
accept: "application/json",
|
|
42
|
+
"AIFP-Agent-Expires": String(expiresAt),
|
|
43
|
+
"AIFP-Agent-Signature": signature,
|
|
44
|
+
},
|
|
45
|
+
redirect: "manual",
|
|
46
|
+
signal: AbortSignal.timeout(ctx.config.timeoutMs ?? 10_000),
|
|
47
|
+
});
|
|
48
|
+
if (response.status === 404)
|
|
49
|
+
return { linked: false, controls };
|
|
50
|
+
if (!response.ok)
|
|
51
|
+
return { linked: "unknown", reason: `HTTP ${response.status}`, controls };
|
|
52
|
+
const body = (await response.json());
|
|
53
|
+
const policy = parsePolicy(body?.policy);
|
|
54
|
+
if (body?.claimed !== true || !policy)
|
|
55
|
+
return { linked: "unknown", reason: "malformed policy", controls };
|
|
56
|
+
return { linked: true, policy, controls };
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
// A network error's message can carry the host and more; its kind is enough.
|
|
60
|
+
return { linked: "unknown", reason: error?.name || "request failed", controls };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Only the owner's limits, each in the one type the dashboard writes; anything else is malformed. */
|
|
64
|
+
function parsePolicy(raw) {
|
|
65
|
+
if (!raw || typeof raw !== "object")
|
|
66
|
+
return undefined;
|
|
67
|
+
const p = raw;
|
|
68
|
+
const usd = (value) => value === null || value === undefined
|
|
69
|
+
? null
|
|
70
|
+
: typeof value === "number" && Number.isFinite(value) && value >= 0
|
|
71
|
+
? value
|
|
72
|
+
: undefined;
|
|
73
|
+
const perTx = usd(p.per_tx_cap_usd);
|
|
74
|
+
const daily = usd(p.daily_cap_usd);
|
|
75
|
+
const expires = p.expires_at === null || p.expires_at === undefined
|
|
76
|
+
? null
|
|
77
|
+
: typeof p.expires_at === "number" && Number.isSafeInteger(p.expires_at)
|
|
78
|
+
? p.expires_at
|
|
79
|
+
: undefined;
|
|
80
|
+
// Merchant ids are repeated to the model, so only plain identifiers pass.
|
|
81
|
+
const allowlist = p.merchant_allowlist === null || p.merchant_allowlist === undefined
|
|
82
|
+
? null
|
|
83
|
+
: Array.isArray(p.merchant_allowlist) &&
|
|
84
|
+
p.merchant_allowlist.every((m) => typeof m === "string" && /^[A-Za-z0-9_.:-]{1,64}$/.test(m))
|
|
85
|
+
? p.merchant_allowlist
|
|
86
|
+
: undefined;
|
|
87
|
+
if (perTx === undefined || daily === undefined || expires === undefined || allowlist === undefined)
|
|
88
|
+
return undefined;
|
|
89
|
+
if (typeof p.paused !== "boolean")
|
|
90
|
+
return undefined;
|
|
91
|
+
return {
|
|
92
|
+
per_tx_cap_usd: perTx,
|
|
93
|
+
daily_cap_usd: daily,
|
|
94
|
+
merchant_allowlist: allowlist,
|
|
95
|
+
expires_at: expires,
|
|
96
|
+
paused: p.paused,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/** Why the backend will refuse every quote for this agent right now, if it will. */
|
|
100
|
+
export function dashboardRefusal(status, now = new Date()) {
|
|
101
|
+
if (status.linked !== true)
|
|
102
|
+
return undefined;
|
|
103
|
+
if (status.policy.paused)
|
|
104
|
+
return `The owner paused payments for this agent in the dashboard Controls: AiFinPay refuses new quotes until they resume at ${status.controls}. Nothing will be paid; tell the owner and stop.`;
|
|
105
|
+
if (status.policy.expires_at !== null && status.policy.expires_at < Math.floor(now.getTime() / 1000))
|
|
106
|
+
return `The owner's dashboard Controls for this agent expired on ${new Date(status.policy.expires_at * 1000).toISOString().slice(0, 10)}: AiFinPay refuses new quotes until the owner sets a new expiry at ${status.controls}. Tell the owner and stop.`;
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
/** One sentence for next_step about the dashboard, given what was read. */
|
|
110
|
+
export function dashboardSentence(status) {
|
|
111
|
+
if (status.linked === true) {
|
|
112
|
+
const p = status.policy;
|
|
113
|
+
const cap = (value) => (value === null ? "no limit" : `$${value}`);
|
|
114
|
+
const expiry = p.expires_at === null ? "" : `, valid until ${new Date(p.expires_at * 1000).toISOString().slice(0, 10)}`;
|
|
115
|
+
return (`Dashboard Controls, enforced by AiFinPay on every quote and payment: per payment ${cap(p.per_tx_cap_usd)}, ` +
|
|
116
|
+
`per day ${cap(p.daily_cap_usd)}${p.merchant_allowlist ? `, only merchants ${p.merchant_allowlist.join(", ")}` : ""}${expiry}. ` +
|
|
117
|
+
`The owner changes them at ${status.controls}; the local limits of this server still apply underneath.`);
|
|
118
|
+
}
|
|
119
|
+
if (status.linked === false)
|
|
120
|
+
return (`This agent is not linked to an owner's dashboard: offer it — the owner generates a one-time URL at ${status.controls} → My Agents → Claim via MCP ` +
|
|
121
|
+
`and gives it to agent_claim_self; from then on the owner sets the working limits in Controls.`);
|
|
122
|
+
return `The dashboard Controls could not be read (${status.reason}); AiFinPay still enforces them on every quote and payment.`;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=dashboard-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-policy.js","sourceRoot":"","sources":["../src/dashboard-policy.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Tools: public addresses, history, quotas, passport resolution, non-signing
|
|
6
6
|
* settlement invoices, local wallet reload, and opt-in dev batch quoting.
|
|
7
|
-
* The one signing tool, payable_fetch, is
|
|
8
|
-
*
|
|
7
|
+
* The one signing tool, payable_fetch, is always listed and on by default; it
|
|
8
|
+
* signs only from a persistent wallet, within the built-in $5 / $20 ceiling.
|
|
9
9
|
*
|
|
10
10
|
* Quick start (stdio transport for Claude Desktop / MCP-aware runtimes):
|
|
11
11
|
*
|
package/dist/index.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Tools: public addresses, history, quotas, passport resolution, non-signing
|
|
6
6
|
* settlement invoices, local wallet reload, and opt-in dev batch quoting.
|
|
7
|
-
* The one signing tool, payable_fetch, is
|
|
8
|
-
*
|
|
7
|
+
* The one signing tool, payable_fetch, is always listed and on by default; it
|
|
8
|
+
* signs only from a persistent wallet, within the built-in $5 / $20 ceiling.
|
|
9
9
|
*
|
|
10
10
|
* Quick start (stdio transport for Claude Desktop / MCP-aware runtimes):
|
|
11
11
|
*
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who may be paid when the owner set no AIFINPAY_GATEWAY_ORIGINS (owner
|
|
3
|
+
* decision, 2026-10-22): only a merchant whose site the AiFinPay backend
|
|
4
|
+
* reports as DNS-verified and, for a site running its own paywall, whose site
|
|
5
|
+
* is the host this payment is for.
|
|
6
|
+
*
|
|
7
|
+
* Without it, any page an agent was steered to could answer 402 with the id of
|
|
8
|
+
* any registered merchant, and the backend would quote that merchant: quotes
|
|
9
|
+
* bind (merchant, resource), not the origin the 402 came from. With it, the
|
|
10
|
+
* payee is the verified owner of the site the agent is actually using.
|
|
11
|
+
*
|
|
12
|
+
* The merchant id checked here is the one in the backend-signed quote, never
|
|
13
|
+
* the 402's, and the check runs in onPrepared — before anything is signed into
|
|
14
|
+
* the journal or broadcast — so a refusal pays nothing.
|
|
15
|
+
*/
|
|
16
|
+
export declare class UnverifiedMerchantSiteError extends Error {
|
|
17
|
+
readonly merchantId: string;
|
|
18
|
+
readonly reason: string;
|
|
19
|
+
constructor(merchantId: string, reason: string);
|
|
20
|
+
}
|
|
21
|
+
export declare function assertVerifiedMerchantSite(opts: {
|
|
22
|
+
fetchImpl: (input: string, init?: RequestInit) => Promise<Response>;
|
|
23
|
+
/** The configured AiFinPay backend; the same origin that signed the quote. */
|
|
24
|
+
apiBase: string;
|
|
25
|
+
/** From the backend-signed quote. */
|
|
26
|
+
merchantId: string;
|
|
27
|
+
/** The URL payable_fetch was asked to fetch. */
|
|
28
|
+
url: URL;
|
|
29
|
+
/** "gateway": the AiFinPay hosted gateway serves it, so no host to compare. */
|
|
30
|
+
pathMode: "gateway" | "direct";
|
|
31
|
+
}): Promise<void>;
|
|
32
|
+
//# sourceMappingURL=merchant-site.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merchant-site.d.ts","sourceRoot":"","sources":["../src/merchant-site.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,qBAAa,2BAA4B,SAAQ,KAAK;aAElC,UAAU,EAAE,MAAM;aAClB,MAAM,EAAE,MAAM;IAFhC,YACkB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EAI/B;CACF;AAcD,wBAAsB,0BAA0B,CAAC,IAAI,EAAE;IACrD,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpE,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,GAAG,EAAE,GAAG,CAAC;IACT,+EAA+E;IAC/E,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAC;CAChC,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBhB"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who may be paid when the owner set no AIFINPAY_GATEWAY_ORIGINS (owner
|
|
3
|
+
* decision, 2026-10-22): only a merchant whose site the AiFinPay backend
|
|
4
|
+
* reports as DNS-verified and, for a site running its own paywall, whose site
|
|
5
|
+
* is the host this payment is for.
|
|
6
|
+
*
|
|
7
|
+
* Without it, any page an agent was steered to could answer 402 with the id of
|
|
8
|
+
* any registered merchant, and the backend would quote that merchant: quotes
|
|
9
|
+
* bind (merchant, resource), not the origin the 402 came from. With it, the
|
|
10
|
+
* payee is the verified owner of the site the agent is actually using.
|
|
11
|
+
*
|
|
12
|
+
* The merchant id checked here is the one in the backend-signed quote, never
|
|
13
|
+
* the 402's, and the check runs in onPrepared — before anything is signed into
|
|
14
|
+
* the journal or broadcast — so a refusal pays nothing.
|
|
15
|
+
*/
|
|
16
|
+
export class UnverifiedMerchantSiteError extends Error {
|
|
17
|
+
merchantId;
|
|
18
|
+
reason;
|
|
19
|
+
constructor(merchantId, reason) {
|
|
20
|
+
super(`Not paid: merchant ${merchantId} ${reason}. Nothing was signed or sent.`);
|
|
21
|
+
this.merchantId = merchantId;
|
|
22
|
+
this.reason = reason;
|
|
23
|
+
this.name = "UnverifiedMerchantSiteError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const hostOf = (value) => {
|
|
27
|
+
if (typeof value !== "string" || !value)
|
|
28
|
+
return null;
|
|
29
|
+
try {
|
|
30
|
+
const url = new URL(value);
|
|
31
|
+
return url.protocol === "https:" ? url.hostname.toLowerCase() : null;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
export async function assertVerifiedMerchantSite(opts) {
|
|
38
|
+
const { merchantId } = opts;
|
|
39
|
+
let body = null;
|
|
40
|
+
try {
|
|
41
|
+
const res = await opts.fetchImpl(new URL(`/v1/merchants/${encodeURIComponent(merchantId)}`, opts.apiBase).href, { headers: { accept: "application/json" }, redirect: "error" });
|
|
42
|
+
if (res.ok)
|
|
43
|
+
body = (await res.json());
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
body = null;
|
|
47
|
+
}
|
|
48
|
+
if (!body || body.merchant_id !== merchantId)
|
|
49
|
+
throw new UnverifiedMerchantSiteError(merchantId, "could not be confirmed with AiFinPay");
|
|
50
|
+
if (body.site_verified !== true)
|
|
51
|
+
throw new UnverifiedMerchantSiteError(merchantId, "has not verified its site with AiFinPay");
|
|
52
|
+
if (opts.pathMode === "direct") {
|
|
53
|
+
const site = hostOf(body.site_url);
|
|
54
|
+
if (!site || site !== opts.url.hostname.toLowerCase())
|
|
55
|
+
throw new UnverifiedMerchantSiteError(merchantId, `is verified for ${site ?? "no https site"}, not ${opts.url.hostname}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=merchant-site.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merchant-site.js","sourceRoot":"","sources":["../src/merchant-site.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,OAAO,2BAA4B,SAAQ,KAAK;IAElC,UAAU;IACV,MAAM;IAFxB,YACkB,UAAkB,EAClB,MAAc;QAE9B,KAAK,CAAC,sBAAsB,UAAU,IAAI,MAAM,+BAA+B,CAAC,CAAC;0BAHjE,UAAU;sBACV,MAAM;QAGtB,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;IAC5C,CAAC;CACF;AAID,MAAM,MAAM,GAAG,CAAC,KAAc,EAAiB,EAAE;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACrD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,IAUhD;IACC,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IAC5B,IAAI,IAAI,GAAwB,IAAI,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAC9B,IAAI,GAAG,CAAC,iBAAiB,kBAAkB,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAC7E,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAC/D,CAAC;QACF,IAAI,GAAG,CAAC,EAAE;YAAE,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAiB,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,GAAG,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,UAAU;QAC1C,MAAM,IAAI,2BAA2B,CAAC,UAAU,EAAE,sCAAsC,CAAC,CAAC;IAC5F,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI;QAC7B,MAAM,IAAI,2BAA2B,CAAC,UAAU,EAAE,yCAAyC,CAAC,CAAC;IAC/F,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE;YACnD,MAAM,IAAI,2BAA2B,CACnC,UAAU,EACV,mBAAmB,IAAI,IAAI,eAAe,SAAS,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CACvE,CAAC;IACN,CAAC;AACH,CAAC"}
|
package/dist/server.d.ts
CHANGED
|
@@ -2,8 +2,10 @@ import { AiFinPayAgent, type AgentFramework } from "@aifinpay/agent";
|
|
|
2
2
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
3
|
import type { McpConfig } from "./config.js";
|
|
4
4
|
import { PaymentStateStore } from "./payment-state.js";
|
|
5
|
-
/**
|
|
6
|
-
*
|
|
5
|
+
/** Payments are on by default (2.12.1) within the built-in ceiling, and only a
|
|
6
|
+
* persistent wallet signs: a server that started ephemeral opens its payment
|
|
7
|
+
* journal at agent_reload after init, without a restart. Legacy signing tools
|
|
8
|
+
* stay retired; payable_fetch is the one reviewed v1.4 path. */
|
|
7
9
|
export declare function createServer(config?: McpConfig): Promise<{
|
|
8
10
|
server: Server<{
|
|
9
11
|
method: string;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkB,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAQnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAS7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAgCvD;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkB,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAQnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAS7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAgCvD;;;gEAGgE;AAChE,wBAAsB,YAAY,CAAC,MAAM,GAAE,SAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqOxD;AA2BD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,6EAA6E;IAC7E,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,+HAA+H;IAC/H,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9D"}
|
package/dist/server.js
CHANGED
|
@@ -26,9 +26,11 @@ const safeFetch = makeSafeFetch({
|
|
|
26
26
|
// for those names — see safe-fetch.ts for why this is not a proxy switch.
|
|
27
27
|
trustedHosts: loadConfigFromEnv().trustedHosts,
|
|
28
28
|
});
|
|
29
|
-
const RELOAD_ENV_NOTE = "
|
|
30
|
-
/**
|
|
31
|
-
*
|
|
29
|
+
const RELOAD_ENV_NOTE = "Payments are off: AIFINPAY_PAYMENTS_ENABLED=0 (or a programmatic config without payments). Env is read only when this server starts; agent_reload re-reads the keystore and nothing else. If the owner has changed it since, have the client restart the aifinpay MCP server (restart the client, or disable and re-enable the server), then call payment_setup_status.";
|
|
30
|
+
/** Payments are on by default (2.12.1) within the built-in ceiling, and only a
|
|
31
|
+
* persistent wallet signs: a server that started ephemeral opens its payment
|
|
32
|
+
* journal at agent_reload after init, without a restart. Legacy signing tools
|
|
33
|
+
* stay retired; payable_fetch is the one reviewed v1.4 path. */
|
|
32
34
|
export async function createServer(config = {}) {
|
|
33
35
|
const log = config.logFn ?? defaultLog;
|
|
34
36
|
assertInjectedWalletChain(config);
|
|
@@ -63,13 +65,23 @@ export async function createServer(config = {}) {
|
|
|
63
65
|
}));
|
|
64
66
|
identitySource = configured?.source ?? "ephemeral";
|
|
65
67
|
if (!configured)
|
|
66
|
-
log("warn", `[aifinpay-mcp] EPHEMERAL wallet — DO NOT FUND. Run \`${initCommand(config.walletHome)}\`, then agent_reload in this connection.`);
|
|
68
|
+
log("warn", `[aifinpay-mcp] EPHEMERAL wallet — DO NOT FUND. Run \`${initCommand(config.walletHome)}\`, then agent_reload in this connection; no restart is needed to pay.`);
|
|
69
|
+
// The journal exists only for a persistent wallet: an ephemeral one cannot
|
|
70
|
+
// pay, and payable_fetch explains instead. A refused setting stops a server
|
|
71
|
+
// whose owner asked for payments by name; with payments on by default it
|
|
72
|
+
// starts read-only and payment_setup_status repeats the refusal.
|
|
67
73
|
let paymentState;
|
|
68
74
|
if (config.paymentsEnabled) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
try {
|
|
76
|
+
validatePaymentConfig(config);
|
|
77
|
+
if (configured)
|
|
78
|
+
paymentState = new PaymentStateStore(agent.evmAddress, config.walletHome);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (!config.paymentsByDefault)
|
|
82
|
+
throw error;
|
|
83
|
+
log("warn", `[aifinpay-mcp] payments stay off until the owner fixes a setting: ${error.message}`);
|
|
84
|
+
}
|
|
73
85
|
}
|
|
74
86
|
// Keep the legacy agent budget configured even though this RC exposes no
|
|
75
87
|
// signing tool. It remains an additional defence for downstream/private code
|
|
@@ -118,7 +130,7 @@ export async function createServer(config = {}) {
|
|
|
118
130
|
agentClaimSelfTool(),
|
|
119
131
|
{
|
|
120
132
|
name: "agent_reload",
|
|
121
|
-
description: "Reload the configured local wallet files after init or a file update, without starting a new conversation. Returns public addresses only.
|
|
133
|
+
description: "Reload the configured local wallet files after init or a file update, without starting a new conversation. Returns public addresses only. With payments on (the default) it also opens the payment journal for the loaded wallet, so a server that started with an ephemeral wallet can pay right after init, without a restart. Env changes (owner overrides, AIFINPAY_PAYMENTS_ENABLED=0) take effect only after the client restarts the aifinpay MCP server; agent_reload does not read them.",
|
|
122
134
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
123
135
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
124
136
|
},
|
|
@@ -155,6 +167,18 @@ export async function createServer(config = {}) {
|
|
|
155
167
|
if (paymentState && replacement.loaded.evmAddress.toLowerCase() !== agent.evmAddress.toLowerCase()) {
|
|
156
168
|
throw new Error("Reconnect to switch payment wallets; pending state must remain associated with its original wallet");
|
|
157
169
|
}
|
|
170
|
+
// init ran after this server started ephemeral: open the journal for
|
|
171
|
+
// the wallet it just loaded. The env is still the one read at start.
|
|
172
|
+
let refusal;
|
|
173
|
+
if (!paymentState && config.paymentsEnabled) {
|
|
174
|
+
try {
|
|
175
|
+
validatePaymentConfig(config);
|
|
176
|
+
paymentState = new PaymentStateStore(replacement.loaded.evmAddress, config.walletHome);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
refusal = `Payments stay off: ${error.message}. Env is read only when this server starts; once the owner fixes it, have the client restart the aifinpay MCP server, then call payment_setup_status.`;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
158
182
|
agent = replacement.loaded;
|
|
159
183
|
identitySource = replacement.source;
|
|
160
184
|
return {
|
|
@@ -171,7 +195,10 @@ export async function createServer(config = {}) {
|
|
|
171
195
|
// env was not picked up", and an agent stopped there
|
|
172
196
|
// (2026-10-19): config is fixed at start, so say so.
|
|
173
197
|
payments_enabled: Boolean(config.paymentsEnabled),
|
|
174
|
-
|
|
198
|
+
// Whether this connection can sign now: the journal is open
|
|
199
|
+
// for the loaded wallet.
|
|
200
|
+
payments_ready: Boolean(paymentState),
|
|
201
|
+
...(config.paymentsEnabled ? (refusal ? { env_note: refusal } : {}) : { env_note: RELOAD_ENV_NOTE }),
|
|
175
202
|
}),
|
|
176
203
|
},
|
|
177
204
|
],
|