Connect an AI agent over MCP
TraceFast runs a Model Context Protocol server: an AI agent calls TraceFast's Ethereum data as tools. Each tool is one method of the REST API — the same data, the same bounds, the same refusals — and it is called under your plan: with an API key, or by signing in with your TraceFast account. A tool call counts against a rate limit and your account's daily quota exactly like a REST call; listing the tools does not count.
Address: https://tracefast.xyz/mcp
Transport: Streamable HTTP, one POST per request
Protocol: 2026-07-28; 2025-11-25 clients are served too
Credential: a TraceFast API key, or sign-in with your TraceFast account
Connect a client
There are two ways in. Claude Code, Cursor, your own agent and claude.ai organizations send an API key in a request header; a personal claude.ai account signs in with your TraceFast account instead — see below.
The key goes in one request header. Use the first one; the second exists for clients that can only send a bearer token:
| Header | When |
|---|---|
X-Api-Key: tf_live_… | the client lets you set a header |
Authorization: Bearer tf_live_… | the client can only send a bearer token |
Keys are created in the TraceFast app on a paid plan — see Managing API keys. Every paid plan can connect; the plan decides which tools answer (see Tools).
Claude Code
claude mcp add --transport http tracefast https://tracefast.xyz/mcp \
--header "X-Api-Key: $TRACEFAST_API_KEY"The shell expands the variable, so the key is saved in your Claude Code
configuration. Add --scope user to have TraceFast in every project; /mcp
inside Claude Code shows whether it is connected.
To share the server through a repository without committing the key, put it in
the project's .mcp.json — Claude Code reads ${TRACEFAST_API_KEY} from the
environment of each person who opens the project:
{
"mcpServers": {
"tracefast": {
"type": "http",
"url": "https://tracefast.xyz/mcp",
"headers": { "X-Api-Key": "${TRACEFAST_API_KEY}" }
}
}
}Cursor
In ~/.cursor/mcp.json for every project, or .cursor/mcp.json for one:
{
"mcpServers": {
"tracefast": {
"url": "https://tracefast.xyz/mcp",
"headers": { "X-Api-Key": "${env:TRACEFAST_API_KEY}" }
}
}
}claude.ai on a Team or Enterprise plan
An organization Owner adds TraceFast once, for the whole organization:
- Open Organization settings → Connectors and click Add custom connector.
- Enter the URL
https://tracefast.xyz/mcp. - Open Request headers, choose
x-api-keyand paste the key.
Members then turn the connector on in their own connector settings.
- One key for everyone. Every member's calls go through the key the Owner entered: they share its rate limit and your account's daily quota, and show in its usage as one.
- Request headers are a claude.ai beta open to a limited set of organizations. If the dialog has no Request headers section, your organization cannot connect TraceFast with a key yet.
claude.ai on a personal account
A personal account connects without a key, by signing in with your TraceFast account:
- In claude.ai open Settings → Connectors and click Add custom connector.
- Name it
TraceFastand enter the URLhttps://tracefast.xyz/mcp. - Keep what the dialog detects: authentication Sign in now, OAuth client Register automatically. Leave Request headers empty — a key there turns every call into a call with that key.
- Click Connect, sign in to TraceFast, and read the consent screen: it
names the access asked for (
tracefast:read), your plan and the address it returns to. Click Allow.
The connector stays connected and renews its sign-in on its own. The dialog also offers your own OAuth client or Claude's published identity; neither is needed.
- Your plan decides the tools. A tool above your plan answers with a plan refusal.
- One budget for every agent you sign in. They share one rate limit and one concurrency cap, and their calls count toward your account's daily quota, which your API keys share too.
- To disconnect, remove the app under Settings → Connected apps in TraceFast.
A client that connects with neither a key nor a sign-in gets 401 with a
WWW-Authenticate header pointing at TraceFast sign-in (resource_metadata,
scope tracefast:read). A client that supports MCP sign-in starts it; one that
does not reports an authentication error — give it the key header.
Your own agent
Any MCP client with the Streamable HTTP transport that can set a request header works. MCP SDKs negotiate the protocol version and set the protocol headers themselves.
Call the server from a backend or a local process. A request that carries a
browser Origin header is refused, and the endpoint answers no CORS preflight
— it cannot be called from a web page.
Calling it by hand
For raw HTTP — curl, a test — protocol 2026-07-28 needs no handshake and
no session, but every request must carry:
- the header
MCP-Protocol-Version: 2026-07-28, matching the body; - the header
Mcp-Methodwith the JSON-RPC method, and ontools/callalsoMcp-Namewith the tool name; params._metawith bothio.modelcontextprotocol/protocolVersionandio.modelcontextprotocol/clientCapabilities. An empty object is a validclientCapabilities.
A request without one of the _meta keys is refused with HTTP 400 and
JSON-RPC error -32602; error.data.missing lists the keys that were absent.
SDK clients add them on their own — this matters only when you write the body
yourself.
List the tools:
curl -s https://tracefast.xyz/mcp \
-H "X-Api-Key: $TRACEFAST_API_KEY" \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/list" \
-d '{
"jsonrpc": "2.0", "id": 1, "method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'The list is one page, the same for every account, and carries ttlMs: 3600000
with cacheScope: public: a client may keep it for an hour. It is large — each
tool comes with its full input and output schemas. Protocol calls such as
server/discover and tools/list do not count toward your plan's rate or daily
quota; only tool calls do.
Call a tool:
curl -s https://tracefast.xyz/mcp \
-H "X-Api-Key: $TRACEFAST_API_KEY" \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/call" \
-H "Mcp-Name: get_latest_block" \
-d '{
"jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": {
"name": "get_latest_block",
"arguments": {},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'Results
A tool that answers returns its REST response whole in structuredContent,
and the same JSON as one text block for clients that read only text:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"resultType": "complete",
"structuredContent": {
"data": { "number": 26091151, "hash": "0xfdd109390c63bb9efa2d86af53b7b06769d7c2151d9a7f95b69e2f076a5b12f7", "…": "…" },
"meta": {
"chain": "ethereum",
"timestamp": 1790781616092,
"cached": false,
"asOfBlock": 26091151,
"docs": "https://docs.tracefast.xyz/api/block-latest"
},
"links": { "web": "https://tracefast.xyz/blocks/26091151" }
},
"content": [{ "type": "text", "text": "{\"data\":{…},\"meta\":{…},\"links\":{…}}" }],
"isError": false
}
}dataandmetaare the method's REST answer — see Conventions.meta.asOfBlockis the block the answer is valid at,meta.cachedsays whether it came from the response cache,meta.docslinks the method page. Not every source reaches the chain head at the same moment: see Data freshness.links.webis the TraceFast page of what the answer is about — the entity page of an address or token, the page of a transaction or a block — so an agent can hand its user a link.resolve_entitylinks its best match, and carries nolinkswhen nothing matched.- List tools return a small page by default — smaller than the REST method's
— and take
limitup to the maximum their description states. A largerlimitis refused, never cut. Tools with acursorargument continue with thenextCursorinsidedata; the others answer in one call.
Refusals
A call can be refused at four points, and each looks different:
| Refused by | What the agent receives | For example |
|---|---|---|
| the credential or a limit | HTTP 401 or 429 with the REST refusal body — no tool runs | api_key_required, invalid_api_key, a 429 with bucket |
| the plan | HTTP 200: a tool result with isError: true and error.code forbidden | plan_scope_missing |
| the protocol | a JSON-RPC error with an integer code | a missing _meta key, an unknown tool or argument |
| the data | HTTP 200: a tool result with isError: true | not_found, block_not_available, bad_request |
The key and the limits
These come from the credential check, before any tool runs, in the same
envelope as on REST. With no credential the 401 also carries a
WWW-Authenticate header that points at TraceFast sign-in:
{
"error": {
"code": "auth_failed",
"message": "authentication failed: sign in with your TraceFast account (OAuth) or send an API key",
"reason": "api_key_required"
}
}401api_key_required— neither a key nor a valid sign-in was sent: no credential, a header value that is not a TraceFast key, or a sign-in that is invalid or expired. Sign in again, or send the key.401invalid_api_key— the value is not a valid key. A disabled, expired or revoked key has its ownreason.429— a rate limit or the daily quota;bucketnames which one, andRetry-Aftersays when to try again where waiting helps. Tool calls share the key's request rate with its REST calls: on a plan with a low rate, two calls sent back to back can get429withbucket: base. Pace them.
Every reason and bucket is explained on
API keys, with the limits under
rate limits and quotas.
The plan
A tool your plan or your key does not open is not an HTTP error on MCP — REST
answers 403 for the same thing. It is a tool result on HTTP 200 with
isError: true, so the agent can read why and tell its user:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"resultType": "complete",
"structuredContent": {
"error": {
"code": "forbidden",
"message": "forbidden: your plan does not include this method — see https://tracefast.xyz/pricing for the plans that do",
"reason": "plan_scope_missing",
"details": { "upgrade": "https://tracefast.xyz/pricing" },
"requestId": "…"
}
},
"content": [{ "type": "text", "text": "{\"error\":{…}}" }],
"isError": true
}
}reason | What happened | What to do |
|---|---|---|
plan_scope_missing | the tool needs a higher plan than yours; details.upgrade links the plans | upgrade the plan — the key itself is fine |
key_scope_missing | your plan opens the tool, but the key was issued without it | issue or rotate a key that includes it |
endpoint_group_not_allowed | this key may not call this tool | check the plan and the key's permissions |
account_suspended | the account is suspended | contact support |
tools/list is the same for every account, so an agent sees tools its plan
does not open; the plan each tool needs is in Tools.
The protocol
A request the server cannot take as MCP gets a JSON-RPC error with an integer
code, on HTTP 400 in protocol 2026-07-28:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "request _meta is missing: io.modelcontextprotocol/clientCapabilities",
"data": {
"missing": ["io.modelcontextprotocol/clientCapabilities"],
"requestId": "01a0f2e6-f020-7e20-b144-c1ebe68220f4"
}
}
}code | Meaning |
|---|---|
-32602 | invalid params: an unknown tool; an argument the tool does not take, a missing required argument or a value of the wrong type — error.data.argument names it; a missing _meta key — error.data.missing lists them |
-32020 | Mcp-Method, Mcp-Name or MCP-Protocol-Version disagrees with the body, is repeated, or is missing |
-32022 | the protocol version is not served; error.data.supported lists the ones that are |
-32601 | the method does not exist — the server offers tools only, no resources, prompts or subscriptions |
-32600 | not a single JSON-RPC 2.0 request — a batch is refused; also a body over 16 KiB, an HTTP method other than POST and a browser Origin |
-32700 | the body is not JSON |
error.data.requestId identifies the request — quote it when you contact
support. A client on protocol 2025-11-25 receives the same errors on HTTP
200, as that version expects.
The data
A tool the data refuses — a malformed address, a block the method cannot
answer yet, a limit above the tool's maximum — is not an HTTP error. It is an
ordinary result on HTTP 200 with isError: true, and structuredContent
holds the refusal the REST method gives:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"resultType": "complete",
"structuredContent": {
"error": {
"code": "not_found",
"message": "no block at height 99999999",
"requestId": "01a0f2e6-efec-73f2-9992-615a0b686e86"
}
},
"content": [{ "type": "text", "text": "{\"error\":{…}}" }],
"isError": true
}
}Branch on error.code and details.reason exactly as on REST — the registry
is under Errors. A block_not_available means "not
built yet" or "not visible right now", never "does not exist": see
Data freshness.
Tools
The list below is generated from the server's own tools/list. Each tool is one
method of the REST API: the same arguments under the same names, the same data
and the same refusals — its method page is the reference. The heading is the
lowest plan that opens the tool; higher plans include it
(plans).
Enriched Data
| Tool | What it answers |
|---|---|
get_block | One block |
get_block_authorizations | EIP-7702 authorizations of one block |
get_block_transactions | Transactions of one block |
get_block_withdrawals | Validator withdrawals of one block |
get_contract | One contract |
get_contract_bytecode | Bytecode of a contract |
get_contract_proxy | Implementations of a proxy contract |
get_contract_selectors | Function selectors of a contract |
get_entity_activity | Activity of an address |
get_entity_balance_history | Native balance history of an address |
get_entity_daily_activity | Daily activity of an address |
get_entity_overview | One address |
get_latest_block | The latest block |
get_token | One token contract |
get_token_stats | Token statistics of the network |
get_token_transfers | Transfers of a token |
get_transaction | One transaction |
get_transaction_events | Event logs of a transaction |
get_transaction_failures | Why a transaction reverted |
Intelligence
| Tool | What it answers |
|---|---|
get_block_addresses | Accounts touched by one block |
get_block_proposers | Block-proposal leaderboard |
get_entity_attribute_history | Attribute history of an address |
get_entity_attribute_proof | Proof of one attribute of an address |
get_entity_attributes | Attributes of an address |
get_entity_attributes_at_block | Attributes of an address at a block |
get_entity_counterparties | Address counterparties |
get_entity_portfolio | Portfolio of an address |
get_entity_relation_history | Relation history of an address |
get_entity_relation_proof | Proof of one relation of an address |
get_entity_relations | Relations of an address |
get_entity_relations_at_block | Relations of an address at a block |
get_entity_token_balance | Balance of one token on an address |
get_token_holders | Top holders of a token |
get_validator_queue_history | Validator queues over time |
get_validator_queues | Validator queues now |
get_validator_withdrawals | Withdrawals of a validator |
resolve_entity | Resolve a name, symbol or address |
Investigation
| Tool | What it answers |
|---|---|
get_blacklist_events | Blacklist events about one address |
get_blacklist_status | Which issuer contracts list one address |
get_contract_events | Events emitted by a contract |
get_entity_internal_transfers | Internal transfers of an address |
get_entity_token_transfers | Token transfers of an address |
get_entity_transactions | Transactions of an address |
get_trace_frames | Call frames of a transaction, paged |
get_transaction_storage_writes | Storage writes of a transaction |
get_transaction_trace | Execution trace of a transaction |
Related pages
- API keys — plans, refusals and limits
- Managing API keys — creating, rotating and revoking keys
- Conventions — responses, errors and data freshness
- All methods — every REST method on one page
- Paying with x402 — the key-less way, paid per call
Last updated 01 Oct 2026, 13:38 UTC · verified against TraceFast v1.0.135 · Markdown