← Back to Blog

Debug Any MCP Server in 5 Minutes with the MCP Inspector

You finished your MCP server. The code looks right. The schema validates. You wire it into Claude Code and call a tool, and Claude says "I cannot find that tool" or worse, returns a stack trace from inside your process. The protocol is doing something you did not expect, and you have no idea which side is wrong.

That is what the MCP Inspector is for. It is the official developer tool from the Model Context Protocol project, and it acts as a client that talks to your server over the same wire format a real host uses. You run it, point it at your server, and you see exactly which messages flow, which capabilities get advertised, and which arguments a real tool call would send. No host involved, no LLM guessing what your function expects. Just the protocol, raw.

The package is @modelcontextprotocol/inspector on npm. Current version is 0.22.0 as of writing. You do not install it. It runs from npx.

Prerequisites

  • Node.js 18+ (node --version to check)
  • Either an MCP server you wrote, or a package name from npm or PyPI
  • A browser (the Inspector is a local web UI on port 6274)

Step 1: Launch the Inspector Against a Remote Package

The fastest way to see what the Inspector does is to point it at a real public server. The official filesystem server is a good target.

npx -y @modelcontextprotocol/inspector   npx -y @modelcontextprotocol/server-filesystem /tmp

That single command starts the Inspector, launches the filesystem server as a child process, and opens the UI at http://localhost:6274. The Inspector stays in front, the server runs in the background, and every JSON-RPC frame between them is visible to you.

If the package is on PyPI instead of npm, swap the launcher:

npx -y @modelcontextprotocol/inspector   uvx mcp-server-git --repository ~/code/some-repo

The general shape is inspector <launcher> <package> [args...]. The Inspector just cares that the first thing you give it is something it can run and talk to over stdio.

Step 2: Read the Four Tabs

The UI has four working tabs and a connection pane at the top. You will spend most of your time in the first three.

Server connection pane. This is the launchpad. It shows the transport (stdio in our case), the command, the arguments, and environment variables. If you are debugging a server that needs an API key, you set it here before connecting. The Inspector spawns the server as a child process and speaks JSON-RPC over its stdin and stdout.

Resources tab. Lists every resource your server advertised during the initialize handshake, with URI, MIME type, and description. You can click a resource to read it, which sends a resources/read request. If a resource is marked as subscribable, you can also test that the subscription flow works. This is the tab you open first when a real client says "I cannot see my files."

Prompts tab. Lists every prompt template your server declared. You fill in the arguments, click "Get Prompt," and the Inspector sends a prompts/get request and shows you the rendered message list. If the prompt expects an argument you forgot to declare as required, the tab tells you before the host does.

Tools tab. This is where most debugging happens. The tab lists every tool with its JSON Schema. You type arguments by hand, hit "Call Tool," and the Inspector sends a tools/call request and shows the response, including any structured content or error. Two debugging scenarios this catches instantly:

  • A tool declared required: ["query"] but the schema marks the field as description only. The Inspector runs the call, the server returns a validation error, and you see the mismatch without needing a host.
  • A tool returns a result the host cannot parse because the content array mixes text and resource items in an order the client does not expect. The Inspector renders the raw response so you can compare.

Notifications pane. Bottom of the window. Every log line and server-sent notification lands here. If your server emits progress updates or log messages, this is where they show up.

Step 3: Point It at Your Own Server

Local development is the real use case. You have a Python file at ./weather.py and you want to see what the protocol looks like.

npx -y @modelcontextprotocol/inspector   uv --directory . run weather.py

If your server is in TypeScript:

npx -y @modelcontextprotocol/inspector   node ./build/index.js

You can also set environment variables before the command launches. The Inspector picks them up, which is useful for testing servers that read secrets at startup.

Step 4: The Development Loop That Actually Catches Bugs

