@t402/mcp 1.0.0 → 2.4.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
@@ -13,20 +13,21 @@ Enable AI agents like Claude to make stablecoin payments across multiple blockch
13
13
 
14
14
  ## Available Tools
15
15
 
16
- | Tool | Description |
17
- |------|-------------|
18
- | `t402/getBalance` | Get token balances for a wallet on a specific network |
19
- | `t402/getAllBalances` | Get balances across all supported networks |
20
- | `t402/pay` | Execute a stablecoin payment |
21
- | `t402/payGasless` | Execute a gasless payment using ERC-4337 |
22
- | `t402/getBridgeFee` | Get fee quote for bridging USDT0 |
23
- | `t402/bridge` | Bridge USDT0 between chains |
16
+ | Tool | Description |
17
+ | --------------------- | ----------------------------------------------------- |
18
+ | `t402/getBalance` | Get token balances for a wallet on a specific network |
19
+ | `t402/getAllBalances` | Get balances across all supported networks |
20
+ | `t402/pay` | Execute a stablecoin payment |
21
+ | `t402/payGasless` | Execute a gasless payment using ERC-4337 |
22
+ | `t402/getBridgeFee` | Get fee quote for bridging USDT0 |
23
+ | `t402/bridge` | Bridge USDT0 between chains |
24
24
 
25
25
  ## Claude Desktop Integration
26
26
 
27
27
  ### Quick Start
28
28
 
29
29
  1. Install the package globally:
30
+
30
31
  ```bash
31
32
  npm install -g @t402/mcp
32
33
  ```
@@ -132,39 +133,40 @@ Configure custom RPC endpoints for better reliability:
132
133
 
133
134
  ## Environment Variables
134
135
 
135
- | Variable | Description |
136
- |----------|-------------|
137
- | `T402_PRIVATE_KEY` | Wallet private key (hex with 0x prefix) |
138
- | `T402_DEMO_MODE` | Set to "true" for simulated transactions |
139
- | `T402_BUNDLER_URL` | ERC-4337 bundler URL for gasless transactions |
140
- | `T402_PAYMASTER_URL` | Paymaster URL for sponsored gas |
141
- | `T402_RPC_ETHEREUM` | Custom RPC URL for Ethereum |
142
- | `T402_RPC_BASE` | Custom RPC URL for Base |
143
- | `T402_RPC_ARBITRUM` | Custom RPC URL for Arbitrum |
144
- | `T402_RPC_OPTIMISM` | Custom RPC URL for Optimism |
145
- | `T402_RPC_POLYGON` | Custom RPC URL for Polygon |
146
- | `T402_RPC_AVALANCHE` | Custom RPC URL for Avalanche |
147
- | `T402_RPC_INK` | Custom RPC URL for Ink |
148
- | `T402_RPC_BERACHAIN` | Custom RPC URL for Berachain |
149
- | `T402_RPC_UNICHAIN` | Custom RPC URL for Unichain |
136
+ | Variable | Description |
137
+ | -------------------- | --------------------------------------------- |
138
+ | `T402_PRIVATE_KEY` | Wallet private key (hex with 0x prefix) |
139
+ | `T402_DEMO_MODE` | Set to "true" for simulated transactions |
140
+ | `T402_BUNDLER_URL` | ERC-4337 bundler URL for gasless transactions |
141
+ | `T402_PAYMASTER_URL` | Paymaster URL for sponsored gas |
142
+ | `T402_RPC_ETHEREUM` | Custom RPC URL for Ethereum |
143
+ | `T402_RPC_BASE` | Custom RPC URL for Base |
144
+ | `T402_RPC_ARBITRUM` | Custom RPC URL for Arbitrum |
145
+ | `T402_RPC_OPTIMISM` | Custom RPC URL for Optimism |
146
+ | `T402_RPC_POLYGON` | Custom RPC URL for Polygon |
147
+ | `T402_RPC_AVALANCHE` | Custom RPC URL for Avalanche |
148
+ | `T402_RPC_INK` | Custom RPC URL for Ink |
149
+ | `T402_RPC_BERACHAIN` | Custom RPC URL for Berachain |
150
+ | `T402_RPC_UNICHAIN` | Custom RPC URL for Unichain |
150
151
 
151
152
  ## Supported Networks
152
153
 
