Events (Request, Schema, Session, Heartbeat)
Every action in mcpr produces a ProxyEvent — a request transaction completed, a session started, a schema captured, a heartbeat ticked. Events flow through the event bus and fan out to registered sinks.
Event types
Section titled “Event types”mcpr’s event bus emits four ProxyEvent variants:
| Variant | When | Key data |
|---|---|---|
Request | A request transaction completes | request and response projections, latency, span breakdown, OpenAI client context |
Session | An MCP initialize handshake captures session info | session ID, AI client name, version, platform |
Schema | A discovery response (tools/list, resources/list, etc.) is captured | method, items, change diff |
Heartbeat | Every 30 seconds | proxy state snapshot — upstream URL, export port, tunnel status, tunnel address |
Request is the primary observability event. One event covers the full request/response transaction, with HTTP body bytes dropped from the logging projection so non-MCP traffic does not bloat sinks. MCP traffic carries the full JSON-RPC envelope.
Built-in sinks
Section titled “Built-in sinks”| Sink | What it does | When it’s enabled |
|---|---|---|
| Stderr | One-line summary per request to stderr | Always on |
| SQLite | Writes events to ~/.mcpr/store.db (override via MCPR_DB) | Always on |
| Cloud | Batched POST to the cloud ingest endpoint | When [cloud].token is set |
[cloud]token = "mcpr_xxxxxxxx"server = "my-proxy"
# Optional tuningbatch_size = 100flush_interval_ms = 5000The CloudSink batches events in memory and flushes on size or interval. If the cloud is unreachable, the proxy keeps operating — cloud connectivity never blocks the proxy.
Schema capture
Section titled “Schema capture”mcpr passively captures your server’s tools, resources, and prompts by intercepting discovery responses. No extra requests, no auth needed, no added latency.
| MCP method | Captured |
|---|---|
initialize | Server name, version, protocol version, capabilities |
tools/list | Tool names, descriptions, inputSchema |
resources/list | Resource URIs, names, descriptions |
resources/templates/list | Template URIs, names, descriptions |
prompts/list | Prompt names, descriptions, arguments |
mcpr detects when entries are added, removed, or modified and writes a full change history. Cloud’s Tools tab surfaces this; locally, query the events table directly with sqlite3.
Custom sinks
Section titled “Custom sinks”Implement the EventSink trait to send events anywhere — Prometheus, Datadog, webhooks, Kafka:
use mcpr_core::event::{EventSink, ProxyEvent};
pub struct MySink;
impl EventSink for MySink { fn on_event(&self, event: &ProxyEvent) { if let ProxyEvent::Request(e) = event { // e.request, e.response, e.latency_us, e.upstream_us, e.spans println!("request {} latency_us={}", e.request_id, e.latency_us); } } fn name(&self) -> &'static str { "my-sink" }}Rules: on_event must not block. Buffer internally, do I/O in flush(). flush() is called on a fixed interval and on shutdown.
See Event Schema for the full field specification.
