Read-only MCP server that monitors a Bitcoin Core full node (Umbrel on a Raspberry Pi 5) over its JSON-RPC interface. Part of a small series of personal MCP servers — see nerdaxe-mcp.
Built with the official MCP Python SDK (mcp), served over stdio.
Four read-only views on a single whitelisted RPC helper:
get_node_status— chain, block height, headers, sync progress, initial block download, human-readable uptimeget_network_info— Core version, connection counts (total/in/out), active networksget_mempool_info— transaction count, memory usage, minimum feeget_peer_info— peer counts in/out and a latency range; no full peer dump
The interesting part of this server is what it refuses to do:
- RPC whitelist. Exactly five read-only methods
(
getblockchaininfo,getnetworkinfo,getmempoolinfo,getpeerinfo,uptime), hardcoded as a constant. Any other method is rejected before a request leaves the machine — no wallet RPCs, no parameters. - Field allowlist per tool. Every tool returns explicitly chosen
fields, never "everything except X". Fields added by a future Core
version cannot leak through;
localaddresses(the node's own public address) is excluded by design. - No addresses in output. Logs and error messages never contain the node URL or IP. The RPC URL is validated at startup; on failure the server aborts without echoing it.
- Errors as messages, not tracebacks. A
safe_outputboundary catches failures at the tool edge and returns a plain explanation; details go to the server-side log only.
tests/test_protocol.py run against the real node — all four tools with
live values, plus the whitelist rejecting an unregistered method:
> .venv\Scripts\python tests\test_protocol.py
ok get_node_status: Report the node's chain sync status.
ok get_network_info: Report the node's network and connection status.
ok get_mempool_info: Report the node's mempool status.
ok get_peer_info: Report a short summary of the node's peer connections.
PASS listing: exactly the four read-only tools, no parameters
ok get_mempool_info: Transactions: 37040
ok get_network_info: Version: 310000
ok get_node_status: Chain: main
ok get_peer_info: Peers: 70 (in: 60, out: 10)
PASS calls: all four tools returned well-formed text
ok breakout: unknown tool 'stop' rejected -> Unknown tool: stop
PASS breakout: only the four registered tools are reachable
ALL PROTOCOL CHECKS PASSED
Windows:
py -m venv .venv
.venv\Scripts\pip install -r requirements.txt
Linux / macOS:
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
Then copy .env.example to .env and fill in NODE_RPC_URL,
NODE_RPC_USER, NODE_RPC_PASSWORD (Umbrel: Bitcoin app → "Connect").
Run directly for local testing:
.venv\Scripts\python main.py
Or wire it into claude_desktop_config.json as bitcoin-node, using
the absolute path to the venv's Python and to main.py.
Verified on three levels against a live node:
- Direct function calls, including forced error paths (node offline, wrong credentials, non-whitelisted method).
tests/test_protocol.py— a programmatic MCP client over stdio with asserts; the regression run after every change:.venv\Scripts\python tests\test_protocol.py- Live smoke test from Claude Desktop: all four tools, plus a whitelist-escape attempt that was correctly rejected.
- Read-only. No wallet operations, no configuration changes, no transaction broadcasting.
- Single node, no multi-node support.
- No caching — every call hits the node live.