@mysten-incubation/suipay-mcp 0.0.0-stage → 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/dist/http.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { I as handleSuipayMcpHttpRequest } from './http-15g02zyM.js';
2
+ import '@modelcontextprotocol/sdk/server/index.js';
3
+ import '@mysten/sui/keypairs/ed25519';
4
+ import 'node:crypto';
package/dist/http.js ADDED
@@ -0,0 +1,6 @@
1
+ import {
2
+ handleSuipayMcpHttpRequest
3
+ } from "./chunk-CXM7PELK.js";
4
+ export {
5
+ handleSuipayMcpHttpRequest
6
+ };
@@ -0,0 +1,604 @@
1
+ import { S as SpendAccountSigningRequest, P as PaidHttpRequest, D as DelegatedKeySigner, G as GetObjectJson, a as DelegatedPayerSession, b as DelegatedPayerConfig, c as DelegatedPayerDeps, d as SpendIntent, e as DelegatedPayResult, f as DelegationScope, C as CodeFor, N as NextAction, g as GrantPolicyBinding, h as PaymentAttemptLedger, O as OfferPublicKeySource, i as DelegatedPayerLog, j as PreparedSettlementTerms, X as X402PayProgress, k as Offer, M as McpConfig, l as McpAuthContext, m as McpTraceHooks, n as SpendAccountPayDeps, o as createReader } from './http-15g02zyM.js';
2
+ export { A as AgentHeldResolver, p as AgentHeldSettlement, q as MCP_TARGET_PRESETS, r as McpEnvelope, s as McpEnvelopeEntry, t as McpServerOptions, u as McpTarget, v as McpTraceContext, w as McpTraceRuntime, x as PACKAGE_NAME, y as PreparedPayment, z as SpendAccountPrepareResult, B as SpendAccountPrepareSession, T as TOOLS, E as buildSpendAccountPayKind, F as canonicalMcpRequestId, H as createServer, I as handleSuipayMcpHttpRequest, J as inspectMcpEnvelope, K as loadMcpConfig, L as parseMcpTargetFlag, Q as prepareSpendAccountPayment, R as resetAgentHeldProcessLedger, U as resolveAgentHeldSettlement, V as resolveGrantTarget, W as resolveMcpTarget, Y as sameMcpGateway, Z as traceMcpHttpRequest, _ as verifySpendAccountPayReconstructs } from './http-15g02zyM.js';
3
+ import { SuiGrpcClient } from '@mysten/sui/grpc';
4
+ import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
5
+ import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
6
+ import '@modelcontextprotocol/sdk/server/index.js';
7
+ import 'node:crypto';
8
+
9
+ /** Holds a key and signs transaction bytes. Never leaves the payer. */
10
+ interface Wallet {
11
+ readonly address: string;
12
+ signTransaction(txBytes: string): Promise<string>;
13
+ }
14
+
15
+ interface SuiPayCredentials {
16
+ /** 64-hex Ed25519 seed. NEVER logged. */
17
+ delegatePrivateKey: string;
18
+ delegatePublicKeyHex: string;
19
+ delegateAddress: string;
20
+ ownerAddress: string;
21
+ allowanceId: string;
22
+ packageId: string;
23
+ coinType: string;
24
+ /** Allowance recipient = the resource's payTo. */
25
+ recipient: string;
26
+ gatewayUrl: string;
27
+ network: string;
28
+ maxPerPayment: string;
29
+ label?: string;
30
+ createdAt: string;
31
+ version: 1;
32
+ }
33
+ /** Public-only view. Never includes the seed. */
34
+ interface LocalSigningKeyIdentity {
35
+ delegateAddress: string;
36
+ publicKeyHex: string;
37
+ }
38
+ type SignerSource = 'secret-key' | 'credentials' | 'mnemonic';
39
+ interface PaymentProfile {
40
+ creds: SuiPayCredentials;
41
+ wallet: Wallet;
42
+ source: SignerSource;
43
+ }
44
+ /**
45
+ * Load a historical V1 allowance payment profile, if present.
46
+ * ADR-0010: not for new settlement. Callers that pay must refuse this profile
47
+ * and point operators at delegate OAuth / delegated-signer flows.
48
+ */
49
+ declare function loadPaymentProfile(): PaymentProfile | null;
50
+ declare function ensureLocalSigningKey(opts?: {
51
+ label?: string;
52
+ }): Promise<LocalSigningKeyIdentity>;
53
+ /**
54
+ * The persisted agent-held delegate signer, or null when this process holds no
55
+ * key. Reads only — it never mints.
56
+ *
57
+ * `ensureLocalSigningKey` is the provisioning entry point and mints on first
58
+ * authorization, which is right there and wrong here: `pay` runs on hosts that
59
+ * are not the agent (the gateway runs the same tool code), and minting on a read
60
+ * path would write key material onto a machine that must hold none, then quietly
61
+ * fail to match any grant. Absent key → no settlement, by construction.
62
+ */
63
+ declare function loadLocalSigner(): {
64
+ address: string;
65
+ signTransaction: (txBytes: string) => Promise<string>;
66
+ signPersonalMessage: (message: Uint8Array) => Promise<string>;
67
+ } | null;
68
+
69
+ /**
70
+ * Client-side completion of an MCP prepared payment.
71
+ *
72
+ * Verifies the server-prepared kind (ADR-0016 §3) then settles through
73
+ * `payDelegatedSpendAccount` — the same path as direct signer mode. This module
74
+ * does not implement a second submitter.
75
+ *
76
+ * Two hops read a 402, and only one of them was verified. The prepare hop's kind
77
+ * is checked here; the payer then reads its own offer and builds the bytes it
78
+ * signs from that. So the verified terms are carried down as `preparedTerms` and
79
+ * re-asserted against the payer's offer before it signs. Without that carry, the
80
+ * two hops can price different recipients and nothing would notice.
81
+ */
82
+
83
+ declare function settlePreparedMcpPayment(args: {
84
+ signingRequest: SpendAccountSigningRequest;
85
+ /**
86
+ * The same paid request that minted the prepare hop. Reconstructing from
87
+ * url+method alone drops a POST body and the settlement hop then prices
88
+ * (or 400s) a different request than the one the tool was called with.
89
+ */
90
+ request: PaidHttpRequest;
91
+ /**
92
+ * What this payment is supposed to move, sourced from the caller's intent —
93
+ * never re-read from the object being verified. Comparing a prepared kind
94
+ * against fields copied out of the same prepare response proves only that the
95
+ * response agrees with itself.
96
+ */
97
+ expected: {
98
+ amount: string;
99
+ recipient: string;
100
+ delegateAddress: string;
101
+ /**
102
+ * From the prepare hop's offer. Never from `submit.moveCallTarget`:
103
+ * that target is the kind this function is checking.
104
+ */
105
+ refundable?: boolean;
106
+ refundConfigId?: string;
107
+ chainId?: number;
108
+ decideWindowMs?: number;
109
+ refundWindowMs?: number;
110
+ paymentSalt?: string;
111
+ };
112
+ signer: DelegatedKeySigner;
113
+ getObjectJson: GetObjectJson;
114
+ session: DelegatedPayerSession;
115
+ cfg: DelegatedPayerConfig;
116
+ deps: DelegatedPayerDeps;
117
+ /**
118
+ * Agent-declared spend bound (optional additional ceiling, ADR-0073 D1).
119
+ */
120
+ intent?: SpendIntent;
121
+ }): Promise<DelegatedPayResult>;
122
+
123
+ /**
124
+ * The executable settlement a 402 carries so the agent needs no chain access.
125
+ *
126
+ * ADR-0016 §2 says "the server prepares, the agent verifies, the agent signs".
127
+ * ADR-0015 shipped only the first half: the prepare path emitted a placeholder
128
+ * `poolInitialSharedVersion: '1'`, so its bytes described a payment instead of
129
+ * executing one, and an agent still had to make two full-node reads to build
130
+ * something submittable. These bytes are executable — the gateway resolves the
131
+ * real shared-object initial versions before it builds them.
132
+ *
133
+ * This travels ALONGSIDE the offer on the 402 body, never inside it, exactly as
134
+ * `requestSchema` does (`src/gateway/app.ts`). The offer digest is a
135
+ * consensus-relevant wire shape whose fields go on chain via `terms_hash`;
136
+ * adding to it is a protocol change. A prepared settlement authorizes nothing
137
+ * on its own — it is unsigned bytes, worthless until the delegate's key signs
138
+ * them — so it has no business inside a signed digest.
139
+ *
140
+ * Every field here exists to let the agent REBUILD the same transaction kind
141
+ * offline and compare it byte for byte. Nothing here is trusted: see
142
+ * `verifyPreparedPayment` in `src/agent-sdk/verify-prepared-settlement.ts`
143
+ * for what an agent must check before it signs, and why what it can check from
144
+ * the 402 alone is sufficient.
145
+ */
146
+
147
+ /** Current prepared-settlement wire version. Bumped on any shape change. */
148
+ declare const PREPARED_SETTLEMENT_VERSION: 1;
149
+ /**
150
+ * An unsigned, executable settlement transaction plus everything needed to
151
+ * reconstruct it offline.
152
+ *
153
+ * `transactionBytes` is the full sponsored `TransactionData` — gas is already
154
+ * attached by the gateway's sponsor, so this is the ONE thing the agent signs.
155
+ * `transactionKindBytes` is the pre-sponsor programmable-transaction kind: the
156
+ * Move call and nothing else, which is what the agent rebuilds and compares.
157
+ */
158
+ interface PreparedSettlement {
159
+ version: typeof PREPARED_SETTLEMENT_VERSION;
160
+ /** Base64 sponsored `TransactionData`. The agent signs exactly these bytes. */
161
+ transactionBytes: string;
162
+ /** Base64 pre-sponsor transaction kind (the Move call baseline). */
163
+ transactionKindBytes: string;
164
+ /**
165
+ * The address that must sign. Move asserts `ctx.sender() == grant.delegate`,
166
+ * so an agent that checks this equals its own address has the chain enforce
167
+ * that the named grant is one it may draw on — no `getObject` required.
168
+ */
169
+ sender: string;
170
+ /** Deployed `suipay` package the call targets (normalized). */
171
+ packageId: string;
172
+ /** Fully-qualified `package::module::function` the call invokes. */
173
+ moveTarget: string;
174
+ /**
175
+ * Delegation scope: `open` pays an arbitrary recipient, `scoped` an
176
+ * allowlist. This is the SCOPE discriminator (which pay function) — distinct
177
+ * from the x402 eligibility (`SpendAccountGrantKind`) and the budget cap. The
178
+ * `'open'`/`'scoped'` value strings are a frozen wire shape (parsed by
179
+ * `asPreparedSettlement`); the type only names the concept.
180
+ */
181
+ accessMode: DelegationScope;
182
+ /** Shared `Account` the payment debits. */
183
+ poolObjectId: string;
184
+ /** Shared `Grant` naming the delegate. */
185
+ grantObjectId: string;
186
+ /** Real initial shared versions — the gap ADR-0015's placeholder `'1'` left. */
187
+ poolInitialSharedVersion: string;
188
+ grantInitialSharedVersion: string;
189
+ clockInitialSharedVersion: string;
190
+ /** On-chain policy id; `'0'` for an open grant. Decimal string (u64). */
191
+ policyId: string;
192
+ /** Coin type the call spends. Must equal the offer's asset. */
193
+ coinType: string;
194
+ /** Atomic amount the call moves. Must equal the offer's amount. */
195
+ amount: string;
196
+ /** Recipient the call pays. Must equal the offer's payTo. */
197
+ recipient: string;
198
+ /**
199
+ * Fresh lineage (ADR-0043 Option B): settlement is MANDATORY-guarded, so the
200
+ * prepared call always consumes the offer's single-use exclusion marker before
201
+ * funds move. These four let the agent rebuild the SAME guarded kind offline
202
+ * and compare it byte for byte. The `ExclusionDirectory` the offer committed
203
+ * to (from its `registryIdentity`), read-only.
204
+ */
205
+ exclusionDirectoryId: string;
206
+ /** The per-recipient `RecipientRegistry` the marker is claimed in (mutable). */
207
+ recipientRegistryId: string;
208
+ /** Real initial shared version of the exclusion directory. */
209
+ exclusionDirectoryInitialSharedVersion: string;
210
+ /** Real initial shared version of the recipient registry. */
211
+ recipientRegistryInitialSharedVersion: string;
212
+ /** Signed expiry (epoch-ms, decimal string) bound into the guarded settle. */
213
+ expiresAtMs: string;
214
+ /**
215
+ * Initial shared version of the RefundConfig, only when the kind opens a
216
+ * vault. The offer names the object; this version is what the rebuild must
217
+ * use so the kind bytes match. Absent on an immediate payment.
218
+ */
219
+ refundConfigInitialSharedVersion?: string;
220
+ /** Absolute URL to POST `{challengeId, signature, body}` to. */
221
+ payUrl: string;
222
+ }
223
+
224
+ /**
225
+ * Connection-manifest → SDK session bridge.
226
+ *
227
+ * The dashboard hands an agent a non-secret "Connection manifest" after it
228
+ * authorizes a delegate key. Historically that manifest could NOT be passed to
229
+ * the SDK: it named the signer `agentAddress` (not `delegateAddress`), the asset
230
+ * by symbol (`"USDC"`, not the full `coinType`), and its policies by off-chain
231
+ * UUID — while the payer needs the full coin type and each policy's NUMERIC
232
+ * on-chain id + target hashes (`GrantPolicyBinding`). This module closes that
233
+ * mismatch two ways:
234
+ *
235
+ * 1. {@link AgentConnectionManifest} — the SDK-consumable shape a corrected
236
+ * console emits directly (delegate address, full coin type, numeric policy
237
+ * ids + target hashes). {@link manifestToSession} turns it, plus an agent
238
+ * key, into a ready `DelegatedPayerSession` — no protocol reverse-engineering
239
+ * and no on-chain lookups.
240
+ *
241
+ * 2. {@link dashboardManifestToAgentManifest} — a bridge from the legacy
242
+ * console shape, resolving asset→coinType and (for scoped grants) UUID→
243
+ * numeric policy binding through injected resolvers.
244
+ *
245
+ * Every failure is a typed, caller-safe error (never a thrown internal): a
246
+ * malformed or legacy manifest that cannot be resolved fails loudly, not
247
+ * silently.
248
+ */
249
+
250
+ /**
251
+ * A manifest or session that cannot be paid from. Nothing was signed, so the
252
+ * money state is always `not_charged`. Branch on `code`; `reason` names the
253
+ * internal check for logs.
254
+ */
255
+ interface ManifestError {
256
+ code: CodeFor<'sdk'>;
257
+ detail: string;
258
+ paymentState: 'not_charged';
259
+ retryable: boolean;
260
+ nextAction: NextAction;
261
+ }
262
+ type ManifestResult<T> = {
263
+ ok: true;
264
+ value: T;
265
+ } | {
266
+ ok: false;
267
+ error: ManifestError;
268
+ };
269
+ /**
270
+ * A manifest policy binding. `onChainPolicyId` is always a validated u64 DECIMAL
271
+ * STRING — never a JS number — so `BigInt(onChainPolicyId)` on the money path
272
+ * (`spend_account::settle_policy`) is exact. A `u64` policy id can exceed `2^53`, past which
273
+ * a JS number loses precision and would bind the WRONG on-chain policy; carrying
274
+ * the string preserves every id exactly.
275
+ */
276
+ type AgentPolicyBinding = Omit<GrantPolicyBinding, 'onChainPolicyId'> & {
277
+ onChainPolicyId: string;
278
+ };
279
+ /** One grant's SDK-consumable binding: everything the payer needs to settle. */
280
+ interface AgentSessionBinding {
281
+ /** Display asset symbol (informational; `coinType` is authoritative). */
282
+ asset: string;
283
+ /** Full coin struct type, e.g. `0x..::usdc::USDC`. Required for pay. */
284
+ coinType: string;
285
+ poolObjectId: string;
286
+ grantObjectId: string;
287
+ /** `open` = capped, no allowlist; `scoped` = policy-bound. */
288
+ accessMode: 'scoped' | 'open';
289
+ /** Grant-level session cap (atomic); null/undefined = unlimited. */
290
+ sessionCap?: string | null;
291
+ /** Grant-level per-payment ceiling (atomic); null/undefined = unlimited. */
292
+ maxPerPayment?: string | null;
293
+ /** On-chain policy ids (u64 strings) + target hashes. Empty for open grants. */
294
+ policies: AgentPolicyBinding[];
295
+ }
296
+ /** Which grant to drive when a manifest carries several. */
297
+ interface SessionSelector {
298
+ grantObjectId?: string;
299
+ asset?: string;
300
+ coinType?: string;
301
+ }
302
+ /** @deprecated Renamed to {@link AgentSessionBinding}. */
303
+ type AgentGrantBinding = AgentSessionBinding;
304
+ /** @deprecated Renamed to {@link SessionSelector}. */
305
+ type GrantSelector = SessionSelector;
306
+
307
+ /**
308
+ * Key + gateway URL → a ready delegated-pay session.
309
+ *
310
+ * This module is the point of `docs/decisions/ADR-0016-delegate-key-sole-agent-input.md`
311
+ * §1. Before it, an agent needed a connection manifest — network, package id,
312
+ * pool id, grant id, caps, expiry — copied out of the console at authorize time
313
+ * and liable to go stale the moment the owner tightened a cap or the operator
314
+ * rotated a package. After it, the agent is handed one secret and one URL, and
315
+ * everything else is resolved from the chain's own projection at startup.
316
+ *
317
+ * The order is forced by the protocol. A bootstrap signature binds `network` and
318
+ * `packageId`, which the gateway reconstructs from its own config, so the agent
319
+ * must know them before it can sign anything that will verify. It learns them
320
+ * from the gateway's public deployment constants — the same two values every 402
321
+ * offer already carries in the clear — and only then signs.
322
+ *
323
+ * Nothing here spends. It resolves authority and hands back a session; the
324
+ * payment is still built and signed later, on this machine, by
325
+ * `payDelegatedSpendAccount` with a key that never leaves the process.
326
+ */
327
+
328
+ /** The gateway's public deployment constants. */
329
+ interface GatewayDeployment {
330
+ network: string;
331
+ packageId: string;
332
+ /**
333
+ * The canonical `ExclusionDirectory` object id, present only while the gateway
334
+ * mints guarded offers. Absent means every offer is unguarded and no registry
335
+ * ever needs resolving.
336
+ *
337
+ * It enables the resolver; it is never resolved against. A guarded settle
338
+ * resolves the directory the OFFER committed to under the HMAC, so a gateway
339
+ * cannot point a payer at a directory of its choosing by answering here.
340
+ */
341
+ exclusionDirectoryObjectId?: string;
342
+ }
343
+
344
+ /**
345
+ * A delegate key and a gateway URL, and the agent can pay.
346
+ *
347
+ * `resolvePayerSession` already turned a key into a pay *session*
348
+ * (ADR-0016 §1). What it did not do was assemble the rest of what
349
+ * `payDelegatedSpendAccount` demands, so a real agent still had to supply four
350
+ * things its key does not carry: the gateway's own HMAC secret, a fullnode
351
+ * connection to confirm settlement, a second fullnode read for live
352
+ * shared-object versions, and a personal-message signer for the sponsor's
353
+ * personal-message challenge, separate from the transaction signer. This module is
354
+ * where those four go.
355
+ *
356
+ * Where each one went, and why that is safe:
357
+ *
358
+ * - **The gateway's HMAC secret is gone, not relocated.** It authenticated the
359
+ * offer's issuer to the agent — but the issuer is the same gateway the agent
360
+ * is paying, reached over TLS at an origin the payer pins, so a gateway that
361
+ * wanted to overcharge never needed to forge its own offer. What replaces it
362
+ * is a bound the gateway cannot see: the agent's own {@link SpendIntent}.
363
+ * - **Both fullnode reads stay with the AGENT**, against a public Sui fullnode
364
+ * derived from the network the gateway reports. They are not proxied through
365
+ * the gateway, because their whole value is that they are independent of it:
366
+ * an agent that asked the gateway whether the gateway's transaction settled
367
+ * would be verifying nothing. The gateway supplies no input here it could
368
+ * not already supply; what it never gains is the ability to answer for the
369
+ * chain.
370
+ * - **The personal-message challenge signer is the same key**, taken from the one
371
+ * keypair the agent already holds. It was never a second credential, only a
372
+ * second callback the caller had to wire.
373
+ *
374
+ * The key never leaves this process, and the gateway never gains the ability to
375
+ * spend: every payment is still built here, checked here against the chain's
376
+ * own view of the grant, and signed here.
377
+ */
378
+
379
+ interface PayerOptions {
380
+ /** Gateway origin, e.g. `https://gateway.suipay.dev`. */
381
+ gatewayUrl: string;
382
+ /**
383
+ * The delegate key. Used for the bootstrap signature, the sponsor
384
+ * personal-message challenge, and the payment signature — one key, three uses, none
385
+ * of which leave this process.
386
+ */
387
+ keypair: Ed25519Keypair;
388
+ /** Which grant to drive when the delegate holds several. */
389
+ select?: GrantSelector;
390
+ /** Injectable fetch (tests / custom transports). Defaults to global `fetch`. */
391
+ fetchImpl?: typeof fetch;
392
+ /**
393
+ * Sui fullnode for the agent's own on-chain reads. Defaults to the public
394
+ * fullnode for the network the gateway reports. An operator running a private
395
+ * network sets it; an agent does not need to.
396
+ */
397
+ fullnodeUrl?: string;
398
+ /**
399
+ * A chain transport to read through, for a caller that already has one (or a
400
+ * test). The seam is the CLIENT, not the individual reads: an option to
401
+ * supply `getSettledTx` directly would let a caller point settlement
402
+ * confirmation at something that is not the chain.
403
+ */
404
+ client?: SuiGrpcClient;
405
+ /**
406
+ * Skip deployment discovery by supplying the constants directly. Same escape
407
+ * hatch `resolvePayerSession` offers.
408
+ */
409
+ deployment?: GatewayDeployment;
410
+ /**
411
+ * Durable payment-attempt ledger. Defaults to an in-process one, which is
412
+ * exactly-once for the lifetime of THIS process. An agent that must survive a
413
+ * restart mid-payment supplies a durable one.
414
+ */
415
+ paymentLedger?: PaymentAttemptLedger;
416
+ /**
417
+ * Gateway offer-signing public key material or resolver (ADR-0073 D1, D3).
418
+ * Used to verify the offer's asymmetric signature before signing.
419
+ */
420
+ offerVerificationKeys?: OfferPublicKeySource;
421
+ /**
422
+ * The canonical `ExclusionDirectory` object id, so this payer can build a
423
+ * GUARDED delegate settle for a guarded offer out of the box.
424
+ *
425
+ * Optional: `createPayer` otherwise takes it from `GET /v1/delegate/deployment`,
426
+ * which discovery already calls, so an agent holding only a key and a gateway
427
+ * URL needs no out-of-band value to pay a guarded offer. Pass it to pin the
428
+ * behaviour against a gateway that does not publish one.
429
+ *
430
+ * When present from either source, `createPayer` constructs the
431
+ * `resolveExclusionRegistry` dependency bound to this payer's own gRPC reader
432
+ * (the same client that reads the grant and confirms settlement), which
433
+ * resolves the per-recipient `RecipientRegistry` from the directory's
434
+ * dynamic-field binding at settle-build time. When absent from BOTH, a guarded
435
+ * offer FAILS CLOSED (BUILD_FAILED) — the payer never builds an unguarded
436
+ * settle, which would reopen the cross-rail double-settle hole and be rejected
437
+ * by the gateway's self-settled verifier anyway. An unguarded offer never
438
+ * resolves a registry, so it is unaffected either way.
439
+ */
440
+ exclusionDirectoryObjectId?: string;
441
+ /** Server-side log port for internal failure detail. Never reaches a result. */
442
+ log?: DelegatedPayerLog;
443
+ }
444
+ /** Result of `payer.pay`. Same shape as the internal settlement result. */
445
+ type PayResult = DelegatedPayResult;
446
+
447
+ /** One paid request. `intent` is what this agent says it is buying. */
448
+ interface PayInput {
449
+ method?: string;
450
+ body?: string | Uint8Array;
451
+ contentType?: string;
452
+ /**
453
+ * Required. Without it nothing bounds what the offer may charge, and the
454
+ * payer refuses — the whole point of the key-only path is that the ceiling
455
+ * comes from the agent, not from a secret it should not hold.
456
+ */
457
+ intent: SpendIntent;
458
+ /**
459
+ * Terms the caller has ALREADY verified, which the offer this payer reads
460
+ * must price exactly or nothing is signed.
461
+ *
462
+ * Distinct from {@link SpendIntent}, and not a replacement for it: `intent`
463
+ * is a ceiling — it refuses an offer that charges MORE — while this is an
464
+ * equality. A caller that showed a person a specific price, or checked a
465
+ * server-prepared kind, is not agreeing to "that or less from anyone in the
466
+ * catalogue"; it is agreeing to one exact payment. The payer fetches its own
467
+ * offer immediately before signing, so without this that final offer is only
468
+ * ceiling-bounded and could legitimately differ from the one the caller
469
+ * verified.
470
+ *
471
+ * Optional, so every existing caller keeps ceiling semantics unchanged.
472
+ */
473
+ preparedTerms?: PreparedSettlementTerms;
474
+ /**
475
+ * Which dialect to pay in. Default `'mpp'`, unchanged: the sponsor executes
476
+ * the pay and the payer presents a finalized proof. `'x402'` signs the pay
477
+ * with the offer's pinned sponsor gas and presents it as `PAYMENT-SIGNATURE`;
478
+ * the gateway co-signs and submits (ADR-0045). Before reserving anything,
479
+ * x402 refuses an open-recipient grant and an offer without the pins.
480
+ */
481
+ dialect?: 'mpp' | 'x402';
482
+ /**
483
+ * x402 only: each step as it happens (built, signed, then presented and
484
+ * answered per presentation). Called synchronously; a throw is logged and
485
+ * never affects the payment.
486
+ */
487
+ onX402Progress?: (event: X402PayProgress) => void;
488
+ }
489
+ interface Payer {
490
+ /** The delegate's own address, derived from the key it holds. */
491
+ address: string;
492
+ /** Deployment constants the gateway published and the bootstrap bound. */
493
+ deployment: GatewayDeployment;
494
+ /** The grant this agent will pay from, as resolved and then verified on chain. */
495
+ grant: AgentGrantBinding;
496
+ /** The assembled session; exposed so a caller can inspect what it will sign with. */
497
+ session: DelegatedPayerSession;
498
+ /** Pay for one resource and return its response. */
499
+ pay(url: string, input: PayInput): Promise<PayResult>;
500
+ /**
501
+ * Verify a 402 prepared settlement against the grant this agent resolved.
502
+ * Always pins {@link Payer.grant} — a settlement drawn on another
503
+ * buyer's grant is refused. Callers with no resolved grant still use
504
+ * {@link verifyPreparedPayment} unpinned.
505
+ */
506
+ verifySettlement(prepared: unknown, offer: Offer): Promise<PreparedSettlement>;
507
+ }
508
+ /**
509
+ * Create a payer from its key and a gateway URL.
510
+ *
511
+ * The call sequence, all of it derivable from those two inputs:
512
+ * 1. `GET /v1/delegate/deployment` — network, package id, and the exclusion
513
+ * directory id when guarded minting is on. All in the clear.
514
+ * 2. `GET /v1/delegate/grants`, signed by the key — the grants naming it.
515
+ * 3. an unsigned `getObject` on the resolved grant, against a public
516
+ * fullnode — the agent's own check that the grant is its own.
517
+ *
518
+ * Typed failure, never a throw: an agent that cannot verify its own authority
519
+ * must refuse to sign, not proceed on the gateway's word.
520
+ */
521
+ declare function createPayer(options: PayerOptions): Promise<ManifestResult<Payer>>;
522
+
523
+ interface StdioLoginOptions {
524
+ consoleUrl: string;
525
+ gatewayUrl: string;
526
+ identity: {
527
+ delegateAddress: string;
528
+ publicKeyHex: string;
529
+ };
530
+ label?: string;
531
+ timeoutMs?: number;
532
+ openBrowser?: boolean;
533
+ onUrl?: (connectUrl: string) => void;
534
+ }
535
+ interface StartedStdioLogin {
536
+ connectUrl: string;
537
+ port: number;
538
+ connectState: string;
539
+ done: Promise<void>;
540
+ close: () => void;
541
+ }
542
+ /**
543
+ * Bind the loopback listener and return the console URL immediately.
544
+ * The wallet callback is awaited on `done`, not on the MCP tool call.
545
+ */
546
+ declare function startStdioLogin(opts: StdioLoginOptions): Promise<StartedStdioLogin>;
547
+
548
+ type ToolResult = CallToolResult;
549
+
550
+ interface ToolDeps {
551
+ fetchImpl?: typeof fetch;
552
+ profileLoader?: () => PaymentProfile | null;
553
+ /** Remote HTTP auth (grant + scope + optional shared-pool pay session). */
554
+ auth?: McpAuthContext;
555
+ /** Wire transport. Hosted HTTP never reads a buyer path. */
556
+ transport?: 'stdio' | 'http';
557
+ /**
558
+ * Proxy-resolved live trace for this MCP request. Observation only: it never
559
+ * changes which rail runs, what is paid, or whether a payment is allowed.
560
+ */
561
+ trace?: McpTraceHooks;
562
+ /**
563
+ * Agent-held delegate key. Present only in the process that stores the
564
+ * key — never on the gateway. When set after a server-side prepare, `pay`
565
+ * verifies the prepared kind and settles through `payDelegatedSpendAccount`.
566
+ */
567
+ agentHeld?: {
568
+ signer: DelegatedKeySigner;
569
+ getObjectJson: GetObjectJson;
570
+ payerDeps: DelegatedPayerDeps;
571
+ };
572
+ /** Override the prepare-time kind builder (tests / offline). */
573
+ buildPayKind?: SpendAccountPayDeps['buildPayKind'];
574
+ /** Override the exclusion-registry resolver (tests / offline). */
575
+ resolveExclusionRegistry?: SpendAccountPayDeps['resolveExclusionRegistry'];
576
+ /**
577
+ * Stdio login surfaces the console URL (MCP progress notification). The URL
578
+ * carries the delegate address only — never the seed.
579
+ */
580
+ onUrl?: (url: string) => void;
581
+ createPayer?: typeof createPayer;
582
+ createReader?: typeof createReader;
583
+ startStdioLogin?: typeof startStdioLogin;
584
+ }
585
+ declare function pay(args: {
586
+ url: string;
587
+ method?: unknown;
588
+ json?: unknown;
589
+ file?: unknown;
590
+ fileField?: unknown;
591
+ recipient?: unknown;
592
+ maxAmount?: unknown;
593
+ }, cfg: McpConfig, deps?: ToolDeps): Promise<ToolResult>;
594
+ declare function receipts(args: {
595
+ challengeId?: string;
596
+ }, cfg: McpConfig, deps?: ToolDeps): Promise<ToolResult>;
597
+
598
+ declare function loadBootProfile(load?: typeof loadPaymentProfile): {
599
+ profile: ReturnType<typeof loadPaymentProfile>;
600
+ unreadable: boolean;
601
+ };
602
+ declare function main(): Promise<void>;
603
+
604
+ export { McpAuthContext, McpConfig, McpTraceHooks, SpendAccountSigningRequest, ensureLocalSigningKey, loadBootProfile, loadLocalSigner, main, pay, receipts, settlePreparedMcpPayment };
package/dist/index.js ADDED
@@ -0,0 +1,56 @@
1
+ import {
2
+ loadBootProfile,
3
+ main
4
+ } from "./chunk-47YNZDCC.js";
5
+ import {
6
+ MCP_TARGET_PRESETS,
7
+ PACKAGE_NAME,
8
+ TOOLS,
9
+ buildSpendAccountPayKind,
10
+ canonicalMcpRequestId,
11
+ createServer,
12
+ ensureLocalSigningKey,
13
+ handleSuipayMcpHttpRequest,
14
+ inspectMcpEnvelope,
15
+ loadLocalSigner,
16
+ loadMcpConfig,
17
+ parseMcpTargetFlag,
18
+ pay,
19
+ prepareSpendAccountPayment,
20
+ receipts,
21
+ resetAgentHeldProcessLedger,
22
+ resolveAgentHeldSettlement,
23
+ resolveGrantTarget,
24
+ resolveMcpTarget,
25
+ sameMcpGateway,
26
+ settlePreparedMcpPayment,
27
+ traceMcpHttpRequest,
28
+ verifySpendAccountPayReconstructs
29
+ } from "./chunk-CXM7PELK.js";
30
+ export {
31
+ MCP_TARGET_PRESETS,
32
+ PACKAGE_NAME,
33
+ TOOLS,
34
+ buildSpendAccountPayKind,
35
+ canonicalMcpRequestId,
36
+ createServer,
37
+ ensureLocalSigningKey,
38
+ handleSuipayMcpHttpRequest,
39
+ inspectMcpEnvelope,
40
+ loadBootProfile,
41
+ loadLocalSigner,
42
+ loadMcpConfig,
43
+ main,
44
+ parseMcpTargetFlag,
45
+ pay,
46
+ prepareSpendAccountPayment,
47
+ receipts,
48
+ resetAgentHeldProcessLedger,
49
+ resolveAgentHeldSettlement,
50
+ resolveGrantTarget,
51
+ resolveMcpTarget,
52
+ sameMcpGateway,
53
+ settlePreparedMcpPayment,
54
+ traceMcpHttpRequest,
55
+ verifySpendAccountPayReconstructs
56
+ };