153
- | Network | Chain ID | Tokens |
154
- |---------|----------|--------|
155
- | Ethereum | 1 | USDC, USDT, USDT0 |
156
- | Base | 8453 | USDC |
157
- | Arbitrum | 42161 | USDC, USDT, USDT0 |
158
- | Optimism | 10 | USDC, USDT |
159
- | Polygon | 137 | USDC, USDT |
160
- | Avalanche | 43114 | USDC, USDT |
161
- | Ink | 57073 | USDT0 |
162
- | Berachain | 80094 | USDT0 |
163
- | Unichain | 130 | USDT0 |
154
+ | Network | Chain ID | Tokens |
155
+ | --------- | -------- | ----------------- |
156
+ | Ethereum | 1 | USDC, USDT, USDT0 |
157
+ | Base | 8453 | USDC |
158
+ | Arbitrum | 42161 | USDC, USDT, USDT0 |
159
+ | Optimism | 10 | USDC, USDT |
160
+ | Polygon | 137 | USDC, USDT |
161
+ | Avalanche | 43114 | USDC, USDT |
162
+ | Ink | 57073 | USDT0 |
163
+ | Berachain | 80094 | USDT0 |
164
+ | Unichain | 130 | USDT0 |
164
165
 
165
166
  ## Cross-Chain Bridging
166
167
 
167
168
  USDT0 can be bridged between these chains using LayerZero:
169
+
168
170
  - Ethereum
169
171
  - Arbitrum
170
172
  - Ink
@@ -184,23 +186,23 @@ Once configured, you can ask Claude to:
184
186
  ## Programmatic Usage
185
187
 
186
188
  ```typescript
187
- import { createT402McpServer, loadConfigFromEnv } from '@t402/mcp';
189
+ import { createT402McpServer, loadConfigFromEnv } from '@t402/mcp'
188
190
 
189
- const config = loadConfigFromEnv();
190
- const server = createT402McpServer(config);
191
- await server.run();
191
+ const config = loadConfigFromEnv()
192
+ const server = createT402McpServer(config)
193
+ await server.run()
192
194
  ```
193
195
 
194
196
  ## Using Individual Tools
195
197
 
196
198
  ```typescript
197
- import { executeGetBalance, executePay } from '@t402/mcp/tools';
199
+ import { executeGetBalance, executePay } from '@t402/mcp/tools'
198
200
 
199
201
  // Check balance
200
202
  const balance = await executeGetBalance({
201
203
  network: 'base',
202
204
  address: '0x...',
203
- });
205
+ })
204
206
 
205
207
  // Execute payment
206
208
  const result = await executePay(
@@ -212,8 +214,8 @@ const result = await executePay(
212
214
  },
213
215
  {
214
216
  privateKey: '0x...',
215
- }
216
- );
217
+ },
218
+ )
217
219
  ```
218
220
 
219
221
  ## Security Considerations
package/bin/t402-mcp.js CHANGED
@@ -20,34 +20,34 @@
20
20
  * ... (other networks follow same pattern)
21
21
  */
22
22
 
23
- import { createT402McpServer, loadConfigFromEnv } from "../dist/esm/index.mjs";
23
+ import { createT402McpServer, loadConfigFromEnv } from '../dist/esm/index.mjs'
24
24
 
25
25
  async function main() {
26
- const config = loadConfigFromEnv();
26
+ const config = loadConfigFromEnv()
27
27
 
28
28
  // Log configuration status (to stderr so it doesn't interfere with stdio)
29
- console.error("t402 MCP Server Configuration:");
30
- console.error(` Private Key: ${config.privateKey ? "configured" : "not set"}`);
31
- console.error(` Demo Mode: ${config.demoMode ? "enabled" : "disabled"}`);
32
- console.error(` Bundler URL: ${config.bundlerUrl ? "configured" : "not set"}`);
33
- console.error(` Paymaster URL: ${config.paymasterUrl ? "configured" : "not set"}`);
29
+ console.error('t402 MCP Server Configuration:')
30
+ console.error(` Private Key: ${config.privateKey ? 'configured' : 'not set'}`)
31
+ console.error(` Demo Mode: ${config.demoMode ? 'enabled' : 'disabled'}`)
32
+ console.error(` Bundler URL: ${config.bundlerUrl ? 'configured' : 'not set'}`)
33
+ console.error(` Paymaster URL: ${config.paymasterUrl ? 'configured' : 'not set'}`)
34
34
 
35
35
  if (config.rpcUrls) {
36
- console.error(` Custom RPC URLs: ${Object.keys(config.rpcUrls).join(", ")}`);
36
+ console.error(` Custom RPC URLs: ${Object.keys(config.rpcUrls).join(', ')}`)
37
37
  }
38
38
 
39
39
  if (!config.privateKey && !config.demoMode) {
40
- console.error("");
41
- console.error("Warning: No private key configured.");
42
- console.error("Set T402_PRIVATE_KEY env var or enable T402_DEMO_MODE=true");
43
- console.error("");
40
+ console.error('')
41
+ console.error('Warning: No private key configured.')
42
+ console.error('Set T402_PRIVATE_KEY env var or enable T402_DEMO_MODE=true')
43
+ console.error('')
44
44
  }
45
45
 
46
- const server = createT402McpServer(config);
47
- await server.run();
46
+ const server = createT402McpServer(config)
47
+ await server.run()
48
48
  }
