fetchTokensOwnedByMultichainAddresses
Retrieve tokens owned by wallet addresses across multiple blockchain networks using a single API call. Streamline multichain token tracking for wallets in one query.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| addresses | Yes | A list of wallet address and network pairs |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"addresses": {
"description": "A list of wallet address and network pairs",
"items": {
"additionalProperties": false,
"properties": {
"address": {
"description": "The wallet address to query. e.g. \"0x1234567890123456789012345678901234567890\"",
"type": "string"
},
"networks": {
"description": "The blockchain networks to query. e.g. [\"eth-mainnet\", \"base-mainnet\"]",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"address",
"networks"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"addresses"
],
"type": "object"
}
Implementation Reference
- index.ts:145-169 (registration)Registration of the MCP tool including Zod input schema and thin wrapper handler that delegates to alchemyApi.getTokensByMultichainAddressserver.tool('fetchTokensOwnedByMultichainAddresses', { addresses: z.array(z.object({ address: z.string().describe('The wallet address to query. e.g. "0x1234567890123456789012345678901234567890"'), networks: z.array(z.string()).describe('The blockchain networks to query. e.g. ["eth-mainnet", "base-mainnet"]') })).describe('A list of wallet address and network pairs'), }, async (params) => { try { const result = await alchemyApi.getTokensByMultichainAddress(params); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } catch (error) { if (error instanceof Error) { console.error('Error in getTokensByMultichainAddress:', error); return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true }; } return { content: [{ type: "text", text: 'Unknown error occurred' }], isError: true }; } });
- api/alchemyApi.ts:65-82 (handler)Core handler function that calls Alchemy's MultiChain Token API endpoint to fetch tokens owned by addresses across networks, processes the response by converting hex balances to decimalsasync getTokensByMultichainAddress(params: MultiChainTokenByAddress) { try { const client = createMultiChainTokenClient(); const response = await client.post('/by-address', { addresses: params.addresses.map((pair: AddressPair) => ({ address: pair.address, networks: pair.networks })) }); const responseData = convertHexBalanceToDecimal(response); return responseData; } catch (error) { console.error('Error fetching token data:', error); throw error; } },
- index.ts:146-150 (schema)Zod schema for input validation defining array of address-network pairsaddresses: z.array(z.object({ address: z.string().describe('The wallet address to query. e.g. "0x1234567890123456789012345678901234567890"'), networks: z.array(z.string()).describe('The blockchain networks to query. e.g. ["eth-mainnet", "base-mainnet"]') })).describe('A list of wallet address and network pairs'), }, async (params) => {
- types/types.d.ts:23-92 (schema)TypeScript type definitions for the input parameters (MultiChainTokenByAddress and AddressPair)export interface MultiChainTokenByAddress { addresses: AddressPair[]; } // || ** MultiChain Transaction History API ** || export interface MultiChainTransactionHistoryByAddress extends MultiChainTokenByAddress { before?: string; after?: string; limit?: number; } // || ** Transfers API ** || export interface AssetTransfersParams { fromBlock: string; toBlock: string; fromAddress?: string; toAddress?: string; contractAddresses: string[]; category: string[]; order: string; withMetadata: boolean; excludeZeroValue: boolean; maxCount: string; pageKey?: string; network: string; } // || ** NFT API ** || export interface NftsByAddressParams { addresses: NftsByAddressPair[]; withMetadata: boolean; pageKey?: string; pageSize: number; } export interface NftsByAddressPair { address: string; networks: string[]; excludeFilters: Array<'SPAM' | 'AIRDROPS'>; includeFilters: Array<'SPAM' | 'AIRDROPS'>; spamConfidenceLevel: 'LOW' | 'MEDIUM' | 'HIGH' | 'VERY_HIGH'; } export interface NftContractsByAddressParams { addresses: AddressPair[]; withMetadata: boolean; } // || ** Wallet API ** || export interface SendTransactionParams { ownerScaAccountAddress: string; signerAddress: string; toAddress: string; value?: string; callData?: string; } export interface SwapParams { ownerScaAccountAddress: string; signerAddress: string; } // || ** Utils ** || export interface AddressPair { address: string; networks: string[]; }
- Utility function to convert hexadecimal token balances to human-readable decimal values using token decimalsexport default function convertHexBalanceToDecimal(response: any) { // Handle nested data structure - API returns { data: { data: { tokens: [...] } } } const responseData = response.data && response.data.data ? response.data.data : response.data; // Process tokens if they exist // LLMs are very bad at arithmetic, so we need to convert the hex balances to decimal if (responseData.tokens && Array.isArray(responseData.tokens)) { // Convert hex balances to decimal responseData.tokens = responseData.tokens.map((token: any) => { try { const processedToken = { ...token }; const hexTokenBalance = token.tokenBalance; const tokenDecimals = parseInt(token.tokenMetadata.decimals || '18', 10); const bigIntBalance = BigInt(hexTokenBalance); const decimalBalance = Number(bigIntBalance) / Math.pow(10, tokenDecimals); // Store both formats processedToken.originalHexBalance = hexTokenBalance; processedToken.tokenBalance = decimalBalance; return processedToken; } catch (error) { // On error, return token with balance as 0 but keep original hex return { ...token, originalHexBalance: token.tokenBalance, tokenBalance: 0 }; } }); } return responseData; }
- api/alchemyClients.ts:18-25 (helper)Helper function creating configured Axios client for Alchemy's MultiChain Token Balances APIexport const createMultiChainTokenClient = () => axios.create({ baseURL: `https://api.g.alchemy.com/data/v1/${API_KEY}/assets/tokens`, headers: { 'accept': 'application/json', 'content-type': 'application/json', 'x-alchemy-client-breadcrumb': BREADCRUMB_HEADER }, });