@cmdoss/suipay-mcp 0.2.2-dev.1 → 0.2.2-dev.3
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
|
@@ -76,8 +76,13 @@ json: {"prompt":"a cat"}
|
|
|
76
76
|
maxAmount: 50000
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
`pay` uses SDK `createPayer` internally. A
|
|
80
|
-
|
|
79
|
+
`pay` uses SDK `createPayer` internally. A binary body is written once under
|
|
80
|
+
`~/.suipay/deliveries/` and named first in the JSON as `savedTo` (absolute
|
|
81
|
+
path) and `savedToUrl` (`file://`). Any MIME — image, audio, pdf,
|
|
82
|
+
octet-stream. JSON stays compact (no base64 wall). An MCP `image` block is an
|
|
83
|
+
extra display hint when the type is `image/*`; hosts such as Claude Code's
|
|
84
|
+
TUI may not render it. Always quote `savedTo` to the user. Do not call `pay`
|
|
85
|
+
again to "save" a delivery that already settled.
|
|
81
86
|
|
|
82
87
|
## Targets
|
|
83
88
|
|
package/dist/bin/suipay.js
CHANGED
|
@@ -6872,6 +6872,52 @@ function joinDiscoverCatalog(opts) {
|
|
|
6872
6872
|
return scoped ? { accessMode: "scoped", count: services.length, services, allowedTargetHashes } : { accessMode: "open", count: services.length, services };
|
|
6873
6873
|
}
|
|
6874
6874
|
|
|
6875
|
+
// src/tool-result.ts
|
|
6876
|
+
import { pathToFileURL } from "url";
|
|
6877
|
+
|
|
6878
|
+
// src/delivery-file.ts
|
|
6879
|
+
import { mkdirSync as mkdirSync2, writeFileSync, chmodSync as chmodSync2 } from "fs";
|
|
6880
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
6881
|
+
function mcpDeliveriesDir() {
|
|
6882
|
+
return join3(dirname2(mcpCredentialsPath()), "deliveries");
|
|
6883
|
+
}
|
|
6884
|
+
var EXT = {
|
|
6885
|
+
"image/png": ".png",
|
|
6886
|
+
"image/jpeg": ".jpg",
|
|
6887
|
+
"image/jpg": ".jpg",
|
|
6888
|
+
"image/webp": ".webp",
|
|
6889
|
+
"image/gif": ".gif",
|
|
6890
|
+
"image/svg+xml": ".svg",
|
|
6891
|
+
"audio/mpeg": ".mp3",
|
|
6892
|
+
"audio/wav": ".wav",
|
|
6893
|
+
"audio/ogg": ".ogg",
|
|
6894
|
+
"video/mp4": ".mp4",
|
|
6895
|
+
"application/pdf": ".pdf",
|
|
6896
|
+
"application/json": ".json",
|
|
6897
|
+
"text/plain": ".txt"
|
|
6898
|
+
};
|
|
6899
|
+
function extensionFor(contentType) {
|
|
6900
|
+
const type = contentType.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
6901
|
+
return EXT[type] ?? ".bin";
|
|
6902
|
+
}
|
|
6903
|
+
function fileStem(digest, challengeId) {
|
|
6904
|
+
const raw = (digest ?? challengeId ?? `delivery-${Date.now()}`).trim();
|
|
6905
|
+
const safe = raw.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
6906
|
+
return (safe.slice(0, 80) || `delivery-${Date.now()}`).replace(/^\.+$/, "delivery");
|
|
6907
|
+
}
|
|
6908
|
+
function saveDeliveredBody(input) {
|
|
6909
|
+
if (input.bytes.byteLength === 0) return void 0;
|
|
6910
|
+
const dir = mcpDeliveriesDir();
|
|
6911
|
+
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
6912
|
+
const path = join3(
|
|
6913
|
+
dir,
|
|
6914
|
+
`${fileStem(input.digest, input.challengeId)}${extensionFor(input.contentType)}`
|
|
6915
|
+
);
|
|
6916
|
+
writeFileSync(path, input.bytes, { mode: 384 });
|
|
6917
|
+
chmodSync2(path, 384);
|
|
6918
|
+
return path;
|
|
6919
|
+
}
|
|
6920
|
+
|
|
6875
6921
|
// src/tool-result.ts
|
|
6876
6922
|
var MAX_MCP_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
6877
6923
|
function text(value) {
|
|
@@ -6893,6 +6939,11 @@ function closedError(code, detail) {
|
|
|
6893
6939
|
function closedPayError(code, detail) {
|
|
6894
6940
|
return error({ status: "failed", paid: false, code, detail });
|
|
6895
6941
|
}
|
|
6942
|
+
function receiptChallengeId(receipt) {
|
|
6943
|
+
if (!receipt || typeof receipt !== "object") return void 0;
|
|
6944
|
+
const id = receipt.challengeId;
|
|
6945
|
+
return typeof id === "string" && id.length > 0 ? id : void 0;
|
|
6946
|
+
}
|
|
6896
6947
|
function paidResult(result) {
|
|
6897
6948
|
if (!isBinaryBody(result.body)) return text(result);
|
|
6898
6949
|
const body = result.body;
|
|
@@ -6901,8 +6952,28 @@ function paidResult(result) {
|
|
|
6901
6952
|
contentType: body.contentType,
|
|
6902
6953
|
byteLength: body.byteLength
|
|
6903
6954
|
};
|
|
6955
|
+
let savedTo;
|
|
6956
|
+
try {
|
|
6957
|
+
savedTo = saveDeliveredBody({
|
|
6958
|
+
bytes: body.bytes,
|
|
6959
|
+
contentType: body.contentType,
|
|
6960
|
+
digest: result.txDigest,
|
|
6961
|
+
challengeId: receiptChallengeId(result.receipt)
|
|
6962
|
+
});
|
|
6963
|
+
} catch {
|
|
6964
|
+
savedTo = void 0;
|
|
6965
|
+
}
|
|
6966
|
+
const payload = savedTo ? {
|
|
6967
|
+
savedTo,
|
|
6968
|
+
savedToUrl: pathToFileURL(savedTo).href,
|
|
6969
|
+
...result,
|
|
6970
|
+
body: shape
|
|
6971
|
+
} : { ...result, body: shape };
|
|
6904
6972
|
const content = [
|
|
6905
|
-
{
|
|
6973
|
+
{
|
|
6974
|
+
type: "text",
|
|
6975
|
+
text: JSON.stringify(payload, null, 2)
|
|
6976
|
+
}
|
|
6906
6977
|
];
|
|
6907
6978
|
if (body.contentType.startsWith("image/") && body.bytes.byteLength > 0 && body.bytes.byteLength <= MAX_MCP_IMAGE_BYTES) {
|
|
6908
6979
|
content.push({
|
|
@@ -7526,7 +7597,7 @@ var TOOLS = [
|
|
|
7526
7597
|
},
|
|
7527
7598
|
{
|
|
7528
7599
|
name: "pay",
|
|
7529
|
-
description: "Pay a HTTP resource via delegate. On hosted /mcp the gateway PREPARES an unsigned transaction and returns it (prepare-only \u2014 it never holds the delegate key and cannot settle). Only a process holding the delegate key the grant names can complete settlement (e.g. local stdio MCP, or any self-hosted process with the matching key). Pass recipient and/or maxAmount to state who you intend to pay and what you will spend; both are checked before anything is signed or handed back. Local V1 allowance pay is retired.",
|
|
7600
|
+
description: "Pay a HTTP resource via delegate. On hosted /mcp the gateway PREPARES an unsigned transaction and returns it (prepare-only \u2014 it never holds the delegate key and cannot settle). Only a process holding the delegate key the grant names can complete settlement (e.g. local stdio MCP, or any self-hosted process with the matching key). Pass recipient and/or maxAmount to state who you intend to pay and what you will spend; both are checked before anything is signed or handed back. Local V1 allowance pay is retired. A paid binary body is written under ~/.suipay/deliveries/ and named as savedTo (absolute path) and savedToUrl (file://) at the top of the JSON. Always quote savedTo to the user so they can open the file. Do not assume the host rendered an image block. Never call pay again to display or save a delivery that already settled.",
|
|
7530
7601
|
inputSchema: {
|
|
7531
7602
|
type: "object",
|
|
7532
7603
|
properties: {
|
package/dist/http.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -340,11 +340,6 @@ interface StartedStdioLogin {
|
|
|
340
340
|
*/
|
|
341
341
|
declare function startStdioLogin(opts: StdioLoginOptions): Promise<StartedStdioLogin>;
|
|
342
342
|
|
|
343
|
-
/**
|
|
344
|
-
* MCP tool payloads. Settlement honesty matches the playground stamp:
|
|
345
|
-
* money that moved is never reported as a tool error (that invites a second pay).
|
|
346
|
-
*/
|
|
347
|
-
|
|
348
343
|
type ToolResult = CallToolResult;
|
|
349
344
|
|
|
350
345
|
interface ToolDeps {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadBootProfile,
|
|
3
3
|
main
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-C2IYSV43.js";
|
|
5
5
|
import {
|
|
6
6
|
MCP_TARGET_PRESETS,
|
|
7
7
|
PACKAGE_NAME,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
settlePreparedMcpPayment,
|
|
27
27
|
traceMcpHttpRequest,
|
|
28
28
|
verifySpendAccountPayReconstructs
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-SRMAH6MK.js";
|
|
30
30
|
export {
|
|
31
31
|
MCP_TARGET_PRESETS,
|
|
32
32
|
PACKAGE_NAME,
|
package/package.json
CHANGED