get-token-transfers
Retrieve ERC20 token transfer history for any Ethereum wallet address to track incoming and outgoing transactions.
Instructions
Get ERC20 token transfers for an Ethereum address
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Ethereum address (0x format) | |
| limit | No | Number of transfers to return (max 100) |
Implementation Reference
- src/services/etherscanService.ts:97-129 (handler)Core implementation of the getTokenTransfers function that fetches and formats ERC20 token transfers from the Etherscan API.async getTokenTransfers(address: string, limit: number = 10): Promise<TokenTransfer[]> { try { const validAddress = ethers.getAddress(address); // Get ERC20 token transfers const result = await fetch( `https://api.etherscan.io/api?module=account&action=tokentx&address=${validAddress}&page=1&offset=${limit}&sort=desc&apikey=${this.provider.apiKey}` ); const data = await result.json(); if (data.status !== "1" || !data.result) { throw new Error(data.message || "Failed to fetch token transfers"); } // Format the results return data.result.slice(0, limit).map((tx: any) => ({ token: tx.contractAddress, tokenName: tx.tokenName, tokenSymbol: tx.tokenSymbol, from: tx.from, to: tx.to, value: ethers.formatUnits(tx.value, parseInt(tx.tokenDecimal)), timestamp: parseInt(tx.timeStamp) || 0, blockNumber: parseInt(tx.blockNumber) || 0 })); } catch (error) { if (error instanceof Error) { throw new Error(`Failed to get token transfers: ${error.message}`); } throw error; } }
- src/server.ts:226-264 (handler)MCP server request handler for the get-token-transfers tool, including input validation, service call, response formatting.if (name === "get-token-transfers") { try { const { address, limit } = TokenTransferSchema.parse(args); const transfers = await etherscanService.getTokenTransfers( address, limit ); const formattedTransfers = transfers .map((tx) => { const date = new Date(tx.timestamp * 1000).toLocaleString(); return ( `Block ${tx.blockNumber} (${date}):\n` + `Token: ${tx.tokenName} (${tx.tokenSymbol})\n` + `From: ${tx.from}\n` + `To: ${tx.to}\n` + `Value: ${tx.value}\n` + `Contract: ${tx.token}\n` + `---` ); }) .join("\n"); const response = transfers.length > 0 ? `Recent token transfers for ${address}:\n\n${formattedTransfers}` : `No token transfers found for ${address}`; return { content: [{ type: "text", text: response }], }; } catch (error) { if (error instanceof z.ZodError) { throw new Error( `Invalid input: ${error.errors.map((e) => e.message).join(", ")}` ); } throw error; } }
- src/server.ts:49-54 (schema)Zod schema used for input validation in the get-token-transfers tool handler.const TokenTransferSchema = z.object({ address: z .string() .regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format"), limit: z.number().min(1).max(100).optional(), });
- src/server.ts:102-122 (registration)Registration of the get-token-transfers tool in the MCP server's listTools response, defining name, description, and JSON input schema.{ name: "get-token-transfers", description: "Get ERC20 token transfers for an Ethereum address", inputSchema: { type: "object", properties: { address: { type: "string", description: "Ethereum address (0x format)", pattern: "^0x[a-fA-F0-9]{40}$", }, limit: { type: "number", description: "Number of transfers to return (max 100)", minimum: 1, maximum: 100, }, }, required: ["address"], }, },
- TypeScript interface defining the structure of token transfer data returned by getTokenTransfers.export interface TokenTransfer { token: string; tokenName: string; tokenSymbol: string; from: string; to: string; value: string; timestamp: number; blockNumber: number; }