mcp-msgdump
README.md
# mcp-msgdump
**Zero-dependency MCP server and CLI that proxies, inspects, and analyzes JSON-RPC message streams between MCP clients and servers.**
> A passive MCP proxy that lets you see every JSON-RPC message crossing the wire — in CI, headless environments, or embedded in test suites.
[](LICENSE)
[](pyproject.toml)
## Quick Start
```bash
# Install (PyPI package coming soon — use git install for now)
pip install git+https://github.com/prasad-a-abhishek/mcp-msgdump.git
# Analyze a trace log
mcp-msgdump analyze /tmp/mcp_session.jsonl --format summary
# Run as an MCP proxy (all messages forwarded + logged to stderr)
mcp-msgdump proxy --target localhost:3000 --port 8080
```
```python
# Library API
from mcp_msgdump import analyze_log, check_schemas, replay_session
report = analyze_log("/tmp/mcp_session.jsonl")
print(report.total_requests) # e.g. 47
print(report.error_count) # e.g. 3
print(report.tools_called) # ['read_file', 'write_file', 'list_dir']
```
## Why mcp-msgdump?
MCP server developers debugging transport issues and AI tooling integrators validating MCP server behavior in CI have no way to inspect, replay, or audit the JSON-RPC message stream without manual debugging or complex proxy setups. Existing tools either require a browser GUI (MCP Inspector), are tied to a specific visualization layer (mcp-reticle), or are too lightweight to be useful in headless/CI environments.
**mcp-msgdump is the only zero-dependency, stdio-native MCP server** that provides both proxy inspection and structured log analysis, usable in both interactive CLI sessions and automated CI pipelines.
## Key Features
- **Zero dependencies** — pure Python 3.11+ stdlib only; no `pip install surprises`
- **Two operating modes** — proxy (pass-through with logging) and analysis (structured report from a log file)
- **MCP stdio server** — exposes `analyze_log`, `replay_session`, and `check_schemas` as MCP tools
- **Structured output** — JSON output for machine consumption, summary format for humans
- **CI-friendly** — non-zero exit codes on malformed input, headless/stdin-safe, no GUI required
- **Schema auditing** — detects dangerously untyped parameters, missing descriptions, and empty object types
## CLI Reference
```
mcp-msgdump [--help]
mcp-msgdump analyze [FILE] [--format {summary,json}]
mcp-msgdump proxy --target HOST:PORT [--port PORT]
```
### `analyze` subcommand
Parses a JSONL log file and emits a structured analysis report.
| Flag | Description |
|------|-------------|
| `FILE` | Path to JSONL log file (use `-` for stdin) |
| `--format summary` | Human-readable summary to stdout (default) |
| `--format json` | Machine-readable JSON to stdout |
Exit codes: `0` clean log, `1` file not found or malformed input.
### `proxy` subcommand
Runs as a passive man-in-the-middle between an MCP client and server. All traffic is forwarded verbatim; every message is also emitted to stderr.
| Flag | Description |
|------|-------------|
| `--target HOST:PORT` | Target MCP server address (required) |
| `--port PORT` | Listen port for the proxy (default: 8080) |
## Library API Reference
### `analyze_log(path: str) -> AnalysisReport`
Parse a JSONL log file and return an `AnalysisReport`:
```python
from mcp_msgdump import analyze_log
report = analyze_log("/tmp/session.jsonl")
assert report.total_requests == 47
assert report.error_count == 3
assert "read_file" in report.tools_called
assert report.schema_issues == []
```
### `check_schemas(path: str) -> list[SchemaIssue]`
Validate tool schemas in a log file. Returns a list of issues:
```python
from mcp_msgdump import check_schemas
issues = check_schemas("/tmp/session.jsonl")
for issue in issues:
print(f"[{issue.severity.value}] {issue.tool_name}.{issue.parameter_name}: {issue.message}")
```
Issues detected:
- `type: string` with no `description` → `dangerously_untyped` warning
- `type: object` with no `properties` → `empty_object` warning
- Missing `type` annotation → `missing_type` error
- Missing description on typed parameter → `missing_description` warning
### `replay_session(path: str, start_index: int = 0, filter_tool: str | None = None) -> list[ReplayResult]`
Replay tool calls from a log file, optionally filtered:
```python
from mcp_msgdump import replay_session
results = replay_session("/tmp/session.jsonl", filter_tool="read_file")
for r in results:
print(f"#{r.index} {r.tool_name}: {r.params}")
```
### Data Models
```python
from mcp_msgdump import AnalysisReport, ReplayResult, SchemaIssue, ToolCall, Mismatch, Severity
# AnalysisReport fields:
report.total_requests # int — count of JSON-RPC requests seen
report.error_count # int — count of error responses
report.tools_called # list[str] — unique tool names called
report.slowest_call # ToolCall | None — slowest tool call by latency_ms
report.schema_mismatches # list[Mismatch] — schema mismatches (v1: always empty)
report.tool_calls # list[ToolCall] — all tool call records
report.schema_issues # list[SchemaIssue] — detected schema issues
report.batch_sub_requests # int — count of sub-requests inside batch arrays
report.empty_file # bool — true if input was empty
report.malformed_lines # int — count of unparseable lines
# ToolCall fields:
tc.method # str — JSON-RPC method name (e.g. "tools/call")
tc.params # dict — parameters passed to the tool
tc.id # int | str | None — request ID
tc.latency_ms # float | None — latency in ms (set when response has duration)
tc.is_notification # bool — true if id was null (no response expected)
tc.is_error # bool — true if response contained an error
tc.error_message # str | None — error message if is_error is True
# ReplayResult fields:
r.index # int — position in the log
r.method # str — JSON-RPC method name
r.params # dict — parameters
r.response # dict | None — response if available
r.skipped # bool — true if filtered out by filter_tool
r.skip_reason # str | None — reason if skipped
# SchemaIssue fields:
issue.tool_name # str — name of the tool
issue.parameter_name # str | None — affected parameter name
issue.issue_type # str — e.g. "untyped", "dangerously_typed", "missing_description"
issue.message # str — human-readable description
issue.severity # Severity — Severity.WARNING or Severity.ERROR
# Mismatch fields:
m.tool_name # str
m.field # str
m.expected # Any
m.actual # Any
m.description # str | None
```
## Limitations
- The proxy mode is a TCP socket proxy — it does not speak the MCP stdio protocol over the proxy itself (the proxy is for TCP-based MCP servers)
- MCP stdio server mode only; HTTP/SSE transport is out of scope for v1
- Streaming/chunked JSON-RPC is not supported in v1
- No persistent storage — logs are written to a file or stdout, not internally buffered
- No authentication, access control, or rate limiting
## Non-Goals
- Executing tools or making real network calls beyond forwarding to the proxy target
- Visualization or GUI output
- HTTP/SSE MCP server transport
- Persistent internal log storage
- Authentication or rate limiting
## Test Suite
```bash
pytest -v
```
**165 tests** covering: proxy forwarding, log analysis, schema checking, replay, CLI parsing, MCP protocol, and zero-dependency enforcement.
## MCP Client Configuration
`mcp-msgdump` is a stdio MCP server — point any MCP client at it to capture and analyze JSON-RPC traffic.
### Claude Desktop (claude_desktop_config.json)
```json
{
"mcpServers": {
"mcp-msgdump": {
"command": "python",
"args": ["-m", "mcp_msgdump", "analyze", "/path/to/session.jsonl"]
}
}
}
```
### Cursor
Add to Cursor settings (JSON mode):
```json
{
"mcpServers": {
"mcp-msgdump": {
"command": "python",
"args": ["-m", "mcp_msgdump", "analyze", "/path/to/session.jsonl"]
}
}
}
```
### Windsurf
Add to Windsurf MCP settings:
```json
{
"mcpServers": {
"mcp-msgdump": {
"command": "python",
"args": ["-m", "mcp_msgdump", "analyze", "/path/to/session.jsonl"]
}
}
}
```
### Cline
Add to Cline MCP settings:
```json
{
"mcpServers": {
"mcp-msgdump": {
"command": "python",
"args": ["-m", "mcp_msgdump", "analyze", "/path/to/session.jsonl"]
}
}
}
```
### AGY
```yaml
mcp_servers:
mcp-msgdump:
command: python
args: ["-m", "mcp_msgdump", "analyze", "/path/to/session.jsonl"]
```
## License
MIT — Prasad A Abhishek
TDQS
A3.8/5.0
Scored across 3 tools
Disambiguation5/5
Each tool has a clearly distinct purpose: analyze_log produces a report, replay_session replays a session, and check_schemas validates schemas. There is no meaningful overlap between the three.
Naming Consistency5/5
All tool names follow a consistent verb_noun snake_case pattern: analyze_log, replay_session, check_schemas. The naming is predictable and easy to infer.
Tool Count5/5
Three tools is well-scoped for the apparent domain of MCP log inspection. Each tool has a distinct role without unnecessary bloat.
Completeness4/5
The core workflows of analyzing, replaying, and schema-checking are covered. Missing features like exporting results or filtering by time could exist, but the current set is reasonably complete for log analysis.
Maintenance
ActivitySlowing
ResponsivenessNo issues