49
49
 
50
50
  main().catch((error) => {
51
- console.error("Fatal error:", error);
52
- process.exit(1);
53
- });
51
+ console.error('Fatal error:', error)
52
+ process.exit(1)
53
+ })
@@ -1,7 +1,7 @@
1
1
  export { T402McpServer, createT402McpServer, loadConfigFromEnv } from './server/index.js';
2
2
  export { AllBalancesResult, BridgeInput, BridgeOptions, GASLESS_SUPPORTED_NETWORKS, GetAllBalancesInput, GetBalanceInput, GetBridgeFeeInput, PayGaslessInput, PayGaslessOptions, PayInput, PayOptions, TOOL_DEFINITIONS, bridgeInputSchema, executeBridge, executeGetAllBalances, executeGetBalance, executeGetBridgeFee, executePay, executePayGasless, formatAllBalancesResult, formatBalanceResult, formatBridgeFeeResult, formatBridgeResult, formatGaslessPaymentResult, formatPaymentResult, getAllBalancesInputSchema, getBalanceInputSchema, getBridgeFeeInputSchema, payGaslessInputSchema, payInputSchema } from './tools/index.js';
3
- import { S as SupportedNetwork } from './types-BINGE6ja.js';
4
- export { B as BridgeFeeQuote, b as BridgeResult, C as ChainBalance, G as GaslessPaymentResult, M as McpServerConfig, P as PaymentParams, a as PaymentResult, T as TokenBalance, c as ToolContext } from './types-BINGE6ja.js';
3
+ import { S as SupportedNetwork } from './types-CWK2p9_n.js';
4
+ export { B as BridgeFeeQuote, b as BridgeResult, C as ChainBalance, G as GaslessPaymentResult, M as McpServerConfig, P as PaymentParams, a as PaymentResult, T as TokenBalance, c as ToolContext } from './types-CWK2p9_n.js';
5
5
  import { Address } from 'viem';
6
6
  import 'zod';
7
7
 
@@ -52,11 +52,11 @@ declare function getLayerZeroScanUrl(messageGuid: string): string;
52
52
  /**
53
53
  * Check if a network supports a specific token
54
54
  */
55
- declare function supportsToken(network: SupportedNetwork, token: "USDC" | "USDT" | "USDT0"): boolean;
55
+ declare function supportsToken(network: SupportedNetwork, token: 'USDC' | 'USDT' | 'USDT0'): boolean;
56
56
  /**
57
57
  * Get token address for a network
58
58
  */
59
- declare function getTokenAddress(network: SupportedNetwork, token: "USDC" | "USDT" | "USDT0"): Address | undefined;
59
+ declare function getTokenAddress(network: SupportedNetwork, token: 'USDC' | 'USDT' | 'USDT0'): Address | undefined;
60
60
  /**
61
61
  * Format token amount for display
62
62
  */
package/dist/cjs/index.js CHANGED
@@ -5,6 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
9
  var __export = (target, all) => {
9
10
  for (var name in all)
10
11
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -26,6 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
27
  mod
27
28
  ));
28
29
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
29
31
 
30
32
  // src/index.ts
31
33
  var src_exports = {};
@@ -145,7 +147,7 @@ var USDT0_ADDRESSES = {
145
147
  arbitrum: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
146
148
  ink: "0x0200C29006150606B650577BBE7B6248F58470c1",
147
149
  berachain: "0x779Ded0c9e1022225f8E0630b35a9b54bE713736",
148
- unichain: "0x588ce4F028D8e7B53B687865d6A67b3A54C75518"
150
+ unichain: "0x9151434b16b9763660705744891fA906F660EcC5"
149
151
  };
