@cmdoss/suipay-mcp 0.2.2 → 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 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. `1.0.1` remains on the
9
- registry as a historical release; do not install it for new agents.
8
+ Pin `@cmdoss/suipay-mcp@0.3.0-dev.0` 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.3.0-dev.0
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 the gateway (`SUIPAY_GATEWAY_URL`) and the same network
30
- the grant was created on.
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,16 +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
- opens `{SUIPAY_CONSOLE_URL}/connect/agent?delegateAddress=0x…`.
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 managed-gateway resources |
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
- | `suipay_login` | Mint or reuse the local delegate key and open the console with the public address only |
62
+ | `access_context` | Report current session / delegate / policy state (no secret material) |
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 |
49
64
  | `suipay_logout` | Remove local credentials |
50
65
 
51
66
  All tools remain visible before a grant is bound. `pay` and `receipts`
@@ -53,13 +68,114 @@ return instruction to run `suipay_login` and bind a spend-account grant
53
68
  when no local credentials exist. Hosted `/mcp` never holds a spendable
54
69
  key.
55
70
 
71
+ ## Use from an agent
72
+
73
+ Install once (above). After that, paying is a prompt — paste it into Claude
74
+ (or any MCP host that has `suipay`). Do not write SDK code.
75
+
76
+ ```
77
+ Pay this SuiPay resource with the suipay MCP `pay` tool. Do not write SDK code.
78
+
79
+ url: https://gateway.example/v1/image/generate
80
+ method: POST
81
+ json: {"prompt":"a cat"}
82
+ maxAmount: 50000
83
+ ```
84
+
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
+ | `detail` | Developer text that states the fix. |
123
+ | `txDigest`, `paymentId` | When known. |
124
+
125
+ The text block holds the same object as JSON. When money moved or may have
126
+ moved it **starts** with a line for the model:
127
+
128
+ ```
129
+ You were charged. Do not pay again for this request.
130
+ { "status": "ambiguous", "paid": true, "code": "delivery.seller_unreachable", "paymentState": "charged", ... }
131
+ ```
132
+
133
+ (`This payment may have gone through. Do not pay again until it is resolved.`
134
+ when `paymentState` is `unknown`.) A result whose `status` is `ok` or
135
+ `prepared` is never an error, including a free response that needed no
136
+ payment.
137
+
138
+ Common local codes: `auth.login_required` (run `suipay_login`),
139
+ `request.file_outside_root` / `request.file_root_unset` (set
140
+ `SUIPAY_MCP_FILE_ROOT`), `client.local_credentials_invalid` (log in again),
141
+ `client.gateway_unreachable` (retry later). An unknown tool name is a JSON-RPC
142
+ error, not a tool result; an invalid argument such as a relative `url` is a
143
+ tool error with a `request.*` code and `nextAction: "fix_request"`.
144
+
145
+ ## Targets
146
+
147
+ Default is Railway **suipay-dev**. `--local` / `target: "local"` is laptop-only.
148
+
149
+ | Target | Console | Gateway | How |
150
+ | --- | --- | --- | --- |
151
+ | `dev` (default) | `https://suipay-dev.up.railway.app` | `https://gateway-dev-ba84.up.railway.app` | no flag, or `--dev` |
152
+ | `local` | `http://localhost:3000` | `http://127.0.0.1:4340` | `--local` / `-local`, or `suipay_login({ target: "local" })` |
153
+
154
+ ```bash
155
+ # Railway suipay-dev (default)
156
+ npx @cmdoss/suipay-mcp@0.3.0-dev.0
157
+
158
+ # Laptop stack
159
+ npx @cmdoss/suipay-mcp@0.3.0-dev.0 --local
160
+ ```
161
+
162
+ `SUIPAY_MCP_TARGET=local|dev` selects the same preset. Explicit
163
+ `SUIPAY_GATEWAY_URL` / `SUIPAY_CONSOLE_URL` fill the process default when no
164
+ credential is bound yet. After a successful login, `credentials.json`
165
+ `gatewayUrl` is the bound gateway: `pay` / `discover` / `suipay_login` without
166
+ `target` stay on that binding so a leftover env cannot silently retarget spend.
167
+ Rebind with `suipay_login({ target: "dev" | "local" })` (same key, new consent
168
+ if that stack has no live grant).
169
+
56
170
  ## Client environment
57
171
 
58
172
  ```bash
173
+ # Optional. Unset = Railway suipay-dev. --local uses localhost:3000 / 127.0.0.1:4340.
59
174
  SUIPAY_GATEWAY_URL=https://gateway.example
60
175
  SUIPAY_CONSOLE_URL=https://console.example
61
176
  SUIPAY_RPC_URL=https://your-testnet-rpc.example
62
177
  SUIPAY_NETWORK=testnet
178
+ SUIPAY_MCP_TARGET=dev
63
179
  ```
64
180
 
65
181
  Optional:
@@ -100,4 +216,8 @@ node packages/mcp/dist/bin/suipay.js
100
216
  Binary writes status banner to stderr only. Stdout stays reserved for
101
217
  MCP protocol.
102
218
 
103
- Do not publish `@cmdoss/suipay-mcp` from this change.
219
+ Publishing is the `release-npm` workflow: merge to `dev` publishes
220
+ `@cmdoss/suipay-mcp@<version>-dev.N` with dist-tag `dev` (OIDC, pack gate,
221
+ provenance). `latest` is a gated dispatch from `main` (`dry_run` default
222
+ true). Do not `npm publish` from a laptop. See
223
+ [`docs/guide/npm-release.md`](../../docs/guide/npm-release.md).
@@ -1,12 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "../chunk-EM7PKWVL.js";
5
- import "../chunk-26NKQ37M.js";
6
- import "../chunk-A3JIIDYT.js";
4
+ } from "../chunk-W4RIN664.js";
5
+ import {
6
+ logError
7
+ } from "../chunk-FKDC22O6.js";
7
8
 
8
9
  // src/bin/suipay.ts
9
10
  main().catch((err) => {
10
- console.error(err instanceof Error ? err.message : String(err));
11
+ logError({ scope: "suipay-mcp", code: "client.unexpected", withStack: true }, err);
11
12
  process.exit(1);
12
13
  });