MCPHawk is DevTools for MCP: it records real traffic between MCP clients and servers
(stdio wrapper, HTTP proxy, passive sniffer), stores it in SQLite, and serves a web UI plus
its own MCP server over the same data. Targets MCP spec 2026-07-28 and still supports the
older initialize handshake era.
- Use the local venv (
.venv/bin/python) and Makefile targets when they exist. - Add dependencies to
requirements.txt/requirements-dev.txtandpyproject.toml; neverpip installad hoc. - Before finishing:
make lintandmake test. Coverage must stay above 85% (make coveragefails below it). - New tests:
tests/unit/for isolated functions,tests/integration/<area>/for anything touching the DB, processes, network or HTTP. Build traffic withtests/traffic.py. - Follow the MCP spec and the official SDK instead of inventing custom protocol behaviour.
- Write PEP 8 from the start (ruff, line length 88, Python 3.10+).
capture/ -> store/recorder.py -> SQLite -> query.py + analysis/ -> web/app.py, mcp_server.py
protocol/: JSON-RPC framing, MCP semantics for both eras, secret masking, token estimatesstore/recorder.py: request/response pairing, multi round-trip chains, client/server identityquery.py: the one read layer; the web API and the MCP server must not query SQL themselvesruns.py: agent runs, computed at read time (client group, split at 5 min idle gaps).sessions.client_keystores only which client process a session belongs toinstall/: client config locations and install/uninstallotel/: OpenTelemetry export (semconv.pymaps to the MCP semantic conventions,exporter.pystreams OTLP frommcphawk up,prometheus.pyserves/metrics)frontend/: Vue 3 app, built intomcphawk/web/static(committed)
make install # deps + editable install + frontend deps
make test # or test-unit / test-integration / test-e2e ...
make dev # mcphawk up on :8484 + Vite on :5173
make build-frontend # then commit mcphawk/web/static; CI fails if it is stale
make demo # demo traffic from three SDK servers- MCP SDK 2.x:
FastMCPis nowmcp.server.mcpserver.MCPServer; the client ismcp.client.client.Client. - The SDK's stdio client gives child processes a filtered environment. Pass
env=when spawningmcphawk wrapin tests or examples, or data lands in~/.mcphawkinstead ofMCPHAWK_DB. - Tests isolate
MCPHAWK_HOME/MCPHAWK_DBintests/conftest.py; never point anything at the real~/.mcphawk. - Async fixtures must not hold an SDK
Clientopen across yield (anyio cancel scopes); open the client inside the test. - The stdio shim forwards bytes before recording them, and its two pump threads race: a response can be recorded before its request. The recorder pairs these; keep it that way.
- Mutating API routes need the
X-MCPHawk: 1header and a localhostHost(CSRF and DNS rebinding guard). The SDK's/mcpendpoint also rejects non-localhost hosts, so usebase_url="http://127.0.0.1:8484"withTestClient. - Secrets are masked before storage. Replay refuses requests or commands that still contain the mask.
- Remote HTTP servers without static headers are assumed to use OAuth and are not proxied by default: their tokens are bound to the server URL.
- Claude Code retitles its process with its version number;
capture/process.pyfalls back toargv[0]for client names. - OpenTelemetry is an optional extra: only
otel/exporter.pymay import the SDK, and only aftermcphawk.otel.available();semconv.pyandprometheus.pymust work without it. Use the convention names verbatim; anything of ours goes undermcphawk.*, andexamples/grafana/mcphawk-dashboard.jsonis checked against/metricsby a test.