Wdk MCP Toolkit
No description available
Ask AI about Wdk MCP Toolkit
Powered by Claude Β· Grounded in docs
I know everything about Wdk MCP Toolkit. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
@tetherto/wdk-mcp-toolkit
https://github.com/user-attachments/assets/9fc1aa65-b76b-4569-bac0-42f75ccdc1ce
Note: This package is currently in beta. Please test thoroughly in development environments before using in production.
A simple and secure package to expose WDK (Wallet Development Kit) functionality through the Model Context Protocol (MCP). This package provides a clean API for creating MCP servers that enable AI agents to interact with cryptocurrency wallets across multiple blockchains.
π About WDK
This module is part of the WDK (Wallet Development Kit) project, which empowers developers to build secure, non-custodial wallets with unified blockchain access, stateless architecture, and complete user control.
For detailed documentation about the complete WDK ecosystem, visit docs.wallet.tether.io.
π Features
- MCP Server Extension: Extends
McpServerfrom @modelcontextprotocol/sdk with all familiar APIs plus WDK-specific functionality - Multi-Chain Support: Register wallets for any blockchain supported by WDK wallet modules (EVM chains, Bitcoin, Solana, TON, TRON, and more)
- Built-in Tools: Pre-built MCP tools for wallet operations, pricing data, and transaction history
- Extensible & Modular: Register only the tools you need, create custom tools, and organize functionality into reusable modules
- Secure by Design: Automatic memory cleanup and secure key disposal
βοΈ Requirements
MCP Client Compatibility
This toolkit requires an MCP client that supports tools. For wallet write operations (sending transactions, signing messages), a client that also supports elicitations is recommended to enable human approval flows before executing sensitive operations. If your MCP client does not support elicitations, you can disable them via the capabilities constructor option (see Client Capabilities).
| Feature | Required For |
|---|---|
| Tools support | All operations (read and write) |
| Elicitations support | Write operations (sendTransaction, transfer, sign) β can be disabled |
See the full list of MCP clients and their capabilities.
β¬οΈ Installation
To install the @tetherto/wdk-mcp-toolkit package, follow these instructions:
You can install it using npm:
npm install @tetherto/wdk-mcp-toolkit @modelcontextprotocol/sdk
You'll also need to install the wallet modules for your target blockchains:
npm install @tetherto/wdk-wallet-evm @tetherto/wdk-wallet-btc
Add "type": "module" to your package.json for ES module support:
{
"type": "module"
}
π Quick Start
Creating a Basic MCP Server
import { WdkMcpServer, WALLET_TOOLS, PRICING_TOOLS, INDEXER_TOOLS } from '@tetherto/wdk-mcp-toolkit'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerBtc from '@tetherto/wdk-wallet-btc'
const server = new WdkMcpServer('my-wallet-server', '1.0.0')
.useWdk({ seed: process.env.WDK_SEED })
.registerWallet('ethereum', WalletManagerEvm, {
provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key'
})
.registerWallet('bitcoin', WalletManagerBtc, {
network: 'bitcoin'
})
.usePricing()
.useIndexer({ apiKey: process.env.WDK_INDEXER_API_KEY })
.registerTools([...WALLET_TOOLS, ...PRICING_TOOLS, ...INDEXER_TOOLS])
const transport = new StdioServerTransport()
await server.connect(transport)
console.error('WDK MCP Server running on stdio')
π Example: See
examples/basic/index.jsfor a complete working example.
Example Prompts
Here are example prompts you can use with your AI agent connected to WDK MCP Toolkit:
| Category | Prompt |
|---|---|
| Wallet | "What's my Ethereum address?" |
| Wallet | "Send 0.01 ETH to Vitalik" |
| Wallet | "How much USDT do I have on Arbitrum?" |
| Pricing | "What's the current price of ETH in USD?" |
| Indexer | "Show my recent XAUT transfers on Ethereum" |
| Swap | "Swap 100 USDT for XAUT on Ethereum" |
| Bridge | "Bridge 50 USDT from Ethereum to Arbitrum" |
| Lending | "Supply 100 USDT to Aave on Ethereum" |
| Fiat On-Ramp | "Buy $100 worth of ETH with USD" |
Custom Token Registration
Token registration maps human-readable symbols (like "USDT") to contract addresses. This is necessary because:
- AI agents work with symbols β Users say "send 100 USDT" not "send 100 tokens with contract address 0xXYZ"
- Decimal handling β Each token has different decimals (USDT uses 6, DAI uses 18). The registry stores this so tools can convert between human amounts and raw values.
- Chain-specific addresses β USDT has different contract addresses on each chain. The registry resolves the correct address per chain.
// Register additional tokens beyond the defaults
server
.registerToken('ethereum', 'USDC', {
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
decimals: 6
})
.registerToken('ethereum', 'DAI', {
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
decimals: 18
})
// Tools use the registry to resolve symbols
const usdc = server.getTokenInfo('ethereum', 'USDC')
console.log('USDC address:', usdc.address)
Using Read-Only vs Write Tools
import { WALLET_READ_TOOLS, WALLET_WRITE_TOOLS } from '@tetherto/wdk-mcp-toolkit'
// For read-only access (balance checks, address lookups, fee estimates)
const readOnlyServer = new WdkMcpServer('read-only-server', '1.0.0')
.useWdk({ seed: process.env.WDK_SEED })
.registerWallet('ethereum', WalletManagerEvm, { provider: '...' })
.registerTools(WALLET_READ_TOOLS)
// For full access (includes sendTransaction, transfer, sign)
const fullAccessServer = new WdkMcpServer('full-access-server', '1.0.0')
.useWdk({ seed: process.env.WDK_SEED })
.registerWallet('ethereum', WalletManagerEvm, { provider: '...' })
.registerTools(WALLET_WRITE_TOOLS)
π‘ Best Practice: Register only the tools you need. Large tool sets increase context size, which can lead to slower responses, higher costs, and potential hallucinations where the AI invokes incorrect tools. If you only need to check balances, import and register just that tool:
import { getBalance } from '@tetherto/wdk-mcp-toolkit' server.registerTools([getBalance])
π Enabling Capabilities
WdkMcpServer uses a capability pattern. The use* methods enable capabilities by initializing underlying clients that tools can access:
| Method | Enables | Tools Can Access |
|---|---|---|
useWdk(config) | Wallet operations | server.wdk |
usePricing() | Price data | server.pricingClient |
useIndexer(config) | Transaction history | server.indexerClient |
How it works:
// 1. Enable capabilities
const server = new WdkMcpServer('my-server', '1.0.0')
.useWdk({ seed: process.env.WDK_SEED }) // server.wdk is now available
.usePricing() // server.pricingClient is now available
.useIndexer({ apiKey: process.env.API_KEY }) // server.indexerClient is now available
// 2. Register tools that use those capabilities
server.registerTools(WALLET_TOOLS) // These tools call server.wdk.*
server.registerTools(PRICING_TOOLS) // These tools call server.pricingClient.*
server.registerTools(INDEXER_TOOLS) // These tools call server.indexerClient.*
Writing custom tools:
You can register tools directly using registerTool() from the MCP SDK, or use our registerTools() utility for bulk registration.
Single tool with registerTool() (MCP SDK method):
import { z } from 'zod'
const chains = server.getChains()
server.registerTool(
'getAllTokenBalances',
{
title: 'Get All Token Balances',
description: 'Get balances for all registered tokens on a chain.',
inputSchema: z.object({
chain: z.enum(chains).describe('The blockchain to query')
}),
annotations: {
readOnlyHint: true,
destructiveHint: false
}
},
async ({ chain }) => {
try {
const account = await server.wdk.getAccount(chain, 0)
const symbols = server.getRegisteredTokens(chain)
const balances = {}
for (const symbol of symbols) {
const token = server.getTokenInfo(chain, symbol)
const rawBalance = await account.getTokenBalance(token.address)
const balance = Number(rawBalance) / Math.pow(10, token.decimals)
balances[symbol] = balance.toString()
}
return {
content: [{
type: 'text',
text: JSON.stringify(balances, null, 2)
}],
structuredContent: balances
}
} catch (error) {
return {
isError: true,
content: [{
type: 'text',
text: `Error getting token balances: ${error.message}`
}]
}
}
}
)
Multiple tools with registerTools() (WdkMcpServer utility):
The registerTools() method is a utility we added on top of the MCP SDK. It accepts an array of tool registration functions, making it easy to organize tools into modules and register them in bulk:
// Tool defined as a registration function
function getAllTokenBalances (server) {
const chains = server.getChains()
server.registerTool(
'getAllTokenBalances',
{ /* schema */ },
async ({ chain }) => { /* handler */ }
)
}
function getPortfolioValue (server) {
server.registerTool(
'getPortfolioValue',
{ /* schema */ },
async (params) => { /* handler */ }
)
}
// Register multiple tools at once
server.registerTools([getAllTokenBalances, getPortfolioValue])
This pattern allows you to:
- Organize tools into separate files/modules
- Conditionally include tools based on enabled capabilities
- Mix custom tools with built-in tool arrays
- Keep tool counts minimal to reduce context bloat
Capability dependencies:
If a tool requires a capability that wasn't enabled, it will fail at runtime. The built-in tools check for this:
WALLET_TOOLSrequireuseWdk()andregisterWallet()PRICING_TOOLSrequireusePricing()INDEXER_TOOLSrequireuseIndexer()SWAP_TOOLSrequireuseWdk()andregisterProtocol()with a swap protocolBRIDGE_TOOLSrequireuseWdk()andregisterProtocol()with a bridge protocolLENDING_TOOLSrequireuseWdk()andregisterProtocol()with a lending protocolFIAT_TOOLSrequireuseWdk()andregisterProtocol()with a fiat protocol
π₯οΈ Using with VS Code GitHub Copilot Chat
You can use this MCP server with VS Code GitHub Copilot Chat.
Quick Setup (Recommended)
The easiest way to get started is using the setup wizard:
git clone https://github.com/tetherto/wdk-mcp-toolkit.git
cd wdk-mcp-toolkit
npm install
npm run setup
The wizard will guide you through:
- Seed phrase (required) β Your BIP-39 wallet seed phrase
- WDK Indexer API key (optional) β For transaction history features (get one here)
- MoonPay credentials (optional) β For fiat on/off-ramp features (MoonPay Dashboard)
After setup, the wizard will:
- Install required dependencies automatically
- Generate
.vscode/mcp.jsonwith your credentials - Open VS Code ready to start the server
π Security: Your seed phrase is stored locally in
.vscode/mcp.jsonwhich is gitignored. We recommend using a dedicated development wallet.
Manual Configuration
If you prefer manual setup, create .vscode/mcp.json in the project root:
{
"servers": {
"wdk": {
"type": "stdio",
"command": "node",
"args": ["examples/basic/index.js"],
"env": {
"WDK_SEED": "your twelve word seed phrase here",
"WDK_INDEXER_API_KEY": "optional - get at https://wdk-api.tether.io/register",
"MOONPAY_API_KEY": "optional - get at https://dashboard.moonpay.com/",
"MOONPAY_SECRET_KEY": "optional - get at https://dashboard.moonpay.com/"
}
}
}
}
Then install the required dependencies:
npm install @tetherto/wdk-wallet-btc @tetherto/wdk-wallet-evm
npm install @tetherto/wdk-protocol-swap-velora-evm @tetherto/wdk-protocol-bridge-usdt0-evm
npm install @tetherto/wdk-protocol-lending-aave-evm @tetherto/wdk-protocol-fiat-moonpay
Starting the Server
- Open
.vscode/mcp.jsonin VS Code - Click the Start button that appears above the server configuration
- Open GitHub Copilot Chat and select Agent mode
- Click Tools to verify the MCP server tools are available
Example Conversations
You: What's my ethereum address?
Copilot: Your Ethereum address is 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
You: Check my ETH balance
Copilot: Your ETH balance is 1.5 ETH
You: What's the current price of BTC?
Copilot: The current price of BTC is $98,450.00 USD
You: Send 1 USDT to vitalik.eth
Copilot: I'll transfer 1 USDT to vitalik.eth.
[Requests approval via elicitation]
Transaction sent! Hash: 0xabc123...
Optional Capabilities
The server conditionally enables capabilities based on which environment variables are set:
| Capability | Environment Variables | Tools |
|---|---|---|
| Wallet, Pricing, Swap, Bridge, Lending | WDK_SEED (required) | Always enabled |
| Transaction History | WDK_INDEXER_API_KEY | INDEXER_TOOLS |
| Fiat On/Off-Ramp | MOONPAY_API_KEY + MOONPAY_SECRET_KEY | FIAT_TOOLS |
Re-run npm run setup to change your configuration or enable additional capabilities.
π Using with LangChain
You can use WDK MCP Toolkit as a tool provider for LangChain agents in both Python and TypeScript. The serve CLI command starts a fully configured MCP server on stdio β no server script required. LangChain's MultiServerMCPClient spawns it as a subprocess and converts WDK tools into LangChain-compatible tools.
Quick Start (Python)
pip install langchain-mcp-adapters langgraph langchain-openai
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
async def main():
client = MultiServerMCPClient({
"wdk": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@tetherto/wdk-mcp-toolkit", "serve"],
"env": {
"WDK_SEED": "your twelve word seed phrase here",
"WDK_MCP_ELICITATION": "false",
},
}
})
tools = await client.get_tools()
agent = create_react_agent(ChatOpenAI(model="gpt-4o"), tools)
result = await agent.ainvoke({
"messages": [{"role": "user", "content": "What is my Ethereum address?"}]
})
print(result["messages"][-1].content)
asyncio.run(main())
Quick Start (TypeScript)
npm install @langchain/mcp-adapters @langchain/langgraph @langchain/core @langchain/openai
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatOpenAI } from "@langchain/openai";
const client = new MultiServerMCPClient({
wdk: {
transport: "stdio",
command: "npx",
args: ["-y", "@tetherto/wdk-mcp-toolkit", "serve"],
env: {
WDK_SEED: "your twelve word seed phrase here",
WDK_MCP_ELICITATION: "false",
},
},
});
const tools = await client.getTools();
const agent = createReactAgent({
llm: new ChatOpenAI({ model: "gpt-4o" }),
tools,
});
const result = await agent.invoke({
messages: [
{ role: "user", content: "What is the current price of Bitcoin?" },
],
});
await client.close();
The serve Command
The serve command auto-discovers installed wallet and protocol modules, so you don't need to write a server script:
# Start with wallet operations
WDK_SEED="..." npx @tetherto/wdk-mcp-toolkit serve
# Start without seed (pricing tools only)
npx @tetherto/wdk-mcp-toolkit serve
It automatically detects and registers:
| Module | Auto-registers |
|---|---|
@tetherto/wdk-wallet-evm | Ethereum + Arbitrum wallets |
@tetherto/wdk-wallet-btc | Bitcoin wallet |
@tetherto/wdk-protocol-swap-velora-evm | Swap tools |
@tetherto/wdk-protocol-bridge-usdt0-evm | Bridge tools |
@tetherto/wdk-protocol-lending-aave-evm | Lending tools |
@tetherto/wdk-protocol-fiat-moonpay | Fiat tools (requires MOONPAY_* env vars) |
Override any chain's RPC endpoint with WDK_RPC_<CHAIN_UPPERCASE> (e.g. WDK_RPC_ETHEREUM=https://my-rpc.com).
Custom chains and protocols β for chains or protocols not in the defaults, create a wdk.config.json and pass its path via WDK_CONFIG:
WDK_CONFIG=./wdk.config.json WDK_SEED="..." npx @tetherto/wdk-mcp-toolkit serve
{
"chains": {
"zksync": {
"module": "@myorg/wdk-wallet-zksync",
"config": { "provider": "https://mainnet.era.zksync.io" }
},
"ethereum": {
"config": { "provider": "https://my-private-rpc.com" }
}
},
"protocols": [
{
"module": "@myorg/wdk-protocol-swap-custom",
"label": "custom-swap",
"type": "swap",
"chains": ["zksync"]
}
],
"enabledChains": ["ethereum", "zksync", "bitcoin"]
}
chainsβ add new chains or override config for built-in ones. New chains require amodulefield; overrides for existing chains can omit it.protocolsβ add custom protocols. Each requiresmodule,label, andchains. Thetypefield (swap,bridge,lending,fiat) maps to the corresponding built-in tool set.enabledChainsβ overridesWDK_CHAINSenv var. If omitted,WDK_CHAINSis used (default:ethereum,arbitrum,bitcoin).
LLM Provider Support
Both examples support OpenAI and Anthropic β set the corresponding environment variable:
| Provider | Environment Variable | Python Package | TypeScript Package |
|---|---|---|---|
| OpenAI | OPENAI_API_KEY | langchain-openai | @langchain/openai |
| Anthropic | ANTHROPIC_API_KEY | langchain-anthropic | @langchain/anthropic |
π Examples: See
examples/langchain/python/andexamples/langchain/typescript/for complete interactive agent examples.
π API Reference
Table of Contents
| Class | Description |
|---|---|
| WdkMcpServer | Main class for creating MCP servers with WDK functionality. Extends McpServer from @modelcontextprotocol/sdk. |
| CHAINS | Convenience constants for chains with pre-configured token addresses. |
| DEFAULT_TOKENS | Pre-configured token addresses for all supported chains. |
WdkMcpServer
The main class for creating MCP servers with WDK wallet functionality. Extends McpServer from @modelcontextprotocol/sdk/server/mcp.js, providing all standard MCP server methods plus WDK-specific functionality.
Constructor
new WdkMcpServer(name, version, options?)
Parameters:
name(string): The server nameversion(string): The server versionoptions(object, optional): Server configuration optionscapabilities(object, optional): MCP client capabilitieselicitation(boolean, optional): Whether the MCP client supports elicitation. Defaults totrue.
Example:
// Default β elicitation enabled
const server = new WdkMcpServer('my-wallet-server', '1.0.0')
// Disable elicitation for clients that don't support it
const server = new WdkMcpServer('my-wallet-server', '1.0.0', {
capabilities: { elicitation: false }
})
Client Capabilities
MCP clients have varying feature support. The capabilities constructor option lets you declare which features your MCP client supports, so the server adapts its behavior accordingly.
| Capability | Default | Effect When Disabled |
|---|---|---|
elicitation | true | Write tools skip confirmation dialogs and execute immediately |
When elicitation is set to false, destructive operations (transfer, sendTransaction, swap, bridge, supply, withdraw, borrow, repay) will execute without presenting a confirmation dialog to the user. Use this when your MCP client does not support the elicitation feature, or when you want to build automated workflows that don't require human-in-the-loop confirmation.
// For MCP clients that support elicitation (default)
const server = new WdkMcpServer('my-server', '1.0.0')
// For MCP clients that do NOT support elicitation
const server = new WdkMcpServer('my-server', '1.0.0', {
capabilities: { elicitation: false }
})
// Access capabilities at runtime
console.log(server.capabilities)
// { elicitation: true }
Security Note: Disabling elicitation removes the human approval step for write operations. Ensure your application has appropriate safeguards when running without elicitation.
Methods
| Method | Description | Returns |
|---|---|---|
useWdk(config) | Initializes the WDK with a seed phrase | WdkMcpServer |
registerWallet(blockchain, WalletManager, config) | Registers a wallet for a blockchain | WdkMcpServer |
useIndexer(config) | Enables the WDK Indexer client for transaction history | WdkMcpServer |
usePricing() | Enables the Bitfinex pricing client | WdkMcpServer |
registerProtocol(chain, label, Protocol, config) | Registers a DeFi protocol (swap, bridge, lending, fiat) | WdkMcpServer |
getSwapChains() | Returns chains with swap protocols registered | string[] |
getSwapProtocols(chain) | Returns swap protocol labels for a chain | string[] |
getBridgeChains() | Returns chains with bridge protocols registered | string[] |
getBridgeProtocols(chain) | Returns bridge protocol labels for a chain | string[] |
getLendingChains() | Returns chains with lending protocols registered | string[] |
getLendingProtocols(chain) | Returns lending protocol labels for a chain | string[] |
getFiatChains() | Returns chains with fiat protocols registered | string[] |
getFiatProtocols(chain) | Returns fiat protocol labels for a chain | string[] |
registerToken(chain, symbol, token) | Registers a token address mapping | WdkMcpServer |
getTokenInfo(chain, symbol) | Returns token info for a symbol | TokenInfo | undefined |
getRegisteredTokens(chain) | Returns all registered token symbols | string[] |
getChains() | Returns all registered blockchain names | string[] |
registerTools(tools) | Bulk registers tools from an array of functions | WdkMcpServer |
requestConfirmation(message, schema) | Requests user confirmation or auto-confirms based on capabilities | Promise<object> |
close() | Closes the server and disposes WDK securely | Promise<void> |
useWdk(config)
Enables wallet capabilities by initializing the Wallet Development Kit. After calling this, server.wdk becomes available for tools to use.
Parameters:
config(object): Configuration objectseed(string, optional): BIP-39 seed phrase. Falls back toWDK_SEEDenvironment variable.
Returns: WdkMcpServer - The server instance for chaining
Throws: Error - If no seed is provided
Example:
server.useWdk({ seed: 'your twelve word seed phrase here' })
// OR use environment variable
server.useWdk({}) // Uses process.env.WDK_SEED
// Now tools can access server.wdk
const account = await server.wdk.getAccount('ethereum', 0)
registerWallet(blockchain, WalletManager, config)
Registers a wallet module for a specific blockchain. Automatically registers default tokens (USDT) for the chain if available.
Parameters:
blockchain(string): The blockchain name (e.g., "ethereum", "bitcoin")WalletManager(class): The wallet manager class from a WDK wallet packageconfig(object): Configuration object specific to the wallet manager
Returns: WdkMcpServer - The server instance for chaining
Throws: Error - If useWdk() has not been called
Example:
server.registerWallet('ethereum', WalletManagerEvm, {
provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key'
})
server.registerWallet('bitcoin', WalletManagerBtc, {
network: 'bitcoin',
host: 'electrum.blockstream.info',
port: 50001
})
registerProtocol(chain, label, Protocol, config)
Registers a DeFi protocol for a blockchain. Protocols enable swap, bridge, lending, and fiat on/off-ramp functionality. The protocol type is automatically detected from the class inheritance.
Parameters:
chain(string): The blockchain name (e.g., "ethereum")label(string): The protocol label (e.g., "velora", "aave", "moonpay")Protocol(class): The protocol class (must extend SwapProtocol, BridgeProtocol, LendingProtocol, or FiatProtocol)config(object, optional): Protocol-specific configuration
Returns: WdkMcpServer - The server instance for chaining
Throws: Error - If useWdk() has not been called, or if unknown protocol type
Example:
import VeloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'
import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
import AaveProtocolEvm from '@tetherto/wdk-protocol-lending-aave-evm'
import MoonPayProtocol from '@tetherto/wdk-protocol-fiat-moonpay'
server
// Swap protocol - enables token swaps
.registerProtocol('ethereum', 'velora', VeloraProtocolEvm)
// Bridge protocol - enables cross-chain transfers
.registerProtocol('ethereum', 'usdt0', Usdt0ProtocolEvm)
// Lending protocol - enables supply, borrow, withdraw, repay
.registerProtocol('ethereum', 'aave', AaveProtocolEvm)
// Fiat protocol - enables buy/sell crypto with fiat
.registerProtocol('ethereum', 'moonpay', MoonPayProtocol, {
secretKey: process.env.MOONPAY_SECRET_KEY,
apiKey: process.env.MOONPAY_API_KEY
})
Learn more about protocols:
useIndexer(config)
Enables transaction history capabilities by initializing the WDK Indexer client. After calling this, server.indexerClient becomes available for tools to use.
Parameters:
config(object): Configuration objectapiKey(string): WDK Indexer API key
Returns: WdkMcpServer - The server instance for chaining
Throws: Error - If no apiKey is provided
Example:
server.useIndexer({ apiKey: process.env.WDK_INDEXER_API_KEY })
// Now tools can access server.indexerClient
const transfers = await server.indexerClient.getTokenTransfers('ethereum', 'usdt', address)
const balance = await server.indexerClient.getTokenBalance('ethereum', 'usdt', address)
usePricing()
Enables pricing capabilities by initializing the Bitfinex pricing client. After calling this, server.pricingClient becomes available for tools to use.
Returns: WdkMcpServer - The server instance for chaining
Example:
server.usePricing()
// Now tools can access server.pricingClient
const price = await server.pricingClient.getCurrentPrice('BTC', 'USD')
registerToken(chain, symbol, token)
Registers a token symbol to contract address mapping for a blockchain.
Parameters:
chain(string): The blockchain namesymbol(string): The token symbol (e.g., "USDT", "USDC")token(object): Token informationaddress(string): Token contract addressdecimals(number): Number of decimal places
Returns: WdkMcpServer - The server instance for chaining
Example:
server.registerToken('ethereum', 'USDC', {
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
decimals: 6
})
getTokenInfo(chain, symbol)
Returns token information for a symbol on a blockchain.
Parameters:
chain(string): The blockchain namesymbol(string): The token symbol (case-insensitive)
Returns: TokenInfo | undefined - The token info or undefined if not found
Example:
const usdt = server.getTokenInfo('ethereum', 'USDT')
// { address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', decimals: 6 }
getRegisteredTokens(chain)
Returns all registered token symbols for a blockchain.
Parameters:
chain(string): The blockchain name
Returns: string[] - Array of token symbols
Example:
const tokens = server.getRegisteredTokens('ethereum')
// ['USDT', 'USDC', 'DAI']
getChains()
Returns all registered blockchain names.
Returns: string[] - Array of blockchain names
Example:
const chains = server.getChains()
// ['ethereum', 'polygon', 'bitcoin']
registerTools(tools)
Utility method for bulk tool registration. This is a convenience wrapper we added on top of the MCP SDK's registerTool() method. Each function in the array receives the server instance and should call server.registerTool() internally.
Parameters:
tools(array): Array of tool registration functions with signature(server: WdkMcpServer) => void
Returns: WdkMcpServer - The server instance for chaining
Example:
import { WALLET_TOOLS, PRICING_TOOLS } from '@tetherto/wdk-mcp-toolkit'
// Register built-in tool arrays
server.registerTools([...WALLET_TOOLS, ...PRICING_TOOLS])
// Or mix with custom tools
server.registerTools([
...WALLET_TOOLS,
myCustomTool,
anotherCustomTool
])
Note: For registering a single tool, you can use registerTool() directly (inherited from McpServer).
close()
Closes the server and securely disposes the WDK instance, clearing sensitive data from memory.
Returns: Promise<void>
Example:
await server.close()
CHAINS
Convenience constants for blockchain names that have pre-configured USDT token addresses. Using these constants triggers automatic token registration via DEFAULT_TOKENS.
Note: You can register any blockchain name you want. CHAINS is purely for convenience. If you use a name not in CHAINS, simply register your tokens manually:
// Using a custom chain name works fine
server.registerWallet('zksync', WalletManagerEvm, {
provider: 'https://mainnet.era.zksync.io'
})
// Just register tokens yourself since there's no default
server.registerToken('zksync', 'USDT', {
address: '0x493257fD37EDB34451f62EDf8D2a0C418852bA4C',
decimals: 6
})
DEFAULT_TOKENS
Pre-configured USDT token addresses for common chains. These are automatically registered when you call registerWallet() with a matching chain name.
| Chain | USDT Address | Decimals |
|---|---|---|
| Ethereum | 0xdAC17F958D2ee523a2206206994597C13D831ec7 | 6 |
| Polygon | 0xc2132D05D31c914a87C6611C10748AEb04B58e8F | 6 |
| Arbitrum | 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9 | 6 |
| Optimism | 0x94b008aA00579c1307B0EF2c499aD98a8ce58e58 | 6 |
| Base | 0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2 | 6 |
| Avalanche | 0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7 | 6 |
| BNB | 0x55d398326f99059fF775485246999027B3197955 | 18 |
| Plasma | 0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb | 6 |
| TRON | TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t | 6 |
| TON | EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs | 6 |
| Solana | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB | 6 |
π§ Built-in Tools
Wallet Tools
| Tool | Category | Description |
|---|---|---|
getAddress | Read | Get wallet address for a blockchain |
getBalance | Read | Get native token balance |
getTokenBalance | Read | Get ERC20/token balance |
getFeeRates | Read | Get current network fee rates |
getMaxSpendableBtc | Read | Get maximum spendable Bitcoin amount |
quoteSendTransaction | Read | Estimate fee for a transaction |
quoteTransfer | Read | Estimate fee for a token transfer |
sendTransaction | Write | Send native tokens |
transfer | Write | Transfer ERC20/tokens |
sign | Write | Sign a message |
verify | Write | Verify a message signature |
Pricing Tools
| Tool | Description |
|---|---|
getCurrentPrice | Get current price for a trading pair |
getHistoricalPrice | Get historical price data |
Indexer Tools
| Tool | Description |
|---|---|
getTokenTransfers | Get token transfer history for an address |
getIndexerTokenBalance | Get token balance via indexer API |
Swap Tools
Enable token swaps through registered swap protocols (e.g., Velora). See Swap Modules for available protocols.
| Tool | Category | Description |
|---|---|---|
quoteSwap | Read | Get a quote for swapping tokens |
swap | Write | Execute a token swap |
Bridge Tools
Enable cross-chain token transfers through registered bridge protocols (e.g., USDT0). See Bridge Modules for available protocols.
| Tool | Category | Description |
|---|---|---|
quoteBridge | Read | Get a quote for bridging tokens |
bridge | Write | Execute a cross-chain bridge transfer |
Lending Tools
Enable DeFi lending operations through registered lending protocols (e.g., Aave). See Lending Modules for available protocols.
| Tool | Category | Description |
|---|---|---|
quoteSupply | Read | Get a quote for supplying tokens |
supply | Write | Supply tokens to a lending protocol |
quoteWithdraw | Read | Get a quote for withdrawing tokens |
withdraw | Write | Withdraw tokens from a lending protocol |
quoteBorrow | Read | Get a quote for borrowing tokens |
borrow | Write | Borrow tokens from a lending protocol |
quoteRepay | Read | Get a quote for repaying borrowed tokens |
repay | Write | Repay borrowed tokens |
Fiat Tools
Enable fiat on/off-ramp operations through registered fiat protocols (e.g., MoonPay). See Fiat Modules for available protocols.
| Tool | Category | Description |
|---|---|---|
quoteBuy | Read | Get a quote for buying crypto with fiat |
buy | Write | Execute a fiat-to-crypto purchase |
quoteSell | Read | Get a quote for selling crypto for fiat |
sell | Write | Execute a crypto-to-fiat sale |
getTransactionDetail | Read | Get details of a fiat transaction |
getSupportedCryptoAssets | Read | Get list of supported cryptocurrencies |
getSupportedFiatCurrencies | Read | Get list of supported fiat currencies |
getSupportedCountries | Read | Get list of supported countries |
π Security Considerations
- Seed Phrase Security: Always store your seed phrase securely and never share it. Use environment variables (
WDK_SEED) instead of hardcoding. - API Key Security: Store API keys in environment variables, never in source code.
- Memory Cleanup: The
close()method automatically callsdispose()on the WDK instance to clear private keys from memory. - Read vs Write Tools: Use
walletReadToolsfor read-only access when write operations are not needed. - Elicitations for Write Operations: For maximum safety, use an MCP client that supports elicitations (like VS Code GitHub Copilot or Cursor) for write operations to ensure human approval before transactions execute. If your client does not support elicitations, you can disable them with
{ capabilities: { elicitation: false } }β but ensure your application has appropriate safeguards. - MCP Transport Security: Use secure transports (stdio, SSE with TLS) in production environments.
- Tool Annotations: All tools include proper
readOnlyHintanddestructiveHintannotations for MCP clients.
π οΈ Development
Building
# Install dependencies
npm install
# Lint code
npm run lint
# Fix linting issues
npm run lint:fix
Testing
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
Project Structure
src/
βββ server.js # WdkMcpServer class, CHAINS, DEFAULT_TOKENS
βββ utils/ # Utility functions
β βββ amount.js # Amount parsing and formatting
βββ tools/
βββ wallet/ # Wallet operation tools
β βββ index.js # Tool exports
β βββ getAddress.js
β βββ getBalance.js
β βββ getTokenBalance.js
β βββ getFeeRates.js
β βββ getMaxSpendableBtc.js
β βββ quoteSendTransaction.js
β βββ quoteTransfer.js
β βββ sendTransaction.js
β βββ transfer.js
β βββ sign.js
β βββ verify.js
βββ pricing/ # Price data tools
β βββ index.js
β βββ getCurrentPrice.js
β βββ getHistoricalPrice.js
βββ indexer/ # Transaction history tools
β βββ index.js
β βββ getTokenTransfers.js
β βββ getTokenBalance.js
βββ swap/ # Token swap tools
β βββ index.js
β βββ quoteSwap.js
β βββ swap.js
βββ bridge/ # Cross-chain bridge tools
β βββ index.js
β βββ quoteBridge.js
β βββ bridge.js
βββ lending/ # DeFi lending tools
β βββ index.js
β βββ quoteSupply.js
β βββ supply.js
β βββ quoteWithdraw.js
β βββ withdraw.js
β βββ quoteBorrow.js
β βββ borrow.js
β βββ quoteRepay.js
β βββ repay.js
βββ fiat/ # Fiat on/off-ramp tools
βββ index.js
βββ quoteBuy.js
βββ buy.js
βββ quoteSell.js
βββ sell.js
βββ getTransactionDetail.js
βββ getSupportedCryptoAssets.js
βββ getSupportedFiatCurrencies.js
βββ getSupportedCountries.js
π License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
π Support
For support, please open an issue on the GitHub repository.
π Learn More
- WDK Documentation: docs.wallet.tether.io
- MCP SDK: github.com/modelcontextprotocol/typescript-sdk
- MCP Specification: modelcontextprotocol.io/specification/2025-11-25
- MCP Clients: modelcontextprotocol.io/clients
- VS Code Copilot MCP: Using MCP servers in VS Code
