chain-reader

chain-reader

A read-only MCP server that lets you interact with the Ethereum blockchain via natural language, providing tools for reading blocks, transactions, token metadata, events, and more, with provenance tracking and no private key access.

Category
Visit Server

README

chain-reader — 読み取り専用の Ethereum MCP サーバ

LLM に Ethereum を自然言語で読ませるための MCP サーバ。 秘密鍵を持たず、署名も送信もしない。すべての結果に「その答えがどこから来たか」が付く。

Tim Weingärtner (HSLU)『Ethereum & Smart Contracts』最終章「ブロックチェーンと AI」の図を、 そのまま動く形にした教材プロトタイプとして書いた。

  LLM         ← 自然言語(「このアドレスは何者?」)
   ↓
  MCP         ← src/server.js
   ↓          ← コード/構造化言語(ABI エンコード)
  RPC         ← src/rpc.js
   ↓
ブロックチェーン

依存は @modelcontextprotocol/sdkzod の 2 つだけ。 Keccak-256 も ABI エンコーダも自前で書いてある(後述の「なぜ自前で書いたか」)。


動かす

git clone <this repo> && cd chain-reader-mcp
npm ci --ignore-scripts
npm test        # 単体 13 件(ネットワーク不要)
npm run smoke   # 実チェーンに対して全ツールを 1 回ずつ

Claude Code に登録する。

claude mcp add chain-reader -- node "$PWD/src/server.js"

このディレクトリで claude を起動するなら .mcp.json があるので登録は不要。 ただし初回だけ承認を求められるclaude mcp list⏸ Pending approval と出る)。 講義当日に慌てないよう、事前に一度起動して承認しておくこと。

Claude Desktop なら claude_desktop_config.jsonmcpServers に同じ内容を書く。 その場合 args は絶対パスにする。

環境変数で対象ネットワークを切り替えられる。既定は mainnet。

変数
ETH_NETWORK mainnet / sepolia / holesky / local
ETH_RPC_URL 独自エンドポイント(指定するとネットワーク名より優先)

いずれも API キー不要の公開エンドポイントを使う。localanvil / hardhat nodehttp://127.0.0.1:8545 を見る。


ツールと講義の対応

講義スライドそのものは別リポジトリ(私家版の日本語訳)にあるが、 節の名前だけ挙げておけば対応は追える。

ツール 対応するスライド 何が見えるか
chain_info ガスと取引手数料 / PoS 基本手数料がブロックの混み具合で動くこと
account_info 2種類のアカウント / Ethereum アドレス コードの有無で EOA とコントラクトが分かれること
read_transaction Etherscan でトランザクションを読む 手数料 = ガス使用量 × 実効ガス価格
read_block ブロック parentHash の連鎖が「改ざん不可能」の実体
call_contract ABI / Solidity 入門 セレクタが keccak256(署名) の先頭 4 バイトであること
read_token ERC-20 / ERC-721 / クロークの引換札 名称も記号もコントラクトの自己申告であること
read_events イベント駆動の UI indexed の引数だけが topic に載ること
prepare_unsigned_transaction MCP を使うときの注意 鍵を持たない側にできることの限界
explain_selector ABI ネットワークに触らずセレクタを計算する(板書用)
verify_anchor (論文側) ハッシュのアンカリングで何が証明でき、何ができないか

lecture_walkthrough プロンプトを選ぶと、1〜6 を順に辿る指示が入る。

講義でそのまま使える問いかけ

このネットワークはいま混んでいますか?
0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 は EOA ですか、コントラクトですか?
USDC の総供給量は? その数字は誰が保証していますか?
transfer(address,uint256) のセレクタはなぜ 0xa9059cbb になるのですか?
私のアドレスから 0.001 ETH を送る取引を組み立ててください

最後の問いには、AI は組み立てた JSON を返すが送れない。 そこで「なぜ送れないのか」を説明させると、スライド「MCP を使うときの注意」の内容が AI 自身の口から出てくる。


設計上の 2 つの約束

1. 鍵を持たない

src/rpc.jsALLOWED_METHODS は読み取り専用メソッドの明示的なホワイトリスト。 eth_sendRawTransaction / eth_sendTransaction / eth_sign はそこに無く、 呼ぼうとするとネットワークに出る前に落ちる(単体テストで固定してある)。

署名の実装も秘密鍵の読み込みもこのリポジトリには存在しない。 LLM がどう誘導されても、ここから資金は動かない。

prepare_unsigned_transaction は、この境界を「できないこと」ではなく 動く形で見せるためにある。nonce もガス見積もりも手数料も埋めた完成品を返し、 署名だけを人間に残す。講義スライドの 「MCP が安全に行えるのは、読み取り専用の呼び出しと、署名済みトランザクションの中継の 2 つに限られる」 がそのまま実装になっている。

