MCP server: agentic fork-and-experiment over Stacks - #85
Merged
Conversation
Add a TS MCP package to the workspace. Exposes create_stack/list_stacks/ delete_stack over stdio against the Stacks REST API, with base64 explorer deep links built from each stack's key-in-url rpc. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
get_block/get_transaction/get_address/get_logs resolve a stack's rpc via GET /stacks/:slug and return bigint-safe data plus an explorer deep link. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
simulate_call dry-runs via eth_call. execute signs with PRIVATE_KEY or the default anvil account 0 (no config needed), waits for the receipt, and returns an explorer link. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- abi.ts loads foundry out/*.json into a merged ABI for calldata/event decode - get_transaction now decodes call + events when FOUNDRY_OUT is set - deploy_contract deploys bytecode from artifacts, returns address + link - execute gains a 'from' param that impersonates any sender (no key) - cheatcodes: impersonate, set_balance, mine, set_block_timestamp, snapshot, revert via raw anvil_/evm_ rpc Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When a selector isn't in local artifacts, resolve the signature via the openchain database and decode args from it. Lets get_transaction decode arbitrary mainnet contracts on a fork. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pnpm demo forks mainnet into a stack, impersonates a USDC whale, transfers to anvil account 0, decodes the tx, prints explorer links, tears down. Doubles as an e2e test (needs STACKS_TOKEN + FORK_URL). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Build a tx/address/block/root explorer link for a stack without a fetch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The create/show urls omit the per-stack key until provisioning catches up (load-dependent, seconds to over a minute), and show returns no urls at all right after create. Build the keyed url from slug + baseHost + the api-key token (populated immediately), then poll eth_chainId until anvil answers. Verified end-to-end against hosted Stacks: create -> get_block -> execute (anvil account 0) -> get_transaction -> delete. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
list/show return http_rpc/ws_rpc/explorer at top level while create nests them under `urls`. Normalize both so list_stacks shows rpc + explorer links. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Serves MCP over streamable HTTP at /mcp on the api host, so tools run inside the app instead of calling its REST api from outside. Chain calls reach anvil on its process-local port, skipping the reverse proxy and the per-stack api key. Auth reuses the REST bearer JWT. Stacks owned by another user read as missing rather than forbidden, to avoid leaking slugs. ABI encoding and decoding stay out of scope: calldata goes in raw, so the caller keeps using cast, viem, or whatever it already has. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Booting a forked anvil outlasts a default GenServer call timeout, so `ensure_running` takes an explicit one and `anvil_url` catches the exit rather than letting callers crash. This covers the proxy path too. Explorer block links carry decimal numbers, matching how the frontend builds them; a block without a number links to the stack root instead of a dangling path. `EXPLORER_BASE` moves to runtime config, where the rest of the env-driven settings live — read from config.exs it was baked in at build time. Sessions now need a bearer token before one is spawned, so an anonymous caller can no longer hold session processes on the public endpoint. The MCP pipeline skips `accepts`, since clients negotiate json and text/event-stream on the same path. Also: roll back the stack row when its anvil fails to boot, default `get_logs` from the fork block instead of scanning upstream history, widen the receipt window, and preload api keys when listing without a user so rpc urls keep their token. The HTTP test now dispatches through the endpoint. Driving the plug directly skipped the router, so it could not have caught the auth gate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bad fork options kill anvil outright, and the call to read its url then exits with `:normal` rather than a timeout, which the earlier catch missed. The agent saw "Tool execution crashed" instead of something it could act on. Found by running a mainnet fork locally: a fork_block_number ahead of the chain head made anvil exit 1. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
mcp/— a TS MCP server (@ethui/stacks-mcp) that lets an agent drive Stacks: provision disposable forked anvil sandboxes, inspect the chain, deploy/simulate/execute, and use anvil cheatcodes. Every result carries an ethui explorer deep link so a human can verify. Full loop: provision → experiment → verify → tear down.Tools (17, over stdio)
create_stack/list_stacks/delete_stackget_block/get_transaction(auto-decodes call + events) /get_address/get_logsdeploy_contractfrom foundryout/simulate_call/execute(fromimpersonates any sender, no key)impersonate/set_balance/mine/set_block_timestamp/snapshot/revertexplorer_linkfor on-demand tx/address/block/root deep linksNotes
frontend.STACKS_TOKEN) for/stacksCRUD only. Per-stack key rides in the returned rpc url path, so viem + the browser self-auth.out/*.json, with an openchain/4byte fallback for contracts not inout/(e.g. arbitrary mainnet on a fork).btoa(rpc)scheme; base64-of-a-URL is path-safe (verified). Route confirmed live (200).pnpm --filter @ethui/stacks-mcp demoruns the fork-mainnet whale flow e2e (needsSTACKS_TOKEN+FORK_URL).Not included
logintool / browser-loopback auth deferred (token-in-env for now).🤖 Generated with Claude Code