crossmint-wallets-mcp 0.1.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/LICENSE +21 -0
- package/README.md +303 -0
- package/dist/core/client.d.ts +24 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +51 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/create-wallet.d.ts +17 -0
- package/dist/core/create-wallet.d.ts.map +1 -0
- package/dist/core/create-wallet.js +44 -0
- package/dist/core/create-wallet.js.map +1 -0
- package/dist/core/get-balance.d.ts +16 -0
- package/dist/core/get-balance.d.ts.map +1 -0
- package/dist/core/get-balance.js +31 -0
- package/dist/core/get-balance.js.map +1 -0
- package/dist/core/pay-x402-endpoint.d.ts +36 -0
- package/dist/core/pay-x402-endpoint.d.ts.map +1 -0
- package/dist/core/pay-x402-endpoint.js +189 -0
- package/dist/core/pay-x402-endpoint.js.map +1 -0
- package/dist/core/transfer-token.d.ts +20 -0
- package/dist/core/transfer-token.d.ts.map +1 -0
- package/dist/core/transfer-token.js +33 -0
- package/dist/core/transfer-token.js.map +1 -0
- package/dist/core/types.d.ts +46 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +6 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/errors.d.ts +23 -0
- package/dist/mcp/errors.d.ts.map +1 -0
- package/dist/mcp/errors.js +34 -0
- package/dist/mcp/errors.js.map +1 -0
- package/dist/mcp/server.d.ts +16 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +34 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +3 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +198 -0
- package/dist/mcp/tools.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { getConfig, getWalletsClient } from "./client.js";
|
|
2
|
+
import { getExplorerLink } from "./create-wallet.js";
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Chain / network mapping
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Maps x402 network identifiers (CAIP-2 or v1 shorthand) to the chain name
|
|
7
|
+
// that the Crossmint SDK's wallet uses. Only Solana mainnet is wired up in
|
|
8
|
+
// v0.1; EVM support is a stretch goal for later phases.
|
|
9
|
+
function resolveChain(network) {
|
|
10
|
+
const lower = network.toLowerCase();
|
|
11
|
+
if (lower === "solana" || lower.startsWith("solana:"))
|
|
12
|
+
return "solana";
|
|
13
|
+
if (lower === "base" || lower === "eip155:8453")
|
|
14
|
+
return "base";
|
|
15
|
+
if (lower === "base-sepolia" || lower === "eip155:84532")
|
|
16
|
+
return "base-sepolia";
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
// Map an asset identifier (mint address or symbol) to the Crossmint SDK's
|
|
20
|
+
// send() token argument. The SDK accepts either a mint address or a symbol
|
|
21
|
+
// like "usdc"; symbols are safer because the SDK resolves the network-
|
|
22
|
+
// correct mint internally.
|
|
23
|
+
function resolveTokenSymbol(asset) {
|
|
24
|
+
const USDC_MAINNET_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
25
|
+
if (asset === USDC_MAINNET_MINT)
|
|
26
|
+
return "usdc";
|
|
27
|
+
if (asset.toLowerCase() === "usdc")
|
|
28
|
+
return "usdc";
|
|
29
|
+
// Fall back to passing the mint/address through as-is
|
|
30
|
+
return asset;
|
|
31
|
+
}
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Amount conversion
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Atomic units → decimal string for a given number of decimals. The Crossmint
|
|
36
|
+
// SDK's send() method expects the amount in decimal units (e.g. "0.01" for
|
|
37
|
+
// 1¢ of USDC), not atomic units.
|
|
38
|
+
function atomicToDecimal(atomic, decimals) {
|
|
39
|
+
const n = BigInt(atomic);
|
|
40
|
+
const base = BigInt(10) ** BigInt(decimals);
|
|
41
|
+
const whole = n / base;
|
|
42
|
+
const frac = n % base;
|
|
43
|
+
if (frac === 0n)
|
|
44
|
+
return whole.toString();
|
|
45
|
+
const fracStr = frac.toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
46
|
+
return `${whole}.${fracStr}`;
|
|
47
|
+
}
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Main entry point
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
/**
|
|
52
|
+
* Pay an x402-protected HTTP endpoint using a Crossmint smart wallet.
|
|
53
|
+
*
|
|
54
|
+
* Flow:
|
|
55
|
+
* 1. Fetch `url` with the caller's original headers/body
|
|
56
|
+
* 2. If the server responds 200, return directly — nothing to pay
|
|
57
|
+
* 3. If the server responds 402, parse the PaymentRequired body and pick
|
|
58
|
+
* the first PaymentRequirements entry on a supported chain (Solana
|
|
59
|
+
* mainnet in v0.1)
|
|
60
|
+
* 4. Load the payer wallet via `wallets.getWallet(payerAddress, ...)`,
|
|
61
|
+
* passing the server recovery signer through the args so the
|
|
62
|
+
* returned Wallet has its `#recovery` field populated. Without this,
|
|
63
|
+
* the SDK's useSigner path crashes because `isRecoverySigner` tries
|
|
64
|
+
* to call `.startsWith` on an undefined secret (chunk-XNZLCUTY:395).
|
|
65
|
+
* The WalletArgsFor TypeScript type doesn't declare a `recovery`
|
|
66
|
+
* field, but the runtime `createWalletInstance` reads it when
|
|
67
|
+
* present, so we pass it via an explicit cast.
|
|
68
|
+
* 5. Call `wallet.send(payTo, tokenSymbol, decimalAmount)` — Crossmint
|
|
69
|
+
* handles the CPI inner instruction wrapping, signing via the server
|
|
70
|
+
* recovery signer, fee payment, and confirmation internally
|
|
71
|
+
* 6. Build the X-PAYMENT header as base64(JSON(PaymentPayload)) with the
|
|
72
|
+
* resulting transaction signature in the payload
|
|
73
|
+
* 7. Retry the original request with the X-PAYMENT header appended
|
|
74
|
+
* 8. Return the response body plus the on-chain tx signature
|
|
75
|
+
*/
|
|
76
|
+
export async function payX402Endpoint(opts) {
|
|
77
|
+
const { url, payerAddress, chain, headers = {}, method = "GET", jsonBody, maxUsdcAtomic, } = opts;
|
|
78
|
+
// -----------------------------------------------------------------------
|
|
79
|
+
// Step 1: initial request — expect 402
|
|
80
|
+
// -----------------------------------------------------------------------
|
|
81
|
+
const initialResponse = await fetchWith(url, method, headers, jsonBody);
|
|
82
|
+
if (initialResponse.status !== 402) {
|
|
83
|
+
if (initialResponse.status >= 200 && initialResponse.status < 300) {
|
|
84
|
+
return {
|
|
85
|
+
url,
|
|
86
|
+
transactionSignature: "",
|
|
87
|
+
responseStatus: initialResponse.status,
|
|
88
|
+
responseBody: await safeJson(initialResponse),
|
|
89
|
+
explorerLink: "",
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
throw new Error(`Expected 200 or 402 on initial request, got ${initialResponse.status}`);
|
|
93
|
+
}
|
|
94
|
+
// -----------------------------------------------------------------------
|
|
95
|
+
// Step 2: parse the PaymentRequired body
|
|
96
|
+
// -----------------------------------------------------------------------
|
|
97
|
+
const paymentRequired = (await initialResponse.json());
|
|
98
|
+
if (!paymentRequired.accepts?.length) {
|
|
99
|
+
throw new Error("402 response has no accepts[] entries");
|
|
100
|
+
}
|
|
101
|
+
// Pick the first requirement whose network we support
|
|
102
|
+
const requirement = paymentRequired.accepts.find((r) => resolveChain(r.network) !== null);
|
|
103
|
+
if (!requirement) {
|
|
104
|
+
const offered = paymentRequired.accepts.map((r) => r.network).join(", ");
|
|
105
|
+
throw new Error(`No supported payment network in 402 response. Offered: [${offered}]. ` +
|
|
106
|
+
`Supported: solana (mainnet).`);
|
|
107
|
+
}
|
|
108
|
+
const resolvedChain = resolveChain(requirement.network);
|
|
109
|
+
if (resolvedChain !== chain) {
|
|
110
|
+
throw new Error(`402 requires payment on ${resolvedChain} but caller chain is ${chain}`);
|
|
111
|
+
}
|
|
112
|
+
// Enforce max payment guardrail
|
|
113
|
+
const amountAtomic = BigInt(requirement.amount);
|
|
114
|
+
if (maxUsdcAtomic != null && amountAtomic > maxUsdcAtomic) {
|
|
115
|
+
throw new Error(`402 requires ${amountAtomic} atomic units but maxUsdcAtomic=${maxUsdcAtomic}`);
|
|
116
|
+
}
|
|
117
|
+
// -----------------------------------------------------------------------
|
|
118
|
+
// Step 3: pay via wallet.send()
|
|
119
|
+
// -----------------------------------------------------------------------
|
|
120
|
+
// getWallet(locator, args) loads an existing wallet by address. The
|
|
121
|
+
// WalletArgsFor type omits `recovery`, but the runtime
|
|
122
|
+
// `createWalletInstance` reads it if present — we use that so the
|
|
123
|
+
// returned Wallet has its recovery field populated with the secret,
|
|
124
|
+
// enabling the auto-assembled signer path to succeed without a separate
|
|
125
|
+
// useSigner call.
|
|
126
|
+
const { recoverySecret } = getConfig();
|
|
127
|
+
const wallets = getWalletsClient();
|
|
128
|
+
const wallet = await wallets.getWallet(payerAddress, {
|
|
129
|
+
chain,
|
|
130
|
+
recovery: { type: "server", secret: recoverySecret },
|
|
131
|
+
});
|
|
132
|
+
const tokenSymbol = resolveTokenSymbol(requirement.asset);
|
|
133
|
+
const decimals = typeof requirement.extra?.decimals === "number"
|
|
134
|
+
? requirement.extra.decimals
|
|
135
|
+
: 6; // USDC default
|
|
136
|
+
const decimalAmount = atomicToDecimal(requirement.amount, decimals);
|
|
137
|
+
console.error(`[payX402Endpoint] paying ${decimalAmount} ${tokenSymbol} to ${requirement.payTo} on ${chain}...`);
|
|
138
|
+
const txResult = await wallet.send(requirement.payTo, tokenSymbol, decimalAmount);
|
|
139
|
+
console.error(`[payX402Endpoint] tx confirmed: ${txResult.hash}`);
|
|
140
|
+
// -----------------------------------------------------------------------
|
|
141
|
+
// Step 4: build X-PAYMENT header + retry
|
|
142
|
+
// -----------------------------------------------------------------------
|
|
143
|
+
const paymentPayload = {
|
|
144
|
+
x402Version: paymentRequired.x402Version,
|
|
145
|
+
accepted: requirement,
|
|
146
|
+
payload: {
|
|
147
|
+
transactionSignature: txResult.hash,
|
|
148
|
+
// Also include under "signature" for compatibility with facilitators
|
|
149
|
+
// that use that field name
|
|
150
|
+
signature: txResult.hash,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
const paymentHeader = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
|
|
154
|
+
const paidResponse = await fetchWith(url, method, { ...headers, "X-PAYMENT": paymentHeader }, jsonBody);
|
|
155
|
+
if (paidResponse.status < 200 || paidResponse.status >= 300) {
|
|
156
|
+
const body = await safeJson(paidResponse);
|
|
157
|
+
throw new Error(`Paid but endpoint returned ${paidResponse.status}: ${JSON.stringify(body)}`);
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
url,
|
|
161
|
+
transactionSignature: txResult.hash,
|
|
162
|
+
responseStatus: paidResponse.status,
|
|
163
|
+
responseBody: await safeJson(paidResponse),
|
|
164
|
+
explorerLink: txResult.explorerLink || getExplorerLink(txResult.hash, chain),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
// Helpers
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
async function fetchWith(url, method, headers, jsonBody) {
|
|
171
|
+
const init = { method, headers: { ...headers } };
|
|
172
|
+
if (jsonBody !== undefined && method !== "GET" && method !== "HEAD") {
|
|
173
|
+
init.body = JSON.stringify(jsonBody);
|
|
174
|
+
init.headers["Content-Type"] = "application/json";
|
|
175
|
+
}
|
|
176
|
+
return fetch(url, init);
|
|
177
|
+
}
|
|
178
|
+
async function safeJson(res) {
|
|
179
|
+
const text = await res.text();
|
|
180
|
+
if (!text)
|
|
181
|
+
return null;
|
|
182
|
+
try {
|
|
183
|
+
return JSON.parse(text);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return text;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=pay-x402-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pay-x402-endpoint.js","sourceRoot":"","sources":["../../src/core/pay-x402-endpoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Chain, TransferResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Transfer a token from a Crossmint smart wallet to any recipient address
|
|
4
|
+
* or user locator. This is the general-purpose sibling of payX402Endpoint:
|
|
5
|
+
* same `wallet.send()` primitive underneath, same getWallet + recovery-cast
|
|
6
|
+
* pattern to work around the SDK 1.0.7 useSigner crash, but with no 402
|
|
7
|
+
* protocol handling — just the raw transfer.
|
|
8
|
+
*
|
|
9
|
+
* `token` accepts either a token symbol the SDK recognizes (e.g. "usdc",
|
|
10
|
+
* "sol", "eth") or a raw mint/contract address. `amount` is a decimal
|
|
11
|
+
* string in human units (e.g. "0.01" for 0.01 USDC), not atomic units.
|
|
12
|
+
*/
|
|
13
|
+
export declare function transferToken(opts: {
|
|
14
|
+
payerAddress: string;
|
|
15
|
+
chain: Chain;
|
|
16
|
+
to: string;
|
|
17
|
+
token: string;
|
|
18
|
+
amount: string;
|
|
19
|
+
}): Promise<TransferResult>;
|
|
20
|
+
//# sourceMappingURL=transfer-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transfer-token.d.ts","sourceRoot":"","sources":["../../src/core/transfer-token.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGxD;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,cAAc,CAAC,CAqB1B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getConfig, getWalletsClient } from "./client.js";
|
|
2
|
+
import { getExplorerLink } from "./create-wallet.js";
|
|
3
|
+
/**
|
|
4
|
+
* Transfer a token from a Crossmint smart wallet to any recipient address
|
|
5
|
+
* or user locator. This is the general-purpose sibling of payX402Endpoint:
|
|
6
|
+
* same `wallet.send()` primitive underneath, same getWallet + recovery-cast
|
|
7
|
+
* pattern to work around the SDK 1.0.7 useSigner crash, but with no 402
|
|
8
|
+
* protocol handling — just the raw transfer.
|
|
9
|
+
*
|
|
10
|
+
* `token` accepts either a token symbol the SDK recognizes (e.g. "usdc",
|
|
11
|
+
* "sol", "eth") or a raw mint/contract address. `amount` is a decimal
|
|
12
|
+
* string in human units (e.g. "0.01" for 0.01 USDC), not atomic units.
|
|
13
|
+
*/
|
|
14
|
+
export async function transferToken(opts) {
|
|
15
|
+
const { payerAddress, chain, to, token, amount } = opts;
|
|
16
|
+
const { recoverySecret } = getConfig();
|
|
17
|
+
const wallets = getWalletsClient();
|
|
18
|
+
const wallet = await wallets.getWallet(payerAddress, {
|
|
19
|
+
chain,
|
|
20
|
+
recovery: { type: "server", secret: recoverySecret },
|
|
21
|
+
});
|
|
22
|
+
const tx = await wallet.send(to, token, amount);
|
|
23
|
+
return {
|
|
24
|
+
chain,
|
|
25
|
+
from: payerAddress,
|
|
26
|
+
to,
|
|
27
|
+
token,
|
|
28
|
+
amount,
|
|
29
|
+
transactionSignature: tx.hash,
|
|
30
|
+
explorerLink: tx.explorerLink || getExplorerLink(tx.hash, chain),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=transfer-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transfer-token.js","sourceRoot":"","sources":["../../src/core/transfer-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAMnC;IACC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAExD,MAAM,EAAE,cAAc,EAAE,GAAG,SAAS,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,YAAY,EAAE;QACnD,KAAK;QACL,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE;KACQ,CAAC,CAAC;IAEhE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAEhD,OAAO;QACL,KAAK;QACL,IAAI,EAAE,YAAY;QAClB,EAAE;QACF,KAAK;QACL,MAAM;QACN,oBAAoB,EAAE,EAAE,CAAC,IAAI;QAC7B,YAAY,EAAE,EAAE,CAAC,YAAY,IAAI,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC;KACjE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the core layer. Kept deliberately narrow so the MCP tool
|
|
3
|
+
* schemas (src/mcp/tools.ts) can mirror them without drift.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Chain literals we expose on the MCP surface. These must be a subset of
|
|
7
|
+
* `@crossmint/wallets-sdk`'s `Chain` type. Note that the SDK does NOT expose
|
|
8
|
+
* a `"solana-devnet"` literal — Solana testnet/devnet is selected by the
|
|
9
|
+
* Crossmint API key environment (staging key → devnet, production key →
|
|
10
|
+
* mainnet), not by a separate chain name. EVM chains DO have explicit
|
|
11
|
+
* testnet literals (e.g. "base-sepolia").
|
|
12
|
+
*/
|
|
13
|
+
export type Chain = "solana" | "base" | "base-sepolia";
|
|
14
|
+
export interface CreateWalletResult {
|
|
15
|
+
owner: string | null;
|
|
16
|
+
chain: Chain;
|
|
17
|
+
address: string;
|
|
18
|
+
explorerLink: string;
|
|
19
|
+
}
|
|
20
|
+
export interface TokenBalance {
|
|
21
|
+
symbol: string;
|
|
22
|
+
amount: string;
|
|
23
|
+
decimals: number;
|
|
24
|
+
}
|
|
25
|
+
export interface BalanceResult {
|
|
26
|
+
address: string;
|
|
27
|
+
chain: Chain;
|
|
28
|
+
balances: TokenBalance[];
|
|
29
|
+
}
|
|
30
|
+
export interface TransferResult {
|
|
31
|
+
chain: Chain;
|
|
32
|
+
from: string;
|
|
33
|
+
to: string;
|
|
34
|
+
token: string;
|
|
35
|
+
amount: string;
|
|
36
|
+
transactionSignature: string;
|
|
37
|
+
explorerLink: string;
|
|
38
|
+
}
|
|
39
|
+
export interface PayX402Result {
|
|
40
|
+
url: string;
|
|
41
|
+
transactionSignature: string;
|
|
42
|
+
responseStatus: number;
|
|
43
|
+
responseBody: unknown;
|
|
44
|
+
explorerLink: string;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;GAOG;AACH,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,cAAc,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,oBAAoB,EAAE,MAAM,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Library entry point. Re-exports the core primitives so consumers can import
|
|
3
|
+
* from `crossmint-wallets-mcp` directly without reaching into `src/core/`.
|
|
4
|
+
*
|
|
5
|
+
* The MCP server entry point lives at `src/mcp/server.ts` (see the `bin`
|
|
6
|
+
* field in package.json).
|
|
7
|
+
*/
|
|
8
|
+
export { createWallet, getExplorerLink } from "./core/create-wallet.js";
|
|
9
|
+
export { getBalance } from "./core/get-balance.js";
|
|
10
|
+
export { transferToken } from "./core/transfer-token.js";
|
|
11
|
+
export { payX402Endpoint } from "./core/pay-x402-endpoint.js";
|
|
12
|
+
export { getConfig, getWalletsClient, resetConfigCache } from "./core/client.js";
|
|
13
|
+
export type { Chain, CreateWalletResult, BalanceResult, TokenBalance, TransferResult, PayX402Result, } from "./core/types.js";
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACjF,YAAY,EACV,KAAK,EACL,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,cAAc,EACd,aAAa,GACd,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Library entry point. Re-exports the core primitives so consumers can import
|
|
3
|
+
* from `crossmint-wallets-mcp` directly without reaching into `src/core/`.
|
|
4
|
+
*
|
|
5
|
+
* The MCP server entry point lives at `src/mcp/server.ts` (see the `bin`
|
|
6
|
+
* field in package.json).
|
|
7
|
+
*/
|
|
8
|
+
export { createWallet, getExplorerLink } from "./core/create-wallet.js";
|
|
9
|
+
export { getBalance } from "./core/get-balance.js";
|
|
10
|
+
export { transferToken } from "./core/transfer-token.js";
|
|
11
|
+
export { payX402Endpoint } from "./core/pay-x402-endpoint.js";
|
|
12
|
+
export { getConfig, getWalletsClient, resetConfigCache } from "./core/client.js";
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standardized error shapes for MCP tool responses.
|
|
3
|
+
*
|
|
4
|
+
* The MCP protocol represents tool failures via `isError: true` plus a
|
|
5
|
+
* human-readable `content` block. We wrap errors in a consistent shape so
|
|
6
|
+
* that clients can display them uniformly and so that smoke tests can match
|
|
7
|
+
* on `error_code` without parsing free-form strings.
|
|
8
|
+
*/
|
|
9
|
+
export type CrossmintMcpErrorCode = "CONFIG_MISSING" | "WALLET_NOT_FOUND" | "INSUFFICIENT_BALANCE" | "X402_CHALLENGE_FAILED" | "X402_PAYMENT_REJECTED" | "SDK_ERROR" | "NETWORK_ERROR" | "VALIDATION_ERROR" | "UNKNOWN";
|
|
10
|
+
export interface CrossmintMcpErrorPayload {
|
|
11
|
+
error_code: CrossmintMcpErrorCode;
|
|
12
|
+
message: string;
|
|
13
|
+
hint?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function toolErrorResponse(code: CrossmintMcpErrorCode, message: string, hint?: string): {
|
|
16
|
+
isError: true;
|
|
17
|
+
content: Array<{
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
export declare function classifyError(err: unknown): CrossmintMcpErrorCode;
|
|
23
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/mcp/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,qBAAqB,GAC7B,gBAAgB,GAChB,kBAAkB,GAClB,sBAAsB,GACtB,uBAAuB,GACvB,uBAAuB,GACvB,WAAW,GACX,eAAe,GACf,kBAAkB,GAClB,SAAS,CAAC;AAEd,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,qBAAqB,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,qBAAqB,EAC3B,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,GACZ;IACD,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD,CAOA;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,qBAAqB,CAWjE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standardized error shapes for MCP tool responses.
|
|
3
|
+
*
|
|
4
|
+
* The MCP protocol represents tool failures via `isError: true` plus a
|
|
5
|
+
* human-readable `content` block. We wrap errors in a consistent shape so
|
|
6
|
+
* that clients can display them uniformly and so that smoke tests can match
|
|
7
|
+
* on `error_code` without parsing free-form strings.
|
|
8
|
+
*/
|
|
9
|
+
export function toolErrorResponse(code, message, hint) {
|
|
10
|
+
const payload = { error_code: code, message };
|
|
11
|
+
if (hint)
|
|
12
|
+
payload.hint = hint;
|
|
13
|
+
return {
|
|
14
|
+
isError: true,
|
|
15
|
+
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function classifyError(err) {
|
|
19
|
+
if (!(err instanceof Error))
|
|
20
|
+
return "UNKNOWN";
|
|
21
|
+
const msg = err.message.toLowerCase();
|
|
22
|
+
if (msg.includes("env var") || msg.includes("required"))
|
|
23
|
+
return "CONFIG_MISSING";
|
|
24
|
+
if (msg.includes("not found") || msg.includes("does not exist"))
|
|
25
|
+
return "WALLET_NOT_FOUND";
|
|
26
|
+
if (msg.includes("insufficient"))
|
|
27
|
+
return "INSUFFICIENT_BALANCE";
|
|
28
|
+
if (msg.includes("402") || msg.includes("x-payment"))
|
|
29
|
+
return "X402_CHALLENGE_FAILED";
|
|
30
|
+
if (msg.includes("fetch") || msg.includes("network") || msg.includes("econn"))
|
|
31
|
+
return "NETWORK_ERROR";
|
|
32
|
+
return "SDK_ERROR";
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/mcp/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAmBH,MAAM,UAAU,iBAAiB,CAC/B,IAA2B,EAC3B,OAAe,EACf,IAAa;IAKb,MAAM,OAAO,GAA6B,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACxE,IAAI,IAAI;QAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAC9B,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACpE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,IAAI,CAAC,CAAC,GAAG,YAAY,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACtC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,gBAAgB,CAAC;IACjF,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAC7D,OAAO,kBAAkB,CAAC;IAC5B,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC;QAAE,OAAO,sBAAsB,CAAC;IAChE,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,uBAAuB,CAAC;IACrF,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC3E,OAAO,eAAe,CAAC;IACzB,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Crossmint Wallets MCP server — stdio transport entry point.
|
|
4
|
+
*
|
|
5
|
+
* IMPORTANT: this process uses stdout as the JSON-RPC transport channel.
|
|
6
|
+
* All human-readable logging MUST go to stderr via `console.error(...)`.
|
|
7
|
+
* Never `console.log` or `process.stdout.write` from anywhere in this
|
|
8
|
+
* server — the MCP client will treat it as malformed protocol traffic.
|
|
9
|
+
*
|
|
10
|
+
* Populated incrementally:
|
|
11
|
+
* - Phase 2B (this file): minimal server that registers zero tools and
|
|
12
|
+
* connects the stdio transport. Proves the pipeline works.
|
|
13
|
+
* - Phase 2E: real tool registration via `registerTools` in ./tools.ts.
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Crossmint Wallets MCP server — stdio transport entry point.
|
|
4
|
+
*
|
|
5
|
+
* IMPORTANT: this process uses stdout as the JSON-RPC transport channel.
|
|
6
|
+
* All human-readable logging MUST go to stderr via `console.error(...)`.
|
|
7
|
+
* Never `console.log` or `process.stdout.write` from anywhere in this
|
|
8
|
+
* server — the MCP client will treat it as malformed protocol traffic.
|
|
9
|
+
*
|
|
10
|
+
* Populated incrementally:
|
|
11
|
+
* - Phase 2B (this file): minimal server that registers zero tools and
|
|
12
|
+
* connects the stdio transport. Proves the pipeline works.
|
|
13
|
+
* - Phase 2E: real tool registration via `registerTools` in ./tools.ts.
|
|
14
|
+
*/
|
|
15
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
16
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
17
|
+
import { registerTools } from "./tools.js";
|
|
18
|
+
const SERVER_NAME = "crossmint-wallets-mcp";
|
|
19
|
+
const SERVER_VERSION = "0.1.0";
|
|
20
|
+
async function main() {
|
|
21
|
+
const server = new McpServer({
|
|
22
|
+
name: SERVER_NAME,
|
|
23
|
+
version: SERVER_VERSION,
|
|
24
|
+
});
|
|
25
|
+
registerTools(server);
|
|
26
|
+
const transport = new StdioServerTransport();
|
|
27
|
+
await server.connect(transport);
|
|
28
|
+
console.error(`[${SERVER_NAME}] v${SERVER_VERSION} connected via stdio transport`);
|
|
29
|
+
}
|
|
30
|
+
main().catch((err) => {
|
|
31
|
+
console.error(`[${SERVER_NAME}] fatal:`, err);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAC5C,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAC;IAEH,aAAa,CAAC,MAAM,CAAC,CAAC;IAEtB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,OAAO,CAAC,KAAK,CACX,IAAI,WAAW,MAAM,cAAc,gCAAgC,CACpE,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,IAAI,WAAW,UAAU,EAAE,GAAG,CAAC,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0CzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwMrD"}
|