2. 答えの出どころを捨てない

すべての結果に _provenance が付く。

"_provenance": {
  "endpoint": "https://ethereum-rpc.publicnode.com",
  "network": "mainnet (Ethereum Mainnet)",
  "rpc_calls": ["eth_blockNumber (1309ms)", "eth_gasPrice (1416ms)", "eth_chainId (1769ms)", "eth_getBlockByNumber (1023ms)"],
  "note": "これは単一の RPC エンドポイントの応答であり、独立に検証したものではない。"
}

「ブロックチェーンだから正しい」で止めないための仕掛け。 LLM は数値を自信たっぷりに言い切る癖があるので、どの主張がどの層に立っているかを 結果自体に持たせる。サーバの instructions でも、チェーンが保証した事実と 誰かが申告した内容を区別して説明するよう指示している。


帰属できることと、検証できることは違う

このサーバの出力設計は、記録管理・デジタルアーカイブの文脈から来ている。 言えることそれが本当であることの差を、ツールの出力に埋め込んである。

read_tokenself_reported_notename() が "USD Coin" を返したという事実は チェーンが保証する。しかしそのコントラクトが本当に Circle のものかは保証しない。 同じ名前と記号のコントラクトは誰でもデプロイできる。 チェーンが保証するのは「この住所のコードがこう答えた」ことまでで、その主張の真偽ではない。

verify_anchorwhat_this_does_not_prove — アンカリングが与えるのは 「いつ・誰が・何を主張したか」であって「その主張が正しいか」ではない。 誤った測定値のハッシュも、正しい測定値のハッシュと同じように刻める。 真正性 (authenticity) は真実性 (truth) ではない、という古文書学の区別がそのまま出る。

_provenance — 記録の品質とは、その来歴グラフの形のことである、という考え方の最小実装。 どのエンドポイントが、どの RPC 呼び出しで、何ミリ秒で答えたか。 PROV-O でいう prov:wasAttributedTo を誰にするかを、後から決められる状態にしておく。

署名された申告 / 公開情報との突合 / TEE アテステーション / 機関的な認証 と層を上げていくと 検証の強度は増すが、どこまで行っても「測定器そのもの」は検証できない。 このプロトタイプが実演しているのはその最下層 —— 帰属はできるが検証はできない領域。 だからこそ、どの層に立っている数値なのかを記録の側に残す。


なぜ Keccak も ABI も自前で書いたか

viemethers を入れれば 3 行で済む。あえて書いた理由が 2 つある。

  1. 講義の題材だから。 ABI が魔法のままでは「なぜ 4 バイトなのか」を説明できない。 src/keccak.jssrc/abi.js は合わせて 300 行ほどで、受講者が読み切れる。
  2. 依存を 2 つに抑えられるから。 サプライチェーンの面積が小さいほど、 3 年後に npm ci して動く確率が上がる。

Node の crypto にある sha3-256 は NIST SHA-3 で、Ethereum の Keccak-256 とは パディングが違う(0x060x01)ので流用できない。ここは実装するしかない。

対応範囲は address / uintN / intN / bool / bytesN / string / bytes と その動的配列まで。タプルと入れ子の動的配列は扱わない。プロトタイプの範囲としては十分だが、 本番で任意のコントラクトを相手にするなら viem に置き換えること。


既知の限界

  • 単一の RPC を信じている。 複数エンドポイントに同じ問いを投げて突き合わせれば 信頼の層が 1 つ上がる。実装していない
  • タプル型を扱えない。 Uniswap V3 の slot0() のような戻り値はデコードできない
  • read_events の走査範囲は既定で 200 ブロック。 公開エンドポイントは 広い eth_getLogs を拒否することがある
  • verify_anchor は部分文字列一致で探している。 アンカー用コントラクトの ABI が分かっているなら、正しく引数をデコードして照合すべき
  • local ネットワーク以外は公開エンドポイント依存。講義当日に落ちている可能性を考えて、 anvil --fork-url でローカルにフォークしておくと安全

ファイル構成

src/keccak.js   Keccak-256(既知ベクタで固定)
src/abi.js      ABI エンコード/デコード
src/rpc.js      JSON-RPC クライアント + 読み取り専用ホワイトリスト
src/tools.js    ツール 10 個の実体。MCP から独立していて単体で呼べる
src/server.js   MCP サーバ(stdio)
test/unit.test.js      ネットワーク不要の単体テスト
test/smoke.mjs         実チェーンに対する疎通確認
test/mcp-handshake.mjs MCP プロトコルの往復確認

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured