Skip to content

Observability & monitoring

The bridge is built to be watched: metrics, traces, usage analytics, alerts and a tamper-evident audit trail, all from the same instance.

Metrics (Prometheus)

Scrape GET /metrics for Prometheus-format metrics. The endpoint exposes only the gateway's own mcp_* metrics — its registry, resilience, health-check, and WS-proxy instrumentation (for example mcp_tool_calls_total{outcome}). One constant mcp_build_info gauge (always 1) carries the running version and bun runtime as labels, so a dashboard can pin exactly which build is live and spot a version skew across replicas. The endpoint does not export default process or HTTP metrics (there is no prom-client / collectDefaultMetrics — no process_*, nodejs_*, or per-route request metrics). Wire it into your usual dashboards and alerting — or start from the ready-to-apply Prometheus rules and Grafana dashboard in the repo's monitoring/ directory.

Tracing (OpenTelemetry)

Set OTEL_EXPORTER_OTLP_ENDPOINT and the bridge exports one OTLP/HTTP span per tool call — dependency-free, so you can send spans to any OTLP collector (Jaeger, Tempo, Honeycomb, …).

Log correlation

Every request is assigned a correlation id — taken from an inbound X-Request-Id header when present, otherwise a fresh UUID — echoed back on the X-Request-ID response header and stamped onto every structured log line emitted while handling that request as a request_id field. To follow a single request end to end, grep your logs for it:

bash
grep '"request_id":"<id>"' gateway.log

Hand the id from the X-Request-ID response header (or a client-supplied one) straight to that grep to pull every log line for the call. The same middleware also honors a W3C traceparent header, so the OTLP span for the call inherits the caller's trace.

Usage analytics & anomaly detection

The admin UI's Usage view shows calls, error rate, latency, top tools and per-key breakdowns over a window — the same window the usage_spike alert below watches.

Alerts

Create alert rules that POST to a webhook on:

EventFires when
circuit_breaker_openA client's breaker trips open
client_unreachableA backend fails health checks
error_rateErrors exceed a threshold over a minimum call count
usage_spikeTraffic spikes vs. baseline

Synthetic monitors can additionally probe tools on a schedule and notify MONITOR_WEBHOOK_URL on failure or schema drift.

Audit trail

Every admin mutation is written to a hash-chained audit log (hash = SHA256(JSON.stringify([prev_hash, actor, action, target, detail, created_at]))) — a JSON-encoded pre-image rather than a bare delimiter join, since caller-influenced fields like target and detail could otherwise collide across distinct rows. Any retroactive edit breaks the chain and is caught by the verify endpoint. Stream events to a SIEM in real time with AUDIT_SINK_URL. Export the log as JSON, CSV, or a self-contained HTML compliance report that embeds the hash-chain verification verdict.

Health

GET /livez is a cheap liveness check — always 200 if the process is responding. GET /readyz is the readiness check: 200 only when this instance holds the leader lease and its SQLite handle answers SELECT 1. Request handling (REST/MCP dispatch) is stateless and runs on every instance regardless of leadership, so a load balancer scaling throughput should route on /health or /livez — pointing it at /readyz takes every non-leader instance out of rotation. Reserve /readyz-gated routing for a deliberate active/passive failover topology. Per-backend health is monitored continuously, with automatic eviction of unhealthy backends and a ping probe for MCP upstreams.

Next: Scaling → · Troubleshooting →

Released under the MIT License · Built with Bun + Vue.