Skip to content
Conduit

mcp server

mcp-audit-tap

A minimal, protocol-agnostic audit wiretap for stdio MCP servers. See what a third-party MCP server actually sends before you decide to trust or gate it.

themsquared/mcp-audit-tapcommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 28, 2026

mcp-audit-tap

📖 Read the write-up: MCP Audit Tap: See What a Third-Party Server Actually Sends

A minimal, protocol-agnostic wiretap for a stdio MCP server. Run any MCP server behind it instead of running the server directly, and get a structured audit log of every tools/call request and result, with PII-pattern flags, before you decide whether to trust what the server sends.

Why

On 2026-10-19 a Show HN post for a "WhatsApp MCP server running free on Cloudflare" hit 124 points and 69 comments in under 16 hours. The thread spent most of its length arguing about whether the tool is actually free, whether using it risks a WhatsApp account ban, and whether decrypting end-to-end-encrypted messages and uploading them to an LLM is a privacy problem. Those are all real questions. None of them is answerable by reading the thread, because none of the commenters had a way to see what the tool actually sends. The same day, a separate HN thread asking "if you don't run your own LLM proxy, how do you know what's going on" collected 213 points and 154 comments arguing the same gap from the infrastructure side.

The common failure in both threads: people evaluate a third-party MCP server by reading its README and its star count, not by watching what crosses the wire. mcp-audit-tap is the smallest possible version of watching the wire. It does not block anything by default. It gives you a log.

What it is not

This is not a production MCP gateway. It does not do authentication, rate limiting, or policy enforcement with CEL expressions. For that, see agentgateway's MCP guardrails, which run inside a real gateway and can reject or mask a tools/call before the tool executes. This repo is the step before that decision: see what a server sends, before you decide it needs a policy.

Architecture

MCP client  <-- stdio -->  audit_tap.py  <-- stdio -->  the real MCP server
                                |
                                v
                            audit.log (JSONL)

audit_tap.py spawns the real MCP server as a child process and relays every line between your client and the server unchanged. In parallel, it parses each JSON-RPC message:

  • A tools/call request (client to server) is logged with the tool name and arguments.
  • The matching result (server to client, matched by JSON-RPC id) is scanned against a small set of regex patterns (phone numbers, email addresses so far; extend PII_PATTERNS in audit_tap.py for more) and logged with whatever flags matched.
  • With --redact, a flagged result is rewritten in place ([REDACTED:phone], [REDACTED:email]) before it reaches the client, and the tap logs that it did so. Without --redact (the default), nothing forwarded is changed; the tap only observes.

That --redact flag is the entire distance between "audit tool" and "policy enforcement point". It's one if statement in audit_tap.py. The point of this repo is that the hard part was never the redaction, it was noticing there was content worth redacting in the first place.

Quickstart

Requires Python 3.9+, no third-party dependencies.

git clone https://github.com/themsquared/mcp-audit-tap.git
cd mcp-audit-tap

Run the toy MCP server directly first, to see what it returns with nothing watching:

python3 test_harness.py -- python3 demo_server.py

The tools/call result includes a phone number and an email address in plain text, standing in for the kind of personal content a real messaging MCP server would forward to whatever LLM is calling it.

Now run the same call through the tap, audit-only:

python3 test_harness.py -- python3 audit_tap.py --log audit.log -- python3 demo_server.py
cat audit.log

The response the client receives is identical. audit.log now has a record of the call and a flags field naming what it found:

{"ts": "...", "direction": "client->server", "event": "tools/call request", "tool": "read_latest_messages", "arguments": {}}
{"ts": "...", "direction": "server->client", "event": "tools/call result", "tool": "read_latest_messages", "flags": ["phone", "email"], "preview": "Jordan: Running late, call me at 555-867-5309 if plans change..."}

Now turn the same tap into an enforcement point:

python3 test_harness.py -- python3 audit_tap.py --redact --log audit.log -- python3 demo_server.py

The tools/call result the client receives now reads call me at [REDACTED:phone], and audit.log has a third line recording that the tap redacted it before forwarding.

Pointing it at a real MCP server

Replace python3 demo_server.py with the real server's launch command. If your MCP client config currently runs:

{"command": "python3", "args": ["-m", "some_mcp_server"]}

point it at the tap instead:

{"command": "python3", "args": ["audit_tap.py", "--log", "audit.log", "--", "python3", "-m", "some_mcp_server"]}

Everything the client sends and the server returns still flows through unchanged (unless you pass --redact); you just get audit.log as a side effect.

Extending the PII patterns

PII_PATTERNS in audit_tap.py is a plain dict of name -> compiled regex. Add entries for whatever your threat model cares about (SSNs, API key shapes, internal hostnames). Each match adds its name to the result's flags list and, with --redact, gets substituted with [REDACTED:<name>].

License

Apache-2.0. See LICENSE.

Topics

mcp model-context-protocol ai-agents ai-security observability

↑↓ navigate openesc close