WDK logoWDK documentation

Configuration

Configure wallets, capabilities, tokens, protocols, and custom tools

Server Setup

Create a server with a name and version:

import { WdkMcpServer } from '@tetherto/wdk-mcp-toolkit'

const server = new WdkMcpServer('my-server', '1.0.0')

The WdkMcpServer extends McpServer from the official @modelcontextprotocol/sdk with WDK-specific capabilities. All standard MCP server features are available.

Confirmation and Agent Access

The server enables MCP elicitation by default. sendTransaction, transfer, sign, swap, bridge, and lending execution tools request approval through the MCP client before continuing. The client must support elicitation and present the request to the user. Fiat buy and sell return provider URLs without this confirmation step; the user completes the purchase or sale with the provider.

For a programmatic server, the setting is options.capabilities.elicitation:

const server = new WdkMcpServer('my-server', '1.0.0', {
  capabilities: { elicitation: true }
})

The serve command uses WDK_MCP_ELICITATION; the exact string "false" disables elicitation. A custom server script must set the constructor option itself.

Disabling elicitation automatically accepts confirmation requests. It removes the human approval step; it does not add policy checks or spending limits. If your client cannot support confirmation, expose only read-only tools or provide authorization outside the agent's control before enabling writes.

These controls apply to the exposed MCP tools. They do not isolate signing keys from code that can access the server's seed, configuration, or runtime. The toolkit does not register transaction policies automatically. The policy engine is experimental and not production ready, and its local method checks are not a substitute for that isolation.

MCP tool annotations and agent instructions describe expected behavior; they do not enforce authorization. For the separate WDK CLI daemon, see its security model.


Wallet Configuration

Enable WDK

Pass a BIP-39 mnemonic resolved by your application to useWdk(). See the custom server example for a command-based loader:

server.useWdk({ seed })

The mnemonic is used for key derivation across all registered blockchains. If config.seed is omitted or empty, useWdk() falls back to WDK_SEED. The API does not resolve WDK_SEED_COMMAND or WDK_SEED_FILE; those sources are implemented by the built-in serve command.

Never hardcode seed phrases in source code or client configuration. Prefer a trusted secret-manager command. Keep credential files out of version control and restrict access; gitignore does not prevent local processes from reading them.

Seed Sources for serve

The built-in serve command selects the first environment variable with a nonempty value in this order:

  1. WDK_SEED: the mnemonic supplied directly.
  2. WDK_SEED_COMMAND: a trusted shell command whose stdout contains the mnemonic.
  3. WDK_SEED_FILE: a UTF-8 file containing the mnemonic.

Prefer WDK_SEED_COMMAND to putting the mnemonic in client configuration. Replace /absolute/path/to/trusted-seed-loader below with your own secret-manager executable; WDK does not supply it. Authenticate the secret manager before starting the MCP client. The command must work without interactive input and print only the mnemonic to stdout.

Terminal
WDK_SEED_COMMAND="/absolute/path/to/trusted-seed-loader" node bin/index.js serve

Unset WDK_SEED when selecting the command source, and unset both preceding variables when selecting a file. Use an absolute file path: relative paths resolve against the server process's working directory.

serve trims the selected value or output. An empty environment value is skipped, but a whitespace-only value or empty command/file output does not trigger fallback to another source; it starts pricing-only mode. A command failure or unreadable file aborts startup. A nonempty invalid mnemonic also aborts startup.

The command runs through a shell and blocks startup until it finishes. serve does not configure a timeout, so a hung command prevents the MCP server from connecting. Use only commands and configuration controlled by your application, never agent-generated command text. Do not include the mnemonic in diagnostics or errors: command failures can reach client logs.

After resolving a nonempty seed, serve removes all three source variables from its own environment as it initializes WDK. This does not delete a seed file, change the parent environment, or isolate the mnemonic from code running in the server process.

Register Wallets

Register a wallet module for each blockchain you want to support:

import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerBtc from '@tetherto/wdk-wallet-btc'
import WalletManagerSolana from '@tetherto/wdk-wallet-solana'

// EVM chains - one module handles all EVM networks
server.registerWallet('ethereum', WalletManagerEvm, {
  provider: 'https://eth-mainnet.g.alchemy.com/v2/KEY'
})
server.registerWallet('polygon', WalletManagerEvm, {
  provider: 'https://polygon-rpc.com'
})

// Bitcoin
server.registerWallet('bitcoin', WalletManagerBtc, {
  network: 'bitcoin',
  host: 'electrum.blockstream.info',
  port: 50001
})

// Solana
server.registerWallet('solana', WalletManagerSolana, {
  provider: 'https://api.mainnet-beta.solana.com'
})

Each registerWallet() call registers the chain name and makes it available to all wallet tools. For configuration details of each wallet module, see the Wallet Modules documentation.


Capabilities

Enable optional capabilities before registering their tools:

CapabilityMethodRequirementUnlocks
Pricingserver.usePricing()NonePRICING_TOOLS (2 tools)
Indexerserver.useIndexer({ apiKey })WDK API keyINDEXER_TOOLS (2 tools)
Swapserver.registerProtocol(chain, label, SwapProtocol)Swap module installedSWAP_TOOLS (2 tools)
Bridgeserver.registerProtocol(chain, label, BridgeProtocol)Bridge module installedBRIDGE_TOOLS (2 tools)
Lendingserver.registerProtocol(chain, label, LendingProtocol)Lending module installedLENDING_TOOLS (8 tools)
Fiatserver.registerProtocol(chain, label, FiatProtocol, config)Fiat module installedFIAT_TOOLS (8 tools)

