Overview Etherscan V2 MCP Server exposes a curated set of Etherscan V2 endpoints as Model Context Protocol (MCP) tools. It can run either as a streamable HTTP MCP endpoint or as a stdio MCP server. Native ESM is used throughout the project.
Key files:
- Server:
src/index.ts
- Tools:
src/tools.ts
- Schemas:
src/schemas.ts
- MCP Resources:
src/resources.ts
Requirements
- Node.js: 20+ (recommended 22+)
- Package manager: npm, yarn, or pnpm
Installation
npm i
Environment
Copy .env.example
to .env
and set values:
- ETHERSCAN_API_KEY: Your Etherscan (or supported explorer) API key.
- ETHERSCAN_PRO: optional, enable pro features if available.
- OPENAI_API_KEY: optional, enables simple NL routing for
ethv2_nl_query
. - REDIS_HOST, REDIS_PORT, REDIS_PASSWORD: optional; if set, server uses Redis-backed cache; otherwise in-memory cache.
- PORT: default 5009.
- HOST: default 0.0.0.0.
Scripts
- build:
tsc
- dev:
tsx src/index.ts
- start:
node dist/index.js
- test:
jest --passWithNoTests
Run (HTTP MCP and REST info)
# Development (tsx)
npm run dev
# Production build
npm run build && npm start
# Stdio mode for MCP-aware clients
node dist/index.js --stdio
HTTP Endpoints (non-MCP)
- GET
/health
: basic liveness payload. - GET
/api/tools
: returns the tool catalog with input JSON Schemas. /mcp
: Streamable HTTP transport for MCP. Initialize the session with a POST first; persist themcp-session-id
header on subsequent requests in the same session.
MCP Resources These are discoverable via MCP requests (not plain REST):
etherscanv2://guide
: Markdown guide on choosing tools and pagination strategies.etherscanv2://api-map
: JSON map of categories ➜ tool names.
Caching
Responses are cached per-tool with small TTLs (e.g., 5–300s typical, longer for static metadata). If REDIS_HOST
is set, Redis is used; otherwise, an in-memory fallback cache is used. See src/tools.ts
for TTLs applied per tool.
Conventions
- Always include
chainid
(EVM chain ID, e.g., 1/Ethereum, 10/Optimism, 42161/Arbitrum, 8453/Base). - Use pagination for list endpoints:
page
andoffset
. Do not aggregate many pages in a single call. - For logs, use address/topic filters and
fromBlock
/toBlock
windows.
Tool Catalog
Below are the tool names, purpose, and concise input schemas (see src/schemas.ts
for authoritative definitions).
Accounts
- ethv2_account_balance – Get account balance at a tag.
- Input:
{ chainid: number, address: string, tag?: 'latest'|'earliest'|'pending' }
- Input:
- ethv2_account_txlist – Normal txs for an address (paginated).
- Input:
{ chainid, address, startblock?, endblock?, sort?: 'asc'|'desc', page?, offset? }
- Input:
- ethv2_account_txlistinternal – Internal txs for an address (paginated).
- Input: same as
ethv2_account_txlist
- Input: same as
- ethv2_account_tokentx – ERC-20 transfers for an address (paginated; optional contract filter).
- Input:
{ chainid, address, contractaddress?, sort?, page?, offset? }
- Input:
Blocks & Transactions
- ethv2_block_by_time – Block number nearest to a timestamp.
- Input:
{ chainid, timestamp: number, closest?: 'before'|'after' }
- Input:
- ethv2_tx_receipt_status – Receipt status for a tx hash.
- Input:
{ chainid, txhash: string }
- Input:
- ethv2_tx_status – Transaction status for a tx hash.
- Input:
{ chainid, txhash: string }
- Input:
Contracts
- ethv2_contract_getabi – Verified contract ABI.
- Input:
{ chainid, address }
- Input:
- ethv2_contract_getsourcecode – Verified contract source code.
- Input:
{ chainid, address }
- Input:
Logs
- ethv2_logs_getLogs – Logs by address/topics (paginated; windowed).
- Input:
{ chainid, address?, fromBlock?, toBlock?, topic0?, topic1?, topic2?, topic3?, page?, offset? }
- Input:
Tokens
- ethv2_token_supply – Token supply by contract.
- Input:
{ chainid, contractaddress }
- Input:
- ethv2_token_balance – Token balance for address.
- Input:
{ chainid, contractaddress, address, tag?: 'latest'|'earliest'|'pending' }
- Input:
- ethv2_token_holderlist – Holder list for a token (paginated).
- Input:
{ chainid, contractaddress, page?, offset? }
- Input:
- ethv2_account_tokennfttx – ERC‑721 transfers for address (paginated; optional contract filter).
- Input:
{ chainid, address, contractaddress?, sort?, page?, offset? }
- Input:
- ethv2_account_token1155tx – ERC‑1155 transfers for address (paginated; optional contract filter).
- Input:
{ chainid, address, contractaddress?, sort?, page?, offset? }
- Input:
Gas & Stats
- ethv2_gas_oracle – Gas oracle (base/rapid/safe) per chain.
- Input:
{ chainid }
- Input:
- ethv2_stats_ethprice – ETH price per chain.
- Input:
{ chainid }
- Input:
- ethv2_stats_ethsupply – ETH supply per chain.
- Input:
{ chainid }
- Input:
Proxy (JSON‑RPC)
- ethv2_proxy_blockNumber –
eth_blockNumber
.- Input:
{ chainid }
- Input:
- ethv2_proxy_getBlockByNumber –
eth_getBlockByNumber
.- Input:
{ chainid, tag: string /* hex or 'latest' */, boolean?: boolean /* include tx objects */ }
- Input:
- ethv2_proxy_getTransactionByHash –
eth_getTransactionByHash
.- Input:
{ chainid, txhash }
- Input:
Nametags
- ethv2_nametag_by_address – Address nametag (where supported).
- Input:
{ chainid, address }
- Input:
Natural Language (optional)
- ethv2_nl_query – Lightweight NL router for common intents.
- Input:
{ chainid: number, query: string }
- Notes: looks for simple intents like gas, tx status, balance, logs; otherwise returns guidance.
- Input:
Examples List tools (REST):
curl http://localhost:5009/api/tools | jq
Get gas oracle via MCP (stdio example with node --stdio
requires an MCP client). For a plain HTTP sanity check, you can quickly call the underlying client from a one-off script or use a tailored MCP client.
ESM Note
This project is native ESM ("type": "module"
). Local imports include explicit .js
extensions in source so that compiled output in dist/
runs under Node ESM without resolution errors.
License MIT