@cmdoss/suipay-mcp 0.2.2-dev.4 → 0.2.2-dev.40
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 +116 -13
- package/dist/bin/suipay.js +2 -2
- package/dist/chunk-IH6HQD2V.js +46 -0
- package/dist/chunk-YMOMYFKL.js +13346 -0
- package/dist/{http-C8xW9F1c.d.ts → http-DvnvTrb3.d.ts} +296 -7
- package/dist/http.d.ts +5 -1
- package/dist/http.js +1 -1
- package/dist/index.d.ts +47 -217
- package/dist/index.js +10 -2
- package/package.json +15 -14
- package/dist/chunk-KDOGSB5I.js +0 -6776
- package/dist/chunk-XAM2YQC6.js +0 -39
package/README.md
CHANGED
|
@@ -5,17 +5,25 @@ buyer-funded spend account. The buyer owns the account. The agent holds the
|
|
|
5
5
|
delegate key and can spend only under the on-chain grant (recipient bind,
|
|
6
6
|
per-payment cap, budget).
|
|
7
7
|
|
|
8
|
-
Pin `@cmdoss/suipay-mcp@0.2.2` in MCP config
|
|
9
|
-
|
|
8
|
+
Pin `@cmdoss/suipay-mcp@0.2.2-dev.40` in MCP config for the `latest` dist-tag.
|
|
9
|
+
`npx -y @cmdoss/suipay-mcp@dev` tracks the `dev` prerelease line.
|
|
10
|
+
`1.0.1` remains on the registry as a historical release; do not install it
|
|
11
|
+
for new agents.
|
|
10
12
|
|
|
11
13
|
## Install
|
|
12
14
|
|
|
13
15
|
```bash
|
|
14
|
-
claude mcp add --scope user suipay -- npx -y @cmdoss/suipay-mcp@0.2.2
|
|
16
|
+
claude mcp add --scope user suipay -- npx -y @cmdoss/suipay-mcp@0.2.2-dev.40
|
|
15
17
|
```
|
|
16
18
|
|
|
19
|
+
`@dev` installs the Railway-dev gateway/console defaults. A workspace
|
|
20
|
+
checkout still defaults to localhost. `SUIPAY_GATEWAY_URL` and
|
|
21
|
+
`SUIPAY_CONSOLE_URL` always override.
|
|
22
|
+
|
|
17
23
|
No wallet secret belongs in this command or MCP config. There is no
|
|
18
|
-
Sign-In With Sui (SIWS) step.
|
|
24
|
+
Sign-In With Sui (SIWS) step. To reuse an existing delegate seed locally,
|
|
25
|
+
set `SUIPAY_MCP_KEY` (64-hex or `suiprivkey1…`) in the MCP env — never in
|
|
26
|
+
the browser.
|
|
19
27
|
|
|
20
28
|
## First connection
|
|
21
29
|
|
|
@@ -26,8 +34,11 @@ First connection is a spend-account grant plus an agent-held delegate key.
|
|
|
26
34
|
2. Persist that delegate key locally at `~/.suipay/credentials.json`
|
|
27
35
|
(mode `0600`). The process that holds this key is the only process
|
|
28
36
|
that can settle.
|
|
29
|
-
3. Point MCP at
|
|
30
|
-
the
|
|
37
|
+
3. Point MCP at a gateway. Default is Railway **suipay-dev**. Pass
|
|
38
|
+
`suipay_login({ target: "local" })` or start the binary with `--local`
|
|
39
|
+
for the laptop stack. Env/CLI fill the process default until a
|
|
40
|
+
credential is bound; after login, stored `gatewayUrl` wins. Rebind
|
|
41
|
+
with `suipay_login({ target })`.
|
|
31
42
|
4. Call `pay`. The tool prepares unsigned `spend_account` settlement
|
|
32
43
|
bytes. If this process holds the grant's key it verifies and settles;
|
|
33
44
|
otherwise it returns the signing request.
|
|
@@ -36,17 +47,20 @@ The agent generates or is handed the delegate key. The key never enters
|
|
|
36
47
|
a browser URL, a SuiPay backend, logs, or a callback payload. Only the
|
|
37
48
|
public address leaves the local process. `suipay_login` mints or reuses
|
|
38
49
|
the local version-2 key at `~/.suipay/credentials.json` (mode `0600`) and
|
|
39
|
-
|
|
50
|
+
returns `{SUIPAY_CONSOLE_URL}/connect/agent?port=&delegateAddress=&connectState=&gateway=`
|
|
51
|
+
immediately. The owner signs in the browser; the loopback callback persists
|
|
52
|
+
key + gateway URL. Subsequent sessions reuse the file unless the grant is
|
|
53
|
+
missing, expired, or revoked.
|
|
40
54
|
|
|
41
55
|
## Tools
|
|
42
56
|
|
|
43
57
|
| Tool | Purpose |
|
|
44
58
|
| --- | --- |
|
|
45
|
-
| `discover` | Search live
|
|
46
|
-
| `pay` | Fetch resource, prepare `spend_account` settlement, settle when this process holds the grant key |
|
|
59
|
+
| `discover` | Search live gateway resources. After login: `name`, `path`, `url`, `targetHash`, catalog price, and `affordable` (can this session cover one call — not authorization). `pay({ url })` still settles |
|
|
60
|
+
| `pay` | Fetch resource, prepare `spend_account` settlement, settle when this process holds the grant key. POST `json` is the paid body. Optional stdio `file` + `fileField` fill one JSON key from a local file as canonical base64 (Walrus `contentBase64`); requires `SUIPAY_MCP_FILE_ROOT`; hosted `/mcp` refuses `file` |
|
|
47
61
|
| `receipts` | List settlement receipts, optionally by challenge ID |
|
|
48
62
|
| `access_context` | Report current session / delegate / policy state (no secret material) |
|
|
49
|
-
| `suipay_login` | Mint or reuse the local delegate key and
|
|
63
|
+
| `suipay_login` | Mint or reuse the local delegate key and return a clickable console URL (does not wait for the wallet). Default target is Railway suipay-dev; pass `target: "local"` for the laptop stack |
|
|
50
64
|
| `suipay_logout` | Remove local credentials |
|
|
51
65
|
|
|
52
66
|
All tools remain visible before a grant is bound. `pay` and `receipts`
|
|
@@ -68,16 +82,101 @@ json: {"prompt":"a cat"}
|
|
|
68
82
|
maxAmount: 50000
|
|
69
83
|
```
|
|
70
84
|
|
|
71
|
-
|
|
72
|
-
|
|
85
|
+
To store local bytes (Walrus), do not paste base64. Name the file and field.
|
|
86
|
+
Set `SUIPAY_MCP_FILE_ROOT` to an absolute directory; `file` must resolve inside
|
|
87
|
+
it (unset disables attach). Paths under `~/.suipay` are refused even if that
|
|
88
|
+
directory falls inside the root.
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Pay this SuiPay resource with the suipay MCP `pay` tool. Do not write SDK code.
|
|
92
|
+
|
|
93
|
+
url: https://gateway.example/v1/walrus/store
|
|
94
|
+
method: POST
|
|
95
|
+
json: {"contentType":"text/plain"}
|
|
96
|
+
file: /absolute/path/to/note.txt
|
|
97
|
+
fileField: contentBase64
|
|
98
|
+
maxAmount: 50000
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`pay` uses SDK `createPayer` internally. When this process settles, a binary
|
|
102
|
+
body is written once under `~/.suipay/deliveries/` and named first in the
|
|
103
|
+
JSON as `savedTo` (absolute path) and `savedToUrl` (`file://`). Hosted `/mcp`
|
|
104
|
+
is prepare-only and does not write a buyer file. Any MIME — image, audio,
|
|
105
|
+
pdf, octet-stream. JSON stays compact (no base64 wall). An MCP `image` block
|
|
106
|
+
is an extra display hint when the type is `image/*`; hosts such as Claude
|
|
107
|
+
Code's TUI may not render it. Always quote `savedTo` when present. If
|
|
108
|
+
`savedTo` is null, quote `saveError` and do not call `pay` again.
|
|
109
|
+
|
|
110
|
+
## Tool errors — branch on `code`
|
|
111
|
+
|
|
112
|
+
A tool result whose `status` is `failed` or `ambiguous` sets `isError: true`
|
|
113
|
+
and puts the error model in `structuredContent`:
|
|
114
|
+
|
|
115
|
+
| Field | Meaning |
|
|
116
|
+
| --- | --- |
|
|
117
|
+
| `status`, `paid` | As before. `paid` is `true`, `false` or `'unknown'`. |
|
|
118
|
+
| `code` | Registered error code, e.g. `request.file_outside_root`. **Branch on this**, never on the text. |
|
|
119
|
+
| `paymentState` | `charged`, `unknown` or `not_charged`; always agrees with `paid`. |
|
|
120
|
+
| `retryable` | `true` only when a retry cannot charge twice. |
|
|
121
|
+
| `nextAction` | `retry`, `retry_later`, `fix_request`, `sign_in`, `approve_access`, `add_funds`, `reconcile`, `contact_support` or `none`. |
|
|
122
|
+
| `supportCode` | Always present. The gateway's when it produced the failure; otherwise minted by this MCP server and written, with the failure, to its stderr log. Find the cause in the MCP host's log by searching for it. |
|
|
123
|
+
| `detail` | Developer text that states the fix. |
|
|
124
|
+
| `txDigest`, `paymentId` | When known. |
|
|
125
|
+
|
|
126
|
+
The text block holds the same object as JSON. When money moved or may have
|
|
127
|
+
moved it **starts** with a line for the model:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
You were charged. Do not pay again for this request.
|
|
131
|
+
{ "status": "ambiguous", "paid": true, "code": "delivery.seller_unreachable", "paymentState": "charged", ... }
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
(`This payment may have gone through. Do not pay again until it is resolved.`
|
|
135
|
+
when `paymentState` is `unknown`.) A result whose `status` is `ok` or
|
|
136
|
+
`prepared` is never an error, including a free response that needed no
|
|
137
|
+
payment.
|
|
138
|
+
|
|
139
|
+
Common local codes: `auth.login_required` (run `suipay_login`),
|
|
140
|
+
`request.file_outside_root` / `request.file_root_unset` (set
|
|
141
|
+
`SUIPAY_MCP_FILE_ROOT`), `client.local_credentials_invalid` (log in again),
|
|
142
|
+
`client.gateway_unreachable` (retry later). An unknown tool name is a JSON-RPC
|
|
143
|
+
error, not a tool result; an invalid argument such as a relative `url` is a
|
|
144
|
+
tool error with a `request.*` code and `nextAction: "fix_request"`.
|
|
145
|
+
|
|
146
|
+
## Targets
|
|
147
|
+
|
|
148
|
+
Default is Railway **suipay-dev**. `--local` / `target: "local"` is laptop-only.
|
|
149
|
+
|
|
150
|
+
| Target | Console | Gateway | How |
|
|
151
|
+
| --- | --- | --- | --- |
|
|
152
|
+
| `dev` (default) | `https://suipay-dev.up.railway.app` | `https://gateway-dev-ba84.up.railway.app` | no flag, or `--dev` |
|
|
153
|
+
| `local` | `http://localhost:3000` | `http://127.0.0.1:4340` | `--local` / `-local`, or `suipay_login({ target: "local" })` |
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Railway suipay-dev (default)
|
|
157
|
+
npx @cmdoss/suipay-mcp@0.2.2-dev.40
|
|
158
|
+
|
|
159
|
+
# Laptop stack
|
|
160
|
+
npx @cmdoss/suipay-mcp@0.2.2-dev.40 --local
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`SUIPAY_MCP_TARGET=local|dev` selects the same preset. Explicit
|
|
164
|
+
`SUIPAY_GATEWAY_URL` / `SUIPAY_CONSOLE_URL` fill the process default when no
|
|
165
|
+
credential is bound yet. After a successful login, `credentials.json`
|
|
166
|
+
`gatewayUrl` is the bound gateway: `pay` / `discover` / `suipay_login` without
|
|
167
|
+
`target` stay on that binding so a leftover env cannot silently retarget spend.
|
|
168
|
+
Rebind with `suipay_login({ target: "dev" | "local" })` (same key, new consent
|
|
169
|
+
if that stack has no live grant).
|
|
73
170
|
|
|
74
171
|
## Client environment
|
|
75
172
|
|
|
76
173
|
```bash
|
|
174
|
+
# Optional. Unset = Railway suipay-dev. --local uses localhost:3000 / 127.0.0.1:4340.
|
|
77
175
|
SUIPAY_GATEWAY_URL=https://gateway.example
|
|
78
176
|
SUIPAY_CONSOLE_URL=https://console.example
|
|
79
177
|
SUIPAY_RPC_URL=https://your-testnet-rpc.example
|
|
80
178
|
SUIPAY_NETWORK=testnet
|
|
179
|
+
SUIPAY_MCP_TARGET=dev
|
|
81
180
|
```
|
|
82
181
|
|
|
83
182
|
Optional:
|
|
@@ -118,4 +217,8 @@ node packages/mcp/dist/bin/suipay.js
|
|
|
118
217
|
Binary writes status banner to stderr only. Stdout stays reserved for
|
|
119
218
|
MCP protocol.
|
|
120
219
|
|
|
121
|
-
|
|
220
|
+
Publishing is the `release-npm` workflow: merge to `dev` publishes
|
|
221
|
+
`@cmdoss/suipay-mcp@<version>-dev.N` with dist-tag `dev` (OIDC, pack gate,
|
|
222
|
+
provenance). `latest` is a gated dispatch from `main` (`dry_run` default
|
|
223
|
+
true). Do not `npm publish` from a laptop. See
|
|
224
|
+
[`docs/guide/npm-release.md`](../../docs/guide/npm-release.md).
|
package/dist/bin/suipay.js
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createServer,
|
|
3
|
+
loadLocalSigner,
|
|
4
|
+
loadLocalSigningKeyRecord,
|
|
5
|
+
loadMcpConfig,
|
|
6
|
+
loadPaymentProfile
|
|
7
|
+
} from "./chunk-YMOMYFKL.js";
|
|
8
|
+
|
|
9
|
+
// src/index.ts
|
|
10
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
+
function loadBootProfile(load = loadPaymentProfile) {
|
|
12
|
+
try {
|
|
13
|
+
return { profile: load(), unreadable: false };
|
|
14
|
+
} catch {
|
|
15
|
+
return { profile: null, unreadable: true };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function main() {
|
|
19
|
+
const argv = process.argv.slice(2);
|
|
20
|
+
const cfg = loadMcpConfig(process.env, argv);
|
|
21
|
+
const target = cfg.target ?? "dev";
|
|
22
|
+
const server = createServer(cfg, void 0, void 0, { transport: "stdio" });
|
|
23
|
+
await server.connect(new StdioServerTransport());
|
|
24
|
+
try {
|
|
25
|
+
const boundGateway = loadLocalSigningKeyRecord()?.gatewayUrl ?? cfg.gatewayUrl;
|
|
26
|
+
const local = loadLocalSigner();
|
|
27
|
+
if (local) {
|
|
28
|
+
console.error(
|
|
29
|
+
`[suipay-mcp] ${target} ${boundGateway} \xB7 delegate ${local.address} \xB7 stdio ready`
|
|
30
|
+
);
|
|
31
|
+
} else {
|
|
32
|
+
console.error(
|
|
33
|
+
`[suipay-mcp] ${target} ${boundGateway} \xB7 not connected \xB7 run suipay_login \xB7 stdio ready`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
console.error(
|
|
38
|
+
`[suipay-mcp] ${target} ${cfg.gatewayUrl} \xB7 credentials unreadable: run suipay_login or suipay_logout force=true \xB7 stdio ready`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
loadBootProfile,
|
|
45
|
+
main
|
|
46
|
+
};
|