Pricing

Fetches live prices from Bitfinex. No API key needed.

server.usePricing()

Indexer

Enables querying token balances and transfer history for any address. Requires an API key.

server.useIndexer({ apiKey: process.env.WDK_INDEXER_API_KEY })

Protocols

Protocol modules are registered per-chain. This example uses MoonPay:

Do not register Velora beta.8 and beta.9, USD₮0 bridge beta.10, or Aave beta.7 with EVM wallet beta.19. These adapters reject the provider on manager-derived accounts, so the example below omits them. Verify the installed versions before enabling their tools; see EVM provider compatibility. A separate direct account does not inherit the server's registered account controls.

import MoonPayProtocol from '@tetherto/wdk-protocol-fiat-moonpay'

server.registerProtocol('ethereum', 'moonpay', MoonPayProtocol, {
  apiKey: process.env.MOONPAY_API_KEY
})

Token Management

Default Tokens

DEFAULT_TOKENS registers Tether-family tokens for configured chains, including USD₮ and XAU₮ on Ethereum. Query the registry for the available machine symbols:

server.getRegisteredTokens('ethereum')  // ['USDT', 'XAUT']

Custom Tokens

Register additional tokens with registerToken():

server.registerToken('ethereum', 'WETH', {
  address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
  decimals: 18
})

Registered tokens are available to all tools that accept a token parameter (getTokenBalance, transfer, quoteTransfer, swap, etc.).


Tool Registration

Built-in Tool Arrays

Each category exports three arrays for fine-grained control:

ExportContents
WALLET_TOOLSAll 11 wallet tools
WALLET_READ_TOOLS7 read-only wallet tools
WALLET_WRITE_TOOLS4 wallet tools that modify state
PRICING_TOOLSAll 2 pricing tools
INDEXER_TOOLSAll 2 indexer tools
SWAP_TOOLSAll 2 swap tools
SWAP_READ_TOOLS1 read-only swap tool
SWAP_WRITE_TOOLS1 swap tool that modifies state
BRIDGE_TOOLSAll 2 bridge tools
BRIDGE_READ_TOOLS1 read-only bridge tool
BRIDGE_WRITE_TOOLS1 bridge tool that modifies state
LENDING_TOOLSAll 8 lending tools
LENDING_READ_TOOLS4 read-only lending tools
LENDING_WRITE_TOOLS4 lending tools that modify state
FIAT_TOOLSAll 8 fiat tools
FIAT_READ_TOOLS6 read-only fiat tools
FIAT_WRITE_TOOLS2 fiat tools that modify state

Read-Only Mode

To expose only read-only MCP tools to an AI agent:

import {
  WALLET_READ_TOOLS,
  PRICING_TOOLS,
  INDEXER_TOOLS,
  SWAP_READ_TOOLS
} from '@tetherto/wdk-mcp-toolkit'

server.registerTools([
  ...WALLET_READ_TOOLS,
  ...PRICING_TOOLS,
  ...INDEXER_TOOLS,
  ...SWAP_READ_TOOLS
])

Individual Tool Registration

You can also import and register tools individually:

import { getAddress, getBalance, getCurrentPrice } from '@tetherto/wdk-mcp-toolkit'

server.registerTools([getAddress, getBalance, getCurrentPrice])

Custom Tools

Add your own MCP tools alongside the built-in ones using the standard registerTool() method (inherited from McpServer). See the MCP SDK tools documentation for full details.

server.registerTool(
  'myCustomTool',
  {
    title: 'My Custom Tool',
    description: 'Description of what this tool does',
    inputSchema: z.object({
      param: z.string().describe('A required parameter')
    }),
    outputSchema: z.object({
      result: z.string()
    }),
    annotations: {
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false
    }
  },
  async ({ param }) => {
    return {
      content: [{ type: 'text', text: `Result: ${param}` }],
      structuredContent: { result: param }
    }
  }
)

Environment Variables

For serve, seed variables are optional individually. Wallet tools require a nonempty resolved seed; see seed sources and precedence. Custom servers must resolve command or file sources in application code before calling useWdk().

VariableRequiredDescription
WDK_SEEDNoDirect mnemonic; first source checked by serve, and fallback for useWdk({})
WDK_SEED_COMMANDNoTrusted command whose stdout supplies the mnemonic to serve
WDK_SEED_FILENoUTF-8 mnemonic file read by serve when both preceding variables are unset or empty
WDK_INDEXER_API_KEYNoAPI key for WDK Indexer
MOONPAY_API_KEYNoAPI key for MoonPay fiat on/off-ramp

Security Checklist

Self-custodial wallets require careful key management. Follow these guidelines to protect user funds.

  • Use a dedicated development wallet - Never use production wallets with real funds for testing
  • Use a secret-manager command - Keep the mnemonic out of source code and client configuration; configure only a trusted loader command and authenticate it before startup
  • Limit the exposed tools - Use read-only tool arrays when writes are unnecessary. Before enabling writes, review confirmation and agent access.
  • Await server.close() on shutdown - WDK disposal runs before the server clears its WDK reference and closes the transport. A disposal error rejects before those later steps. Successful cleanup does not guarantee erasure of every seed or key copy in process memory.
  • Use stdio transport - The default transport communicates only with the local AI client process
  • Review MCP annotations - Tools declare readOnlyHint and destructiveHint so clients can warn users appropriately
  • Keep client configuration gitignored - Exclude files containing wallet credentials and restrict which processes can read them

Need Help?

On this page