@aibtc/mcp-server 1.74.0 → 1.75.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.
|
@@ -126,6 +126,12 @@ export type PaymentTokenType = 'STX' | 'sBTC' | 'unsupported';
|
|
|
126
126
|
* @param asset - Full contract identifier or token name
|
|
127
127
|
*/
|
|
128
128
|
export declare function detectTokenType(asset: string): PaymentTokenType;
|
|
129
|
+
/**
|
|
130
|
+
* Memo for an x402 payment from the server's `extra.payment_id`, cut to the
|
|
131
|
+
* first 34 UTF-8 bytes (the Stacks memo limit) on a character boundary.
|
|
132
|
+
* Gateways that bind payments on the memo match that prefix.
|
|
133
|
+
*/
|
|
134
|
+
export declare function paymentIdMemo(extra?: Record<string, unknown>): string | undefined;
|
|
129
135
|
/**
|
|
130
136
|
* Best-effort display symbol for an asset. Servers advertise a friendly name in
|
|
131
137
|
* `extra.tokenType` (arc0btc sends "USDCx"); otherwise fall back to the contract
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
|
-
import { makeSTXTokenTransfer, makeContractCall, uintCV, principalCV, noneCV, Pc, PostConditionMode, } from "@stacks/transactions";
|
|
2
|
+
import { makeSTXTokenTransfer, makeContractCall, uintCV, principalCV, noneCV, someCV, bufferCVFromString, Pc, PostConditionMode, } from "@stacks/transactions";
|
|
3
3
|
import { decodePaymentRequired, encodePaymentPayload, generatePaymentId, buildPaymentIdentifierExtension, X402_HEADERS, } from "../utils/x402-protocol.js";
|
|
4
4
|
import { generateWallet, getStxAddress } from "@stacks/wallet-sdk";
|
|
5
5
|
import { NETWORK, API_URL, getStacksNetwork } from "../config/networks.js";
|
|
@@ -681,6 +681,7 @@ export async function createApiClient(baseUrl, options) {
|
|
|
681
681
|
// — this is the same tx shape the x402-stacks lib produces, and the
|
|
682
682
|
// balance check in onBeforePayment already accounts for the gas.
|
|
683
683
|
const networkName = getStacksNetwork(acct.network);
|
|
684
|
+
const memo = paymentIdMemo(selectedOption.extra);
|
|
684
685
|
let transaction;
|
|
685
686
|
if (tokenType === "sBTC") {
|
|
686
687
|
const contracts = getContracts(acct.network);
|
|
@@ -693,7 +694,7 @@ export async function createApiClient(baseUrl, options) {
|
|
|
693
694
|
uintCV(amount),
|
|
694
695
|
principalCV(acct.address),
|
|
695
696
|
principalCV(selectedOption.payTo),
|
|
696
|
-
noneCV(),
|
|
697
|
+
memo ? someCV(bufferCVFromString(memo)) : noneCV(),
|
|
697
698
|
],
|
|
698
699
|
senderKey: acct.privateKey,
|
|
699
700
|
network: networkName,
|
|
@@ -717,7 +718,7 @@ export async function createApiClient(baseUrl, options) {
|
|
|
717
718
|
amount,
|
|
718
719
|
senderKey: acct.privateKey,
|
|
719
720
|
network: networkName,
|
|
720
|
-
memo: "",
|
|
721
|
+
memo: memo ?? "",
|
|
721
722
|
fee: await resolveDefaultFee(acct.network, "token_transfer"),
|
|
722
723
|
});
|
|
723
724
|
}
|
|
@@ -813,6 +814,27 @@ export function detectTokenType(asset) {
|
|
|
813
814
|
}
|
|
814
815
|
return 'unsupported';
|
|
815
816
|
}
|
|
817
|
+
const STACKS_MEMO_MAX_BYTES = 34;
|
|
818
|
+
/**
|
|
819
|
+
* Memo for an x402 payment from the server's `extra.payment_id`, cut to the
|
|
820
|
+
* first 34 UTF-8 bytes (the Stacks memo limit) on a character boundary.
|
|
821
|
+
* Gateways that bind payments on the memo match that prefix.
|
|
822
|
+
*/
|
|
823
|
+
export function paymentIdMemo(extra) {
|
|
824
|
+
const id = extra?.payment_id;
|
|
825
|
+
if (typeof id !== "string" || id.length === 0)
|
|
826
|
+
return undefined;
|
|
827
|
+
let memo = "";
|
|
828
|
+
let bytes = 0;
|
|
829
|
+
for (const ch of id) {
|
|
830
|
+
const size = Buffer.byteLength(ch, "utf8");
|
|
831
|
+
if (bytes + size > STACKS_MEMO_MAX_BYTES)
|
|
832
|
+
break;
|
|
833
|
+
memo += ch;
|
|
834
|
+
bytes += size;
|
|
835
|
+
}
|
|
836
|
+
return memo;
|
|
837
|
+
}
|
|
816
838
|
/**
|
|
817
839
|
* Best-effort display symbol for an asset. Servers advertise a friendly name in
|
|
818
840
|
* `extra.tokenType` (arc0btc sends "USDCx"); otherwise fall back to the contract
|
|
@@ -7,9 +7,9 @@ import { createJsonResponse } from "../utils/index.js";
|
|
|
7
7
|
// was unstable: a burst of sends with an uninitialized local nonce could wedge
|
|
8
8
|
// the relay's sponsor queue (nonces stuck `held(gap)`), leaving payments
|
|
9
9
|
// accepted but messages undelivered (issue #540/#592). All inbox sends now go
|
|
10
|
-
// through send_inbox_message_direct, which
|
|
11
|
-
// transfer
|
|
12
|
-
//
|
|
10
|
+
// through send_inbox_message_direct, which is gasless: x402-stacks signs a
|
|
11
|
+
// sponsored transfer when the inbox advertises a fee payer, and the relay
|
|
12
|
+
// sponsors it in one step (aibtcdev/x402-sponsor-relay#436).
|
|
13
13
|
//
|
|
14
14
|
// This tool is retained only as a redirect so existing agents that still call
|
|
15
15
|
// send_inbox_message get pointed to the working tool instead of an
|
|
@@ -17,10 +17,8 @@ import { createJsonResponse } from "../utils/index.js";
|
|
|
17
17
|
// ============================================================================
|
|
18
18
|
export function registerInboxTools(server) {
|
|
19
19
|
server.registerTool("send_inbox_message", {
|
|
20
|
-
description: "⛔ DEPRECATED — do not use.
|
|
21
|
-
"
|
|
22
|
-
"through the x402 facilitator (no relay). Requires an unlocked wallet holding sBTC (message cost) " +
|
|
23
|
-
"and STX (gas). Mainnet only.",
|
|
20
|
+
description: "⛔ DEPRECATED — do not use. Use send_inbox_message_direct instead: it is gasless (the relay " +
|
|
21
|
+
"pays the STX gas), so you need only the sBTC message cost in an unlocked wallet. Mainnet only.",
|
|
24
22
|
inputSchema: z.object({
|
|
25
23
|
recipientBtcAddress: z
|
|
26
24
|
.string()
|
|
@@ -37,12 +35,10 @@ export function registerInboxTools(server) {
|
|
|
37
35
|
return createJsonResponse({
|
|
38
36
|
success: false,
|
|
39
37
|
deprecated: true,
|
|
40
|
-
error: "send_inbox_message has been removed.
|
|
41
|
-
"(payments could be accepted but never delivered when the relay's sponsor nonce " +
|
|
42
|
-
"queue wedged).",
|
|
38
|
+
error: "send_inbox_message has been removed.",
|
|
43
39
|
useInstead: "send_inbox_message_direct",
|
|
44
40
|
note: "Call send_inbox_message_direct with the same recipientBtcAddress, recipientStxAddress, " +
|
|
45
|
-
"and content. It
|
|
41
|
+
"and content. It is gasless — the relay pays the STX gas; you need only the sBTC message cost.",
|
|
46
42
|
});
|
|
47
43
|
});
|
|
48
44
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aibtc/mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.75.0",
|
|
4
4
|
"description": "Bitcoin-native MCP server for AI agents: BTC/STX wallets, DeFi yield, sBTC peg, NFTs, and x402 payments.",
|
|
5
5
|
"mcpName": "io.github.aibtcdev/mcp-server",
|
|
6
6
|
"type": "module",
|
package/skill/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Bitcoin L1 wallet for agents - check balances, send BTC, manage UTX
|
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
author: aibtcdev
|
|
7
|
-
version: 1.
|
|
7
|
+
version: 1.75.0 # x-release-please-version
|
|
8
8
|
npm: "@aibtc/mcp-server"
|
|
9
9
|
github: https://github.com/aibtcdev/aibtc-mcp-server
|
|
10
10
|
---
|
|
@@ -206,8 +206,9 @@ Always probe before executing paid endpoints. Never call `execute_x402_endpoint`
|
|
|
206
206
|
|
|
207
207
|
**send_inbox_message_direct** — dedicated tool for aibtc.com inbox messages:
|
|
208
208
|
- Parameters: `recipientBtcAddress` (bc1...), `recipientStxAddress` (SP...), `content` (max 500 chars)
|
|
209
|
-
-
|
|
210
|
-
-
|
|
209
|
+
- Gasless: the inbox advertises a fee payer, so the tool signs a sponsored sBTC transfer (fee 0) and the relay pays the STX gas
|
|
210
|
+
- Requires an unlocked wallet holding the sBTC message cost (100 sats) — no STX needed (mainnet only)
|
|
211
|
+
- One pending payment per sender: wait for the previous message's payment to confirm before sending the next
|
|
211
212
|
- Implements the full x402 v2 payment flow with a balance pre-check
|
|
212
213
|
- Note: the older sponsored `send_inbox_message` tool is deprecated and no longer sends — use this tool instead
|
|
213
214
|
|
|
@@ -115,15 +115,20 @@ send_inbox_message_direct({
|
|
|
115
115
|
})
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
pays
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
Inbox sends are **gasless**. The inbox's 402 advertises `extra.feePayer` (the relay's sponsor
|
|
119
|
+
address), so the x402-stacks interceptor signs a sponsored sBTC transfer with fee 0 and the relay
|
|
120
|
+
pays the STX gas. The wallet must be unlocked and hold the sBTC message cost (100 sats) — no STX
|
|
121
|
+
needed. Mainnet only. The tool runs a balance pre-check before signing. If the inbox ever stops
|
|
122
|
+
advertising `feePayer`, the same tool signs a standard transfer and the sender pays its own gas.
|
|
123
|
+
|
|
124
|
+
Sponsored sends follow a few rules (the inbox returns a clear error otherwise):
|
|
125
|
+
- **One pending payment per sender** — wait for the previous inbox payment to confirm (seconds)
|
|
126
|
+
before sending the next; a second one while it's pending gets `SENDER_NONCE_DUPLICATE` (409).
|
|
127
|
+
- **Up to 10 sponsored payments per sender per minute** (`RATE_LIMITED`, 429).
|
|
128
|
+
- **No messages to yourself** — a transfer to your own address fails on-chain, so it's refused.
|
|
129
|
+
|
|
130
|
+
> **Deprecated:** the older `send_inbox_message` tool no longer sends. It returns a message
|
|
131
|
+
> directing callers to `send_inbox_message_direct`, which is now the gasless path.
|
|
127
132
|
|
|
128
133
|
## More Information
|
|
129
134
|
|