Skip to content

Structured Events

mcpr parses every MCP request at the protocol level and emits structured JSON events. This gives you visibility into what’s happening through your proxy — which tools are called, by whom, how long they take, and what fails.

Terminal window
mcpr --mcp http://localhost:9000 --events 2>/dev/null | jq

The --events flag emits newline-delimited JSON to stdout. The 2>/dev/null redirects the TUI logs to stderr so only clean JSON goes to stdout.

Even without the --events flag, mcpr logs every request with MCP-level context in the terminal:

21:23:11 POST 200 8.0KB 16ms 15ms↑ 1ms↓ initialize → http://localhost:9000/mcp
21:23:11 POST 200 73.6KB 11ms 7ms↑ 4ms↓ tools/list → http://localhost:9000/mcp
21:23:11 POST 200 147B 8ms 8ms↑ 0ms↓ tools/call get_weather → http://localhost:9000/mcp
21:23:11 POST 200 147B 8ms 8ms↑ 0ms↓ tools/call search [-32602 Invalid params] → ...

Each line shows: HTTP method, status, response size, total time, upstream time (↑), proxy overhead (↓), MCP method, tool name, and any JSON-RPC errors.

This is the “protocol-level debugging” that generic HTTP proxies can’t do — mcpr understands JSON-RPC and shows you tool names and error codes, not just HTTP status codes.

{
"ts": "2026-04-02T10:15:30.142Z",
"type": "tool_call",
"method": "tools/call",
"tool": "search_products",
"session": "sess_abc123",
"user": null,
"latency_ms": 142,
"status": "ok",
"upstream": "http://localhost:9000",
"csp_applied": true
}
TypeWhenKey fields
tool_callAn MCP tool was calledtool, latency_ms, status, error_code
tool_listClient requested the tool listlatency_ms, status
session_startNew MCP session initializedsession
session_endSession closedsession
widget_serveWidget HTML was servedpath
csp_violationCSP violation detectedblocked_uri, directive

See Event Schema for the full specification of all fields.

Terminal window
# Only tool calls
mcpr --events 2>/dev/null | jq 'select(.type == "tool_call")'
# Only errors
mcpr --events 2>/dev/null | jq 'select(.status == "error")'
# Only CSP violations
mcpr --events 2>/dev/null | jq 'select(.type == "csp_violation")'
# Slow tool calls (over 500ms)
mcpr --events 2>/dev/null | jq 'select(.type == "tool_call" and .latency_ms > 500)'
# Specific tool
mcpr --events 2>/dev/null | jq 'select(.tool == "search_products")'

Events are newline-delimited JSON (NDJSON) — compatible with any log pipeline:

Terminal window
# Write to file
mcpr --events 2>/dev/null >> mcpr-events.jsonl
# Datadog
mcpr --events 2>/dev/null | datadog-agent ...
# CloudWatch
mcpr --events 2>/dev/null | aws logs put-log-events ...
# Grafana Loki
mcpr --events 2>/dev/null | promtail ...

With mcpr Cloud, events sync automatically to the cloud dashboard. Add your cloud config:

[cloud]
token = "mcpr_xxxxxxxx"
server = "my-proxy" # identifies this server in your cloud project

Event metadata is synced — tool parameters and response bodies are not included. Events are batched in memory and sent via HTTPS. If the cloud is unreachable, the proxy falls back to stdout — cloud connectivity never blocks proxy operation.

See mcpr Cloud for dashboard, Studio, and alerting features.