@cmdoss/suipay-mcp 0.2.1 → 0.2.2
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,13 +5,13 @@ 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.
|
|
8
|
+
Pin `@cmdoss/suipay-mcp@0.2.2` in MCP config. `1.0.1` remains on the
|
|
9
9
|
registry as a historical release; do not install it for new agents.
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
claude mcp add --scope user suipay -- npx -y @cmdoss/suipay-mcp@0.2.
|
|
14
|
+
claude mcp add --scope user suipay -- npx -y @cmdoss/suipay-mcp@0.2.2
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
No wallet secret belongs in this command or MCP config. There is no
|
package/dist/bin/suipay.js
CHANGED
|
@@ -3650,7 +3650,7 @@ import {
|
|
|
3650
3650
|
} from "fs";
|
|
3651
3651
|
import { Ed25519Keypair as Ed25519Keypair2 } from "@mysten/sui/keypairs/ed25519";
|
|
3652
3652
|
import { fromBase64 as fromBase643 } from "@mysten/sui/utils";
|
|
3653
|
-
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
|
|
3653
|
+
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils.js";
|
|
3654
3654
|
|
|
3655
3655
|
// src/config.ts
|
|
3656
3656
|
import { homedir } from "os";
|
|
@@ -3686,8 +3686,8 @@ function loadMcpConfig(env = process.env) {
|
|
|
3686
3686
|
|
|
3687
3687
|
// src/crypto.ts
|
|
3688
3688
|
import { getPublicKeyAsync, utils } from "@noble/ed25519";
|
|
3689
|
-
import { blake2b } from "@noble/hashes/
|
|
3690
|
-
import { bytesToHex } from "@noble/hashes/utils";
|
|
3689
|
+
import { blake2b } from "@noble/hashes/blake2.js";
|
|
3690
|
+
import { bytesToHex } from "@noble/hashes/utils.js";
|
|
3691
3691
|
var ED25519_FLAG = 0;
|
|
3692
3692
|
function deriveSuiAddress(publicKey) {
|
|
3693
3693
|
const data = new Uint8Array(1 + publicKey.length);
|
|
@@ -3758,6 +3758,28 @@ function loadCreds() {
|
|
|
3758
3758
|
}
|
|
3759
3759
|
return parsed;
|
|
3760
3760
|
}
|
|
3761
|
+
function writeCredentialsFile(payload) {
|
|
3762
|
+
const dir = credsDir();
|
|
3763
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3764
|
+
try {
|
|
3765
|
+
chmodSync(dir, 448);
|
|
3766
|
+
} catch {
|
|
3767
|
+
}
|
|
3768
|
+
const path = credsPath();
|
|
3769
|
+
const tmp = join2(dir, `.credentials.${process.pid}.tmp`);
|
|
3770
|
+
const fd = openSync(tmp, "w", 384);
|
|
3771
|
+
try {
|
|
3772
|
+
writeSync(fd, JSON.stringify(payload, null, 2));
|
|
3773
|
+
fsyncSync(fd);
|
|
3774
|
+
} finally {
|
|
3775
|
+
closeSync(fd);
|
|
3776
|
+
}
|
|
3777
|
+
renameSync(tmp, path);
|
|
3778
|
+
try {
|
|
3779
|
+
chmodSync(path, 384);
|
|
3780
|
+
} catch {
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3761
3783
|
function createCredentialsFileExclusive(payload) {
|
|
3762
3784
|
const dir = credsDir();
|
|
3763
3785
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
@@ -3855,6 +3877,23 @@ function identityFromStored(privateKeyHex, publicKeyHex, address) {
|
|
|
3855
3877
|
}
|
|
3856
3878
|
return { delegateAddress: address, publicKeyHex };
|
|
3857
3879
|
}
|
|
3880
|
+
function rewriteV1ToLocalSigningKey(creds, opts = {}) {
|
|
3881
|
+
const identity = identityFromStored(
|
|
3882
|
+
creds.delegatePrivateKey,
|
|
3883
|
+
creds.delegatePublicKeyHex,
|
|
3884
|
+
creds.delegateAddress
|
|
3885
|
+
);
|
|
3886
|
+
const record = {
|
|
3887
|
+
version: 2,
|
|
3888
|
+
delegatePrivateKey: creds.delegatePrivateKey,
|
|
3889
|
+
delegatePublicKeyHex: creds.delegatePublicKeyHex,
|
|
3890
|
+
delegateAddress: creds.delegateAddress,
|
|
3891
|
+
createdAt: creds.createdAt,
|
|
3892
|
+
...opts.label?.trim() ? { label: opts.label.trim() } : creds.label?.trim() ? { label: creds.label.trim() } : {}
|
|
3893
|
+
};
|
|
3894
|
+
writeCredentialsFile(record);
|
|
3895
|
+
return identity;
|
|
3896
|
+
}
|
|
3858
3897
|
async function ensureLocalSigningKey(opts = {}) {
|
|
3859
3898
|
const parsed = readCredentialsJson();
|
|
3860
3899
|
if (parsed !== null) {
|
|
@@ -3866,11 +3905,7 @@ async function ensureLocalSigningKey(opts = {}) {
|
|
|
3866
3905
|
);
|
|
3867
3906
|
}
|
|
3868
3907
|
if (isValid(parsed)) {
|
|
3869
|
-
return
|
|
3870
|
-
parsed.delegatePrivateKey,
|
|
3871
|
-
parsed.delegatePublicKeyHex,
|
|
3872
|
-
parsed.delegateAddress
|
|
3873
|
-
);
|
|
3908
|
+
return rewriteV1ToLocalSigningKey(parsed, opts);
|
|
3874
3909
|
}
|
|
3875
3910
|
throw new Error(`credentials file at ${credsPath()} failed schema validation - refusing to continue`);
|
|
3876
3911
|
}
|
|
@@ -3887,13 +3922,16 @@ async function ensureLocalSigningKey(opts = {}) {
|
|
|
3887
3922
|
return { delegateAddress: kp.suiAddress, publicKeyHex: kp.publicKeyHex };
|
|
3888
3923
|
}
|
|
3889
3924
|
const winner = readCredentialsJson();
|
|
3890
|
-
if (winner !== null &&
|
|
3925
|
+
if (winner !== null && isLocalSigningKeyRecord(winner)) {
|
|
3891
3926
|
return identityFromStored(
|
|
3892
3927
|
winner.delegatePrivateKey,
|
|
3893
3928
|
winner.delegatePublicKeyHex,
|
|
3894
3929
|
winner.delegateAddress
|
|
3895
3930
|
);
|
|
3896
3931
|
}
|
|
3932
|
+
if (winner !== null && isValid(winner)) {
|
|
3933
|
+
return rewriteV1ToLocalSigningKey(winner, opts);
|
|
3934
|
+
}
|
|
3897
3935
|
throw new Error(
|
|
3898
3936
|
`credentials file at ${credsPath()} appeared during authorization but is unusable - refusing to continue`
|
|
3899
3937
|
);
|
|
@@ -5313,8 +5351,18 @@ async function payStdioWithLocalKey(args) {
|
|
|
5313
5351
|
});
|
|
5314
5352
|
}
|
|
5315
5353
|
const agentHeld = deps.agentHeld ?? settlementFromLocalSigner(cfg, local, packageId);
|
|
5354
|
+
const grantCeiling = resolved.value.binding.maxPerPayment;
|
|
5355
|
+
const maxAmount = intent.maxAmount !== void 0 ? intent.maxAmount.toString() : grantCeiling != null && grantCeiling !== "" ? grantCeiling : null;
|
|
5356
|
+
if (maxAmount === null) {
|
|
5357
|
+
return error({
|
|
5358
|
+
status: "failed",
|
|
5359
|
+
paid: false,
|
|
5360
|
+
code: "POLICY_REJECTED",
|
|
5361
|
+
detail: "stdio pay requires maxAmount or a grant maxPerPayment; refusing to default the ceiling to the offer"
|
|
5362
|
+
});
|
|
5363
|
+
}
|
|
5316
5364
|
const spendIntent = {
|
|
5317
|
-
maxAmount
|
|
5365
|
+
maxAmount,
|
|
5318
5366
|
asset: resolved.value.binding.coinType,
|
|
5319
5367
|
...intent.recipient ? { recipient: intent.recipient } : {}
|
|
5320
5368
|
};
|
package/dist/http.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadBootProfile,
|
|
3
3
|
main
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EM7PKWVL.js";
|
|
5
5
|
import {
|
|
6
6
|
PACKAGE_NAME,
|
|
7
7
|
TOOLS,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
settlePreparedMcpPayment,
|
|
21
21
|
traceMcpHttpRequest,
|
|
22
22
|
verifySpendAccountPayReconstructs
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-26NKQ37M.js";
|
|
24
24
|
import "./chunk-A3JIIDYT.js";
|
|
25
25
|
export {
|
|
26
26
|
PACKAGE_NAME,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmdoss/suipay-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "SuiPay MCP — pay MPP-gated APIs from a spend-account grant with an agent-held delegate key.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
35
35
|
"@mysten/sui": "2.24.0",
|
|
36
36
|
"@noble/ed25519": "^2.1.0",
|
|
37
|
-
"@noble/hashes": "^
|
|
37
|
+
"@noble/hashes": "^2.3.0",
|
|
38
38
|
"open": "^11.0.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"tsup": "^8.0.0",
|
|
42
|
-
"typescript": "^
|
|
42
|
+
"typescript": "^6.0.3",
|
|
43
43
|
"vitest": "^3.0.0"
|
|
44
44
|
}
|
|
45
45
|
}
|