mcp-tenderly

mcp-tenderly

Simulates EVM transactions against forked chain state and explains why they revert, using Tenderly's free-tier API with decoded traces and source-mapped errors. Provides tools to simulate single transactions or bundles and inspect saved simulations, all with output size controls to keep responses affordable.

Category
访问服务器

README

mcp-tenderly

An MCP server that gives an AI assistant the ability to simulate EVM transactions and debug why they revert, using Tenderly's free-tier simulation API.

Ask "would this transaction work?" or "why did this fail?" and get an answer grounded in real forked chain state — the decoded call trace, the revert reason, the exact source line — instead of a guess.

Nothing is ever broadcast. Simulations are read-only against a fork, so they are safe to run freely.

Why this exists

An assistant reasoning about an on-chain transaction is normally working blind: it can read the contract source, but it cannot tell you whether a call reverts against current state, what the gas actually costs, or which of eight nested delegatecalls is the one that failed. Tenderly can answer all three, and its simulation API is usable on a free account.

The hard part is not calling the API — it is that a simulation_type: "full" response for a real DeFi transaction is frequently over a megabyte of JSON: a state diff over every touched storage slot, a call tree hundreds of frames deep. Handing that to a model is both unaffordable and useless, because the answer to "why did this revert" is four lines buried inside it.

So this server's real work is the formatter: it puts the outcome first, then the revert reason and the source-mapped frame, then decoded events, then the call tree as an indented ASCII diagram — and it always states when it truncated something, because a silent cap reads as "that was everything".

Quickstart

Requires Node.js 22.12 or newer.

1. Get Tenderly credentials

All three come from a free Tenderly account:

Variable Where to find it
TENDERLY_API_KEY Dashboard → Account Settings → Access TokensGenerate Access Token
TENDERLY_ACCOUNT_SLUG The first path segment of your dashboard URL: dashboard.tenderly.co/<this>/…
TENDERLY_PROJECT_SLUG The second segment: dashboard.tenderly.co/…/<this>

Both slugs are the URL slugs, not display names — a project shown as "My Project" is usually my-project. The server validates this at startup and tells you which variable is wrong rather than letting it surface later as a 404.

2. Register the server with your client

Claude Code

claude mcp add tenderly \
  -e TENDERLY_API_KEY=your-token \
  -e TENDERLY_ACCOUNT_SLUG=your-account \
  -e TENDERLY_PROJECT_SLUG=your-project \
  -- npx -y mcp-tenderly

Claude Desktop, Cursor, or any other MCP host — add to the client's MCP config file:

{
  "mcpServers": {
    "tenderly": {
      "command": "npx",
      "args": ["-y", "mcp-tenderly"],
      "env": {
        "TENDERLY_API_KEY": "your-token",
        "TENDERLY_ACCOUNT_SLUG": "your-account",
        "TENDERLY_PROJECT_SLUG": "your-project"
      }
    }
  }
}

Running from a local clone

git clone https://github.com/py-zoid/mcp-tenderly.git
cd mcp-tenderly
npm install
npm run build

Then point the client at the build output, replacing <repo> with the absolute path to your clone:

{
  "mcpServers": {
    "tenderly": {
      "command": "node",
      "args": ["<repo>/dist/index.js"],
      "env": { "TENDERLY_API_KEY": "…", "TENDERLY_ACCOUNT_SLUG": "…", "TENDERLY_PROJECT_SLUG": "…" }
    }
  }
}

Tools

tenderly_simulate_transaction

Simulate one transaction against forked chain state. Returns success or revert, gas used, the revert reason with a source-mapped stack trace where the contract is verified, decoded events, token transfers, and the decoded call trace.

Accepts network as a name (base, arbitrum, polygon, sepolia, …) or a numeric chain id, the usual transaction fields (from, to, data, value, gas, gas_price), an optional block_number to fork from, and state_overrides to fake balances, nonces, storage slots or bytecode.

tenderly_simulate_bundle

Simulate up to 20 transactions in order against shared state, so each sees the effects of the ones before it. This is the tool for flows that cannot be checked one transaction at a time — approve then swap, deploy then initialise, or replaying an exploit sequence. It reports which step in the sequence broke.

tenderly_get_simulation

Look up a saved simulation by id and render its outcome and full call trace. Use it to go deeper on a trace that was truncated, to pull the state diff that is omitted by default, or to inspect a simulation created earlier or from the Tenderly UI.

One thing worth knowing, because it shapes how this tool behaves: Tenderly's saved-simulation record stores only metadata — inputs, gas, status, error message. The call trace is not kept. So the trace is reproduced by replaying the recorded inputs at the recorded block, which is faithful (same fork, same outcome) but costs one simulation against your rate limit. The replay is not saved, so it does not consume stored-simulation quota. Pass reconstruct_trace: false for a cheap metadata-only lookup.

