@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.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # @cmdoss/suipay-mcp
2
+
3
+ SuiPay MCP lets an MCP-capable agent pay MPP-gated HTTP resources from a buyer-funded Sui allowance. Buyer owns escrow. Local delegate can spend only to bound recipient, under on-chain per-payment cap.
4
+
5
+ ## Install
6
+
7
+ Pin package version in MCP config:
8
+
9
+ ```bash
10
+ claude mcp add --scope user suipay -- npx -y @cmdoss/suipay-mcp@1.0.0
11
+ ```
12
+
13
+ No wallet secret belongs in this command or MCP config.
14
+
15
+ ## First connection
16
+
17
+ 1. Ask agent to call `suipay_login`.
18
+ 2. Browser opens SuiPay console.
19
+ 3. Connect buyer wallet, choose funding and per-payment cap, then approve allowance creation.
20
+ 4. Local MCP process saves delegate credentials to `~/.suipay/credentials.json` with mode `0600`.
21
+ 5. Agent can call `pay` in same MCP session.
22
+
23
+ Delegate private key is generated locally. It never enters browser URL, browser page, SuiPay backend, logs, or callback payload. Only delegate public key and address leave local process. Platform sponsors create and pay gas through backend Enoki key. Owner and delegate need no SUI gas.
24
+
25
+ ## Tools
26
+
27
+ | Tool | Purpose |
28
+ | --- | --- |
29
+ | `discover` | Search live managed-gateway resources |
30
+ | `pay` | Fetch resource, settle MPP challenge from allowance, present finalized proof |
31
+ | `receipts` | List settlement receipts, optionally by challenge ID |
32
+ | `suipay_login` | Open browser allowance provisioning flow |
33
+ | `suipay_logout` | Remove local credentials, guarded while live escrow still holds funds |
34
+
35
+ All tools remain visible before login. `pay` and `receipts` return instruction to run `suipay_login` when no credentials exist.
36
+
37
+ ## Client environment
38
+
39
+ ```bash
40
+ SUIPAY_GATEWAY_URL=https://gateway.example
41
+ SUIPAY_CONSOLE_URL=https://console.example
42
+ SUIPAY_RPC_URL=https://your-testnet-rpc.example
43
+ SUIPAY_NETWORK=testnet
44
+ ```
45
+
46
+ Optional:
47
+
48
+ ```bash
49
+ # Defaults to $SUIPAY_GATEWAY_URL/api/sponsor
50
+ SUIPAY_SPONSOR_URL=https://gateway.example/api/sponsor
51
+
52
+ # Fallback payment terms when suipay_login receives no gatewayResourceUrl
53
+ SUIPAY_PACKAGE_ID=0x...
54
+ SUIPAY_RECIPIENT=0x...
55
+ SUIPAY_COIN_TYPE=0x...::usdc::USDC
56
+
57
+ SUIPAY_MIN_FUNDED=5000000
58
+ SUIPAY_MIN_MAX_PER_PAYMENT=5000000
59
+ SUIPAY_LABEL="My agent"
60
+ ```
61
+
62
+ `ENOKI_PRIVATE_API_KEY` is backend-only. Never set it in MCP config or local SuiPay credentials.
63
+
64
+ If `SUI_SECRET_KEY` is present, it must derive to delegate address stored in credentials. Mismatch or malformed credentials stop signing. No mnemonic or ephemeral payment fallback exists.
65
+
66
+ ## Logout safety
67
+
68
+ `suipay_logout` refuses to delete local key while live allowance still holds funds. Revoke and refund allowance in console first. `force=true` removes local credentials but does not recover escrow.
69
+
70
+ ## Build and run locally
71
+
72
+ ```bash
73
+ pnpm --filter @cmdoss/suipay-mcp build
74
+ node packages/mcp/dist/bin/suipay.js
75
+ ```
76
+
77
+ Binary writes status banner to stderr only. Stdout stays reserved for MCP protocol.
78
+
79
+ ## Testnet E2E
80
+
81
+ See root `.env.testnet.example`, start backend with Enoki sponsorship, then run:
82
+
83
+ ```bash
84
+ SUIPAY_E2E_CONFIRM=1 pnpm tsx scripts/e2e-mcp-testnet.ts
85
+ ```
86
+
87
+ Script uses real testnet assets. Default funding equals one payment so successful run leaves escrow balance at zero. It verifies delegate SUI balance stays zero before and after pay.
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ main
4
+ } from "../chunk-5I6V7N3R.js";
5
+ import "../chunk-772CHNGT.js";
6
+
7
+ // src/bin/suipay.ts
8
+ main().catch((err) => {
9
+ console.error(err instanceof Error ? err.message : String(err));
10
+ process.exit(1);
11
+ });
@@ -0,0 +1,67 @@
1
+ import {
2
+ createSuipayMcpServer,
3
+ loadPaymentProfile
4
+ } from "./chunk-772CHNGT.js";
5
+
6
+ // src/index.ts
7
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
+
9
+ // src/config.ts
10
+ import { SuiGrpcClient } from "@mysten/sui/grpc";
11
+ var GRPC_URLS = {
12
+ mainnet: "https://fullnode.mainnet.sui.io:443",
13
+ testnet: "https://fullnode.testnet.sui.io:443",
14
+ devnet: "https://fullnode.devnet.sui.io:443",
15
+ localnet: "http://127.0.0.1:9000"
16
+ };
17
+ function loadMcpConfig(env = process.env) {
18
+ const network = env.SUIPAY_NETWORK ?? "testnet";
19
+ const gatewayUrl = env.SUIPAY_GATEWAY_URL ?? "http://localhost:4340";
20
+ return {
21
+ consoleUrl: env.SUIPAY_CONSOLE_URL ?? "http://localhost:3000",
22
+ gatewayUrl,
23
+ rpcUrl: env.SUIPAY_RPC_URL ?? GRPC_URLS[network],
24
+ network,
25
+ packageId: env.SUIPAY_PACKAGE_ID ?? "",
26
+ recipient: env.SUIPAY_RECIPIENT ?? "",
27
+ coinType: env.SUIPAY_COIN_TYPE ?? "",
28
+ sponsorUrl: env.SUIPAY_SPONSOR_URL ?? `${gatewayUrl.replace(/\/$/, "")}/api/sponsor`,
29
+ minFunded: BigInt(env.SUIPAY_MIN_FUNDED ?? "0"),
30
+ minMaxPerPayment: BigInt(env.SUIPAY_MIN_MAX_PER_PAYMENT ?? "0"),
31
+ label: env.SUIPAY_LABEL ?? "SuiPay MCP"
32
+ };
33
+ }
34
+
35
+ // src/index.ts
36
+ function loadBootProfile(load = loadPaymentProfile) {
37
+ try {
38
+ return { profile: load(), unreadable: false };
39
+ } catch {
40
+ return { profile: null, unreadable: true };
41
+ }
42
+ }
43
+ async function main() {
44
+ const cfg = loadMcpConfig();
45
+ const { profile: bootProfile, unreadable: bootProfileUnreadable } = loadBootProfile();
46
+ const server = createSuipayMcpServer(cfg);
47
+ await server.connect(new StdioServerTransport());
48
+ if (bootProfileUnreadable) {
49
+ console.error(
50
+ "[suipay-mcp] credentials unreadable: run suipay_login or suipay_logout force=true \xB7 stdio ready"
51
+ );
52
+ } else if (bootProfile) {
53
+ console.error(
54
+ `[suipay-mcp] delegate ${bootProfile.creds.delegateAddress} (${bootProfile.source}) \xB7 stdio ready`
55
+ );
56
+ } else {
57
+ console.error(
58
+ "[suipay-mcp] not connected \xB7 run suipay_login \xB7 stdio ready"
59
+ );
60
+ }
61
+ }
62
+
63
+ export {
64
+ loadMcpConfig,
65
+ loadBootProfile,
66
+ main
67
+ };