The Inspector documentation lists a workflow. I follow a tighter version of it.

  1. Launch the Inspector pointed at your server. Confirm the connection pane shows the right transport and that the "Connected" indicator is green. If it is red, the server failed during the initialize handshake. The Notifications pane has the reason.

  2. Check capability negotiation. Open the Resources, Prompts, and Tools tabs. The lists should match what your server actually exposes. If a tool is missing, the bug is almost always in your registration code, not in the protocol.

  3. Call every tool once with minimal arguments. You are not testing business logic here. You are testing that the round trip works and that the response shape matches the schema. Most protocol mismatches show up here.

  4. Call each tool with edge cases. Empty strings, missing optional fields, very long inputs, unicode, and anything else that might trip your handler. The Inspector lets you send whatever you want, so push it.

  5. Reconnect after every meaningful code change. The Inspector does not hot-reload. You change your server, you click "Reconnect," and you re-test. This sounds obvious but I have watched engineers spend twenty minutes debugging a fix that was never actually loaded.

  6. Read the Notifications pane. If your server is silent, that is information too. A well-behaved server emits a log line on connection. A silent one is hiding something.

What the Inspector Catches That Hosts Hide

Real hosts add layers between you and the protocol. Claude Code retries failed calls. Claude Desktop normalizes errors. IDE integrations may filter resources before they reach you. The Inspector does none of that. If your server has a bug, you see the bug, not a host's interpretation of it.

Three things I have personally caught with the Inspector that I would have missed otherwise:

  • A tool handler that returned a Python datetime object instead of a string. The Python SDK serialized it as a string, but the schema said string with a date-time format, and the host's validator rejected it. The Inspector showed the schema mismatch in the Tools tab.

  • A resource that pointed to a file path the server process could not read because the working directory was different from what I assumed. The Resources tab let me click and see the actual error from the server, which was a clear "Permission denied." I had been looking at the host log saying "Resource not found" and assuming the URI was wrong.

  • A logging/setLevel call that my server never implemented. The Inspector surfaces it as a "Method not found" in the Notifications pane. A host would have silently ignored it.

Common Pitfalls

Stdio buffering. If your server writes to stdout but the Inspector sees no output, the cause is almost always buffered I/O. In Python, call sys.stdout.flush() after every write, or use print(..., flush=True). Stdio MCP servers must flush after every JSON-RPC frame, or the Inspector will hang waiting for messages that are sitting in a buffer.

Wrong working directory. The Inspector spawns your server in the directory you launched npx from, not in the server's directory. If your server reads a relative config file, run the Inspector from the right directory or pass an absolute path.

Long-lived processes. The Inspector kills the server child process when you close the connection. If you started the server outside the Inspector and pointed it at the URL, that is a different code path. For local development, keep the Inspector as the parent.

Authentication for remote servers. The Inspector supports streamable HTTP and SSE, with bearer token support in the connection pane. For OAuth 2.1 flows (the spec added these in the 2025-06-18 revision), the Inspector does not yet do the full authorization dance. You will need to obtain a token out of band and paste it in.

When to Use the Inspector vs Claude Code

The Inspector is for protocol debugging. Claude Code is for end-to-end behavior. Use the Inspector when the question is "what does the protocol see." Use Claude Code when the question is "does the agent do the right thing with my server."

A practical split: build the server, debug every tool and resource in the Inspector until the round trips are clean, then connect it to Claude Code and test the agentic behavior. Mixing the two is a recipe for chasing the wrong layer when something goes wrong.

Where to Go Next

  • The Inspector itself: github.com/modelcontextprotocol/inspector. It is open source and accepts contributions.
  • The official spec at modelcontextprotocol.io/specification/2025-06-18. The Inspector only checks what the spec says it should check, so the spec is the source of truth when a behavior surprises you.
  • The Debugging Guide at modelcontextprotocol.io/docs/tools/debugging. Covers tools beyond the Inspector, including mcp-debug and manual curl testing for streamable HTTP servers.

Need Help Implementing This?

I help teams design and build scalable cloud infrastructure, DevOps pipelines, and production-grade systems.

Book a Free Consultation