tenderly_list_simulations

List recent saved simulations in the project, one line each, to find an id.

Controlling output size

Every read tool takes the same output controls. The defaults are tuned to keep a typical response affordable:

Argument Default Notes
include_call_trace true The main debugging artefact.
include_state_diff false Off by default — by far the bulkiest section.
include_opcode_frames false Show SLOAD/SSTORE/LOG frames. See below.
max_trace_nodes 200 Truncation is always reported in the output.
max_trace_depth 12 Deep proxy chains hit this before the node cap.
include_raw_response false Appends the untouched Tenderly JSON. Very large.

A full Tenderly trace interleaves storage and log opcodes with real calls — a plain USDC transfer yields a dozen SLOADs around four actual calls, and a DeFi transaction yields hundreds. Left in, they consume the frame budget and push the calls that explain a revert out of the output, so they are hidden by default and the count is reported. Internal Solidity function frames (JUMPDEST) are kept: those are what let you follow a revert through a library or proxy.

Free-tier notes

This server deliberately uses only the v1 simulation REST endpoints that work on a free plan: /simulate, /simulate-bundle, /simulations and /simulations/{id}. It never touches the Web3 Gateway, DevNets, Virtual TestNets, Alerts or the Actions API — those are paid or OAuth-gated, and reaching for them would make the server fail confusingly for exactly the users it targets.

Two things to know about quota:

  • Saved simulations consume quota. By default simulations are saved, because a dashboard URL is worth a great deal when debugging. Set TENDERLY_SAVE_SIMULATIONS=false, or pass save: false per call, to keep them ephemeral.
  • Rate limits produce a 429. The client retries these with backoff, honouring Retry-After, and then reports the limit plainly rather than hanging.

Optional configuration

Variable Default Purpose
TENDERLY_SAVE_SIMULATIONS true Persist simulations and return a URL.
TENDERLY_LOG_LEVEL info debug, info, warn, error.
TENDERLY_TIMEOUT_MS 30000 Per-request timeout.
TENDERLY_BASE_URL https://api.tenderly.co Override for testing against a stub.

Security and trust model

Simulations never broadcast. Every call is read-only against a Tenderly fork. No transaction is signed or sent, and the server holds no keys beyond your Tenderly access token.

One outbound host. The server talks only to api.tenderly.co. Nothing else is contacted, and no telemetry is collected.

Your access token stays out of output. It is sent only as the X-Access-Key header, is never logged at any log level, and is excluded from error messages and paths. A test asserts it is absent from both stdout and stderr.

Simulation output is treated as untrusted input. This is the one worth understanding, because it is easy to miss. Contract names, token symbols, function names, decoded strings, verified source lines and revert reasons are all controlled by whoever deployed the contract — and the point of this server is pointing it at contracts you do not yet trust. A contract can revert() with any string it likes, which lands in the most prominent position in the output.

So all such text is passed through a sanitiser before rendering: whitespace is collapsed to a single line, zero-width and bidi-override characters are removed, and length is capped with the truncation stated. That prevents hostile chain data from forging a markdown heading, a list item, or anything else that could read to a model as instructions rather than as data. It is a structural defence, not an attempt to detect malicious intent — untrusted text simply cannot escape the field it belongs to. Ordinary revert strings are unaffected.

This does not make a hostile contract's output true, only inert. Treat a simulation result as a report about untrusted code, which is what it is.

Troubleshooting

The server exits immediately with a config message. That is by design — it refuses to start rather than failing inside your first tool call. The message names the variable at fault. Exit code is 78 (EX_CONFIG).

401 or 403. The token must be an Access Token from Account Settings, not a project secret or an RPC key, and it must belong to an account with access to TENDERLY_ACCOUNT_SLUG.

404. Almost always a slug problem: display name instead of slug, or account/project pasted into one variable.

No revert reason on a failure. The contract is probably unverified, or it used a custom error. The call trace still identifies the failing frame, and the selector is shown so you can look it up.

Everything looks empty. Re-run with include_raw_response: true to see what Tenderly actually returned.

Server logs go to stderr as JSON — check your MCP client's server log view. The API key is never logged.

Development

npm install        # also installs the git hooks via core.hooksPath
npm run verify     # everything CI runs: format, lint, types, unit, stdio smoke
npm test           # unit tests only
npm run test:smoke # builds, then drives dist/index.js over real stdio

npm run verify is exactly what CI executes — the workflow YAML only invokes .github/scripts/verify.sh, so there is nothing you cannot reproduce locally.

See CLAUDE.md for the architecture and the design decisions worth knowing before changing anything.

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选