agentpay-mcp 4.1.0 → 4.1.4
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 +299 -2
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/otel-budget.d.ts +265 -0
- package/dist/tools/otel-budget.d.ts.map +1 -0
- package/dist/tools/otel-budget.js +399 -0
- package/dist/tools/otel-budget.js.map +1 -0
- package/dist/tools/session.d.ts.map +1 -1
- package/dist/tools/session.js +2 -0
- package/dist/tools/session.js.map +1 -1
- package/dist/tools/x402.d.ts.map +1 -1
- package/dist/tools/x402.js +58 -0
- package/dist/tools/x402.js.map +1 -1
- package/dist/utils/client.d.ts.map +1 -1
- package/dist/utils/client.js +8 -1
- package/dist/utils/client.js.map +1 -1
- package/dist/utils/x402-networks.d.ts +12 -0
- package/dist/utils/x402-networks.d.ts.map +1 -0
- package/dist/utils/x402-networks.js +30 -0
- package/dist/utils/x402-networks.js.map +1 -0
- package/docs/channel-agent-affiliate-controls.md +142 -0
- package/docs/hitl-reference-architecture.md +140 -0
- package/docs/security-posture.md +74 -0
- package/docs/trust-architecture.md +127 -0
- package/docs/vercel-deployment-hardening.md +115 -0
- package/docs/whatsapp-smb-agent-controls.md +130 -0
- package/docs/x402-batch-settlement-channels.md +199 -0
- package/docs/x402-bazaar-observability.md +209 -0
- package/docs/x402-chain-drift-compatibility.md +63 -0
- package/docs/x402-mcp-funding-ux-benchmark.md +36 -0
- package/docs/x402-multi-sdk-batch-settlement-parity.md +167 -0
- package/docs/x402-scanner-readiness.md +110 -0
- package/docs/x402-tvm-readiness.md +53 -0
- package/package.json +6 -5
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# x402 batch-settlement channel compatibility for AgentPay MCP
|
|
2
|
+
|
|
3
|
+
x402 Foundation PR #2061 moves the TypeScript SDK toward batch-settlement channels for repeat paid calls. Instead of one paid request mapping to one immediate facilitator settle call, the client deposits once, signs cumulative vouchers off-chain, and lets the server claim or refund later.
|
|
4
|
+
|
|
5
|
+
That is good for low-latency paid MCP tools. It also changes the control surface. AgentPay MCP integrations must audit channel state, voucher caps, storage atomicity, corrective 402 recovery, and delayed settlement evidence before relying on batch-settlement for production tool calls.
|
|
6
|
+
|
|
7
|
+
## Compatibility goal
|
|
8
|
+
|
|
9
|
+
AgentPay MCP should treat batch-settlement as a channel lifecycle, not a single payment event.
|
|
10
|
+
|
|
11
|
+
A production integration is compatible only when it records and enforces these checkpoints:
|
|
12
|
+
|
|
13
|
+
1. Deposit created or topped up before the first paid call in the channel.
|
|
14
|
+
2. Voucher signed for each paid request with a cumulative maximum claimable amount.
|
|
15
|
+
3. Server verify path checks the voucher without settling every request.
|
|
16
|
+
4. Refund path closes unused channel balance with outstanding vouchers accounted for.
|
|
17
|
+
5. Claim path proves which cumulative voucher amount was claimed before final settle.
|
|
18
|
+
6. Storage uses an atomic compare-and-set or transaction boundary per `channelId`.
|
|
19
|
+
7. Corrective 402 recovery resyncs the client when cumulative state diverges.
|
|
20
|
+
8. Audit logs preserve off-chain voucher state and eventual on-chain settlement proof.
|
|
21
|
+
|
|
22
|
+
## Channel state AgentPay must persist
|
|
23
|
+
|
|
24
|
+
Batch-settlement adds durable per-channel state on both sides of the request.
|
|
25
|
+
|
|
26
|
+
AgentPay MCP should store a sanitized record keyed by `channelId`, `payer`, `receiver`, `token`, and `network`:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"event_type": "x402_batch_channel_state",
|
|
31
|
+
"agent_id": "agent_123",
|
|
32
|
+
"task_id": "task_456",
|
|
33
|
+
"mcp_tool": "agentpay.x402_pay",
|
|
34
|
+
"channel_id": "0xchannel",
|
|
35
|
+
"network": "eip155:84532",
|
|
36
|
+
"token": "USDC",
|
|
37
|
+
"payer_hash": "sha256:...",
|
|
38
|
+
"payer_authorizer_hash": "sha256:...",
|
|
39
|
+
"receiver_hash": "sha256:...",
|
|
40
|
+
"receiver_authorizer_hash": "sha256:...",
|
|
41
|
+
"deposit_amount": "500000",
|
|
42
|
+
"charged_cumulative_amount": "200000",
|
|
43
|
+
"signed_max_claimable": "250000",
|
|
44
|
+
"total_claimed": "0",
|
|
45
|
+
"refund_nonce": "0",
|
|
46
|
+
"storage_version": "42",
|
|
47
|
+
"policy_version": "agentpay-policy-2026-04-30",
|
|
48
|
+
"created_at": "2026-04-30T13:20:00Z"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Public logs should hash payer, receiver, payer authorizer, and receiver authorizer addresses. Internal reconciliation can retain raw addresses in encrypted storage.
|
|
53
|
+
|
|
54
|
+
## Deposit gate
|
|
55
|
+
|
|
56
|
+
A deposit is not a policy approval. It is a funding action that creates channel capacity.
|
|
57
|
+
|
|
58
|
+
Before any deposit or top-up, AgentPay MCP should check:
|
|
59
|
+
|
|
60
|
+
- the deposit amount is under the agent's per-channel deposit cap,
|
|
61
|
+
- the token and network are allowlisted,
|
|
62
|
+
- the receiver and server-owned `receiverAuthorizer` are expected for the paid MCP provider,
|
|
63
|
+
- the deposit multiplier or custom deposit strategy cannot exceed the daily budget,
|
|
64
|
+
- human approval is present when policy requires it.
|
|
65
|
+
|
|
66
|
+
The policy row should say whether the deposit was approved, declined, or skipped. Never infer approval from the x402 SDK choosing a default deposit amount.
|
|
67
|
+
|
|
68
|
+
## Voucher cap checks
|
|
69
|
+
|
|
70
|
+
Batch-settlement vouchers are cumulative. The important value is not only the current request price. It is the new `signedMaxClaimable` amount compared with policy.
|
|
71
|
+
|
|
72
|
+
Before signing a voucher, AgentPay MCP should compute:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
const nextSignedMaxClaimable = currentSignedMaxClaimable + requestCharge;
|
|
76
|
+
|
|
77
|
+
if (nextSignedMaxClaimable > policy.perChannelVoucherCap) {
|
|
78
|
+
throw new Error("voucher cap exceeded");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (nextSignedMaxClaimable > approvedChannelBudget) {
|
|
82
|
+
throw new Error("approved channel budget exceeded");
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Required checks:
|
|
87
|
+
|
|
88
|
+
- per-request price is under `maxAmountRequired`,
|
|
89
|
+
- cumulative voucher amount is under the channel voucher cap,
|
|
90
|
+
- cumulative voucher amount is under the human-approved channel budget,
|
|
91
|
+
- channel balance covers the voucher or a policy-approved top-up is required,
|
|
92
|
+
- voucher signer delegation is recorded when `payerAuthorizer` differs from the payer.
|
|
93
|
+
|
|
94
|
+
If any check fails, signing must fail closed. A skipped facilitator settle call must never skip AgentPay policy.
|
|
95
|
+
|
|
96
|
+
## Atomic storage requirement
|
|
97
|
+
|
|
98
|
+
A batch channel can receive overlapping paid calls. Application-level `get` then `set` is not enough because two requests can sign from the same base cumulative amount.
|
|
99
|
+
|
|
100
|
+
AgentPay MCP should require compare-and-set semantics per channel:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
await storage.updateChannel(channelId, current => {
|
|
104
|
+
if (!current) return createInitialChannel();
|
|
105
|
+
if (current.storageVersion !== expectedVersion) return current;
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
...current,
|
|
109
|
+
chargedCumulativeAmount: nextChargedCumulativeAmount,
|
|
110
|
+
signedMaxClaimable: nextSignedMaxClaimable,
|
|
111
|
+
storageVersion: current.storageVersion + 1,
|
|
112
|
+
lastRequestTimestamp: Date.now()
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Acceptable production backends:
|
|
118
|
+
|
|
119
|
+
- Redis or Valkey with Lua or `WATCH` / `MULTI` / `EXEC`,
|
|
120
|
+
- SQL transaction with `SELECT ... FOR UPDATE` or optimistic version checks,
|
|
121
|
+
- Cloudflare Durable Objects when a single object owns one channel,
|
|
122
|
+
- any backend that gives atomic conditional mutation for all app instances sharing the channel.
|
|
123
|
+
|
|
124
|
+
In-memory storage is acceptable only for a single-process demo.
|
|
125
|
+
|
|
126
|
+
## Corrective 402 recovery
|
|
127
|
+
|
|
128
|
+
PR #2061 adds corrective 402 recovery for cumulative mismatches. AgentPay MCP should log recovery as a first-class payment event because it means client and server channel state diverged.
|
|
129
|
+
|
|
130
|
+
Recovery handling should verify and record:
|
|
131
|
+
|
|
132
|
+
- corrective error code, such as `batch_settlement_cumulative_amount_mismatch`,
|
|
133
|
+
- server-provided `chargedCumulativeAmount`,
|
|
134
|
+
- server-provided `signedMaxClaimable`,
|
|
135
|
+
- voucher signature used to prove the server snapshot,
|
|
136
|
+
- whether recovery came from server signature or on-chain state,
|
|
137
|
+
- local storage version before and after resync,
|
|
138
|
+
- whether the original request was retried.
|
|
139
|
+
|
|
140
|
+
If recovery cannot verify the signature, channel config, or on-chain state, AgentPay MCP should mark the channel `recovery_failed` and block more voucher signing until a human or operator reconciles it.
|
|
141
|
+
|
|
142
|
+
## Refund and claim audit path
|
|
143
|
+
|
|
144
|
+
Refund and claim are delayed settlement operations. They need different audit rows from a normal one-shot x402 payment.
|
|
145
|
+
|
|
146
|
+
For refunds, record:
|
|
147
|
+
|
|
148
|
+
- requested refund amount or full refund flag,
|
|
149
|
+
- outstanding signed max claimable amount,
|
|
150
|
+
- server claim action before refund if any,
|
|
151
|
+
- refund transaction hash or pending status,
|
|
152
|
+
- remaining channel balance after refund.
|
|
153
|
+
|
|
154
|
+
For claims, record:
|
|
155
|
+
|
|
156
|
+
- claimed channel IDs,
|
|
157
|
+
- claimed cumulative amount per channel,
|
|
158
|
+
- claim transaction hash,
|
|
159
|
+
- settle transaction hash if funds are swept separately,
|
|
160
|
+
- receiver and receiver authorizer hashes,
|
|
161
|
+
- failed, partial, or retried claims.
|
|
162
|
+
|
|
163
|
+
A paid MCP provider should be able to answer: which tool call increased the voucher, which cumulative voucher got claimed, and which on-chain transaction settled it.
|
|
164
|
+
|
|
165
|
+
## Server-owned receiver authorizer
|
|
166
|
+
|
|
167
|
+
The batch-settlement scheme includes `receiverAuthorizer` in channel config. For AgentPay MCP, this is part of provider identity.
|
|
168
|
+
|
|
169
|
+
AgentPay MCP should pin or allowlist expected receiver authorizers per paid MCP provider. If the receiver authorizer changes, the integration should require one of these outcomes:
|
|
170
|
+
|
|
171
|
+
- a signed provider rotation notice,
|
|
172
|
+
- a fresh human approval,
|
|
173
|
+
- or fail-closed rejection.
|
|
174
|
+
|
|
175
|
+
Do not treat a matching receiver address as enough. The receiver authorizer can become the operational key that approves server-side settlement behavior.
|
|
176
|
+
|
|
177
|
+
## Off-chain settlement audit checklist
|
|
178
|
+
|
|
179
|
+
Before enabling batch-settlement for a paid MCP tool, require:
|
|
180
|
+
|
|
181
|
+
- `channel_id` in every payment attempt row,
|
|
182
|
+
- `deposit_amount`, `charged_cumulative_amount`, and `signed_max_claimable` in channel rows,
|
|
183
|
+
- policy approval ID attached to deposit and voucher signing,
|
|
184
|
+
- CAS or transaction proof for channel storage mutations,
|
|
185
|
+
- corrective 402 recovery rows,
|
|
186
|
+
- refund and claim rows with transaction hashes when available,
|
|
187
|
+
- hashed payer, receiver, payer authorizer, and receiver authorizer fields,
|
|
188
|
+
- failure rows for skipped deposits, voucher cap rejection, recovery failure, refund failure, and claim failure.
|
|
189
|
+
|
|
190
|
+
## Acceptance checklist
|
|
191
|
+
|
|
192
|
+
- [ ] Deposit policy enforces per-channel and daily caps before channel funding.
|
|
193
|
+
- [ ] Voucher signing checks cumulative voucher caps, not only per-request price.
|
|
194
|
+
- [ ] Server-owned `receiverAuthorizer` is pinned or routed through approval.
|
|
195
|
+
- [ ] Channel storage uses atomic compare-and-set or transaction semantics.
|
|
196
|
+
- [ ] Corrective 402 recovery is logged and fails closed when verification fails.
|
|
197
|
+
- [ ] Refund flows account for outstanding signed vouchers before returning balance.
|
|
198
|
+
- [ ] Claim flows log cumulative claimed amount and settlement transaction proof.
|
|
199
|
+
- [ ] Audit rows connect MCP tool name, policy version, channel ID, voucher state, and on-chain settlement.
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# x402 Bazaar observability for paid MCP tools
|
|
2
|
+
|
|
3
|
+
x402 Bazaar is moving from passive discovery metadata to searchable catalog behavior. AgentPay MCP should treat that as a production contract: paid MCP tools need searchable metadata, shared facilitator auth, and visible extension outcomes after verify and settle.
|
|
4
|
+
|
|
5
|
+
This recipe tracks the x402 Foundation Apr 29 signal: WithBazaar SDK wrappers now support search, unified auth, and Python parity, and PR #2161 adds EXTENSION-RESPONSES header readback for verify and settle.
|
|
6
|
+
|
|
7
|
+
## Production goal
|
|
8
|
+
|
|
9
|
+
A paid MCP tool is Bazaar-ready only when all four checks pass:
|
|
10
|
+
|
|
11
|
+
1. The 402 response carries a `bazaar` extension with MCP search metadata.
|
|
12
|
+
2. The facilitator client can list and search Bazaar resources with the same auth provider used for `verify`, `settle`, and `supported`.
|
|
13
|
+
3. The client reads `EXTENSION-RESPONSES` from verify and settle responses.
|
|
14
|
+
4. AgentPay MCP writes sanitized audit rows for catalog status, policy approval, and settlement.
|
|
15
|
+
|
|
16
|
+
If any check fails, AgentPay MCP should still fail closed for payment signing. Discovery failure must not become silent spend authority.
|
|
17
|
+
|
|
18
|
+
## Bazaar metadata for MCP tools
|
|
19
|
+
|
|
20
|
+
For each paid MCP tool, the 402 response should include a `bazaar` extension under `extensions`.
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"extensions": {
|
|
25
|
+
"bazaar": {
|
|
26
|
+
"info": {
|
|
27
|
+
"input": {
|
|
28
|
+
"type": "mcp",
|
|
29
|
+
"tool": "agentpay.x402_pay",
|
|
30
|
+
"description": "Pay an x402-protected API after AgentPay MCP policy approval",
|
|
31
|
+
"transport": "streamable-http",
|
|
32
|
+
"inputSchema": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {
|
|
35
|
+
"resource": { "type": "string" },
|
|
36
|
+
"maxAmountRequired": { "type": "string" },
|
|
37
|
+
"network": { "type": "string" },
|
|
38
|
+
"payTo": { "type": "string" }
|
|
39
|
+
},
|
|
40
|
+
"required": ["resource", "maxAmountRequired", "network", "payTo"]
|
|
41
|
+
},
|
|
42
|
+
"example": {
|
|
43
|
+
"resource": "https://api.example.com/research/report",
|
|
44
|
+
"maxAmountRequired": "100000",
|
|
45
|
+
"network": "eip155:8453",
|
|
46
|
+
"payTo": "0x0000000000000000000000000000000000000000"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"output": {
|
|
50
|
+
"type": "json",
|
|
51
|
+
"example": {
|
|
52
|
+
"approved": true,
|
|
53
|
+
"transaction": "0x...",
|
|
54
|
+
"policy_version": "agentpay-policy-2026-04-30"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"schema": {
|
|
59
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
60
|
+
"type": "object",
|
|
61
|
+
"required": ["input"],
|
|
62
|
+
"properties": {
|
|
63
|
+
"input": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"required": ["type", "tool", "inputSchema"],
|
|
66
|
+
"properties": {
|
|
67
|
+
"type": { "const": "mcp" },
|
|
68
|
+
"tool": { "type": "string" },
|
|
69
|
+
"description": { "type": "string" },
|
|
70
|
+
"transport": { "enum": ["streamable-http", "sse"] },
|
|
71
|
+
"inputSchema": { "type": "object" },
|
|
72
|
+
"example": { "type": "object" }
|
|
73
|
+
},
|
|
74
|
+
"additionalProperties": false
|
|
75
|
+
},
|
|
76
|
+
"output": { "type": "object" }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Required AgentPay fields:
|
|
85
|
+
|
|
86
|
+
- `input.type`: `mcp`
|
|
87
|
+
- `input.tool`: MCP tool name passed to `tools/call`
|
|
88
|
+
- `input.description`: one sentence with the paid action and policy boundary
|
|
89
|
+
- `input.transport`: `streamable-http` by default, `sse` only when the server uses SSE
|
|
90
|
+
- `input.inputSchema`: the same schema the MCP tool advertises
|
|
91
|
+
- `input.example`: a safe example that does not include a real private key, API token, wallet secret, or customer identifier
|
|
92
|
+
- `output.example.policy_version`: the policy revision attached to the approval decision
|
|
93
|
+
|
|
94
|
+
For MCP resources, the catalog key is the tuple `resource.url` plus `input.tool`. Do not assume one MCP endpoint maps to one paid capability.
|
|
95
|
+
|
|
96
|
+
## Search checks with WithBazaar
|
|
97
|
+
|
|
98
|
+
AgentPay MCP should be discoverable by a Bazaar search query, not only by a raw list call.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { HTTPFacilitatorClient } from "@x402/core/http";
|
|
102
|
+
import { withBazaar } from "@x402/extensions";
|
|
103
|
+
|
|
104
|
+
const facilitator = new HTTPFacilitatorClient({
|
|
105
|
+
url: process.env.X402_FACILITATOR_URL,
|
|
106
|
+
createAuthHeaders: async () => ({
|
|
107
|
+
verify: { Authorization: `Bearer ${process.env.X402_FACILITATOR_TOKEN}` },
|
|
108
|
+
settle: { Authorization: `Bearer ${process.env.X402_FACILITATOR_TOKEN}` },
|
|
109
|
+
supported: { Authorization: `Bearer ${process.env.X402_FACILITATOR_TOKEN}` },
|
|
110
|
+
bazaar: { Authorization: `Bearer ${process.env.X402_FACILITATOR_TOKEN}` }
|
|
111
|
+
})
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const client = withBazaar(facilitator);
|
|
115
|
+
|
|
116
|
+
const matches = await client.extensions.bazaar.search({
|
|
117
|
+
query: "approval gated x402 MCP payment tool",
|
|
118
|
+
type: "mcp",
|
|
119
|
+
network: "eip155:8453",
|
|
120
|
+
scheme: "exact",
|
|
121
|
+
extensions: "bazaar",
|
|
122
|
+
limit: 10
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The `bazaar` auth header must use the same auth source as `verify`, `settle`, and `supported`. Divergent auth is a bad production signal because the agent may be able to pay but not prove catalog status.
|
|
127
|
+
|
|
128
|
+
## EXTENSION-RESPONSES readback
|
|
129
|
+
|
|
130
|
+
Facilitators may return an `EXTENSION-RESPONSES` header from `verify` or `settle`. The value is base64-encoded JSON keyed by extension name.
|
|
131
|
+
|
|
132
|
+
Example decoded value:
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"bazaar": {
|
|
137
|
+
"status": "success"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Rejected example:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"bazaar": {
|
|
147
|
+
"status": "rejected",
|
|
148
|
+
"rejectedReason": "info failed schema validation"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
AgentPay MCP should parse the header, keep only allowlisted fields, and write the result into the payment audit row. Never log full request bodies, auth headers, private keys, payment signatures, or customer contact data.
|
|
154
|
+
|
|
155
|
+
Allowlisted fields:
|
|
156
|
+
|
|
157
|
+
- `status`
|
|
158
|
+
- `rejectedReason`
|
|
159
|
+
- `reason`
|
|
160
|
+
- `code`
|
|
161
|
+
|
|
162
|
+
## Audit row shape
|
|
163
|
+
|
|
164
|
+
Paid MCP tool audit rows should include enough state to debug Bazaar cataloging without leaking secrets.
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"event_type": "x402_paid_mcp_tool_settled",
|
|
169
|
+
"agent_id": "agent_123",
|
|
170
|
+
"task_id": "task_456",
|
|
171
|
+
"mcp_tool": "agentpay.x402_pay",
|
|
172
|
+
"resource": "https://api.example.com/research/report",
|
|
173
|
+
"network": "eip155:8453",
|
|
174
|
+
"asset": "USDC",
|
|
175
|
+
"max_amount_required": "100000",
|
|
176
|
+
"pay_to_hash": "sha256:...",
|
|
177
|
+
"policy_version": "agentpay-policy-2026-04-30",
|
|
178
|
+
"approval_id": "approval_789",
|
|
179
|
+
"verify_extension_responses": {
|
|
180
|
+
"bazaar": { "status": "processing" }
|
|
181
|
+
},
|
|
182
|
+
"settle_extension_responses": {
|
|
183
|
+
"bazaar": { "status": "success" }
|
|
184
|
+
},
|
|
185
|
+
"settlement_tx": "0x...",
|
|
186
|
+
"created_at": "2026-04-30T05:14:00Z"
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`pay_to_hash` is preferred for public logs. Internal systems can keep the raw address in encrypted storage when reconciliation needs it.
|
|
191
|
+
|
|
192
|
+
## Failure handling
|
|
193
|
+
|
|
194
|
+
- Missing Bazaar search result: payment can proceed only if the normal AgentPay policy approves it, but write `bazaar_catalog_status: missing`.
|
|
195
|
+
- Missing `EXTENSION-RESPONSES`: write `extension_response_status: absent`, not `success`.
|
|
196
|
+
- Malformed `EXTENSION-RESPONSES`: ignore the raw header, write `extension_response_status: malformed`, and keep the payment state separate.
|
|
197
|
+
- `bazaar.status: rejected`: surface the rejection reason to the operator and flag the MCP metadata for repair.
|
|
198
|
+
- Auth failure on Bazaar search: do not downgrade verify or settle auth. Fix the `bazaar` auth header path.
|
|
199
|
+
|
|
200
|
+
## Acceptance checklist
|
|
201
|
+
|
|
202
|
+
- [ ] 402 response includes `extensions.bazaar.info.input.type = "mcp"`.
|
|
203
|
+
- [ ] `input.tool` matches the MCP `tools/call` name.
|
|
204
|
+
- [ ] `input.inputSchema` matches the MCP tool schema.
|
|
205
|
+
- [ ] `withBazaar(...).search({ type: "mcp", extensions: "bazaar" })` returns the paid tool or a clear miss.
|
|
206
|
+
- [ ] `createAuthHeaders` includes `verify`, `settle`, `supported`, and `bazaar` entries.
|
|
207
|
+
- [ ] Verify and settle read `EXTENSION-RESPONSES` when present.
|
|
208
|
+
- [ ] Logs keep only `status`, `rejectedReason`, `reason`, and `code` from extension response payloads.
|
|
209
|
+
- [ ] Payment signing remains gated by AgentPay policy approval even when Bazaar metadata is valid.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# x402 chain-drift compatibility note and test plan
|
|
2
|
+
|
|
3
|
+
x402 paywall templates are moving faster than static client examples. The risk is simple: a paid-agent demo assumes yesterday's chain list, then a PaymentWrapper or paywall update emits payment metadata for a chain the client does not recognize.
|
|
4
|
+
|
|
5
|
+
AgentPay MCP must not silently coerce unknown x402 chains to Base. The package now depends on `viem` `^2.47.12`, matching or exceeding the x402 Foundation paywall-template baseline that added Mezo, MegaETH, Stable, and Radius chain definitions.
|
|
6
|
+
|
|
7
|
+
## Current boundary
|
|
8
|
+
|
|
9
|
+
AgentPay MCP `4.1.4` supports Base Mainnet and Base Sepolia for the core configured wallet client. Other tools in the repo support broader token, bridge, and swap surfaces, but x402 payment execution should treat unsupported chains as a fail-closed condition until the chain is explicitly mapped, tested, and funded.
|
|
10
|
+
|
|
11
|
+
This is safer than guessing. A failed payment is recoverable. A wrong-chain signature is not.
|
|
12
|
+
|
|
13
|
+
## Chains to watch
|
|
14
|
+
|
|
15
|
+
Track x402 Foundation paywall and PaymentWrapper changes for these chain definitions:
|
|
16
|
+
|
|
17
|
+
- Mezo
|
|
18
|
+
- MegaETH
|
|
19
|
+
- Stable
|
|
20
|
+
- Radius
|
|
21
|
+
- Any new `viem/chains` entry that appears in x402 paywall templates before AgentPay MCP docs or tests mention it
|
|
22
|
+
|
|
23
|
+
## Compatibility requirements
|
|
24
|
+
|
|
25
|
+
- Parse the chain or network value from x402 payment metadata without assuming Base.
|
|
26
|
+
- Match known networks to explicit AgentPay MCP chain configuration.
|
|
27
|
+
- Reject unknown networks with a clear error that names the unsupported chain.
|
|
28
|
+
- Never fall back to `8453` when the server requested a different chain.
|
|
29
|
+
- Keep docs, tests, and package examples aligned with the current x402 Foundation template set.
|
|
30
|
+
|
|
31
|
+
## Test coverage
|
|
32
|
+
|
|
33
|
+
`tests/chain-drift.test.ts` is the current smoke gate. It verifies that the installed `viem/chains` baseline exposes Mezo, MegaETH, Stable, and Radius, then verifies that AgentPay MCP still rejects those chain IDs instead of routing them through Base.
|
|
34
|
+
|
|
35
|
+
Future fixture-driven tests for x402 payment metadata should use this shape:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const paymentRequirements = [
|
|
39
|
+
{ network: "base", chainId: 8453, shouldPay: true },
|
|
40
|
+
{ network: "base-sepolia", chainId: 84532, shouldPay: true },
|
|
41
|
+
{ network: "mezo", shouldPay: false },
|
|
42
|
+
{ network: "megaeth", shouldPay: false },
|
|
43
|
+
{ network: "stable", shouldPay: false },
|
|
44
|
+
{ network: "radius", shouldPay: false },
|
|
45
|
+
];
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Expected results:
|
|
49
|
+
|
|
50
|
+
- `base` and `base-sepolia` route only when the configured wallet, token registry, RPC URL, and policy allow them.
|
|
51
|
+
- Mezo, MegaETH, Stable, and Radius return `Unsupported x402 network` until explicit support lands.
|
|
52
|
+
- The error includes the requested network and the configured network.
|
|
53
|
+
- Tests assert that the signing function is not called for unsupported networks.
|
|
54
|
+
|
|
55
|
+
## Release gate
|
|
56
|
+
|
|
57
|
+
Before any future AgentPay MCP release claiming new x402 chain support:
|
|
58
|
+
|
|
59
|
+
1. Update the chain map and explorer map.
|
|
60
|
+
2. Add payment metadata fixtures from the current x402 Foundation paywall templates.
|
|
61
|
+
3. Run unit tests for accept, deny, cancel, cap exceeded, and unknown chain paths.
|
|
62
|
+
4. Run `npm run typecheck`, `npm test`, `npm run build`, and `npm pack --dry-run`.
|
|
63
|
+
5. Update this document with the supported network set and validation date.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# x402 MCP funding UX benchmark
|
|
2
|
+
|
|
3
|
+
A new public repo, `yayashuxue/agent-marketplace-mcp`, is testing an x402-paid MCP server with hosted funding UX, local hot-wallet generation, optional Coinbase-managed mode, and Smithery hosting metadata. As of 2026-05-01 04:48 CT, `npm view agent-marketplace-mcp` returned 404, so this benchmark treats it as a public repo signal, not as a live npm package.
|
|
4
|
+
|
|
5
|
+
The signal matters because paid MCP builders are moving funding into the product pitch. AgentPay MCP should make the tradeoff clear: fast top-up is useful, but production agents need approval gates, daily caps, auditability, and a non-custodial posture before they can spend real budgets.
|
|
6
|
+
|
|
7
|
+
## Comparison
|
|
8
|
+
|
|
9
|
+
| Area | AgentPay MCP | agent-marketplace-mcp signal |
|
|
10
|
+
|------|--------------|------------------------------|
|
|
11
|
+
| Funding model | Bring a funded non-custodial Agent Wallet. Funding can happen through any wallet workflow the operator approves. | Public README describes a hosted fund link and optional managed wallet mode. |
|
|
12
|
+
| Approval gates | Payment tools are designed to sit behind human approval, policy checks, and per-call caps before signing. | The repo emphasizes easier funding. Approval gating is not the main product claim in the observed public metadata. |
|
|
13
|
+
| Daily caps | AgentPay MCP exposes spend limits and budget checks as first-class controls before paid tool use. | Funding UX may reduce onboarding friction, but a funded wallet still needs enforceable spend caps. |
|
|
14
|
+
| Auditability | AgentPay MCP records payment amount, recipient, network, transaction hash, and history through wallet activity tools. | Hosted top-up can help users fund faster, but operators still need agent-level audit rows for every paid call. |
|
|
15
|
+
| Custody posture | Non-custodial by default. The agent signs with its configured wallet key and policy layer. | Optional Coinbase-managed mode may be easier for onboarding, but it changes custody and operational risk assumptions. |
|
|
16
|
+
| Failure mode | Unsupported chains and unsupported x402 requirements fail closed. | Hosted funding does not remove the need to reject unsupported networks, assets, payees, and settlement paths. |
|
|
17
|
+
|
|
18
|
+
## Safe funding UX for AgentPay MCP
|
|
19
|
+
|
|
20
|
+
AgentPay MCP should keep funding easy without weakening spend controls:
|
|
21
|
+
|
|
22
|
+
1. Show wallet funding status before a paid tool call.
|
|
23
|
+
2. Link to operator-approved funding instructions, not an automatic top-up that bypasses review.
|
|
24
|
+
3. Require an approval gate before the first payment to a new service or payee.
|
|
25
|
+
4. Enforce per-call and daily caps before signing.
|
|
26
|
+
5. Log each payment with service, URL, amount, asset, recipient, network, transaction hash, and policy version.
|
|
27
|
+
6. Fail closed for unsupported networks, including TVM/TON exact-payment offers.
|
|
28
|
+
7. Keep managed-wallet mode as an explicit integration choice, not a silent default.
|
|
29
|
+
|
|
30
|
+
## Buyer guidance
|
|
31
|
+
|
|
32
|
+
Pick hosted funding when the goal is a fast demo and the budget is small.
|
|
33
|
+
|
|
34
|
+
Pick AgentPay MCP when a production agent needs to prove who approved the spend, how much it can spend per call, what daily ceiling applies, which wallet signed, and where the receipt lives.
|
|
35
|
+
|
|
36
|
+
Funding UX gets the wallet ready. Spend governance decides whether the agent is allowed to use it.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# x402 multi-SDK batch-settlement parity for AgentPay MCP
|
|
2
|
+
|
|
3
|
+
x402 Foundation PR #2164 extends the batch-settlement work from the TypeScript branch into Go client, server, facilitator, and e2e paths. That changes the AgentPay MCP compatibility bar. Paid MCP providers should not prove batch-settlement safety with one SDK only.
|
|
4
|
+
|
|
5
|
+
The minimum proof now needs TypeScript and Go clients to produce the same channel-state evidence for deposits, vouchers, recovery, refunds, claims, and final settlement.
|
|
6
|
+
|
|
7
|
+
## Compatibility target
|
|
8
|
+
|
|
9
|
+
AgentPay MCP should treat multi-SDK batch settlement as one shared channel lifecycle with SDK-specific implementations.
|
|
10
|
+
|
|
11
|
+
A provider is compatible only when a TypeScript client and a Go client can both show:
|
|
12
|
+
|
|
13
|
+
- the same `channelId` derivation inputs for payer, `payerAuthorizer`, receiver, `receiverAuthorizer`, token, network, withdraw delay, and salt,
|
|
14
|
+
- the same policy approval gate before deposit or top-up,
|
|
15
|
+
- the same cumulative voucher cap checks before every voucher signature,
|
|
16
|
+
- the same recovery behavior after a corrective 402,
|
|
17
|
+
- the same refund and claim audit rows,
|
|
18
|
+
- the same proof bundle shape for paid MCP operators.
|
|
19
|
+
|
|
20
|
+
If one SDK emits less state than another, use the stricter shape. Do not let a Go integration skip an audit row that the TypeScript path already records, or vice versa.
|
|
21
|
+
|
|
22
|
+
## Cross-SDK channel identity
|
|
23
|
+
|
|
24
|
+
PR #2164 adds Go batch-settlement examples and e2e wiring around `CHANNEL_SALT`. AgentPay MCP should use the salt as part of the channel identity record, not as a test-only detail.
|
|
25
|
+
|
|
26
|
+
Store this channel identity before signing any voucher:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"event_type": "x402_batch_sdk_parity_channel",
|
|
31
|
+
"sdk": "go",
|
|
32
|
+
"sdk_version": "pr-2164-head",
|
|
33
|
+
"channel_id": "0xchannel",
|
|
34
|
+
"network": "eip155:84532",
|
|
35
|
+
"token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
36
|
+
"payer_hash": "sha256:...",
|
|
37
|
+
"payer_authorizer_hash": "sha256:...",
|
|
38
|
+
"receiver_hash": "sha256:...",
|
|
39
|
+
"receiver_authorizer_hash": "sha256:...",
|
|
40
|
+
"withdraw_delay_seconds": 86400,
|
|
41
|
+
"channel_salt_hash": "sha256:...",
|
|
42
|
+
"channel_config_hash": "sha256:...",
|
|
43
|
+
"policy_version": "agentpay-policy-2026-04-30"
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The `channel_config_hash` must be computed from the normalized config fields, not from a raw SDK struct dump. Field order and JSON tags differ across languages.
|
|
48
|
+
|
|
49
|
+
## Phased e2e proof
|
|
50
|
+
|
|
51
|
+
PR #2164 adds fixed batch-settlement phases for e2e clients:
|
|
52
|
+
|
|
53
|
+
- `initial`: deposit plus first voucher,
|
|
54
|
+
- `recovery-refund`: corrective recovery voucher plus cooperative refund,
|
|
55
|
+
- `full`: deposit, voucher, and refund in one flow.
|
|
56
|
+
|
|
57
|
+
AgentPay MCP test evidence should preserve the same phase names. Each phase needs one proof row per SDK:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"event_type": "x402_batch_sdk_parity_phase",
|
|
62
|
+
"phase": "recovery-refund",
|
|
63
|
+
"sdk": "go",
|
|
64
|
+
"mcp_tool": "agentpay.x402_pay",
|
|
65
|
+
"channel_id": "0xchannel",
|
|
66
|
+
"deposit_tx": "0x...",
|
|
67
|
+
"voucher_signature_hash": "sha256:...",
|
|
68
|
+
"recovery_error_code": "batch_settlement_cumulative_amount_mismatch",
|
|
69
|
+
"refund_tx": "0x...",
|
|
70
|
+
"storage_version_before": "42",
|
|
71
|
+
"storage_version_after": "43",
|
|
72
|
+
"result": "passed"
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
A provider can run more phases, but it should not rename these three. Stable phase names make cross-SDK failures searchable in CI and production incident logs.
|
|
77
|
+
|
|
78
|
+
## Voucher signer separation
|
|
79
|
+
|
|
80
|
+
The Go client path adds optional `EVM_VOUCHER_SIGNER_PRIVATE_KEY`, matching the TypeScript direction where the payer key and voucher signer can be separated.
|
|
81
|
+
|
|
82
|
+
AgentPay MCP should record signer separation as a first-class policy fact:
|
|
83
|
+
|
|
84
|
+
- payer key signs deposits and channel funding authorizations,
|
|
85
|
+
- voucher signer signs repeat-call vouchers as `payerAuthorizer`,
|
|
86
|
+
- receiver authorizer signs claim and refund settlement actions,
|
|
87
|
+
- facilitator wallet submits on-chain settlement transactions.
|
|
88
|
+
|
|
89
|
+
A dedicated voucher signer is allowed only when policy records the delegated signer address and its scope. It must not inherit all payer permissions by accident.
|
|
90
|
+
|
|
91
|
+
Fail closed when:
|
|
92
|
+
|
|
93
|
+
- `payerAuthorizer` changes without a fresh approval,
|
|
94
|
+
- `EVM_VOUCHER_SIGNER_PRIVATE_KEY` appears in a provider runtime where voucher delegation is not expected,
|
|
95
|
+
- a voucher signer can also move funds directly from the payer wallet,
|
|
96
|
+
- the SDK reports a payer authorizer address that does not match the approved delegation.
|
|
97
|
+
|
|
98
|
+
## Facilitator and receiver authorizer expectations
|
|
99
|
+
|
|
100
|
+
Go examples add facilitator and server authorizer paths. AgentPay MCP should distinguish three operational roles:
|
|
101
|
+
|
|
102
|
+
1. Receiver: the payee address used for the channel.
|
|
103
|
+
2. Receiver authorizer: the key that signs claim and refund payloads.
|
|
104
|
+
3. Facilitator signer: the key that submits or sponsors on-chain settlement actions.
|
|
105
|
+
|
|
106
|
+
For production paid MCP providers, the safest path is a self-managed receiver authorizer controlled by the provider, with facilitator rotation treated as operational infrastructure. Delegating receiver authorization to a facilitator is acceptable for demos, but it should be logged as higher operational risk.
|
|
107
|
+
|
|
108
|
+
Audit rows must include hashed receiver authorizer and facilitator identity fields. A matching receiver address is not enough proof.
|
|
109
|
+
|
|
110
|
+
## Refund and recovery visibility
|
|
111
|
+
|
|
112
|
+
The Go e2e path makes recovery and refund behavior explicit. AgentPay MCP should expose the same visibility in provider logs:
|
|
113
|
+
|
|
114
|
+
- corrective 402 code,
|
|
115
|
+
- server-reported cumulative charge,
|
|
116
|
+
- client-local cumulative charge before recovery,
|
|
117
|
+
- recovered voucher hash,
|
|
118
|
+
- refund amount requested,
|
|
119
|
+
- outstanding signed max claimable before refund,
|
|
120
|
+
- claim-before-refund decision,
|
|
121
|
+
- refund transaction or pending status.
|
|
122
|
+
|
|
123
|
+
A refund that hides outstanding voucher state is not production-safe. The operator needs to know whether the server claimed first, refunded the unclaimed remainder, retried, or failed.
|
|
124
|
+
|
|
125
|
+
## Cross-SDK proof bundle
|
|
126
|
+
|
|
127
|
+
Before enabling batch-settlement for a paid MCP provider, require a proof bundle with this shape:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"provider": "paid-mcp-provider.example",
|
|
132
|
+
"x402_pr_reference": "https://github.com/x402-foundation/x402/pull/2164",
|
|
133
|
+
"agentpay_doc_reference": "docs/x402-multi-sdk-batch-settlement-parity.md",
|
|
134
|
+
"sdk_matrix": [
|
|
135
|
+
{
|
|
136
|
+
"sdk": "typescript",
|
|
137
|
+
"phases": ["initial", "recovery-refund", "full"],
|
|
138
|
+
"voucher_signer_separation": true,
|
|
139
|
+
"receiver_authorizer_pinned": true,
|
|
140
|
+
"cas_storage_proven": true,
|
|
141
|
+
"refund_recovery_rows_present": true
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"sdk": "go",
|
|
145
|
+
"phases": ["initial", "recovery-refund", "full"],
|
|
146
|
+
"voucher_signer_separation": true,
|
|
147
|
+
"receiver_authorizer_pinned": true,
|
|
148
|
+
"cas_storage_proven": true,
|
|
149
|
+
"refund_recovery_rows_present": true
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
"acceptance": "passed"
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The proof should link to CI output or a local validation artifact. Screenshots are not enough.
|
|
157
|
+
|
|
158
|
+
## Acceptance checklist
|
|
159
|
+
|
|
160
|
+
- [ ] TypeScript and Go runs use the same normalized channel identity fields.
|
|
161
|
+
- [ ] `CHANNEL_SALT` is recorded in hashed form and tied to the `channelId` proof.
|
|
162
|
+
- [ ] `initial`, `recovery-refund`, and `full` phase results are logged per SDK.
|
|
163
|
+
- [ ] `EVM_VOUCHER_SIGNER_PRIVATE_KEY` or equivalent delegation is recorded as `payerAuthorizer` scope, not broad payer authority.
|
|
164
|
+
- [ ] Receiver authorizer and facilitator signer roles are logged separately.
|
|
165
|
+
- [ ] Corrective 402 recovery rows include before and after cumulative state.
|
|
166
|
+
- [ ] Refund rows include outstanding signed max claimable and claim-before-refund behavior.
|
|
167
|
+
- [ ] The provider can hand operators one proof bundle that compares TypeScript and Go results side by side.
|