search_tokens
Find token contract addresses by searching names, symbols, or addresses in the deBridge database to prepare for cross-chain swaps.
Instructions
Search for tokens by name, symbol, or contract address in the deBridge token database. Returns matching tokens with address, symbol, name, decimals, and chain info. Use this to resolve human-readable token names to contract addresses before creating swap orders.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Token name, symbol, or contract address. Examples: 'USDC', 'ethereum', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' | |
| chainId | No | Filter by chain ID. Examples: '1' (Ethereum), '42161' (Arbitrum), '7565164' (Solana) | |
| name | No | Filter by token name (partial, case-insensitive). Examples: 'coin', 'ether' | |
| limit | No | Max results (default 10) |
Implementation Reference
- src/tools/search-tokens.ts:5-42 (handler)The registerSearchTokens function that implements the search_tokens tool, including the async handler that performs token lookups using tokenDb.search() and filters by name if provided
export function registerSearchTokens(server: McpServer, tokenDb: TokenDb) { server.registerTool( "search_tokens", { description: "Search for tokens by name, symbol, or contract address in the deBridge token database. Returns matching tokens with address, symbol, name, decimals, and chain info. Use this to resolve human-readable token names to contract addresses before creating swap orders.", inputSchema: { query: z.string().describe( "Token name, symbol, or contract address. Examples: 'USDC', 'ethereum', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'", ), chainId: z.string().optional().describe( "Filter by chain ID. Examples: '1' (Ethereum), '42161' (Arbitrum), '7565164' (Solana)", ), name: z.string().optional().describe( "Filter by token name (partial, case-insensitive). Examples: 'coin', 'ether'", ), limit: z.number().optional().default(10).describe("Max results (default 10)"), }, }, async ({ query, chainId, name, limit }) => { let results = tokenDb.search(query, chainId, limit); if (name) { const lower = name.toLowerCase(); results = results.filter((t) => t.names.some((n) => n.toLowerCase().includes(lower)), ); } return { content: [ { type: "text" as const, text: JSON.stringify({ results, total: results.length, query, chainId, name }), }, ], }; }, ); } - src/tools/search-tokens.ts:11-22 (schema)Input schema definition using zod that defines the parameters for search_tokens: query (required), chainId (optional), name (optional), and limit (optional with default 10)
inputSchema: { query: z.string().describe( "Token name, symbol, or contract address. Examples: 'USDC', 'ethereum', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'", ), chainId: z.string().optional().describe( "Filter by chain ID. Examples: '1' (Ethereum), '42161' (Arbitrum), '7565164' (Solana)", ), name: z.string().optional().describe( "Filter by token name (partial, case-insensitive). Examples: 'coin', 'ether'", ), limit: z.number().optional().default(10).describe("Max results (default 10)"), }, - src/server.ts:6-6 (registration)Import statement that imports registerSearchTokens from the tools module
import { registerSearchTokens } from "./tools/search-tokens.js"; - src/server.ts:36-36 (registration)Tool registration call that registers the search_tokens tool with the MCP server
registerSearchTokens(server, tokenDb); - src/lib/token-db.ts:30-69 (helper)The TokenDb.search method that implements the core token search logic with priority ranking: exact symbol > exact name > symbol starts-with > name includes, plus chain filtering and address lookup
search(query: string, chainId?: string, limit = 10): TokenEntry[] { let pool = this.tokens; if (chainId) { pool = pool.filter((t) => t.chainId === chainId); } // Address lookup: exact match only if (isAddress(query)) { const lower = query.toLowerCase(); return pool .filter((t) => t.address.toLowerCase() === lower) .slice(0, limit); } // Text search with priority: exact symbol > exact name > symbol starts-with > name includes const q = query.toLowerCase(); const exactSymbol: TokenEntry[] = []; const exactName: TokenEntry[] = []; const symbolPrefix: TokenEntry[] = []; const nameSubstring: TokenEntry[] = []; for (const t of pool) { const sym = t.symbol.toLowerCase(); const namesLower = t.names.map((n) => n.toLowerCase()); if (sym === q) exactSymbol.push(t); else if (namesLower.some((n) => n === q)) exactName.push(t); else if (sym.startsWith(q)) symbolPrefix.push(t); else if (namesLower.some((n) => n.includes(q))) nameSubstring.push(t); } const byChain = (a: TokenEntry, b: TokenEntry) => a.chainId.localeCompare(b.chainId); return [ ...exactSymbol.sort(byChain), ...exactName.sort(byChain), ...symbolPrefix.sort(byChain), ...nameSubstring.sort(byChain), ].slice(0, limit); }