@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.d.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import '@cmdoss/suipay-core/policy/grant-target';
|
|
3
|
-
import '@cmdoss/suipay-sdk/mcp/access-context';
|
|
4
|
-
import '@cmdoss/suipay-sdk/buyer/settlement-dto';
|
|
1
|
+
export { H as handleSuipayMcpHttpRequest } from './http-BCFfQFIg.js';
|
|
5
2
|
import '@modelcontextprotocol/sdk/server/index.js';
|
|
6
|
-
import '@
|
|
7
|
-
import '@cmdoss/suipay-sdk/delegated-signer/payer';
|
|
8
|
-
import '@cmdoss/suipay-core/trace/types';
|
|
9
|
-
import '@cmdoss/suipay-sdk/protocol/paid-http-request';
|
|
10
|
-
import '@cmdoss/suipay-sdk/protocol/types';
|
|
11
|
-
import '@cmdoss/suipay-sdk/pay-operation';
|
|
3
|
+
import '@mysten/sui/keypairs/ed25519';
|
package/dist/http.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import { DelegatedKeySigner, DelegatedPayerSession, DelegatedPayerConfig, DelegatedPayerDeps, SpendIntent, DelegatedPayResult } from '@cmdoss/suipay-sdk/delegated-signer/payer';
|
|
6
|
-
import { PaidHttpRequest } from '@cmdoss/suipay-sdk/protocol/paid-http-request';
|
|
7
|
-
import { createPayer } from '@cmdoss/suipay-sdk/agent-sdk/delegate-agent';
|
|
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, i as DelegatedPayerLog, j as PreparedSettlementTerms, X as X402PayProgress, O as Offer, M as McpConfig, k as McpAuthContext, l as McpTraceHooks, m as SpendAccountPayDeps, n as createReader } from './http-BCFfQFIg.js';
|
|
2
|
+
export { A as AgentHeldResolver, o as AgentHeldSettlement, p as MCP_TARGET_PRESETS, q as McpEnvelope, r as McpEnvelopeEntry, s as McpServerOptions, t as McpTarget, u as McpTraceContext, v as McpTraceRuntime, w as PACKAGE_NAME, x as PreparedPayment, y as SpendAccountPrepareResult, z as SpendAccountPrepareSession, T as TOOLS, B as buildSpendAccountPayKind, E as canonicalMcpRequestId, F as createServer, H as handleSuipayMcpHttpRequest, I as inspectMcpEnvelope, J as loadMcpConfig, K as parseMcpTargetFlag, L as prepareSpendAccountPayment, Q as resetAgentHeldProcessLedger, R as resolveAgentHeldSettlement, U as resolveGrantTarget, V as resolveMcpTarget, W as sameMcpGateway, Y as traceMcpHttpRequest, Z as verifySpendAccountPayReconstructs } from './http-BCFfQFIg.js';
|
|
3
|
+
import { SuiGrpcClient } from '@mysten/sui/grpc';
|
|
4
|
+
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
|
|
8
5
|
import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
-
export { resolveGrantTarget } from '@cmdoss/suipay-core/policy/grant-target';
|
|
10
|
-
import '@cmdoss/suipay-sdk/mcp/access-context';
|
|
11
|
-
import '@cmdoss/suipay-sdk/buyer/settlement-dto';
|
|
12
6
|
import '@modelcontextprotocol/sdk/server/index.js';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
|
|
8
|
+
/** Holds a key and signs transaction bytes. Never leaves the payer. */
|
|
9
|
+
interface Wallet {
|
|
10
|
+
readonly address: string;
|
|
11
|
+
signTransaction(txBytes: string): Promise<string>;
|
|
12
|
+
}
|
|
16
13
|
|
|
17
14
|
interface SuiPayCredentials {
|
|
18
15
|
/** 64-hex Ed25519 seed. NEVER logged. */
|
|
@@ -113,6 +110,401 @@ declare function settlePreparedMcpPayment(args: {
|
|
|
113
110
|
intent?: SpendIntent;
|
|
114
111
|
}): Promise<DelegatedPayResult>;
|
|
115
112
|
|
|
113
|
+
/**
|
|
114
|
+
* The executable settlement a 402 carries so the agent needs no chain access.
|
|
115
|
+
*
|
|
116
|
+
* ADR-0016 §2 says "the server prepares, the agent verifies, the agent signs".
|
|
117
|
+
* ADR-0015 shipped only the first half: the prepare path emitted a placeholder
|
|
118
|
+
* `poolInitialSharedVersion: '1'`, so its bytes described a payment instead of
|
|
119
|
+
* executing one, and an agent still had to make two full-node reads to build
|
|
120
|
+
* something submittable. These bytes are executable — the gateway resolves the
|
|
121
|
+
* real shared-object initial versions before it builds them.
|
|
122
|
+
*
|
|
123
|
+
* This travels ALONGSIDE the offer on the 402 body, never inside it, exactly as
|
|
124
|
+
* `requestSchema` does (`src/gateway/app.ts`). The offer digest is a
|
|
125
|
+
* consensus-relevant wire shape whose fields go on chain via `terms_hash`;
|
|
126
|
+
* adding to it is a protocol change. A prepared settlement authorizes nothing
|
|
127
|
+
* on its own — it is unsigned bytes, worthless until the delegate's key signs
|
|
128
|
+
* them — so it has no business inside a signed digest.
|
|
129
|
+
*
|
|
130
|
+
* Every field here exists to let the agent REBUILD the same transaction kind
|
|
131
|
+
* offline and compare it byte for byte. Nothing here is trusted: see
|
|
132
|
+
* `verifyPreparedPayment` in `src/agent-sdk/verify-prepared-settlement.ts`
|
|
133
|
+
* for what an agent must check before it signs, and why what it can check from
|
|
134
|
+
* the 402 alone is sufficient.
|
|
135
|
+
*/
|
|
136
|
+
|
|
137
|
+
/** Current prepared-settlement wire version. Bumped on any shape change. */
|
|
138
|
+
declare const PREPARED_SETTLEMENT_VERSION: 1;
|
|
139
|
+
/**
|
|
140
|
+
* An unsigned, executable settlement transaction plus everything needed to
|
|
141
|
+
* reconstruct it offline.
|
|
142
|
+
*
|
|
143
|
+
* `transactionBytes` is the full sponsored `TransactionData` — gas is already
|
|
144
|
+
* attached by the gateway's sponsor, so this is the ONE thing the agent signs.
|
|
145
|
+
* `transactionKindBytes` is the pre-sponsor programmable-transaction kind: the
|
|
146
|
+
* Move call and nothing else, which is what the agent rebuilds and compares.
|
|
147
|
+
*/
|
|
148
|
+
interface PreparedSettlement {
|
|
149
|
+
version: typeof PREPARED_SETTLEMENT_VERSION;
|
|
150
|
+
/** Base64 sponsored `TransactionData`. The agent signs exactly these bytes. */
|
|
151
|
+
transactionBytes: string;
|
|
152
|
+
/** Base64 pre-sponsor transaction kind (the Move call baseline). */
|
|
153
|
+
transactionKindBytes: string;
|
|
154
|
+
/**
|
|
155
|
+
* The address that must sign. Move asserts `ctx.sender() == grant.delegate`,
|
|
156
|
+
* so an agent that checks this equals its own address has the chain enforce
|
|
157
|
+
* that the named grant is one it may draw on — no `getObject` required.
|
|
158
|
+
*/
|
|
159
|
+
sender: string;
|
|
160
|
+
/** Deployed `suipay` package the call targets (normalized). */
|
|
161
|
+
packageId: string;
|
|
162
|
+
/** Fully-qualified `package::module::function` the call invokes. */
|
|
163
|
+
moveTarget: string;
|
|
164
|
+
/**
|
|
165
|
+
* Delegation scope: `open` pays an arbitrary recipient, `scoped` an
|
|
166
|
+
* allowlist. This is the SCOPE discriminator (which pay function) — distinct
|
|
167
|
+
* from the x402 eligibility (`SpendAccountGrantKind`) and the budget cap. The
|
|
168
|
+
* `'open'`/`'scoped'` value strings are a frozen wire shape (parsed by
|
|
169
|
+
* `asPreparedSettlement`); the type only names the concept.
|
|
170
|
+
*/
|
|
171
|
+
accessMode: DelegationScope;
|
|
172
|
+
/** Shared `Account` the payment debits. */
|
|
173
|
+
poolObjectId: string;
|
|
174
|
+
/** Shared `Grant` naming the delegate. */
|
|
175
|
+
grantObjectId: string;
|
|
176
|
+
/** Real initial shared versions — the gap ADR-0015's placeholder `'1'` left. */
|
|
177
|
+
poolInitialSharedVersion: string;
|
|
178
|
+
grantInitialSharedVersion: string;
|
|
179
|
+
clockInitialSharedVersion: string;
|
|
180
|
+
/** On-chain policy id; `'0'` for an open grant. Decimal string (u64). */
|
|
181
|
+
policyId: string;
|
|
182
|
+
/** Coin type the call spends. Must equal the offer's asset. */
|
|
183
|
+
coinType: string;
|
|
184
|
+
/** Atomic amount the call moves. Must equal the offer's amount. */
|
|
185
|
+
amount: string;
|
|
186
|
+
/** Recipient the call pays. Must equal the offer's payTo. */
|
|
187
|
+
recipient: string;
|
|
188
|
+
/**
|
|
189
|
+
* Fresh lineage (ADR-0043 Option B): settlement is MANDATORY-guarded, so the
|
|
190
|
+
* prepared call always consumes the offer's single-use exclusion marker before
|
|
191
|
+
* funds move. These four let the agent rebuild the SAME guarded kind offline
|
|
192
|
+
* and compare it byte for byte. The `ExclusionDirectory` the offer committed
|
|
193
|
+
* to (from its `registryIdentity`), read-only.
|
|
194
|
+
*/
|
|
195
|
+
exclusionDirectoryId: string;
|
|
196
|
+
/** The per-recipient `RecipientRegistry` the marker is claimed in (mutable). */
|
|
197
|
+
recipientRegistryId: string;
|
|
198
|
+
/** Real initial shared version of the exclusion directory. */
|
|
199
|
+
exclusionDirectoryInitialSharedVersion: string;
|
|
200
|
+
/** Real initial shared version of the recipient registry. */
|
|
201
|
+
recipientRegistryInitialSharedVersion: string;
|
|
202
|
+
/** Signed expiry (epoch-ms, decimal string) bound into the guarded settle. */
|
|
203
|
+
expiresAtMs: string;
|
|
204
|
+
/** Absolute URL to POST `{challengeId, signature, body}` to. */
|
|
205
|
+
payUrl: string;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Connection-manifest → SDK session bridge.
|
|
210
|
+
*
|
|
211
|
+
* The dashboard hands an agent a non-secret "Connection manifest" after it
|
|
212
|
+
* authorizes a delegate key. Historically that manifest could NOT be passed to
|
|
213
|
+
* the SDK: it named the signer `agentAddress` (not `delegateAddress`), the asset
|
|
214
|
+
* by symbol (`"USDC"`, not the full `coinType`), and its policies by off-chain
|
|
215
|
+
* UUID — while the payer needs the full coin type and each policy's NUMERIC
|
|
216
|
+
* on-chain id + target hashes (`GrantPolicyBinding`). This module closes that
|
|
217
|
+
* mismatch two ways:
|
|
218
|
+
*
|
|
219
|
+
* 1. {@link AgentConnectionManifest} — the SDK-consumable shape a corrected
|
|
220
|
+
* console emits directly (delegate address, full coin type, numeric policy
|
|
221
|
+
* ids + target hashes). {@link manifestToSession} turns it, plus an agent
|
|
222
|
+
* key, into a ready `DelegatedPayerSession` — no protocol reverse-engineering
|
|
223
|
+
* and no on-chain lookups.
|
|
224
|
+
*
|
|
225
|
+
* 2. {@link dashboardManifestToAgentManifest} — a bridge from the legacy
|
|
226
|
+
* console shape, resolving asset→coinType and (for scoped grants) UUID→
|
|
227
|
+
* numeric policy binding through injected resolvers.
|
|
228
|
+
*
|
|
229
|
+
* Every failure is a typed, caller-safe error (never a thrown internal): a
|
|
230
|
+
* malformed or legacy manifest that cannot be resolved fails loudly, not
|
|
231
|
+
* silently.
|
|
232
|
+
*/
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* A manifest or session that cannot be paid from. Nothing was signed, so the
|
|
236
|
+
* money state is always `not_charged`. Branch on `code`; `reason` names the
|
|
237
|
+
* internal check for logs.
|
|
238
|
+
*/
|
|
239
|
+
interface ManifestError {
|
|
240
|
+
code: CodeFor<'sdk'>;
|
|
241
|
+
detail: string;
|
|
242
|
+
paymentState: 'not_charged';
|
|
243
|
+
retryable: boolean;
|
|
244
|
+
nextAction: NextAction;
|
|
245
|
+
}
|
|
246
|
+
type ManifestResult<T> = {
|
|
247
|
+
ok: true;
|
|
248
|
+
value: T;
|
|
249
|
+
} | {
|
|
250
|
+
ok: false;
|
|
251
|
+
error: ManifestError;
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* A manifest policy binding. `onChainPolicyId` is always a validated u64 DECIMAL
|
|
255
|
+
* STRING — never a JS number — so `BigInt(onChainPolicyId)` on the money path
|
|
256
|
+
* (`spend_account::settle_policy`) is exact. A `u64` policy id can exceed `2^53`, past which
|
|
257
|
+
* a JS number loses precision and would bind the WRONG on-chain policy; carrying
|
|
258
|
+
* the string preserves every id exactly.
|
|
259
|
+
*/
|
|
260
|
+
type AgentPolicyBinding = Omit<GrantPolicyBinding, 'onChainPolicyId'> & {
|
|
261
|
+
onChainPolicyId: string;
|
|
262
|
+
};
|
|
263
|
+
/** One grant's SDK-consumable binding: everything the payer needs to settle. */
|
|
264
|
+
interface AgentSessionBinding {
|
|
265
|
+
/** Display asset symbol (informational; `coinType` is authoritative). */
|
|
266
|
+
asset: string;
|
|
267
|
+
/** Full coin struct type, e.g. `0x..::usdc::USDC`. Required for pay. */
|
|
268
|
+
coinType: string;
|
|
269
|
+
poolObjectId: string;
|
|
270
|
+
grantObjectId: string;
|
|
271
|
+
/** `open` = capped, no allowlist; `scoped` = policy-bound. */
|
|
272
|
+
accessMode: 'scoped' | 'open';
|
|
273
|
+
/** Grant-level session cap (atomic); null/undefined = unlimited. */
|
|
274
|
+
sessionCap?: string | null;
|
|
275
|
+
/** Grant-level per-payment ceiling (atomic); null/undefined = unlimited. */
|
|
276
|
+
maxPerPayment?: string | null;
|
|
277
|
+
/** On-chain policy ids (u64 strings) + target hashes. Empty for open grants. */
|
|
278
|
+
policies: AgentPolicyBinding[];
|
|
279
|
+
}
|
|
280
|
+
/** Which grant to drive when a manifest carries several. */
|
|
281
|
+
interface SessionSelector {
|
|
282
|
+
grantObjectId?: string;
|
|
283
|
+
asset?: string;
|
|
284
|
+
coinType?: string;
|
|
285
|
+
}
|
|
286
|
+
/** @deprecated Renamed to {@link AgentSessionBinding}. */
|
|
287
|
+
type AgentGrantBinding = AgentSessionBinding;
|
|
288
|
+
/** @deprecated Renamed to {@link SessionSelector}. */
|
|
289
|
+
type GrantSelector = SessionSelector;
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Key + gateway URL → a ready delegated-pay session.
|
|
293
|
+
*
|
|
294
|
+
* This module is the point of `docs/decisions/ADR-0016-delegate-key-sole-agent-input.md`
|
|
295
|
+
* §1. Before it, an agent needed a connection manifest — network, package id,
|
|
296
|
+
* pool id, grant id, caps, expiry — copied out of the console at authorize time
|
|
297
|
+
* and liable to go stale the moment the owner tightened a cap or the operator
|
|
298
|
+
* rotated a package. After it, the agent is handed one secret and one URL, and
|
|
299
|
+
* everything else is resolved from the chain's own projection at startup.
|
|
300
|
+
*
|
|
301
|
+
* The order is forced by the protocol. A bootstrap signature binds `network` and
|
|
302
|
+
* `packageId`, which the gateway reconstructs from its own config, so the agent
|
|
303
|
+
* must know them before it can sign anything that will verify. It learns them
|
|
304
|
+
* from the gateway's public deployment constants — the same two values every 402
|
|
305
|
+
* offer already carries in the clear — and only then signs.
|
|
306
|
+
*
|
|
307
|
+
* Nothing here spends. It resolves authority and hands back a session; the
|
|
308
|
+
* payment is still built and signed later, on this machine, by
|
|
309
|
+
* `payDelegatedSpendAccount` with a key that never leaves the process.
|
|
310
|
+
*/
|
|
311
|
+
|
|
312
|
+
/** The gateway's public deployment constants. */
|
|
313
|
+
interface GatewayDeployment {
|
|
314
|
+
network: string;
|
|
315
|
+
packageId: string;
|
|
316
|
+
/**
|
|
317
|
+
* The canonical `ExclusionDirectory` object id, present only while the gateway
|
|
318
|
+
* mints guarded offers. Absent means every offer is unguarded and no registry
|
|
319
|
+
* ever needs resolving.
|
|
320
|
+
*
|
|
321
|
+
* It enables the resolver; it is never resolved against. A guarded settle
|
|
322
|
+
* resolves the directory the OFFER committed to under the HMAC, so a gateway
|
|
323
|
+
* cannot point a payer at a directory of its choosing by answering here.
|
|
324
|
+
*/
|
|
325
|
+
exclusionDirectoryObjectId?: string;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* A delegate key and a gateway URL, and the agent can pay.
|
|
330
|
+
*
|
|
331
|
+
* `resolvePayerSession` already turned a key into a pay *session*
|
|
332
|
+
* (ADR-0016 §1). What it did not do was assemble the rest of what
|
|
333
|
+
* `payDelegatedSpendAccount` demands, so a real agent still had to supply four
|
|
334
|
+
* things its key does not carry: the gateway's own HMAC secret, a fullnode
|
|
335
|
+
* connection to confirm settlement, a second fullnode read for live
|
|
336
|
+
* shared-object versions, and a personal-message signer for the sponsor's
|
|
337
|
+
* personal-message challenge, separate from the transaction signer. This module is
|
|
338
|
+
* where those four go.
|
|
339
|
+
*
|
|
340
|
+
* Where each one went, and why that is safe:
|
|
341
|
+
*
|
|
342
|
+
* - **The gateway's HMAC secret is gone, not relocated.** It authenticated the
|
|
343
|
+
* offer's issuer to the agent — but the issuer is the same gateway the agent
|
|
344
|
+
* is paying, reached over TLS at an origin the payer pins, so a gateway that
|
|
345
|
+
* wanted to overcharge never needed to forge its own offer. What replaces it
|
|
346
|
+
* is a bound the gateway cannot see: the agent's own {@link SpendIntent}.
|
|
347
|
+
* - **Both fullnode reads stay with the AGENT**, against a public Sui fullnode
|
|
348
|
+
* derived from the network the gateway reports. They are not proxied through
|
|
349
|
+
* the gateway, because their whole value is that they are independent of it:
|
|
350
|
+
* an agent that asked the gateway whether the gateway's transaction settled
|
|
351
|
+
* would be verifying nothing. The gateway supplies no input here it could
|
|
352
|
+
* not already supply; what it never gains is the ability to answer for the
|
|
353
|
+
* chain.
|
|
354
|
+
* - **The personal-message challenge signer is the same key**, taken from the one
|
|
355
|
+
* keypair the agent already holds. It was never a second credential, only a
|
|
356
|
+
* second callback the caller had to wire.
|
|
357
|
+
*
|
|
358
|
+
* The key never leaves this process, and the gateway never gains the ability to
|
|
359
|
+
* spend: every payment is still built here, checked here against the chain's
|
|
360
|
+
* own view of the grant, and signed here.
|
|
361
|
+
*/
|
|
362
|
+
|
|
363
|
+
interface PayerOptions {
|
|
364
|
+
/** Gateway origin, e.g. `https://gateway.suipay.dev`. */
|
|
365
|
+
gatewayUrl: string;
|
|
366
|
+
/**
|
|
367
|
+
* The delegate key. Used for the bootstrap signature, the sponsor
|
|
368
|
+
* personal-message challenge, and the payment signature — one key, three uses, none
|
|
369
|
+
* of which leave this process.
|
|
370
|
+
*/
|
|
371
|
+
keypair: Ed25519Keypair;
|
|
372
|
+
/** Which grant to drive when the delegate holds several. */
|
|
373
|
+
select?: GrantSelector;
|
|
374
|
+
/** Injectable fetch (tests / custom transports). Defaults to global `fetch`. */
|
|
375
|
+
fetchImpl?: typeof fetch;
|
|
376
|
+
/**
|
|
377
|
+
* Sui fullnode for the agent's own on-chain reads. Defaults to the public
|
|
378
|
+
* fullnode for the network the gateway reports. An operator running a private
|
|
379
|
+
* network sets it; an agent does not need to.
|
|
380
|
+
*/
|
|
381
|
+
fullnodeUrl?: string;
|
|
382
|
+
/**
|
|
383
|
+
* A chain transport to read through, for a caller that already has one (or a
|
|
384
|
+
* test). The seam is the CLIENT, not the individual reads: an option to
|
|
385
|
+
* supply `getSettledTx` directly would let a caller point settlement
|
|
386
|
+
* confirmation at something that is not the chain.
|
|
387
|
+
*/
|
|
388
|
+
client?: SuiGrpcClient;
|
|
389
|
+
/**
|
|
390
|
+
* Skip deployment discovery by supplying the constants directly. Same escape
|
|
391
|
+
* hatch `resolvePayerSession` offers.
|
|
392
|
+
*/
|
|
393
|
+
deployment?: GatewayDeployment;
|
|
394
|
+
/**
|
|
395
|
+
* Durable payment-attempt ledger. Defaults to an in-process one, which is
|
|
396
|
+
* exactly-once for the lifetime of THIS process. An agent that must survive a
|
|
397
|
+
* restart mid-payment supplies a durable one.
|
|
398
|
+
*/
|
|
399
|
+
paymentLedger?: PaymentAttemptLedger;
|
|
400
|
+
/**
|
|
401
|
+
* The gateway's HMAC secret, when the caller legitimately holds one (an
|
|
402
|
+
* operator running its own gateway). An external agent leaves it unset and
|
|
403
|
+
* relies on its spend intent; see {@link SpendIntent}.
|
|
404
|
+
*/
|
|
405
|
+
offerSecret?: string;
|
|
406
|
+
/**
|
|
407
|
+
* The canonical `ExclusionDirectory` object id, so this payer can build a
|
|
408
|
+
* GUARDED delegate settle for a guarded offer out of the box.
|
|
409
|
+
*
|
|
410
|
+
* Optional: `createPayer` otherwise takes it from `GET /v1/delegate/deployment`,
|
|
411
|
+
* which discovery already calls, so an agent holding only a key and a gateway
|
|
412
|
+
* URL needs no out-of-band value to pay a guarded offer. Pass it to pin the
|
|
413
|
+
* behaviour against a gateway that does not publish one.
|
|
414
|
+
*
|
|
415
|
+
* When present from either source, `createPayer` constructs the
|
|
416
|
+
* `resolveExclusionRegistry` dependency bound to this payer's own gRPC reader
|
|
417
|
+
* (the same client that reads the grant and confirms settlement), which
|
|
418
|
+
* resolves the per-recipient `RecipientRegistry` from the directory's
|
|
419
|
+
* dynamic-field binding at settle-build time. When absent from BOTH, a guarded
|
|
420
|
+
* offer FAILS CLOSED (BUILD_FAILED) — the payer never builds an unguarded
|
|
421
|
+
* settle, which would reopen the cross-rail double-settle hole and be rejected
|
|
422
|
+
* by the gateway's self-settled verifier anyway. An unguarded offer never
|
|
423
|
+
* resolves a registry, so it is unaffected either way.
|
|
424
|
+
*/
|
|
425
|
+
exclusionDirectoryObjectId?: string;
|
|
426
|
+
/** Server-side log port for internal failure detail. Never reaches a result. */
|
|
427
|
+
log?: DelegatedPayerLog;
|
|
428
|
+
}
|
|
429
|
+
/** Result of `payer.pay`. Same shape as the internal settlement result. */
|
|
430
|
+
type PayResult = DelegatedPayResult;
|
|
431
|
+
|
|
432
|
+
/** One paid request. `intent` is what this agent says it is buying. */
|
|
433
|
+
interface PayInput {
|
|
434
|
+
method?: string;
|
|
435
|
+
body?: string | Uint8Array;
|
|
436
|
+
contentType?: string;
|
|
437
|
+
/**
|
|
438
|
+
* Required. Without it nothing bounds what the offer may charge, and the
|
|
439
|
+
* payer refuses — the whole point of the key-only path is that the ceiling
|
|
440
|
+
* comes from the agent, not from a secret it should not hold.
|
|
441
|
+
*/
|
|
442
|
+
intent: SpendIntent;
|
|
443
|
+
/**
|
|
444
|
+
* Terms the caller has ALREADY verified, which the offer this payer reads
|
|
445
|
+
* must price exactly or nothing is signed.
|
|
446
|
+
*
|
|
447
|
+
* Distinct from {@link SpendIntent}, and not a replacement for it: `intent`
|
|
448
|
+
* is a ceiling — it refuses an offer that charges MORE — while this is an
|
|
449
|
+
* equality. A caller that showed a person a specific price, or checked a
|
|
450
|
+
* server-prepared kind, is not agreeing to "that or less from anyone in the
|
|
451
|
+
* catalogue"; it is agreeing to one exact payment. The payer fetches its own
|
|
452
|
+
* offer immediately before signing, so without this that final offer is only
|
|
453
|
+
* ceiling-bounded and could legitimately differ from the one the caller
|
|
454
|
+
* verified.
|
|
455
|
+
*
|
|
456
|
+
* Optional, so every existing caller keeps ceiling semantics unchanged.
|
|
457
|
+
*/
|
|
458
|
+
preparedTerms?: PreparedSettlementTerms;
|
|
459
|
+
/**
|
|
460
|
+
* Which dialect to pay in. Default `'mpp'`, unchanged: the sponsor executes
|
|
461
|
+
* the pay and the payer presents a finalized proof. `'x402'` signs the pay
|
|
462
|
+
* with the offer's pinned sponsor gas and presents it as `PAYMENT-SIGNATURE`;
|
|
463
|
+
* the gateway co-signs and submits (ADR-0045). Before reserving anything,
|
|
464
|
+
* x402 refuses an open-recipient grant and an offer without the pins.
|
|
465
|
+
*/
|
|
466
|
+
dialect?: 'mpp' | 'x402';
|
|
467
|
+
/**
|
|
468
|
+
* x402 only: each step as it happens (built, signed, then presented and
|
|
469
|
+
* answered per presentation). Called synchronously; a throw is logged and
|
|
470
|
+
* never affects the payment.
|
|
471
|
+
*/
|
|
472
|
+
onX402Progress?: (event: X402PayProgress) => void;
|
|
473
|
+
}
|
|
474
|
+
interface Payer {
|
|
475
|
+
/** The delegate's own address, derived from the key it holds. */
|
|
476
|
+
address: string;
|
|
477
|
+
/** Deployment constants the gateway published and the bootstrap bound. */
|
|
478
|
+
deployment: GatewayDeployment;
|
|
479
|
+
/** The grant this agent will pay from, as resolved and then verified on chain. */
|
|
480
|
+
grant: AgentGrantBinding;
|
|
481
|
+
/** The assembled session; exposed so a caller can inspect what it will sign with. */
|
|
482
|
+
session: DelegatedPayerSession;
|
|
483
|
+
/** Pay for one resource and return its response. */
|
|
484
|
+
pay(url: string, input: PayInput): Promise<PayResult>;
|
|
485
|
+
/**
|
|
486
|
+
* Verify a 402 prepared settlement against the grant this agent resolved.
|
|
487
|
+
* Always pins {@link Payer.grant} — a settlement drawn on another
|
|
488
|
+
* buyer's grant is refused. Callers with no resolved grant still use
|
|
489
|
+
* {@link verifyPreparedPayment} unpinned.
|
|
490
|
+
*/
|
|
491
|
+
verifySettlement(prepared: unknown, offer: Offer): Promise<PreparedSettlement>;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Create a payer from its key and a gateway URL.
|
|
495
|
+
*
|
|
496
|
+
* The call sequence, all of it derivable from those two inputs:
|
|
497
|
+
* 1. `GET /v1/delegate/deployment` — network, package id, and the exclusion
|
|
498
|
+
* directory id when guarded minting is on. All in the clear.
|
|
499
|
+
* 2. `GET /v1/delegate/grants`, signed by the key — the grants naming it.
|
|
500
|
+
* 3. an unsigned `getObject` on the resolved grant, against a public
|
|
501
|
+
* fullnode — the agent's own check that the grant is its own.
|
|
502
|
+
*
|
|
503
|
+
* Typed failure, never a throw: an agent that cannot verify its own authority
|
|
504
|
+
* must refuse to sign, not proceed on the gateway's word.
|
|
505
|
+
*/
|
|
506
|
+
declare function createPayer(options: PayerOptions): Promise<ManifestResult<Payer>>;
|
|
507
|
+
|
|
116
508
|
interface StdioLoginOptions {
|
|
117
509
|
consoleUrl: string;
|
|
118
510
|
gatewayUrl: string;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadBootProfile,
|
|
3
3
|
main
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-W4RIN664.js";
|
|
5
5
|
import {
|
|
6
6
|
MCP_TARGET_PRESETS,
|
|
7
7
|
PACKAGE_NAME,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
settlePreparedMcpPayment,
|
|
27
27
|
traceMcpHttpRequest,
|
|
28
28
|
verifySpendAccountPayReconstructs
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-FKDC22O6.js";
|
|
30
30
|
export {
|
|
31
31
|
MCP_TARGET_PRESETS,
|
|
32
32
|
PACKAGE_NAME,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmdoss/suipay-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-dev.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "SuiPay MCP — pay MPP-gated APIs from a spend-account grant with an agent-held delegate key.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"tsup": "^8.0.0",
|
|
38
38
|
"typescript": "^6.0.3",
|
|
39
39
|
"vitest": "^4.1.10",
|
|
40
|
-
"@cmdoss/suipay-
|
|
41
|
-
"@cmdoss/suipay-
|
|
40
|
+
"@cmdoss/suipay-sdk": "0.1.0",
|
|
41
|
+
"@cmdoss/suipay-core": "0.1.0"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "tsup",
|