MP-201a · Module 3

Monitoring & Debugging

3 min read

MCP servers fail silently. The client sends a request, the server crashes, and the LLM gets a transport error with no diagnostic information. Structured logging is not optional — it is the only way you will know what happened. Log every tool call with its name, arguments (sanitized), execution time, and result status (success/error). Write logs to stderr for stdio servers or to a logging service for HTTP servers. Include a request ID in every log line so you can correlate entries across a single tool execution.

The MCP Inspector is your primary debugging tool during development. Run it with npx @modelcontextprotocol/inspector to get an interactive UI that connects to your server, lists all tools and resources, and lets you call them with custom inputs while showing the raw JSON-RPC messages in both directions. For production debugging, capture the JSON-RPC traffic by wrapping your transport in a logging proxy — log every message before passing it to the SDK. This gives you a complete replay of the conversation between client and server.

import { CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";

// Structured logging wrapper for tool calls
function withLogging(
  server: Server,
  handler: (request: unknown) => Promise<unknown>
) {
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
    const callStart = Date.now();
    const toolName = request.params.name;
    const requestId = crypto.randomUUID().slice(0, 8);

    // Log the call (stderr for stdio servers)
    console.error(JSON.stringify({
      event: "tool_call",
      requestId,
      tool: toolName,
      args: request.params.arguments,
      timestamp: new Date().toISOString(),
    }));

    try {
      const result = await handler(request);
      console.error(JSON.stringify({
        event: "tool_result",
        requestId,
        tool: toolName,
        durationMs: Date.now() - callStart,
      }));
      return result;
    } catch (err) {
      console.error(JSON.stringify({
        event: "tool_error",
        requestId,
        tool: toolName,
        error: (err as Error).message,
        durationMs: Date.now() - callStart,
      }));
      throw err;
    }
  });
}
  1. Add structured logging Wrap every tool handler with a logging function that captures tool name, arguments, duration, and result status. Use JSON format so logs are parseable by monitoring tools.
  2. Set up MCP Inspector Run `npx @modelcontextprotocol/inspector` and connect to your server. Test every tool with valid inputs, invalid inputs, and edge cases. Check the raw JSON-RPC panel for protocol issues.
  3. Monitor in production For HTTP servers, export metrics: tool call count, error rate, and p95 latency per tool. Alert on error rate spikes — a tool that starts failing 50% of the time is worse than a tool that does not exist.