I Read BlueRock Open-Source MCP Hooks: What They Actually Catch and What They Miss
When AI agents share tools across different AI providers, they use a protocol called MCP. But the teams running MCP in production have had almost no way to see what those tools actually do once they start running — which files they touched, what network connections they opened, what child processes they spawned. BlueRock's answer, released Tuesday as open source under the Apache 2.0 license, is a Python runtime sensor that attaches via python -m bluepython --oss at startup with no code changes. It captures every JSON-RPC message between client and server — tool calls, arguments, session IDs — and it fingerprints every imported Python module with a SHA-256 hash. What it does not capture: whether a tool actually opened a file, whether it opened a network connection, or whether it spawned a subprocess. The gap is deliberate and documented in the README. It is also the line between the free open-source release and the paid enforcement tier.
The question, as Jeremiah Lowin, founder and CEO of Prefect and creator of the FastMCP framework, wrote in BlueRock's release post, is not whether the MCP server processed a request. It is what the server — and by extension the tool it manages — actually did while running, unmonitored, on your infrastructure.
Security researchers at PipeLab documented why this gap matters at scale: their analysis of 2,614 MCP implementations found 82% use file operations prone to path traversal and 67% use APIs related to code injection. That context anchors the stakes before the specific BlueRock implementation.
BlueRock's open-source sensor layer is the entry point. The code is where the actual boundaries become visible.
The core of the open-source release is two hooks. The MCP hook lives in mcp_hooks.py and uses wrapt, a library that intercepts method calls without modifying the original class. The decorator @wrapt_pre_hook on each MCP session method fires before the underlying implementation runs; it serializes the full JSON-RPC payload — direction, method name, arguments, result — to the event log. The import hook lives in import_hooks.py and inserts a custom finder into sys.meta_path at position zero, which fires on every import statement in the Python process including inside third-party dependencies. It records the module path and a SHA-256 hash of the file contents, storing the hash for comparison on subsequent runs.
Here is what that architecture means for the six event types BlueRock captures. python_mcp_server_init fires once at startup and records the server's identity and configuration. python_mcp_server_add logs each new server registration. python_mcp_event is the workhorse — it captures every tool call, function invocation, and notification with full JSON-RPC payloads. python_mcp_session_created and python_mcp_session_terminated bracket each client session. python_mcp_client_connect records client attachment. None of these six event types fire on os.open(), subprocess.Popen(), or socket.connect() — they observe the protocol layer, not the system call layer. The gap is architectural, not incidental.
The concrete version: a malicious MCP tool receives a request to list /tmp. BlueRock logs the JSON-RPC request — {"method": "list_files", "params": {"path": "/tmp"}} — and the response — {"files": ["secrets.txt"]}. The audit trail shows the agent asked for a directory listing and got one. What it does not show is whether the tool then opened /tmp/secrets.txt, read its contents, and sent them somewhere. The protocol saw the question and the answer. It did not see what happened in between.
Independent researchers at ARMO have documented why this distinction matters in production: APM and OpenTelemetry see requests entering an MCP server and responses leaving, but nothing underneath. They measure latency and error rates. They cannot see what the tool process did between those points. PipeLab's data makes the stakes concrete — 82% of analyzed MCP implementations use file operations prone to path traversal, 67% use APIs related to code injection.
The full version — subprocess monitoring, LLM API hooks, Flask and Django integrations — requires a paid license and closes some of those gaps. But if visibility becomes commoditized via this open-source layer, the paid tier has to offer something the free layer cannot: enforcement, not just observation. Whether that is enough for teams running untrusted tools in production is the unresolved question the piece leaves with.