150
152
  var BRIDGEABLE_CHAINS = [
151
153
  "ethereum",
@@ -345,13 +347,9 @@ async function executeGetBalance(input, rpcUrls) {
345
347
  tokenAddresses.push({ token: USDT0_ADDRESSES[network], expected: "USDT0" });
346
348
  }
347
349
  const tokenBalances = await Promise.all(
348
- tokenAddresses.map(
349
- ({ token }) => getTokenBalance(client, token, walletAddress)
350
- )
351
- );
352
- const tokens = tokenBalances.filter(
353
- (t) => t !== null
350
+ tokenAddresses.map(({ token }) => getTokenBalance(client, token, walletAddress))
354
351
  );
352
+ const tokens = tokenBalances.filter((t) => t !== null);
355
353
  return {
356
354
  network,
357
355
  chainId: CHAIN_IDS[network],
@@ -539,7 +537,7 @@ function getViemChain2(network) {
539
537
  }
540
538
  }
541
539
  async function executePay(input, options) {
542
- const { to, amount, token, network, memo } = input;
540
+ const { to, amount, token, network, memo: _memo } = input;
543
541
  const { privateKey, rpcUrl, demoMode } = options;
544
542
  if (!supportsToken(network, token)) {
545
543
  throw new Error(`Token ${token} is not supported on ${network}`);
@@ -625,14 +623,7 @@ var payGaslessInputSchema = import_zod4.z.object({
625
623
  to: import_zod4.z.string().regex(/^0x[a-fA-F0-9]{40}$/).describe("Recipient address"),
626
624
  amount: import_zod4.z.string().regex(/^\d+(\.\d+)?$/).describe("Amount to pay (e.g., '10.50' for 10.50 USDC)"),
627
625
  token: import_zod4.z.enum(["USDC", "USDT", "USDT0"]).describe("Token to use for payment"),
628
- network: import_zod4.z.enum([
629
- "ethereum",
630
- "base",
631
- "arbitrum",
632
- "optimism",
633
- "polygon",
634
- "avalanche"
635
- ]).describe("Network to execute gasless payment on (must support ERC-4337)")
626
+ network: import_zod4.z.enum(["ethereum", "base", "arbitrum", "optimism", "polygon", "avalanche"]).describe("Network to execute gasless payment on (must support ERC-4337)")
636
627
  });
637
628
  var GASLESS_SUPPORTED_NETWORKS = [
638
629
  "ethereum",
@@ -668,7 +659,7 @@ function getViemChain3(network) {
668
659
  }
669
660
  async function executePayGasless(input, options) {
670
661
  const { to, amount, token, network } = input;
671
- const { privateKey, bundlerUrl, paymasterUrl, rpcUrl, demoMode } = options;
662
+ const { privateKey, bundlerUrl, paymasterUrl: _paymasterUrl, rpcUrl, demoMode } = options;
672
663
  if (!GASLESS_SUPPORTED_NETWORKS.includes(network)) {
673
664
  throw new Error(
674
665
  `Network ${network} does not support ERC-4337 gasless transactions. Supported: ${GASLESS_SUPPORTED_NETWORKS.join(", ")}`
@@ -1058,9 +1049,7 @@ var OFT_ABI2 = [
1058
1049
  ]
1059
1050
  }
1060
1051
  ];
1061
- var OFT_SENT_EVENT_TOPIC = (0, import_viem5.keccak256)(
1062
- (0, import_viem5.toBytes)("OFTSent(bytes32,uint32,address,uint256,uint256)")
1063
- );
1052
+ var OFT_SENT_EVENT_TOPIC = (0, import_viem5.keccak256)((0, import_viem5.toBytes)("OFTSent(bytes32,uint32,address,uint256,uint256)"));
1064
1053
  function getViemChain5(network) {
1065
1054
  switch (network) {
1066
1055
  case "ethereum":
@@ -1160,11 +1149,7 @@ async function executeBridge(input, options) {
1160
1149
  address: usdt0Address,
1161
1150
  abi: OFT_ABI2,
1162
1151
  functionName: "send",
1163
- args: [
1164
- sendParam,
1165
- { nativeFee: nativeFeeWithBuffer, lzTokenFee: 0n },
1166
- account.address
1167
- ],
1152
+ args: [sendParam, { nativeFee: nativeFeeWithBuffer, lzTokenFee: 0n }, account.address],
1168
1153
  value: nativeFeeWithBuffer
1169
1154
  });
1170
1155
  const receipt = await publicClient.waitForTransactionReceipt({ hash });
@@ -1207,7 +1192,7 @@ function formatBridgeResult(result) {
1207
1192
  `- [View on LayerZero Scan](${result.trackingUrl})`,
1208
1193
  `- [View Source TX](${getExplorerTxUrl(result.fromChain, result.txHash)})`,
1209
1194
  "",
1210
- "_Your USDT0 will arrive on ${result.toChain} once the LayerZero message is delivered._"
1195
+ `_Your USDT0 will arrive on ${result.toChain} once the LayerZero message is delivered._`
1211
1196
  ].join("\n");
1212
1197
  }
1213
1198
 
@@ -1415,6 +1400,8 @@ var TOOL_DEFINITIONS = {
1415
1400
  // src/server/t402Server.ts
1416
1401
  var T402McpServer = class {
1417
1402
  constructor(config = {}) {
1403
+ __publicField(this, "server");
1404
+ __publicField(this, "config");
1418
1405
  this.config = config;
1419
1406
  this.server = new import_server.Server(
1420
1407
  {