How to Debug an MCP Server with MCP Inspector
Debug an MCP server fast with MCP Inspector: launch it against stdio and remote servers, test tools interactively, read MCP logs, and catch failures in CI.
MCP Inspector is the official debugging tool for Model Context Protocol servers, and it should be the first thing you reach for when a server misbehaves. Instead of guessing why Claude Code or Cursor silently refuses to list your tools, you run one command -- npx @modelcontextprotocol/inspector <your server command> -- open the web UI it prints, and exercise every tool, resource, and prompt directly against your server with full visibility into the JSON-RPC messages going back and forth.
This guide covers the practical workflow: how to launch Inspector against local stdio servers and remote HTTP servers, how to test tools interactively, the two gotchas that cause most "it works in Inspector but not in my client" confusion, where to find MCP logs inside Claude Code and Cursor, and how to turn Inspector's CLI mode into a CI smoke test so a broken server never ships. If you need to debug MCP server behavior regularly, this loop is dramatically faster than restarting your AI client after every change.
What Is MCP Inspector and When to Reach for It
MCP Inspector is a browser-based client purpose-built for testing MCP servers. It ships as an npm package and consists of two parts: a web UI where you click through your server's capabilities, and a local proxy process that actually speaks MCP to your server on the UI's behalf. That split matters later -- it is the source of one of the most common setup gotchas.
Reach for Inspector when:
- Your MCP server is not working in a client. Claude Code shows the server as failed, or the tools never appear. Inspector isolates whether the bug is in your server or in your client configuration.
- A tool returns wrong output or errors. Inspector shows the exact request arguments, the raw response, and any error payloads without an LLM in the loop deciding what to call.
- You are iterating on tool schemas. Input schemas, descriptions, and annotations render directly in the UI, so you can see what a client (and the model behind it) will actually receive.
- You are about to publish. A five-minute Inspector pass catches broken handlers, malformed schemas, and crash-on-startup bugs before anyone else hits them.
If you are still building your first server, start with our guide to building an MCP server in TypeScript and come back here when something breaks. Something always breaks.
Launch MCP Inspector Against Local and Remote Servers
Step 1: Run Inspector against a local stdio server
Point Inspector at whatever command starts your server. For a compiled TypeScript server:
npx @modelcontextprotocol/inspector node build/index.js
For a Python server:
npx @modelcontextprotocol/inspector uv run python server.py
Inspector spawns your server as a child process, connects over stdio, and prints a URL. Recent versions include a session token in that URL (a MCP_PROXY_AUTH_TOKEN query parameter) that authenticates the browser to the local proxy -- open the exact URL it prints rather than typing localhost:6274 by hand, or the proxy will reject your requests.
Step 2: Connect and verify the handshake
In the UI, hit Connect. If the connection succeeds you will see your server's declared capabilities: which of tools, resources, and prompts it supports, plus its name and version from the initialize handshake. If the connection fails immediately, your server is crashing on startup -- check the error output pane, which captures your server's stderr. This alone answers the most common "why is my server not showing up" question: the process never survived the handshake.
Step 3: Connect to a remote server over HTTP
For servers running behind a URL instead of a local command, select the Streamable HTTP transport in the UI and enter the endpoint. Inspector supports adding auth headers (for example a bearer token) and can walk a full OAuth flow for servers that require it -- useful for testing production deployments, not just local builds. If you are unsure which transport your server should be speaking in the first place, our breakdown of MCP transports: stdio vs Streamable HTTP vs SSE covers when each one applies.
This is also how you can poke at hosted servers you rely on. The localskills.sh MCP server, for instance, exposes skill search and install over Streamable HTTP with OAuth and scoped access -- connecting Inspector to a real production server is a good way to see what a well-formed initialize response and tool list look like.
Test MCP Server Tools, Resources, and Prompts Interactively
Once connected, the workflow to test MCP server behavior is the same loop every time:
- List tools. Open the Tools tab and click List Tools. Every tool your server registered should appear with its description and input schema. If a tool is missing here, no client will ever see it -- fix registration before debugging anything downstream.
- Inspect the schema. Click a tool and read the rendered input schema. This is exactly what gets sent to the model. Vague descriptions and untyped parameters are bugs even when the code works: the model chooses tools based on this text.
- Call the tool with real arguments. Fill in the form and run it. You get the raw result -- content blocks, structured output, or the error payload -- with no model interpretation layered on top. Test the happy path, then deliberately pass bad input and confirm your server returns a useful error instead of crashing.
- Repeat for resources and prompts. The Resources tab lists resource URIs and lets you read their contents and test subscriptions; the Prompts tab renders prompt templates with whatever arguments you supply.
- Watch the notifications pane. Log messages your server emits via MCP logging notifications, progress updates, and list-changed events all land here. If your server sends nothing, that is worth fixing too -- silent servers are miserable to operate.
One setting worth knowing: Inspector's default request timeout is 10 seconds. If you are testing a tool that legitimately takes longer (a big fetch, a slow API), bump the timeout in the Configuration pane instead of chasing a phantom bug.
Gotchas: Why Your MCP Server Is Not Working
Two failure modes account for a remarkable share of MCP debugging time. Check both before doing anything clever.
console.log breaks stdio servers
On the stdio transport, stdout is the protocol channel. Every byte your process writes to stdout must be a valid JSON-RPC message. A single stray console.log -- yours, or a dependency's -- corrupts the stream and produces baffling parse errors or a client that drops the connection.
// Bad: corrupts the JSON-RPC stream on stdio
console.log("handling request...");
// Good: stderr is not part of the protocol
console.error("handling request...");
Route all diagnostic output to stderr, or better, use MCP logging notifications so messages show up in Inspector's notifications pane and in client-side MCP logs. If your server works over HTTP but fails over stdio, a stdout write is the prime suspect. Audit your dependencies too -- a library that prints a startup banner will break you.
The 6274/6277 port split
Inspector runs on two ports, not one: the web UI is served on 6274, and the MCP proxy -- the process that actually talks to your server -- listens on 6277. The browser page you interact with sends every request through that proxy.
This split causes predictable trouble:
- Both ports must be free. Another Inspector instance (or anything else) squatting on 6277 gives you a UI that loads fine but cannot connect to anything.
- Remote development needs both ports forwarded. If you run Inspector on a devbox or in a container and forward only 6274, the UI renders and every connection fails.
- Override with environment variables when you need different ports:
CLIENT_PORT=8080 SERVER_PORT=9000 npx @modelcontextprotocol/inspector node build/index.js
And again: use the tokened URL Inspector prints. The proxy rejects unauthenticated requests by design, so a hand-typed URL without the session token looks exactly like a mysterious connection failure.
Reading MCP Logs in Claude Code and Cursor
Inspector proves your server works in isolation. When it passes there but fails inside a client, the problem is almost always configuration -- wrong command path, missing environment variable, wrong transport -- and the client's own MCP logs tell you which.
Claude Code:
- Run
claude mcp listin your terminal to see every configured server and whether it connected. - Inside a session, run
/mcpto check server status, view available tools, and re-authenticate OAuth servers. - Launch with
claude --debugto get verbose output that includes MCP connection attempts, spawn errors, and handshake failures -- this is where "command not found" and bad-path errors surface. - Check your
.mcp.json(project scope) or user-level config for typos in the command, args, and env. A server that works when you run it by hand but fails in Claude Code usually has a relative path or a missing env var in its config entry.
Our Claude Code MCP guide walks through the full configuration model, including project versus user scope.
Cursor:
- Open Settings → MCP to see each server with a status indicator; a red dot means the process failed to start or the handshake failed.
- Open the Output panel (View → Output) and select the MCP channel from the dropdown to read the actual MCP logs, including stderr from your server process.
- Verify
.cursor/mcp.json-- same class of issues as Claude Code: paths, args, environment.
The debugging order matters: Inspector first, client logs second. If a server fails in both, fix the server. If it passes Inspector and fails in the client, stop editing server code and read the client's MCP logs.
Add MCP Server Checks to CI
Inspector has a CLI mode that skips the browser entirely, which makes it a cheap CI smoke test. If the server crashes on startup, fails the handshake, or returns malformed responses, the command exits nonzero and fails the build:
# List tools -- fails if the server won't start or handshake
npx @modelcontextprotocol/inspector --cli node build/index.js --method tools/list
# Call a specific tool with arguments
npx @modelcontextprotocol/inspector --cli node build/index.js \
--method tools/call --tool-name search_docs --tool-arg query=timeouts
In GitHub Actions:
- name: Smoke-test MCP server
run: |
npm ci
npm run build
npx @modelcontextprotocol/inspector --cli node build/index.js --method tools/list
For stronger guarantees, pipe the tools/list output through jq and assert that the tools you expect are present -- catching an accidentally unregistered tool is exactly the kind of regression that otherwise ships silently. Teams that pin their agent tooling in version control (the same instinct behind sharing AI coding rules across tools) tend to wire this in next to their lint step: it runs in seconds and catches the worst failure mode an MCP server has, which is not starting at all.
FAQ
What ports does MCP Inspector use?
Two: 6274 for the web UI and 6277 for the local proxy that communicates with your server. Both must be free, and both must be forwarded if you run Inspector on a remote machine. Override them with the CLIENT_PORT and SERVER_PORT environment variables.
Why does my MCP server work in Inspector but not in Claude Code?
Because Inspector validated the server, the remaining suspect is client configuration: a wrong command path, missing environment variables, or the wrong transport in .mcp.json. Run claude mcp list and claude --debug to see the connection error, and remember that clients spawn stdio servers from a different working directory than your shell -- use absolute paths.
How do I test an MCP server without a browser?
Use Inspector's CLI mode: npx @modelcontextprotocol/inspector --cli <command> --method tools/list. It performs the handshake, runs the requested method, prints JSON, and exits nonzero on failure -- ideal for scripts and CI.
Why does my stdio MCP server fail with JSON parse errors?
Something is writing non-protocol bytes to stdout -- usually a console.log or print call, sometimes a dependency's startup banner. On stdio, stdout is reserved for JSON-RPC messages. Send all logging to stderr or use MCP logging notifications.
Can MCP Inspector connect to remote servers with authentication?
Yes. Choose the Streamable HTTP transport, enter the server URL, and attach custom headers such as a bearer token. Inspector can also complete OAuth flows for servers that require them, so you can debug deployed servers the same way you debug local ones.
Debugging your server is half the job; distributing the conventions around it is the other half. Sign up for localskills.sh to publish and share agent skills and rules across Claude Code, Cursor, Windsurf, and the rest of your team's tools.
npm install -g @localskills/cli
localskills login
localskills install <org>/<skill>