MCP server for Ethereum Virtual Machine (EVM) RPC APIs, powered by evmdecoder.
This server exposes curated EVM read/decoding tools for LLM clients while keeping RPC endpoints hidden from tool schemas.
- FastMCP stdio server (
mcp-evm) - Hidden per-request RPC URL support via
context.extraArgs.rpcUrl - Fallback RPC URL via
EVM_RPC_URL - Per-RPC decoder instance pooling with LRU eviction
- Curated tool surface (15 tools) to avoid oversized payloads
- Timestamp normalization to human-readable UTC text before returning results
- Type-safe schemas with strict TypeScript
- CI build/test and npm publish GitHub Actions
The server currently exposes these tools:
evm_decode_function_callevm_decode_function_call_v2evm_contract_infoevm_get_blockevm_get_slim_blockevm_get_slim_block_by_hashevm_get_full_blockevm_get_pending_transactionsevm_get_pending_transactionevm_get_transactionevm_get_transaction_receiptevm_get_internal_transactionevm_get_internal_transactions_by_blockevm_get_fee_historyevm_get_latest_block_number
Notes:
initializeis not exposed as a tool; decoder initialization is internal.- High-volume/batch tools and raw processing utilities are intentionally not exposed.
evm_get_pending_transactionsdefaults todecode: falseto reduce response size.
Sample payloads for a subset of tools are available in sample-data/.
Not every tool currently has sample data.
Available samples:
evm_contract_info:sample-data/evm_contract_info.jsonevm_decode_function_call:sample-data/evm_decode_function_call.jsonevm_decode_function_call_v2:sample-data/evm_decode_function_call_v2.jsonevm_get_block:evm_get_slim_block:sample-data/evm_get_slim_block.jsonevm_get_transaction:sample-data/evm_get_transaction.jsonevm_get_transaction_receipt:sample-data/evm_get_transaction_receipt.jsonevm_get_internal_transaction:sample-data/evm_get_internal_transaction.jsonevm_get_fee_history:sample-data/get_fee_history.json
- Node.js
>=20 - Yarn (project scripts use Yarn)
yarn install --frozen-lockfile
yarn build
yarn startmcp-evmThe server runs over stdio transport.
Each tool call resolves RPC URL in this order:
- Hidden extra argument:
rpcUrl(preferred) - Environment fallback:
EVM_RPC_URL
If neither is present, the tool throws a user-facing error.
Important: rpcUrl is intentionally not part of public tool schemas.
Copy .env.example to .env and set values as needed.
| Variable | Required | Default |
|---|---|---|
EVM_RPC_URL |
No | unset |
EVM_ABI_DIRECTORY |
No | ../abis relative to built files |
EVM_HTTP_TIMEOUT_MS |
No | 60000 |
EVM_HTTP_VALIDATE_CERTIFICATE |
No | false |
EVM_HTTP_KEEP_ALIVE |
No | true |
EVM_HTTP_MAX_SOCKETS |
No | 256 |
EVM_HTTP_MAX_RETRIES |
No | 10 |
EVM_HTTP_MAX_BATCH_SPLITS |
No | 15 |
EVM_CLIENT_MAX_BATCH_SIZE |
No | 100 |
EVM_CLIENT_MAX_BATCH_TIME |
No | 0 |
EVM_CLIENT_INDIVIDUAL_RECEIPTS |
No | true |
EVM_CLIENT_MAX_RETRY_TIME |
No | 10000 |
EVM_CLIENT_TRACER_TIMEOUT |
No | 100 |
EVM_CONTRACT_INFO_MAX_CACHE_ENTRIES |
No | 25000 |
EVM_EXPERIMENTAL |
No | false |
EVM_DECODER_POOL_MAX_ENTRIES |
No | 25 |
- If
EVM_ABI_DIRECTORYexists, it is used for ABI discovery. - If configured/default ABI directory does not exist, the server falls back cleanly and continues with built-in anonymous signature support from
evmdecoder. abis.zipis committed and published, and is automatically extracted into./abisduring package install viapostinstall.- Manual extraction is also available:
yarn extract:abisDecode EVM function input.
Parameters:
input: stringaddress?: string
Sample:
Decode function input and include contract info.
Parameters:
input: stringaddress?: string
Sample:
Classify/inspect a contract address.
Parameters:
address: string
Sample:
Get block with decoded transactions by default.
Parameters:
blockNumber: numberdecode?: boolean(defaulttrue)
Samples:
Get slim block.
Parameters:
blockNumber: numberraw?: boolean(defaulttrue)
Sample:
Get slim block by hash.
Parameters:
hash: stringraw?: boolean(defaulttrue)
Get full block with receipts.
Parameters:
blockNumber: numberdecode?: boolean(defaulttrue)
Get pending transactions; decode is off by default.
Parameters:
decode?: boolean(defaultfalse)
Get one pending transaction by hash.
Parameters:
hash: stringdecode?: boolean(defaulttrue)
Get transaction by hash.
Parameters:
hash: stringdecode?: boolean(defaulttrue)
Sample:
Get transaction receipt.
Parameters:
hash: stringdecode?: boolean(defaulttrue)
Sample:
Get internal trace for one transaction.
Parameters:
hash: stringdecode?: boolean(defaulttrue)
Sample:
Get internal traces by block number.
Parameters:
blockNumber: numberdecode?: boolean(defaulttrue)
Get fee history.
Parameters:
blockCount: numberblockTarget: number
Sample:
Get latest block number.
Parameters:
- none
Before returning tool results, any field named timestamp is normalized recursively to human-readable UTC text:
- Supports numeric epoch seconds
- Supports numeric epoch milliseconds
- Supports numeric strings and hex strings (for example
0x...) - Output format:
YYYY-MM-DD HH:mm:ss.sss UTC
All non-timestamp fields are returned unchanged.
Tool handlers return deterministic JSON text (stringified payload). In MCP responses, this appears as text content and should be parsed by clients that need structured access.
Response normalization also applies two token-optimization/enrichment rules:
- If a formatted transaction includes decoded
call, the rawinputfield is removed. - If decoded transactions/logs are missing
call/event, the server attempts to enrich them before returning.
JSON-RPC tools/call with hidden RPC URL
{
"method": "tools/call",
"params": {
"name": "evm_get_block",
"arguments": {
"blockNumber": 19000000,
"decode": true,
"rpcUrl": "https://mainnet.infura.io/v3/<key>"
}
}
}{
"method": "tools/call",
"params": {
"name": "evm_get_latest_block_number",
"arguments": {}
}
}await client.callTool('evm_get_transaction', {
hash: '0x...',
decode: true,
rpcUrl: 'https://mainnet.infura.io/v3/<key>',
})yarn build- clean + compile TypeScript + make CLI executableyarn start- run built serveryarn dev- watch compile and runyarn inspect- inspect MCP server with FastMCP inspectoryarn test- run unit testsyarn test:watch- run tests in watch modeyarn test:coverage- run tests with V8 coverage reportyarn format- check Prettier formattingyarn format:write- apply formatting
yarn test:coverageVitest writes a coverage report under coverage/.
Workflows are in .github/workflows/:
build.yaml: build + test on pull requestspublish.yaml: build + test + publish to npm onmainpushes (ignoring markdown-only changes)
Publish job requires repository secret:
NPM_TOKEN(used asNODE_AUTH_TOKEN)
Package is configured for scoped public publish:
- name:
@missionsquad/mcp-evm publishConfig.access:publicprepublishOnly: runs tests and build before publish
Manual publish (if needed):
npm publish --access publicProvide hidden rpcUrl in tool arguments or set EVM_RPC_URL.
If you want local ABI matching, set EVM_ABI_DIRECTORY to an existing folder or run yarn extract:abis.
Use slim/single-item tools and keep decode flags intentional. evm_get_pending_transactions defaults to decode: false for this reason.
Mission Squad provides a platform for building and running AI agents with production-ready tooling, including MCP server integrations like this one.
You can configure MCP servers, connect external systems, and create specialized agents quickly without rebuilding core infrastructure each time.
MIT