Field note progress0%
← All field notes

Engineering / 5 min

MCP server observability: a practical OpenTelemetry guide

Instrument MCP tool calls with OpenTelemetry or AGNTCY Observe, preserve consent boundaries, reconstruct journeys and verify outcomes instead of stopping at server health.

MCP server observability should explain the complete path from an agent's intent through tools/call execution to the result the client received. Server logs alone cannot reveal repeated paths, missing outcomes or the user sessions affected.

What to capture

Create one server span for every MCP tools/call request. The span should represent the server-side operation and preserve enough context to reconstruct a journey.

At minimum, capture:

  • MCP server and tool name
  • Stable request, session and parent trace relationships
  • Validated arguments that the tool actually received
  • Start time, duration and final status
  • The final client-visible result, including structured error content
  • User or tenant identity when permitted and available
  • A short reason or user-intent field when the client supplies it
  • A measurable outcome when the application can report one

Do not treat a transport-level 200 response as tool success if the MCP result contains an error. Do not treat a successful tool call as proof that the user's broader task succeeded.

Choose an instrumentation path

For a compatible Python server based on the official MCP package, the Flowlines skill prefers AGNTCY Observe when it can provide the canonical server span cleanly. For TypeScript, other Python frameworks or incompatible versions, use vanilla OpenTelemetry.

The OpenTelemetry semantic conventions provide the common vocabulary and transport. Flowlines adds an MCP-specific contract for the journey fields it analyzes.

This is standards-based instrumentation, but it is still instrumentation. The "no proprietary SDK" path applies when an application already emits usable traces. An MCP server without the necessary tools/call span must be changed before MCP journey analytics can work.

Protect the data boundary

Tool arguments and results may contain customer data, personal information, credentials or source code. Before changing the server:

  1. Inventory every exported field.
  2. Identify sensitive arguments and result fragments.
  3. Redact or omit fields that are not necessary.
  4. Prefer pseudonymous user identifiers.
  5. Confirm retention and regional requirements.
  6. Obtain explicit approval for the proposed export boundary.

Never capture secrets merely because they appear in an argument object.

Send and correlate spans

Export OTLP traces to https://api.flowlines.ai/v1/traces or the compatible https://api.flowlines.ai/traces endpoint. Authenticate with the x-flowlines-api-key header and set a stable service name for the MCP server.

Propagate the incoming trace context when one exists. If the client cannot send a parent, preserve stable request and session identifiers so later analysis can correlate calls responsibly.

Verify with a representative journey

Exercise a real multi-tool workflow in a safe environment. Confirm:

  • Exactly one server span exists per tools/call
  • Tool names and validated arguments match execution
  • Errors are represented in status and result content
  • The client-visible result is present after serialization
  • User, session and request fields correlate correctly
  • The intended use case and outcome can be reconstructed
  • Retries create distinct calls without breaking the parent journey

Then test one failure, one recovery and one repeated-call path. A happy-path trace cannot validate observability for the cases that need it most.

Operational views that matter

Track calls, failed calls, sessions, reported users, call success, p95 latency and outcome coverage by server and tool. At the journey level, measure calls per session, repeated-call loops, failed sessions and typical paths by intent.

Flowlines uses these spans to connect MCP health with user behavior and affected sessions. Its repository skill can inspect, propose, implement and verify the integration after you approve the data boundary.

Read the product page or follow the setup documentation.

A concrete MCP journey to verify

Use a synthetic CRM server with a two-step task: find an account, then enrich it. The caller's user intent stays “Prepare an account brief.” The reason changes for each tool: “Find the account record,” then “Fill in the company details.”

The distinction matters. Tool names describe your API; user intent describes the work customers want done. Without intent and session identity, a chart of tool calls cannot reliably tell you how many account briefs users attempted.

Instrument the right boundary

Install the official Flowlines plugin and run Flowlines MCP Observability against the server repository. The skill checks the framework and chooses AGNTCY Observe or a compatible OpenTelemetry integration. Instrument one MCP-level tools/call boundary around the final client-visible result, not merely the HTTP route and not both middleware and each handler.

The plugin's workspace connection and the server's namespace API key have different purposes. Sign in to the Flowlines MCP connection to inspect workspace data. Create the namespace key under Flowlines Settings, API keys, for telemetry export. If the freshly installed skill is unavailable, start a new task before instrumentation. Start with the guided prompt.

Inspect a synthetic canonical span

This is an attribute example, not a complete OTLP request or a drop-in server implementation:

{
  "gen_ai.operation.name": "execute_tool",
  "gen_ai.tool.name": "find_account",
  "gen_ai.tool.call.id": "example-call-001",
  "gen_ai.tool.call.reason": "Find the account record",
  "session.user_intent": "Prepare an account brief",
  "mcp.method.name": "tools/call",
  "mcp.server.name": "example-crm",
  "session.id": "example-session-001",
  "user.id": "example-user-001",
  "gen_ai.tool.call.arguments": "{\"name\":\"Example Co\",\"reason\":\"Find the account record\",\"user_intent\":\"Prepare an account brief\"}",
  "gen_ai.tool.call.result": "{\"content\":[{\"type\":\"text\",\"text\":\"Account found\"}]}"
}

Use a fresh invocation ID for every real call, with the same session ID across the journey. Prefer verified identity from the server's authentication context. Client-supplied identity is analytics context, never authorization. Export only the reviewed argument/result fields and exclude raw authorization metadata. The span must have SERVER kind and an explicit completed-call status; an MCP error result is not success merely because transport returned 200.

Run the acceptance journey

  1. Call find_account and enrich_account with a stable test session and permitted user identity.
  2. Finish the journey using the instrumented report_outcome tool.
  3. Repeat with an expected tool error and a partial result.
  4. Confirm each invocation appears once under the intended MCP server.
  5. Open the session and check intent, tool order, client-visible result and reported outcome.
  6. Confirm that failure changes the call result while missing outcomes remain visibly missing.

A reported outcome is a signal supplied by the caller, not independently verified business completion. Where possible, compare it with the external transaction or artifact.

Troubleshoot the missing layer

No calls: check export endpoint, namespace credentials and whether the MCP middleware ran. Calls but no journeys: check session IDs and user intent. Duplicate calls: remove overlapping instrumentation. Unknown status: check successful and failed result handling. Wrong users: check identity precedence and mappings. Missing outcomes: confirm the caller invoked report_outcome as the final tool call.

Use the plugin's Flowlines Doctor for incomplete ingestion. Review the maintained MCP telemetry contract before copying integration code.

Last reviewed Sep 7, 2026

Keep reading

Engineering

How to debug AI agents in production

Engineering

How to detect AI agent drift in production

Engineering

How to connect Flowlines to production traces

Start free

Apply behavioral observability to your production agent.