@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 +87 -0
- package/dist/bin/suipay.d.ts +1 -0
- package/dist/bin/suipay.js +11 -0
- package/dist/chunk-5I6V7N3R.js +67 -0
- package/dist/chunk-772CHNGT.js +3879 -0
- package/dist/http-B5iGH5mf.d.ts +427 -0
- package/dist/http.d.ts +1 -0
- package/dist/http.js +6 -0
- package/dist/index.d.ts +283 -0
- package/dist/index.js +32 -0
- package/package.json +33 -0
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,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
|
+
};
|