Logging and OpenTelemetry
The Zuplo MCP Gateway emits structured logs alongside its analytics events. Each
log entry is keyed by an event string, carries auto- attached fields for the
route and authenticated user, and explicitly excludes any credentials. Pair the
logs with one of Zuplo's log plugins or the OpenTelemetry plugin to route them
to your provider.
What the gateway logs
Every log entry uses the structured-first form:
Code
The event field is the searchable key. Names use snake-case throughout, with
mcp_ as the family prefix. Examples:
mcp_auth_downstream_token_issuedmcp_auth_downstream_token_revokedmcp_auth_upstream_connection_establishedmcp_capability_invoked
Severity follows three audiences:
- Audit entries (
info) — OAuth token issuance, consent approval, upstream connection established, token revocation. - Debug / visibility entries (
debug/info) — request acceptance, response shaping. - Errors (
error) — every error includes flattened error-chain fields (errName,errMessage,causeName,causeMessage, up to four cause levels) so the original failure context survives the rethrows.
Fields attached to every request log
Three identifying fields are attached to every log entry emitted during an MCP request:
operationId— the route identity, the same value used as thevirtualServerNamein analytics.upstreamServerId— the upstream id from the token exchange policy, populated once the upstream is resolved.subjectId— the authenticated user's stable subject id, populated once the bearer token is validated.
These fields make it trivial to filter your log provider by route, upstream, or user without scanning message bodies.
You can attach additional custom log properties from a policy or handler using
context.log.setLogProperties(). See
Logging → Custom log properties.
What the gateway never logs
The gateway is deliberately strict about what it doesn't emit:
- Bearer tokens (downstream or upstream)
- OAuth authorization codes
- PKCE code verifiers
- Client secrets
- Raw signed JWTs (state, session, browser-ticket)
- Full redirect URIs (only the host is logged, via a
safeHost()helper) - Customer request bodies
If you need to inspect any of these for debugging, do it through purpose-built tooling — never widen the gateway's log surface.
Routing logs to your provider
The MCP Gateway logs flow through the standard Zuplo logging pipeline. Enable
one of the log plugins in zuplo.runtime.ts to
forward the data to your provider of choice. The plugin choice is independent of
the MCP Gateway — once the plugin is wired up, gateway logs appear alongside the
rest of your project's logs.
Supported destinations include:
- AWS CloudWatch
- Datadog
- Dynatrace
- Google Cloud Logging
- Loki
- New Relic
- Splunk
- Sumo Logic
- VMware Log Insight
For destinations not in this list, build a custom logging plugin.
OpenTelemetry
The gateway integrates with Zuplo's
OpenTelemetry plugin to export traces and
logs in OTLP format. Register the plugin in modules/zuplo.runtime.ts alongside
McpGatewayPlugin:
Code
Traces include spans for the request, every inbound policy (mcp-*-inbound),
the handler, and the upstream fetch. Logs export the same structured entries
described above with their event field preserved.
Example: Grafana Cloud OTLP
Grafana Cloud is one common destination. Define the endpoint and credentials in
.env:
Code
Use the base OTLP endpoint that ends in /otlp — the runtime appends
/v1/traces and /v1/logs itself. Other OTLP-compatible destinations
(Honeycomb, Dynatrace, New Relic, Tempo, self-hosted Jaeger) work the same way;
substitute the endpoint and credential headers.
Metrics export isn't supported by the current OpenTelemetry plugin. The plugin exports traces and logs only. For metrics, use a dedicated metrics plugin.
Cross-referencing logs and analytics
The gateway uses the same identifiers in logs and analytics events, so you can pivot between the two:
- An analytics event's
reasonCodematches thereasonCodefield on the corresponding log entry (e.g.,missing_token,invalid_audience,connect_required). - The analytics
virtualServerNameis the same value as the log entry'soperationId. - The analytics
subjectIdis the log entry'ssubjectId. - The analytics
upstreamServerNameis the log entry'supstreamServerId.
When debugging an entry in the Analytics dashboard, filter your log provider by the same fields to surface every related log entry for that request.
Related
- Logging — Zuplo's general logging guide, including custom log properties and the full plugin list.
- OpenTelemetry — trace and log export configuration, including the available options on the plugin.
- Metrics plugins — metrics destinations (separate from the OTel plugin).
- Analytics — the dashboard view of the same data.