Skip to main content
Glama

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 두 개뿐이다. 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

두 종류의 계정 / 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 자신의 입에서 나온다.


설계상의 두 가지 약속

1. 키를 갖지 않는다

src/rpc.jsALLOWED_METHODS는 읽기 전용 메서드의 명시적 화이트리스트다. eth_sendRawTransaction / eth_sendTransaction / eth_sign은 거기에 없으며, 호출하려고 하면 네트워크에 나가기 전에 실패한다(단위 테스트로 고정되어 있다).

서명 구현도 비밀 키 읽기도 이 리포지토리에는 존재하지 않는다. LLM이 어떻게 유도되어도 여기서 자금은 움직이지 않는다.

prepare_unsigned_transaction은 이 경계를 "할 수 없는 일"이 아니라 동작하는 형태로 보여 주기 위해 있다. nonce도 가스 추정도 수수료도 채운 완성품을 반환하고, 서명만 인간에게 남긴다. 강의 슬라이드의 "MCP가 안전하게 수행할 수 있는 것은 읽기 전용 호출과 서명된 트랜잭션의 중계 두 가지로 한정된다" 가 그대로 구현이 되어 있다.

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도 직접 작성했는가

viem이나 ethers를 넣으면 3줄이면 끝난다. 굳이 작성한 이유가 두 가지 있다.

  1. 강의의 주제이기 때문이다. ABI가 마법으로 남아 있으면 "왜 4바이트인가"를 설명할 수 없다. src/keccak.jssrc/abi.js는 합쳐서 300줄 정도라서 수강생이 다 읽을 수 있다.

  2. 의존성을 두 개로 억제할 수 있기 때문이다. 공급망의 면적이 작을수록 3년 후에 npm ci 해서 동작할 확률이 올라간다.

Node의 crypto에 있는 sha3-256은 NIST SHA-3이며, Ethereum의 Keccak-256과는 패딩이 다르므로(0x060x01) 그대로 쓸 수 없다. 이 부분은 구현할 수밖에 없다.

대응 범위는 address / uintN / intN / bool / bytesN / string / bytes와 그 동적 배열까지다. 튜플과 중첩된 동적 배열은 다루지 않는다. 프로토타입의 범위로는 충분하지만, 프로덕션에서 임의의 컨트랙트를 상대하려면 viem으로 교체할 것.


알려진 한계

  • 단일 RPC를 신뢰하고 있다. 여러 엔드포인트에 같은 질문을 던져 대조하면 신뢰의 층이 하나 올라간다. 구현하지 않았다

  • 튜플 형식을 다룰 수 없다. 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 プロトコルの往復確認
-
license - not tested
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Free OpenAI-compatible inference with signed provenance receipts and 3 focused MCP tools.

  • Read-only MCP server for Robinhood Chain token discovery, research, and due diligence via GMGN.

  • MCP server for Blockscout

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nakamura196/chain-reader-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server