@cmdoss/suipay-mcp 0.2.2-dev.9 → 0.3.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -6
- package/dist/bin/suipay.js +5 -3
- package/dist/{chunk-NDJ7BFI4.js → chunk-FKDC22O6.js} +4181 -632
- package/dist/{chunk-LQOZBRH6.js → chunk-W4RIN664.js} +18 -11
- package/dist/http-BCFfQFIg.d.ts +4786 -0
- package/dist/http.d.ts +2 -10
- package/dist/http.js +1 -1
- package/dist/index.d.ts +405 -13
- package/dist/index.js +2 -2
- package/package.json +3 -3
- package/dist/http-RP-Xlg60.d.ts +0 -645
package/dist/http-RP-Xlg60.d.ts
DELETED
|
@@ -1,645 +0,0 @@
|
|
|
1
|
-
import { GrantSnapshot } from '@cmdoss/suipay-core/policy/grant-target';
|
|
2
|
-
import { McpAccessContext } from '@cmdoss/suipay-sdk/mcp/access-context';
|
|
3
|
-
import { SettlementDTO } from '@cmdoss/suipay-sdk/buyer/settlement-dto';
|
|
4
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
5
|
-
import { GetObjectJson } from '@cmdoss/suipay-sdk/agent-sdk/reads';
|
|
6
|
-
import { DelegatedKeySigner, DelegatedPayerDeps, GuardedSettleFields } from '@cmdoss/suipay-sdk/delegated-signer/payer';
|
|
7
|
-
import { TraceRunResolver, TraceSink } from '@cmdoss/suipay-core/trace/types';
|
|
8
|
-
import { PaidHttpRequest } from '@cmdoss/suipay-sdk/protocol/paid-http-request';
|
|
9
|
-
import { Dialect } from '@cmdoss/suipay-sdk/protocol/types';
|
|
10
|
-
import { PayOperationDeps } from '@cmdoss/suipay-sdk/pay-operation';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Authenticated MCP request context (remote Streamable HTTP).
|
|
14
|
-
* Bearer is required on /mcp; tools enforce scope from the resolved grant.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Read/prepare-only shared-pool context for an authenticated MCP bearer.
|
|
19
|
-
*
|
|
20
|
-
* Non-custodial: the gateway holds NO key that can spend. There is deliberately
|
|
21
|
-
* no `decryptDelegateSeed` and no forwarded `sponsorAuthorization` here — the
|
|
22
|
-
* `pay` tool only PREPARES an unsigned `spend_account::settle_policy` / `settle_any_recipient` transaction from the
|
|
23
|
-
* immutable grant snapshot (`prepareSpendAccountPayment`), and the client that
|
|
24
|
-
* holds the delegate key signs locally and submits. Only signatures ever reach
|
|
25
|
-
* the gateway. See docs/design/mcp-non-custodial-signing.md and ADR-0013 §3.
|
|
26
|
-
*/
|
|
27
|
-
interface McpSpendAccountPayAuth {
|
|
28
|
-
snapshot: GrantSnapshot;
|
|
29
|
-
packageId: string;
|
|
30
|
-
/**
|
|
31
|
-
* Re-verify the paying authority against a FRESH graph + injected clock at
|
|
32
|
-
* prepare time. Throws on drift/expiry so the pay tool refuses to hand back a
|
|
33
|
-
* signing request for a grant that just went paused/revoked/expired. Optional:
|
|
34
|
-
* absent for legacy/local paths.
|
|
35
|
-
*/
|
|
36
|
-
assertLive?: () => Promise<void>;
|
|
37
|
-
}
|
|
38
|
-
interface McpAuthContext {
|
|
39
|
-
grantId: string;
|
|
40
|
-
buyerAccountId: string;
|
|
41
|
-
/** Space-separated scopes from the access token. */
|
|
42
|
-
scope: string;
|
|
43
|
-
/** Public, descriptive policy context. Never used as payment authority. */
|
|
44
|
-
access?: McpAccessContext;
|
|
45
|
-
/**
|
|
46
|
-
* When present, `pay` prepares unsigned spend_account::settle_policy / settle_any_recipient bytes for the
|
|
47
|
-
* client-held delegate key to sign locally — no server-side decrypt or
|
|
48
|
-
* signing. Stdio local V1 profile path remains when absent.
|
|
49
|
-
*/
|
|
50
|
-
spendAccountPay?: McpSpendAccountPayAuth;
|
|
51
|
-
/**
|
|
52
|
-
* Server-scoped receipts reader, built by the /mcp route from the verified
|
|
53
|
-
* bearer's connection. The `receipts` tool calls this instead of hitting the
|
|
54
|
-
* global settlement feed with a forwarded credential — the bearer never
|
|
55
|
-
* enters the tool surface, and scoping is enforced server-side. Absent for
|
|
56
|
-
* local stdio (no connection, no settlement source).
|
|
57
|
-
*/
|
|
58
|
-
listReceipts?: (challengeId?: string) => Promise<SettlementDTO[]>;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
type McpTarget = 'dev' | 'local';
|
|
62
|
-
/**
|
|
63
|
-
* Public suipay-dev origins (Railway). `local` is the laptop stack from
|
|
64
|
-
* `pnpm demo:testnet`. Explicit `SUIPAY_GATEWAY_URL` / `SUIPAY_CONSOLE_URL`
|
|
65
|
-
* still win over the preset.
|
|
66
|
-
*/
|
|
67
|
-
declare const MCP_TARGET_PRESETS: Record<McpTarget, {
|
|
68
|
-
consoleUrl: string;
|
|
69
|
-
gatewayUrl: string;
|
|
70
|
-
}>;
|
|
71
|
-
interface McpConfig {
|
|
72
|
-
/** Preset used when console/gateway env is unset. Set by `loadMcpConfig`. */
|
|
73
|
-
target?: McpTarget;
|
|
74
|
-
consoleUrl: string;
|
|
75
|
-
gatewayUrl: string;
|
|
76
|
-
rpcUrl: string;
|
|
77
|
-
network: 'testnet' | 'mainnet' | 'devnet' | 'localnet';
|
|
78
|
-
packageId: string;
|
|
79
|
-
recipient: string;
|
|
80
|
-
coinType: string;
|
|
81
|
-
sponsorUrl: string;
|
|
82
|
-
minFunded: bigint;
|
|
83
|
-
minMaxPerPayment: bigint;
|
|
84
|
-
label: string;
|
|
85
|
-
/**
|
|
86
|
-
* Optional override of the gateway's published `ExclusionDirectory` id.
|
|
87
|
-
* When null, pay reads `GET /v1/delegate/deployment` and turns the resolver
|
|
88
|
-
* on only if that response names one. The id here does not choose the
|
|
89
|
-
* directory a settle uses — the offer's `registryIdentity` does.
|
|
90
|
-
*/
|
|
91
|
-
exclusionDirectoryObjectId: string | null;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* CLI flags: `--local` / `-local`, `--dev` / `-dev`. Unknown args are ignored
|
|
95
|
-
* so an MCP host can pass extra argv without breaking stdio.
|
|
96
|
-
*/
|
|
97
|
-
declare function parseMcpTargetFlag(argv: readonly string[]): McpTarget | undefined;
|
|
98
|
-
declare function resolveMcpTarget(env?: NodeJS.ProcessEnv, argv?: readonly string[]): McpTarget;
|
|
99
|
-
/** Same public origin, or the same laptop loopback port (`localhost` ≡ `127.0.0.1`). */
|
|
100
|
-
declare function sameMcpGateway(a: string, b: string): boolean;
|
|
101
|
-
declare function loadMcpConfig(env?: NodeJS.ProcessEnv, argv?: readonly string[]): McpConfig;
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Agent-held settlement wiring for the `pay` tool.
|
|
105
|
-
*
|
|
106
|
-
* The gateway prepares (it holds no key). Settlement needs the delegate key, so
|
|
107
|
-
* it can only happen in the process that holds one. This module answers a single
|
|
108
|
-
* question for a given grant: *is this process that grant's agent, and is it
|
|
109
|
-
* configured to settle?* Any "no" returns null and `pay` falls back to handing
|
|
110
|
-
* back unsigned bytes — the pre-existing behavior.
|
|
111
|
-
*
|
|
112
|
-
* Two conditions gate it, and the first is the security one:
|
|
113
|
-
*
|
|
114
|
-
* 1. **The persisted key must be the key the grant names.** A hosted gateway
|
|
115
|
-
* running this same tool code either holds no credentials file (null) or
|
|
116
|
-
* holds one for some unrelated key (address mismatch → null). It can only
|
|
117
|
-
* settle by already possessing the grant's delegate seed — which is exactly
|
|
118
|
-
* the custody ADR-0015 removed, not a state a flag protects against.
|
|
119
|
-
* 2. **The settlement dependencies must all be present.** A half-configured
|
|
120
|
-
* settler is worse than none: it would sign and then fail to confirm. Missing
|
|
121
|
-
* anything → null, prepare-only.
|
|
122
|
-
*
|
|
123
|
-
* The key is read, never minted. See `loadLocalSigner`.
|
|
124
|
-
*/
|
|
125
|
-
|
|
126
|
-
/** Everything `pay` needs to settle rather than prepare. */
|
|
127
|
-
interface AgentHeldSettlement {
|
|
128
|
-
signer: DelegatedKeySigner;
|
|
129
|
-
getObjectJson: GetObjectJson;
|
|
130
|
-
payerDeps: DelegatedPayerDeps;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Resolve agent-held settlement for one grant, or null to stay prepare-only.
|
|
134
|
-
* Injectable so `createServer` can be driven without touching disk,
|
|
135
|
-
* chain, or environment.
|
|
136
|
-
*/
|
|
137
|
-
type AgentHeldResolver = (cfg: McpConfig, spendAccountPay: McpSpendAccountPayAuth) => AgentHeldSettlement | null;
|
|
138
|
-
/** Test seam: drop the process ledger so suites do not share reservations. */
|
|
139
|
-
declare function resetAgentHeldProcessLedger(): void;
|
|
140
|
-
declare function resolveAgentHeldSettlement(cfg: McpConfig, spendAccountPay: McpSpendAccountPayAuth, env?: NodeJS.ProcessEnv): AgentHeldSettlement | null;
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Transparent MCP wire proxy.
|
|
144
|
-
*
|
|
145
|
-
* This module is the *only* place in the system that parses MCP methods and
|
|
146
|
-
* JSON-RPC ids. The gateway authenticates and hands over a run manager and a
|
|
147
|
-
* sink; it never sniffs an MCP body a second time. Payment code emits domain
|
|
148
|
-
* facts, never wire facts. That single-owner rule is what stops two subsystems
|
|
149
|
-
* from disagreeing about which tool call a payment belongs to.
|
|
150
|
-
*
|
|
151
|
-
* Transparency is the top invariant, and it is structural rather than
|
|
152
|
-
* best-effort:
|
|
153
|
-
*
|
|
154
|
-
* - With no runtime, this file is a pass-through and does not touch the
|
|
155
|
-
* request or the response at all.
|
|
156
|
-
* - With a runtime, observation reads `Request.clone()` and `Response.clone()`
|
|
157
|
-
* only. The exact `Response` instance the handler produced is what the caller
|
|
158
|
-
* receives, so byte equality is by construction, not by careful copying.
|
|
159
|
-
* - Response observation is started and deliberately not awaited. A trace
|
|
160
|
-
* store that hangs cannot hold an MCP response open.
|
|
161
|
-
* - The request side cannot be fire-and-forget — the proxy must know the run
|
|
162
|
-
* and the JSON-RPC ids before the handler runs — so it is bounded instead:
|
|
163
|
-
* one deadline over envelope parsing plus run selection, and the same byte
|
|
164
|
-
* cap the response observer uses. A hung store or an oversized body costs
|
|
165
|
-
* the trace, never the request.
|
|
166
|
-
* - Every observation path is wrapped: a hostile body, a failing run manager or
|
|
167
|
-
* a throwing sink degrades to "no trace", never to a changed response.
|
|
168
|
-
*
|
|
169
|
-
* Volume control lives here too. One `tool_called` per JSON-RPC id and one
|
|
170
|
-
* terminal `tool_result` / `tool_error` per id — never one row per SSE frame.
|
|
171
|
-
*/
|
|
172
|
-
|
|
173
|
-
/** Everything the proxy needs to attribute wire facts to one owned run. */
|
|
174
|
-
interface McpTraceRuntime {
|
|
175
|
-
buyerAccountId: string;
|
|
176
|
-
connectionId: string;
|
|
177
|
-
runs: TraceRunResolver;
|
|
178
|
-
sink: TraceSink;
|
|
179
|
-
/**
|
|
180
|
-
* HMAC secret for signed cross-request context. Supplied by the composition
|
|
181
|
-
* root so a published SDK never reads a gateway-only environment variable.
|
|
182
|
-
* Absent means internal hops carry no correlation and the gateway simply
|
|
183
|
-
* emits no linked events.
|
|
184
|
-
*/
|
|
185
|
-
secret?: string | null;
|
|
186
|
-
/** Injected clock; tests pin it, production leaves it out. */
|
|
187
|
-
now?: () => number;
|
|
188
|
-
}
|
|
189
|
-
/** The proxy-resolved context handed down to payment code (Task 5 seams). */
|
|
190
|
-
interface McpTraceContext {
|
|
191
|
-
traceId: string;
|
|
192
|
-
requestId: string | null;
|
|
193
|
-
}
|
|
194
|
-
interface McpTraceHooks {
|
|
195
|
-
runtime: McpTraceRuntime;
|
|
196
|
-
context: McpTraceContext;
|
|
197
|
-
sink: TraceSink;
|
|
198
|
-
}
|
|
199
|
-
/** One JSON-RPC message read off the request side. */
|
|
200
|
-
interface McpEnvelopeEntry {
|
|
201
|
-
method: string | null;
|
|
202
|
-
jsonRpcId: string | number | null;
|
|
203
|
-
/** Canonical, header-safe request id. `null` for notifications. */
|
|
204
|
-
requestId: string | null;
|
|
205
|
-
toolName: string | null;
|
|
206
|
-
toolArguments: unknown;
|
|
207
|
-
clientName: string | null;
|
|
208
|
-
clientVersion: string | null;
|
|
209
|
-
protocolVersion: string | null;
|
|
210
|
-
}
|
|
211
|
-
interface McpEnvelope {
|
|
212
|
-
batch: boolean;
|
|
213
|
-
entries: McpEnvelopeEntry[];
|
|
214
|
-
/** First entry's method — what run selection keys on. */
|
|
215
|
-
method: string | null;
|
|
216
|
-
requestId: string | null;
|
|
217
|
-
clientName: string | null;
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Canonical MCP request id.
|
|
221
|
-
*
|
|
222
|
-
* JSON-RPC allows both `7` and `"7"` as distinct ids, and they must stay
|
|
223
|
-
* distinct: correlating a payment to the wrong tool call is worse than not
|
|
224
|
-
* correlating it. Numbers keep their JSON form under `n:`; strings are
|
|
225
|
-
* base64url-encoded under `s:` so an id containing newlines, colons or quotes
|
|
226
|
-
* survives being carried in an HTTP header without escaping games.
|
|
227
|
-
*/
|
|
228
|
-
declare function canonicalMcpRequestId(id: unknown): string | null;
|
|
229
|
-
/**
|
|
230
|
-
* Read the JSON-RPC envelope from a request **clone**.
|
|
231
|
-
*
|
|
232
|
-
* The caller owns cloning; this consumes the body it is given. An unparsable,
|
|
233
|
-
* bodiless or over-cap request yields an empty envelope rather than an error — a
|
|
234
|
-
* malformed request is the transport's problem to answer, not tracing's problem
|
|
235
|
-
* to block.
|
|
236
|
-
*/
|
|
237
|
-
declare function inspectMcpEnvelope(request: Request, maxBytes?: number): Promise<McpEnvelope>;
|
|
238
|
-
interface TraceMcpHttpRequestInput {
|
|
239
|
-
request: Request;
|
|
240
|
-
/**
|
|
241
|
-
* The real MCP handler. Receives the untouched original request, plus the
|
|
242
|
-
* resolved trace context when tracing is live.
|
|
243
|
-
*/
|
|
244
|
-
handle: (request: Request, hooks?: McpTraceHooks) => Promise<Response>;
|
|
245
|
-
runtime?: McpTraceRuntime | null;
|
|
246
|
-
/** Cap on bytes read for observation, request and response. Never unbounded. */
|
|
247
|
-
maxObservedBytes?: number;
|
|
248
|
-
/**
|
|
249
|
-
* Deadline for envelope parsing plus run selection, the only trace work that
|
|
250
|
-
* happens before the handler. Past it the exchange proceeds untraced.
|
|
251
|
-
*/
|
|
252
|
-
runSetupTimeoutMs?: number;
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Wrap one MCP HTTP exchange in observation.
|
|
256
|
-
*
|
|
257
|
-
* The response returned here is the exact object `handle` produced. Nothing on
|
|
258
|
-
* the observation path can change it, delay it, or prevent it.
|
|
259
|
-
*/
|
|
260
|
-
declare function traceMcpHttpRequest(input: TraceMcpHttpRequestInput): Promise<Response>;
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Shared pay-request helpers.
|
|
264
|
-
*
|
|
265
|
-
* The V1 allowance sponsored payer (ADR-0010) is retired; only the
|
|
266
|
-
* rail-neutral request surface the SpendAccount payer depends on survives here:
|
|
267
|
-
* the `PayResult` shape every payer returns. `paidRequestInit` is the SDK helper
|
|
268
|
-
* that builds the one RequestInit replayed byte for byte on both calls.
|
|
269
|
-
*/
|
|
270
|
-
|
|
271
|
-
type PayResult = {
|
|
272
|
-
status: 'ok' | 'failed' | 'ambiguous';
|
|
273
|
-
/**
|
|
274
|
-
* `true` — settlement confirmed. `false` — money did not leave the
|
|
275
|
-
* account. `'unknown'` — execute/finality did not resolve; a retry can
|
|
276
|
-
* pay twice.
|
|
277
|
-
*/
|
|
278
|
-
paid: boolean | 'unknown';
|
|
279
|
-
body?: unknown;
|
|
280
|
-
receipt?: unknown;
|
|
281
|
-
code?: string;
|
|
282
|
-
detail?: string;
|
|
283
|
-
txDigest?: string;
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* SpendAccount PREPARE-only client (non-custodial MCP).
|
|
288
|
-
*
|
|
289
|
-
* The remote MCP `pay` tool runs inside the gateway, which holds NO key that can
|
|
290
|
-
* spend. So this module does not sign or submit: it PREPARES a payment and hands
|
|
291
|
-
* back an unsigned `spend_account::settle_policy` / `settle_any_recipient` transaction plus everything the client
|
|
292
|
-
* needs. The client — which holds the delegate key — sponsors, signs locally,
|
|
293
|
-
* and submits through the same personal-message challenge → local-sign → submit flow the
|
|
294
|
-
* REST/SDK delegate path uses. Only signatures ever reach the gateway; the
|
|
295
|
-
* private key is never placed in an HTTP body, a bearer, or any header.
|
|
296
|
-
*
|
|
297
|
-
* Flow: 402 Offer → request-binding → package/network SSOT →
|
|
298
|
-
* resolveGrantTarget(snapshot, offer.targetHash) (pause/revoke gate) → cap/coin
|
|
299
|
-
* checks → assertLive (fresh authority) → build unsigned kind bytes → return the
|
|
300
|
-
* signing request. There is deliberately no sponsor call, no decrypt, no
|
|
301
|
-
* signature, and no forwarded bearer here.
|
|
302
|
-
*
|
|
303
|
-
* See docs/design/mcp-non-custodial-signing.md and ADR-0013 §3.
|
|
304
|
-
*/
|
|
305
|
-
|
|
306
|
-
type SharedObjectReader = (objectId: string) => Promise<{
|
|
307
|
-
owner?: unknown;
|
|
308
|
-
} | null | undefined>;
|
|
309
|
-
/**
|
|
310
|
-
* Read/prepare-only session for the non-custodial MCP pay tool. It carries the
|
|
311
|
-
* immutable grant snapshot and an optional prepare-time live gate — and no key,
|
|
312
|
-
* by construction. There is no `decryptDelegateSeed` and no `sponsorAuthorization`.
|
|
313
|
-
*/
|
|
314
|
-
interface SpendAccountPrepareSession {
|
|
315
|
-
snapshot: GrantSnapshot;
|
|
316
|
-
/** SpendAccount package id (V2). */
|
|
317
|
-
packageId: string;
|
|
318
|
-
/**
|
|
319
|
-
* Re-assert the grant is still live (not paused/revoked/expired) against fresh
|
|
320
|
-
* canonical state, invoked immediately before a signing request is handed back.
|
|
321
|
-
* Throw to abort. Optional; when absent, only the request-time snapshot gates
|
|
322
|
-
* the prepare (on-chain `spend_account::settle_policy` remains the final backstop for any
|
|
323
|
-
* spend the client later submits).
|
|
324
|
-
*/
|
|
325
|
-
assertLive?: () => Promise<void>;
|
|
326
|
-
}
|
|
327
|
-
interface SpendAccountPayDeps {
|
|
328
|
-
fetchImpl?: typeof fetch;
|
|
329
|
-
/**
|
|
330
|
-
* Build only-transaction-kind bytes for the canonical guarded debit
|
|
331
|
-
* (`spend_account::settle_policy` / `settle_any_recipient`).
|
|
332
|
-
*
|
|
333
|
-
* The guarded-settle fields ({@link GuardedSettleFields}) are required on the
|
|
334
|
-
* fresh lineage: every delegate settle consumes the shared exclusion marker.
|
|
335
|
-
* Dropping them fails closed rather than building an unguarded call that no
|
|
336
|
-
* longer exists on chain.
|
|
337
|
-
*/
|
|
338
|
-
buildPayKind?: (input: {
|
|
339
|
-
delegate: string;
|
|
340
|
-
coinType: string;
|
|
341
|
-
poolObjectId: string;
|
|
342
|
-
grantObjectId: string;
|
|
343
|
-
policyId: number | string;
|
|
344
|
-
targetHash: string;
|
|
345
|
-
amount: string;
|
|
346
|
-
paymentIdHash: Uint8Array;
|
|
347
|
-
termsHash: Uint8Array;
|
|
348
|
-
recipient?: string;
|
|
349
|
-
accessMode?: 'scoped' | 'open';
|
|
350
|
-
} & GuardedSettleFields) => Promise<{
|
|
351
|
-
kindBytes: string;
|
|
352
|
-
}>;
|
|
353
|
-
/**
|
|
354
|
-
* Resolve the per-recipient `RecipientRegistry` bound in the offer's exclusion
|
|
355
|
-
* directory (guarded offers only). Injected seam for tests; production
|
|
356
|
-
* leaves it unset and the prepare wires a live gRPC-backed resolver from the
|
|
357
|
-
* configured `ExclusionDirectory` id when present, else fails closed.
|
|
358
|
-
*/
|
|
359
|
-
resolveExclusionRegistry?: PayOperationDeps['resolveExclusionRegistry'];
|
|
360
|
-
/**
|
|
361
|
-
* Read a shared object's owner so prepare binds the real initial version.
|
|
362
|
-
* Missing owner fails the prepare; version 1 is not a substitute.
|
|
363
|
-
*/
|
|
364
|
-
readSharedObject?: SharedObjectReader;
|
|
365
|
-
/**
|
|
366
|
-
* Live trace for this prepare. Purely observational: emission records what the
|
|
367
|
-
* canonical read decisions already returned — an event is written after a check
|
|
368
|
-
* passes and can never be the thing that lets the next step run.
|
|
369
|
-
*/
|
|
370
|
-
trace?: SpendAccountPayTrace;
|
|
371
|
-
}
|
|
372
|
-
interface SpendAccountPayTrace {
|
|
373
|
-
sink: TraceSink;
|
|
374
|
-
traceId: string;
|
|
375
|
-
requestId: string | null;
|
|
376
|
-
buyerAccountId: string;
|
|
377
|
-
connectionId: string;
|
|
378
|
-
/** HMAC secret for signed cross-request context. Absent disables signing. */
|
|
379
|
-
secret?: string | null;
|
|
380
|
-
/** Injected clock, for tests. */
|
|
381
|
-
now?: () => number;
|
|
382
|
-
}
|
|
383
|
-
/** The unsigned payment the client signs locally and submits. */
|
|
384
|
-
interface SpendAccountSigningRequest {
|
|
385
|
-
/**
|
|
386
|
-
* Unsigned `spend_account::settle_policy` / `settle_any_recipient` transaction-kind bytes (base64), sender set to
|
|
387
|
-
* `delegateAddress`. The client sponsors these for gas, signs with the delegate
|
|
388
|
-
* key, and submits — the gateway never receives the key.
|
|
389
|
-
*/
|
|
390
|
-
unsignedKindBytes: string;
|
|
391
|
-
delegateAddress: string;
|
|
392
|
-
packageId: string;
|
|
393
|
-
poolObjectId: string;
|
|
394
|
-
grantObjectId: string;
|
|
395
|
-
/** On-chain policy id the pay is bound to. */
|
|
396
|
-
policyId: number | string;
|
|
397
|
-
coinType: string;
|
|
398
|
-
targetHash: string;
|
|
399
|
-
amount: string;
|
|
400
|
-
/** Hex (no 0x) of the payment-id hash bound into the transaction. */
|
|
401
|
-
paymentIdHashHex: string;
|
|
402
|
-
/** Hex (no 0x) of the terms hash bound into the transaction. */
|
|
403
|
-
termsHashHex: string;
|
|
404
|
-
challengeId: string;
|
|
405
|
-
/** The exact paid request to replay after the client submits. */
|
|
406
|
-
resource: {
|
|
407
|
-
url: string;
|
|
408
|
-
method: string;
|
|
409
|
-
};
|
|
410
|
-
dialect: Dialect;
|
|
411
|
-
/** Recipient the agent requested (offer.payTo). */
|
|
412
|
-
recipient: string;
|
|
413
|
-
/** Where the client (holding the key) sponsors and submits. */
|
|
414
|
-
submit: {
|
|
415
|
-
sponsorUrl: string;
|
|
416
|
-
executeUrl: string;
|
|
417
|
-
moveCallTarget: string;
|
|
418
|
-
};
|
|
419
|
-
/**
|
|
420
|
-
* ISO-8601 timestamp when this prepared operation expires. After this time the
|
|
421
|
-
* unsigned bytes are no longer valid and the client must re-call pay() for a
|
|
422
|
-
* fresh prepare. Derived from the offer TTL.
|
|
423
|
-
*/
|
|
424
|
-
expiresAt: string;
|
|
425
|
-
/** Restated hard rule for the agent host. */
|
|
426
|
-
note: string;
|
|
427
|
-
}
|
|
428
|
-
interface PreparedPayment {
|
|
429
|
-
status: 'prepared';
|
|
430
|
-
paid: false;
|
|
431
|
-
signingRequest: SpendAccountSigningRequest;
|
|
432
|
-
}
|
|
433
|
-
/** Prepared signing request, or a canonical failure (never a spend). */
|
|
434
|
-
type SpendAccountPrepareResult = PreparedPayment | PayResult;
|
|
435
|
-
/** Default kind builder (no chain client — pure PTB). */
|
|
436
|
-
declare function buildSpendAccountPayKind(input: {
|
|
437
|
-
packageId: string;
|
|
438
|
-
delegate: string;
|
|
439
|
-
coinType: string;
|
|
440
|
-
poolObjectId: string;
|
|
441
|
-
grantObjectId: string;
|
|
442
|
-
policyId: number | string;
|
|
443
|
-
targetHash: string;
|
|
444
|
-
amount: string;
|
|
445
|
-
paymentIdHash: Uint8Array;
|
|
446
|
-
termsHash: Uint8Array;
|
|
447
|
-
poolInitialSharedVersion?: string;
|
|
448
|
-
grantInitialSharedVersion?: string;
|
|
449
|
-
clockInitialSharedVersion?: string;
|
|
450
|
-
} & GuardedSettleFields): Promise<{
|
|
451
|
-
kindBytes: string;
|
|
452
|
-
}>;
|
|
453
|
-
/**
|
|
454
|
-
* Refuse blind signing: a client validating a sponsored transaction must be able
|
|
455
|
-
* to prove the sponsored bytes reconstruct the intended spend_account::settle_policy. Kept
|
|
456
|
-
* here (and exported) so both the client signer and its tests share one check.
|
|
457
|
-
*/
|
|
458
|
-
declare function verifySpendAccountPayReconstructs(bytes: string, expected: {
|
|
459
|
-
kindBytes: string;
|
|
460
|
-
packageId: string;
|
|
461
|
-
delegate: string;
|
|
462
|
-
poolObjectId: string;
|
|
463
|
-
grantObjectId: string;
|
|
464
|
-
amount: string;
|
|
465
|
-
}): void;
|
|
466
|
-
/**
|
|
467
|
-
* Prepare a delegate payment WITHOUT signing. Reads the 402 offer, binds it,
|
|
468
|
-
* gates on the immutable grant snapshot + a fresh authority check, builds the
|
|
469
|
-
* unsigned transaction, and returns a signing request. The client holding the
|
|
470
|
-
* delegate key signs locally and submits. This function never decrypts, signs,
|
|
471
|
-
* sponsors, or submits.
|
|
472
|
-
*
|
|
473
|
-
* Uses `resolvePayment` from the SDK pay-operation module for the
|
|
474
|
-
* shared offer-acquisition + authority-resolution pipeline (steps 1–5 + assertLive
|
|
475
|
-
* + hash derivation + buildPayKind). This module wraps that with MCP-specific
|
|
476
|
-
* concerns: trace events, dialect-mode ceiling check, and signing-request
|
|
477
|
-
* construction.
|
|
478
|
-
*/
|
|
479
|
-
declare function prepareSpendAccountPayment(args: {
|
|
480
|
-
url: string;
|
|
481
|
-
/** The one normalized paid request, replayed byte for byte after signing. */
|
|
482
|
-
request?: PaidHttpRequest;
|
|
483
|
-
session: SpendAccountPrepareSession;
|
|
484
|
-
cfg: McpConfig;
|
|
485
|
-
deps?: SpendAccountPayDeps;
|
|
486
|
-
/** Preferred dialect when the 402 advertises both (default mpp). */
|
|
487
|
-
preferredDialect?: Dialect;
|
|
488
|
-
}): Promise<SpendAccountPrepareResult>;
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* Transport-neutral SuiPay MCP server + tool registry.
|
|
492
|
-
* Used by stdio (index.ts) and Streamable HTTP (http.ts).
|
|
493
|
-
* Remote HTTP passes McpAuthContext so tools enforce OAuth scope + shared-pool pay.
|
|
494
|
-
*/
|
|
495
|
-
|
|
496
|
-
declare const PACKAGE_NAME = "@cmdoss/suipay-mcp";
|
|
497
|
-
declare const TOOLS: readonly [{
|
|
498
|
-
readonly name: "access_context";
|
|
499
|
-
readonly description: "Inspect profiles, policies, service targets, spend caps, usage, and lifecycle state enforced for this authenticated SuiPay session. Call before choosing a paid service.";
|
|
500
|
-
readonly inputSchema: {
|
|
501
|
-
readonly type: "object";
|
|
502
|
-
readonly properties: {};
|
|
503
|
-
};
|
|
504
|
-
}, {
|
|
505
|
-
readonly name: "pay";
|
|
506
|
-
readonly description: string;
|
|
507
|
-
readonly inputSchema: {
|
|
508
|
-
readonly type: "object";
|
|
509
|
-
readonly properties: {
|
|
510
|
-
readonly url: {
|
|
511
|
-
readonly type: "string";
|
|
512
|
-
readonly description: "Full gateway resource URL.";
|
|
513
|
-
};
|
|
514
|
-
readonly method: {
|
|
515
|
-
readonly type: "string";
|
|
516
|
-
readonly enum: readonly ["GET", "POST"];
|
|
517
|
-
readonly description: "HTTP method of the paid request. Defaults to GET.";
|
|
518
|
-
};
|
|
519
|
-
readonly json: {
|
|
520
|
-
readonly type: "object";
|
|
521
|
-
readonly description: "JSON request body for a POST. Sent as application/json and bound to the payment.";
|
|
522
|
-
};
|
|
523
|
-
readonly file: {
|
|
524
|
-
readonly type: "string";
|
|
525
|
-
readonly description: "Absolute path under SUIPAY_MCP_FILE_ROOT (unset disables attach). Stdio POST only; requires fileField. Regular non-empty file whose decoded size fits the paid-body ceiling. Not a URL, FIFO, device, or path under ~/.suipay. Bytes fill json[fileField] as canonical base64.";
|
|
526
|
-
};
|
|
527
|
-
readonly fileField: {
|
|
528
|
-
readonly type: "string";
|
|
529
|
-
readonly description: "JSON key to set from file (e.g. contentBase64). Required with file. Pattern [A-Za-z][A-Za-z0-9_]{0,63}. Must not already be present on json.";
|
|
530
|
-
};
|
|
531
|
-
readonly recipient: {
|
|
532
|
-
readonly type: "string";
|
|
533
|
-
readonly description: "Sui address you expect to be paid. The payment is refused, unsigned, if the prepared transaction pays anyone else.";
|
|
534
|
-
};
|
|
535
|
-
readonly maxAmount: {
|
|
536
|
-
readonly type: "string";
|
|
537
|
-
readonly description: "Atomic ceiling you will spend on this call. The payment is refused, unsigned, if the offer costs more.";
|
|
538
|
-
};
|
|
539
|
-
};
|
|
540
|
-
readonly required: readonly ["url"];
|
|
541
|
-
};
|
|
542
|
-
}, {
|
|
543
|
-
readonly name: "discover";
|
|
544
|
-
readonly description: "Search SuiPay gateway resources. After login, each row includes name, path, url, catalog price, and whether the current session can cover one call at that price (descriptive only — pay still enforces the grant).";
|
|
545
|
-
readonly inputSchema: {
|
|
546
|
-
readonly type: "object";
|
|
547
|
-
readonly properties: {
|
|
548
|
-
readonly query: {
|
|
549
|
-
readonly type: "string";
|
|
550
|
-
readonly description: "Optional service search terms.";
|
|
551
|
-
};
|
|
552
|
-
};
|
|
553
|
-
};
|
|
554
|
-
}, {
|
|
555
|
-
readonly name: "receipts";
|
|
556
|
-
readonly description: "List SuiPay settlement receipts, optionally filtered by challenge id.";
|
|
557
|
-
readonly inputSchema: {
|
|
558
|
-
readonly type: "object";
|
|
559
|
-
readonly properties: {
|
|
560
|
-
readonly challengeId: {
|
|
561
|
-
readonly type: "string";
|
|
562
|
-
readonly description: "Optional payment challenge id.";
|
|
563
|
-
};
|
|
564
|
-
};
|
|
565
|
-
};
|
|
566
|
-
}, {
|
|
567
|
-
readonly name: "suipay_login";
|
|
568
|
-
readonly description: "Mint or reuse the local delegate key (version-2, mode 0600) and return a clickable console URL immediately so the owner can bind a spend-account grant. Does not wait for the wallet. Default target is Railway suipay-dev; pass target=\"local\" (or start the binary with --local) for the laptop stack. Stdio only; hosted /mcp never holds a spendable key.";
|
|
569
|
-
readonly inputSchema: {
|
|
570
|
-
readonly type: "object";
|
|
571
|
-
readonly properties: {
|
|
572
|
-
readonly label: {
|
|
573
|
-
readonly type: "string";
|
|
574
|
-
readonly description: "Label shown in SuiPay console.";
|
|
575
|
-
};
|
|
576
|
-
readonly target: {
|
|
577
|
-
readonly type: "string";
|
|
578
|
-
readonly enum: readonly ["dev", "local"];
|
|
579
|
-
readonly description: "Where to bind the grant. Default is Railway suipay-dev. Pass \"local\" for localhost:3000 / 127.0.0.1:4340.";
|
|
580
|
-
};
|
|
581
|
-
readonly gatewayResourceUrl: {
|
|
582
|
-
readonly type: "string";
|
|
583
|
-
readonly description: "Gateway resource URL whose 402 defines recipient, asset, and package.";
|
|
584
|
-
};
|
|
585
|
-
};
|
|
586
|
-
};
|
|
587
|
-
}, {
|
|
588
|
-
readonly name: "suipay_logout";
|
|
589
|
-
readonly description: "Remove the local delegate-key credentials file. Missing file is success. Force clears a corrupt file without printing the seed.";
|
|
590
|
-
readonly inputSchema: {
|
|
591
|
-
readonly type: "object";
|
|
592
|
-
readonly properties: {
|
|
593
|
-
readonly force: {
|
|
594
|
-
readonly type: "boolean";
|
|
595
|
-
readonly description: "Remove local credentials even if the file is unreadable.";
|
|
596
|
-
};
|
|
597
|
-
};
|
|
598
|
-
};
|
|
599
|
-
}];
|
|
600
|
-
/**
|
|
601
|
-
* Create a Server with the public SuiPay tool surface registered.
|
|
602
|
-
*
|
|
603
|
-
* `trace` is the proxy-resolved run for this HTTP exchange. It is threaded into
|
|
604
|
-
* tool dependencies so payment code can emit *domain* events, and nothing else:
|
|
605
|
-
* this wrapper deliberately emits no tool lifecycle of its own, because the
|
|
606
|
-
* proxy observes the actual JSON-RPC wire and a second source would double-count
|
|
607
|
-
* every call and disagree on ids.
|
|
608
|
-
*/
|
|
609
|
-
interface McpServerOptions {
|
|
610
|
-
/**
|
|
611
|
-
* How `pay` finds an agent-held delegate key for the authenticated grant.
|
|
612
|
-
* Defaults to the persisted local key (`resolveAgentHeldSettlement`), which
|
|
613
|
-
* returns null on any process that does not hold the key the grant names — so
|
|
614
|
-
* the default is prepare-only everywhere except the agent's own machine.
|
|
615
|
-
* Injectable for tests; there is no way to make it hand over a key the grant
|
|
616
|
-
* does not already authorize.
|
|
617
|
-
*/
|
|
618
|
-
resolveAgentHeld?: AgentHeldResolver;
|
|
619
|
-
/** Override the exclusion-registry resolver (tests / offline). */
|
|
620
|
-
resolveExclusionRegistry?: SpendAccountPayDeps['resolveExclusionRegistry'];
|
|
621
|
-
/**
|
|
622
|
-
* Wire that created this server. Hosted HTTP never forwards `file` into `pay`.
|
|
623
|
-
* Stdio is the default so existing tests stay local.
|
|
624
|
-
*/
|
|
625
|
-
transport?: 'stdio' | 'http';
|
|
626
|
-
}
|
|
627
|
-
declare function createServer(cfg: McpConfig, auth?: McpAuthContext, trace?: McpTraceHooks, options?: McpServerOptions): Server;
|
|
628
|
-
|
|
629
|
-
/**
|
|
630
|
-
* Streamable HTTP transport for SuiPay MCP.
|
|
631
|
-
* Stateless per-request (sessionIdGenerator undefined) — same public tools as stdio.
|
|
632
|
-
* Auth context is required for remote gateway /mcp (bearer resolved upstream).
|
|
633
|
-
*
|
|
634
|
-
* The optional trace runtime turns on live observation. It is a pure wrapper:
|
|
635
|
-
* `traceMcpHttpRequest` reads clones and returns the transport's own Response,
|
|
636
|
-
* so passing a runtime cannot change what an MCP client sees.
|
|
637
|
-
*/
|
|
638
|
-
|
|
639
|
-
/**
|
|
640
|
-
* Handle one MCP Streamable HTTP request (initialize, tools/list, tools/call, …).
|
|
641
|
-
* Creates a fresh transport+server pair per request (stateless mode).
|
|
642
|
-
*/
|
|
643
|
-
declare function handleSuipayMcpHttpRequest(req: Request, cfg: McpConfig, auth?: McpAuthContext, trace?: McpTraceRuntime | null, options?: McpServerOptions): Promise<Response>;
|
|
644
|
-
|
|
645
|
-
export { type AgentHeldResolver as A, traceMcpHttpRequest as B, verifySpendAccountPayReconstructs as C, type McpConfig as M, PACKAGE_NAME as P, type SpendAccountSigningRequest as S, TOOLS as T, type McpAuthContext as a, type McpTraceHooks as b, type SpendAccountPayDeps as c, type AgentHeldSettlement as d, MCP_TARGET_PRESETS as e, type McpEnvelope as f, type McpEnvelopeEntry as g, type McpServerOptions as h, type McpTarget as i, type McpTraceContext as j, type McpTraceRuntime as k, type PreparedPayment as l, type SpendAccountPrepareResult as m, type SpendAccountPrepareSession as n, buildSpendAccountPayKind as o, canonicalMcpRequestId as p, createServer as q, handleSuipayMcpHttpRequest as r, inspectMcpEnvelope as s, loadMcpConfig as t, parseMcpTargetFlag as u, prepareSpendAccountPayment as v, resetAgentHeldProcessLedger as w, resolveAgentHeldSettlement as x, resolveMcpTarget as y, sameMcpGateway as z };
|