Skip to main content
Glama
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.

[![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Python 3.11+](https://img.shields.io/badge/Python-3.11+-green.svg)](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