@cmdoss/suipay-mcp 1.0.1

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.
@@ -0,0 +1,283 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { M as McpConfig, a as McpAuthContext, b as McpTraceHooks, G as GrantSnapshot, T as TraceSink, D as Dialect } from './http-B5iGH5mf.js';
3
+ export { c as McpEnvelope, d as McpEnvelopeEntry, e as McpTraceContext, f as McpTraceRuntime, g as canonicalMcpRequestId, h as handleSuipayMcpHttpRequest, i as inspectMcpEnvelope, l as loadMcpConfig, r as resolveGrantTarget, t as traceMcpHttpRequest } from './http-B5iGH5mf.js';
4
+
5
+ /** Holds a key and signs transaction bytes. Never leaves the payer. */
6
+ interface Wallet {
7
+ readonly address: string;
8
+ signTransaction(txBytes: string): Promise<string>;
9
+ }
10
+
11
+ type PaidHttpMethod = 'GET' | 'POST';
12
+ interface PaidHttpRequest {
13
+ url: string;
14
+ method: PaidHttpMethod;
15
+ /** Exact wire bytes. Empty for GET. */
16
+ body: Uint8Array;
17
+ /** Normalized media type, or null when no body is sent. */
18
+ contentType: string | null;
19
+ /** `hashRequestBody(body)` — the single canonical body hash. */
20
+ bodyHash: string;
21
+ }
22
+
23
+ interface SuiPayCredentials {
24
+ /** 64-hex Ed25519 seed. NEVER logged. */
25
+ delegatePrivateKey: string;
26
+ delegatePublicKeyHex: string;
27
+ delegateAddress: string;
28
+ ownerAddress: string;
29
+ allowanceId: string;
30
+ packageId: string;
31
+ coinType: string;
32
+ /** Allowance recipient = the resource's payTo. */
33
+ recipient: string;
34
+ gatewayUrl: string;
35
+ network: string;
36
+ maxPerPayment: string;
37
+ label?: string;
38
+ createdAt: string;
39
+ version: 1;
40
+ }
41
+ type SignerSource = 'secret-key' | 'credentials' | 'mnemonic';
42
+ interface PaymentProfile {
43
+ creds: SuiPayCredentials;
44
+ wallet: Wallet;
45
+ source: SignerSource;
46
+ }
47
+ /**
48
+ * Load a historical V1 allowance payment profile, if present.
49
+ * ADR-0010: not for new settlement. Callers that pay must refuse this profile
50
+ * and point operators at shared_pool OAuth / delegated-signer flows.
51
+ */
52
+ declare function loadPaymentProfile(): PaymentProfile | null;
53
+
54
+ /**
55
+ * Transport-neutral SuiPay MCP server + tool registry.
56
+ * Used by stdio (index.ts) and Streamable HTTP (http.ts).
57
+ * Remote HTTP passes McpAuthContext so tools enforce OAuth scope + shared-pool pay.
58
+ */
59
+
60
+ declare const PACKAGE_NAME = "@cmdoss/suipay-mcp";
61
+ declare const TOOLS: readonly [{
62
+ readonly name: "access_context";
63
+ 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.";
64
+ readonly inputSchema: {
65
+ readonly type: "object";
66
+ readonly properties: {};
67
+ };
68
+ }, {
69
+ readonly name: "pay";
70
+ readonly description: "Fetch a paid HTTP resource and settle its MPP challenge via shared_pool (remote OAuth MCP). Local V1 allowance pay is retired. Use method POST with json to pay for a JSON request body; the body you send is signed into the offer, so it cannot be changed after payment.";
71
+ readonly inputSchema: {
72
+ readonly type: "object";
73
+ readonly properties: {
74
+ readonly url: {
75
+ readonly type: "string";
76
+ readonly description: "Full gateway resource URL.";
77
+ };
78
+ readonly method: {
79
+ readonly type: "string";
80
+ readonly enum: readonly ["GET", "POST"];
81
+ readonly description: "HTTP method of the paid request. Defaults to GET.";
82
+ };
83
+ readonly json: {
84
+ readonly type: "object";
85
+ readonly description: "JSON request body for a POST. Sent as application/json and bound to the payment.";
86
+ };
87
+ };
88
+ readonly required: readonly ["url"];
89
+ };
90
+ }, {
91
+ readonly name: "discover";
92
+ readonly description: "Search SuiPay gateway resources.";
93
+ readonly inputSchema: {
94
+ readonly type: "object";
95
+ readonly properties: {
96
+ readonly query: {
97
+ readonly type: "string";
98
+ readonly description: "Optional service search terms.";
99
+ };
100
+ };
101
+ };
102
+ }, {
103
+ readonly name: "receipts";
104
+ readonly description: "List SuiPay settlement receipts, optionally filtered by challenge id.";
105
+ readonly inputSchema: {
106
+ readonly type: "object";
107
+ readonly properties: {
108
+ readonly challengeId: {
109
+ readonly type: "string";
110
+ readonly description: "Optional payment challenge id.";
111
+ };
112
+ };
113
+ };
114
+ }, {
115
+ readonly name: "suipay_login";
116
+ readonly description: "Legacy V1 allowance login (retired). Returns an error directing you to remote MCP OAuth or delegated-signer provisioning.";
117
+ readonly inputSchema: {
118
+ readonly type: "object";
119
+ readonly properties: {
120
+ readonly label: {
121
+ readonly type: "string";
122
+ readonly description: "Label shown in SuiPay console.";
123
+ };
124
+ readonly gatewayResourceUrl: {
125
+ readonly type: "string";
126
+ readonly description: "Gateway resource URL whose 402 defines recipient, asset, and package.";
127
+ };
128
+ };
129
+ };
130
+ }, {
131
+ readonly name: "suipay_logout";
132
+ readonly description: "Remove local SuiPay credentials. Refuses while live allowance holds funds unless forced.";
133
+ readonly inputSchema: {
134
+ readonly type: "object";
135
+ readonly properties: {
136
+ readonly force: {
137
+ readonly type: "boolean";
138
+ readonly description: "Remove local credentials even if allowance still holds funds.";
139
+ };
140
+ };
141
+ };
142
+ }];
143
+ /**
144
+ * Create a Server with the public SuiPay tool surface registered.
145
+ *
146
+ * `trace` is the proxy-resolved run for this HTTP exchange. It is threaded into
147
+ * tool dependencies so payment code can emit *domain* events, and nothing else:
148
+ * this wrapper deliberately emits no tool lifecycle of its own, because the
149
+ * proxy observes the actual JSON-RPC wire and a second source would double-count
150
+ * every call and disagree on ids.
151
+ */
152
+ declare function createSuipayMcpServer(cfg: McpConfig, auth?: McpAuthContext, trace?: McpTraceHooks): Server;
153
+
154
+ interface PayResult {
155
+ status: 'ok' | 'failed' | 'ambiguous';
156
+ paid: boolean;
157
+ body?: unknown;
158
+ receipt?: unknown;
159
+ code?: string;
160
+ detail?: string;
161
+ txDigest?: string;
162
+ }
163
+
164
+ /**
165
+ * SharedPool pay-then-prove client (WS7.6).
166
+ *
167
+ * Flow: 402 Offer → resolveGrantTarget(snapshot, offer.targetHash) → build
168
+ * shared_pool::pay kind → sponsor → briefly decrypt delegate, sign, wipe →
169
+ * execute → wait finality → present MPP proof.
170
+ *
171
+ * Pause/revoke is checked via resolveGrantTarget BEFORE decrypt.
172
+ * Never accepts gas from the buyer. No blind retry on ambiguous finality.
173
+ */
174
+
175
+ interface SharedPoolPaySession {
176
+ snapshot: GrantSnapshot;
177
+ /**
178
+ * Decrypt delegate seed for signing. Caller must only implement this after
179
+ * pause/revoke checks. Returns 32-byte seed; payer wipes after sign.
180
+ */
181
+ decryptDelegateSeed: () => Promise<Buffer | Uint8Array>;
182
+ /** SharedPool package id (V2). */
183
+ packageId: string;
184
+ /**
185
+ * Re-assert the grant is still live (not paused/revoked) against canonical
186
+ * state, invoked immediately before decrypt to close the snapshot→decrypt
187
+ * race: the snapshot is loaded when the request begins, and a pause/revoke
188
+ * arriving after that must stop key decryption — not merely fail on-chain.
189
+ * Throw to abort. Optional; when absent, only the request-time snapshot gates
190
+ * decrypt (on-chain rejection remains the final backstop).
191
+ */
192
+ assertLive?: () => Promise<void>;
193
+ /**
194
+ * Authorization header value (e.g. `Bearer <token>`) sent to the gateway's
195
+ * `/api/sponsor` create/execute calls. Required when the payer runs inside
196
+ * the gateway (remote `/mcp`): the sponsor guard authenticates the delegate
197
+ * from this bearer, and without it the internal sponsor call is unauthorized.
198
+ */
199
+ sponsorAuthorization?: string;
200
+ }
201
+ interface SharedPoolPayDeps {
202
+ fetchImpl?: typeof fetch;
203
+ /** Build only-transaction-kind bytes for shared_pool::pay. */
204
+ buildPayKind?: (input: {
205
+ delegate: string;
206
+ coinType: string;
207
+ poolObjectId: string;
208
+ grantObjectId: string;
209
+ policyId: number | string;
210
+ targetHash: string;
211
+ amount: string;
212
+ paymentIdHash: Uint8Array;
213
+ termsHash: Uint8Array;
214
+ }) => Promise<{
215
+ kindBytes: string;
216
+ }>;
217
+ /** Wait for chain finality of a digest. */
218
+ getFinalizedTx?: (digest: string) => Promise<{
219
+ status: 'success' | 'failed';
220
+ reason?: string;
221
+ } | null>;
222
+ /**
223
+ * Live trace for this payment.
224
+ *
225
+ * Two jobs, both purely observational. Emission records what the canonical
226
+ * decisions already returned — an event is written *after* a check passes and
227
+ * can never be the thing that lets the next step run. Signing attaches
228
+ * correlation headers to the internal sponsor and settle hops so the gateway
229
+ * can attribute its own facts to the same run; the sponsor allowlist, guard
230
+ * and simulation gates behave identically with or without them.
231
+ */
232
+ trace?: SharedPoolPayTrace;
233
+ }
234
+ interface SharedPoolPayTrace {
235
+ sink: TraceSink;
236
+ traceId: string;
237
+ requestId: string | null;
238
+ buyerAccountId: string;
239
+ connectionId: string;
240
+ /** HMAC secret for signed cross-request context. Absent disables signing. */
241
+ secret?: string | null;
242
+ /** Injected clock, for tests. */
243
+ now?: () => number;
244
+ }
245
+ /** Default kind builder (no chain client — pure PTB). */
246
+ declare function buildSharedPoolPayKind(input: {
247
+ packageId: string;
248
+ delegate: string;
249
+ coinType: string;
250
+ poolObjectId: string;
251
+ grantObjectId: string;
252
+ policyId: number | string;
253
+ targetHash: string;
254
+ amount: string;
255
+ paymentIdHash: Uint8Array;
256
+ termsHash: Uint8Array;
257
+ }): Promise<{
258
+ kindBytes: string;
259
+ }>;
260
+ declare function paySharedPoolResource(args: {
261
+ url: string;
262
+ /**
263
+ * The one normalized paid request, replayed byte for byte on the unpaid and
264
+ * the paid call. Omitted by legacy GET callers.
265
+ */
266
+ request?: PaidHttpRequest;
267
+ session: SharedPoolPaySession;
268
+ cfg: McpConfig;
269
+ deps?: SharedPoolPayDeps;
270
+ /**
271
+ * Preferred dialect when the 402 advertises both (WS12.3).
272
+ * Default: mpp (pay-then-prove). x402 = gateway-submitted credential.
273
+ */
274
+ preferredDialect?: Dialect;
275
+ }): Promise<PayResult>;
276
+
277
+ declare function loadBootProfile(load?: typeof loadPaymentProfile): {
278
+ profile: ReturnType<typeof loadPaymentProfile>;
279
+ unreadable: boolean;
280
+ };
281
+ declare function main(): Promise<void>;
282
+
283
+ export { McpTraceHooks, PACKAGE_NAME, type SharedPoolPaySession, TOOLS, buildSharedPoolPayKind, createSuipayMcpServer, loadBootProfile, main, paySharedPoolResource };
package/dist/index.js ADDED
@@ -0,0 +1,32 @@
1
+ import {
2
+ loadBootProfile,
3
+ loadMcpConfig,
4
+ main
5
+ } from "./chunk-5I6V7N3R.js";
6
+ import {
7
+ PACKAGE_NAME,
8
+ TOOLS,
9
+ buildSharedPoolPayKind,
10
+ canonicalMcpRequestId,
11
+ createSuipayMcpServer,
12
+ handleSuipayMcpHttpRequest,
13
+ inspectMcpEnvelope,
14
+ paySharedPoolResource,
15
+ resolveGrantTarget,
16
+ traceMcpHttpRequest
17
+ } from "./chunk-772CHNGT.js";
18
+ export {
19
+ PACKAGE_NAME,
20
+ TOOLS,
21
+ buildSharedPoolPayKind,
22
+ canonicalMcpRequestId,
23
+ createSuipayMcpServer,
24
+ handleSuipayMcpHttpRequest,
25
+ inspectMcpEnvelope,
26
+ loadBootProfile,
27
+ loadMcpConfig,
28
+ main,
29
+ paySharedPoolResource,
30
+ resolveGrantTarget,
31
+ traceMcpHttpRequest
32
+ };
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@cmdoss/suipay-mcp",
3
+ "version": "1.0.1",
4
+ "type": "module",
5
+ "description": "SuiPay MCP — pay MPP-gated APIs from an on-chain allowance.",
6
+ "bin": {
7
+ "suipay": "dist/bin/suipay.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "engines": {
13
+ "node": ">=20"
14
+ },
15
+ "scripts": {
16
+ "build": "tsup",
17
+ "e2e:protocol:testnet": "tsx scripts/e2e-protocol-testnet.ts",
18
+ "test": "vitest run",
19
+ "typecheck": "tsc -p tsconfig.json --noEmit"
20
+ },
21
+ "dependencies": {
22
+ "@modelcontextprotocol/sdk": "^1.29.0",
23
+ "@mysten/sui": "2.23.1",
24
+ "@noble/ed25519": "^2.1.0",
25
+ "@noble/hashes": "^1.4.0",
26
+ "open": "^10.1.0"
27
+ },
28
+ "devDependencies": {
29
+ "tsup": "^8.0.0",
30
+ "typescript": "^5.9.0",
31
+ "vitest": "^3.0.0"
32
+ }
33
+ }