Noi e terze parti selezionate usiamo cookie o tecnologie simili per finalità tecniche e, con il tuo consenso, per analizzare l’uso del sito.

Puoi liberamente prestare, negare o revocare il tuo consenso in qualsiasi momento.

How to Debug an MCP Server: Inspector, Logs and Common Errors

Debug an MCP server: MCP Inspector web and CLI, client logs in Claude Code, VS Code and Cursor, a curl server/discover probe, and what each error code means.

Questo articolo è in inglese.

TL;DR. To debug an MCP server, test it outside your AI client first. Run MCP Inspector (npx @modelcontextprotocol/inspector) against the same command or URL your client uses, read tools/list from the command line, and only then open the client's own status view and logs. Most failures are one of a few things: a stdio server that writes to stdout, a wrong path or missing environment variable, an unfinished sign-in, a protocol version the server does not support, or a page link pasted where a server URL belongs. This guide gives the exact command, log path or error code for each.

Where does an MCP connection fail?

An MCP connection fails at one of five points: the client cannot read its configuration, the server process or endpoint cannot be reached, the first request is rejected, the tool list comes back empty or different from what you expected, or a single tool call returns an error. To debug an MCP server, find which of the five it is before changing anything.

The order matters because each layer hides the ones below it. A client that skips a config entry never starts the process, so there is no log to read. A process that starts and then prints a banner to stdout looks, from the client's side, like a server that never answered. A remote endpoint that rejects the protocol version looks like a dead URL unless you read the response body.

So the working rule is: reproduce the failure with the smallest tool that reaches that layer. For configuration, that is the client's own list command. For the process and the handshake, it is MCP Inspector or curl. For the tool list, it is Inspector's CLI mode or npx mcp-tc check, and for tool calls, Inspector's CLI mode. The sections below go through them in that order.

How do I test a server with MCP Inspector?

MCP Inspector is the reference tool for testing an MCP server with no AI client in the way. The Inspector docs describe one npm package, @modelcontextprotocol/inspector, with three clients behind one binary: a web UI (the default), a --cli mode for scripts and CI, and a --tui terminal UI. It needs Node 22.19.0 or newer and runs through npx with no installation.

Pass it exactly what your client would run or connect to:

bash
# A local stdio server: the same command your client config uses
npx @modelcontextprotocol/inspector node path/to/server/index.js

# A remote server over Streamable HTTP
npx @modelcontextprotocol/inspector --server-url https://mcp.example.com/mcp --transport http

The launcher prints a URL that carries a per-launch API token and opens it in your browser. The web client page asks you to open that printed URL rather than typing localhost:6274 from memory, because the Node backend behind the UI can spawn processes on your machine and guards its API with that token. Set MCP_AUTO_OPEN_ENABLED=false if you do not want the browser to open.

Once connected, the tab bar tells you something before you click anything: which tabs appear depends on the capabilities the server reported. No Tools tab means the server did not declare tools. The three monitoring tabs are where the debugging happens:

  • Protocol is the JSON-RPC transcript, with requests paired to responses and spec errors rendered by class.
  • Network is the HTTP layer for Streamable HTTP and SSE servers: status codes, request and response headers, bodies.
  • Console is the stdio server process's stderr, which is where most local servers put their own diagnostics.

Network and Console never appear together, since a server is one or the other. If the Tools tab lists a tool but calling it fails, the Protocol tab shows the exact -32602 or other error the server returned.

One documented behavior worth knowing before you paste a token: the Inspector stores OAuth tokens, OAuth client secrets and stdio env: values in the OS keychain when one is available. On a machine without a keychain (Linux without libsecret, headless or SSH sessions, containers with a mounted volume) they go to ~/.mcp-inspector/secrets.json, unencrypted unless you supply a key. The configuration page documents MCP_INSPECTOR_SECRET_STORE=memory for keeping them in memory only.

How do I read a server's tool list from the command line?

The fastest check is the Inspector's CLI mode: one command connects, sends the single request you name with --method, prints the result and exits with a code that says why it failed. The CLI client page documents the methods, the output formats and the exit codes.

bash
# List a stdio server's tools and exit
npx @modelcontextprotocol/inspector --cli node path/to/server/index.js --method tools/list

# Same for a remote server, as JSON, piped to jq
npx @modelcontextprotocol/inspector --cli https://mcp.example.com/mcp --transport http \
  --method tools/list --format json | jq '.result.tools[].name'

If your stdio server takes its own flags, put -- between the server command and the Inspector's options. In CLI mode everything before -- is the target and everything after it belongs to the Inspector. The exit code tells you which layer failed:

Exit codeMeaning (CLI docs)
0Success
1Usage or unexpected error
3Server requires authentication (HTTP 401 or 403)
4Server unreachable (DNS, connection refused, timeout)
5Tool error: tools/call returned isError: true, or the tool was not found
6--strict found an error-severity tool-schema portability problem

On any non-zero exit the CLI also writes one JSON line to stderr with a stable code such as auth_required, unreachable or tool_not_found, plus the HTTP status and URL when known. In CI, add --stored-auth-only so a server that needs sign-in fails at once instead of waiting on a browser callback.

For a server on the 2026-07-28 revision you can go one level lower with plain curl and server/discover. The Streamable HTTP transport requires an Accept header listing both application/json and text/event-stream, an MCP-Protocol-Version header and an Mcp-Method header on every POST, and the discovery page shows the request carrying only _meta:

bash
curl -sS https://mcp.example.com/mcp \
  -H 'Accept: application/json, text/event-stream' \
  -H 'Content-Type: application/json' \
  -H 'MCP-Protocol-Version: 2026-07-28' \
  -H 'Mcp-Method: server/discover' \
  -d '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"curl","version":"0"},"io.modelcontextprotocol/clientCapabilities":{}}}}'

A modern server answers with supportedVersions, capabilities, optional instructions, and its name and version under _meta["io.modelcontextprotocol/serverInfo"]. The spec notes that serverInfo is self-reported and not verified, so treat it as a label for logs, not as proof of anything.

A third option reads the server the way mcp.tc does. npx mcp-tc check https://mcp.example.com/mcp sends server/discover and, for older versions, initialize, then reads serverInfo, tools/list with each tool's readOnlyHint and destructiveHint, the 401 response and its WWW-Authenticate header, the protected resource metadata, and the server card, and it flags keys that appear in the URL. It prints findings marked ok, warn, error or tip and exits 6 on errors or 5 when the server cannot be read at all. For a project folder, --stdio or --command "<command>" starts the server on your computer; the mcp-tc README documents these options and the exit codes. The mcp-tc page is clear that check does not predict whether a server will be listed; it tells you what a reader of your endpoint sees.

Where are the MCP logs in Claude Code, VS Code, Cursor and Claude Desktop?

Each MCP client keeps its own status view and its own log, and that is where the error text lives when a server shows as failed. The table lists the command or menu from each client's documentation that shows a server's state, and the place its output goes.

ClientServer statusLogs and failure detail
Claude Code/mcp in a session, or claude mcp list in a shellclaude mcp get <name> adds an Issue: line on failures; claude --debug-file /tmp/claude-debug.log writes a debug log
Claude DesktopThe plus icon in the chat input, then the Connectors menu~/Library/Logs/Claude on macOS, %APPDATA%\Claude\logs on Windows
VS CodeMCP: List Servers in the Command PaletteShow Output opens the Output view on that server's channel
CursorCustomize in the sidebarOutput panel (Cmd+Shift+U), then "MCP Logs" in the dropdown

The Claude Code MCP docs list the status labels /mcp shows, including ✔ Connected, ! Needs authentication, ✘ Failed to connect and ⏸ Pending approval. claude mcp list appends failure detail to a failed line, with credential-like text redacted. Two settings matter when a server is slow rather than broken: MCP_TIMEOUT is the startup timeout in milliseconds (for example MCP_TIMEOUT=10000 claude), and MCP_TOOL_TIMEOUT is the tool-call timeout across servers. A stdio server that fails on its first connection is not retried automatically; select Reconnect in /mcp.

The MCP debugging guide gives the command for following Claude Desktop's logs on macOS:

bash
tail -n 20 -F ~/Library/Logs/Claude/mcp*.log

It also says that after a server code change you must fully quit and reopen Claude Desktop; closing the window is not enough. In VS Code, the manage servers page offers Start Server, Stop Server and Restart Server from the same list, and MCP: Reset Trust clears MCP trust decisions. In Cursor, the MCP docs say the MCP Logs channel shows initialization, tool calls and error messages, and that config lives in .cursor/mcp.json for a project or ~/.cursor/mcp.json globally.

What do the most common MCP errors mean?

Most MCP errors can be read straight off the HTTP status and the JSON-RPC error code, because the 2026-07-28 base protocol assigns each protocol-level failure its own code in the -32020 to -32099 range, and the transport pairs each with a specific status. The table maps what you see to what to check.

What you seeWhat it usually meansWhat to check
Client reports a failed connection to a stdio serverThe process exited, or wrote something to stdout that is not an MCP messageRun the exact command in a terminal; open the Inspector's Console tab
HTTP 401 or 403Sign-in required, or a token the server rejectedFinish the OAuth flow: claude mcp login <name> or Authenticate in /mcp; codex mcp login in Codex; /mcp auth in Gemini CLI
HTTP 400, code -32022The server does not support the protocol version you sentdata lists the versions it supports
HTTP 400, code -32602A required _meta field is missing, or the params are invalidio.modelcontextprotocol/protocolVersion and clientCapabilities must be on every request; for tools/call, the arguments
HTTP 400, code -32021The server needs a client capability the request did not declaredata.requiredCapabilities
HTTP 400, code -32020An Mcp-* header does not match the body, or is missingMCP-Protocol-Version, Mcp-Method, Mcp-Name
HTTP 404 with a -32601 bodyA modern server does not implement that methodThe method name
HTTP 404 or 405 with no JSON-RPC bodyWrong path, or an older-era flow (GET or DELETE) sent to a 2026-07-28-only endpointThe URL on the listing; the server's protocol era
HTTP 403 on a local server with no auth challengeThe server rejected the Origin headerThe spec requires 403 for an invalid Origin to stop DNS rebinding
HTTP 409, code -32001An mcp.tc listing link was pasted as the server URLUse the server's own URL, which the message names

Two of these need a note. The Claude Code docs say a server is marked as needing authentication on 401 or 403, but if you set headers.Authorization yourself and the server rejects it, that shows as a failed connection rather than an authentication prompt; check the token or remove the header to use OAuth. And the Streamable HTTP page says a client that gets a 400 should inspect the body before falling back to the legacy initialize flow, because a modern server also uses 400 for the version, capability and header errors above.

Claude Code also reports configuration problems in words. A JSON entry with a url but no type is skipped with the message MCP server "<name>" has a "url" but no "type"; add "type": "http" (or "sse" / "ws") to this entry. Leading or trailing whitespace in command, url, args, env or headers is flagged, which the docs attribute to a pasted token with a trailing newline. A ${VAR} reference with no value and no default produces a missing-variable warning and the literal text is sent.

The last row in the table is specific to mcp.tc. A listing page such as https://mcp.tc/i/example-server is a web page, and the connect docs explain that an MCP client pointed at it gets HTTP 409 with a JSON-RPC error whose message names the server's own URL, or the install command for a local server. Copy the URL from the box at the top of the listing, or use the client's setup step on that page.

Why won't a local stdio server start?

A local stdio server fails to start for one of three documented reasons: the client launched it from an undefined working directory, it did not inherit the environment variables it needs, or the runtime it depends on (Node.js for npx, uv for uvx, Docker for docker) is missing on the machine. All three show up as a generic connection failure in the client.

The debugging guide states the first two plainly. The working directory for servers launched via the client's config "may be undefined (like / on macOS)", so use absolute paths in the configuration and in any .env file. And stdio servers "inherit only a limited subset of environment variables automatically", with the exact set depending on the platform, so pass what the server needs with the env key:

json
{
  "mcpServers": {
    "example-server": {
      "command": "/absolute/path/to/example-server",
      "args": ["--data", "/absolute/path/to/data"],
      "env": {
        "EXAMPLE_API_KEY": "replace-me"
      }
    }
  }
}

The third reason is the first check in mcp.tc's troubleshooting list: run the install command from the listing in a terminal before adding it to a client. If it fails there, the usual cause is a missing runtime, or a placeholder such as <YOUR_API_KEY> that was never replaced.

Once the process starts, the only remaining stdio rule is about stdout. The stdio transport says the server "MUST NOT write anything to its stdout that is not a valid MCP message" and "MAY write UTF-8 strings to stderr for any logging purposes". A startup banner, a progress bar or a console.log call on stdout corrupts the stream, and the client sees a server that never completed the handshake. In the Inspector, pass -e KEY=VALUE to set environment variables and --cwd <path> to set the working directory, then read the Console tab, which shows exactly what the process wrote to stderr.

Legacy or 2026-07-28: which protocol era is the server speaking?

A server speaks one of two eras: the legacy era, where an initialize handshake opens a session, or the modern 2026-07-28 era, where every request carries its own _meta and there are no sessions. A client that assumes the wrong era gets errors that look like the server is down, so settle the era before reading anything else.

The Inspector treats this as a per-server setting. The protocol eras page documents three values for --protocol-era (or protocolEra in a config file): legacy, the default, sends a plain initialize with no probing; auto probes server/discover first and falls back to initialize on any non-modern outcome; modern pins exactly 2026-07-28 with no fallback, "so a non-modern server fails loudly". The docs explain the default: a debugging tool must not auto-probe, because a probe stalls against silent legacy stdio servers and clutters the transcript you came to read. Once connected, the negotiated era appears as a badge on the Protocol tab.

The probe itself has three outcomes, spelled out on the stdio transport page. A DiscoverResult means the server is modern. A recognized modern error such as UnsupportedProtocolVersionError means the server is modern and you should use one of the versions it advertises, without falling back. Any other error, or no answer within a reasonable timeout, means the server is legacy. The spec adds that the fallback must not be keyed to one specific error code, since legacy servers answer an unknown pre-initialize request with -32601, -32602, or nothing at all.

For remote servers, the revision also changed the transport. The Streamable HTTP page lists what 2026-07-28 removed: the GET stream endpoint and protocol-level sessions. A server that supports only this revision answers a GET or DELETE with 405 Method Not Allowed and ignores an Mcp-Session-Id header. If you are moving your own server across that line, the stateless migration guide walks through server/discover, per-request _meta and the Mcp-Method and Mcp-Name headers.

What you can do next on mcp.tc

A listing on mcp.tc gives you the inputs this guide keeps asking for: the server's own URL or install command, whether it needs sign-in, and setup steps for Claude Code, claude.ai, Claude Desktop, ChatGPT, Cursor, VS Code, Devin Desktop, Codex and Gemini CLI. Search the directory by name, or filter to servers that need no sign-in when you want a quick connection test. Every setup step uses the vendor's own URL or package, so the client connects straight to the server and nothing on mcp.tc is in between.

From a terminal, npx mcp-tc scan reads the MCP configs of Claude Code, Claude Desktop, Cursor, VS Code, Devin Desktop, Codex and Gemini CLI on your computer and shows which servers are on mcp.tc, sending one address per server and no keys, headers or environment values. npx mcp-tc add <slug> --client cursor shows the command or config change for a listing and asks before writing. Both are on the CLI page, along with check for your own server.

If a server connected fine last week and a tool is now missing or renamed, open the listing's History tab. mcp.tc reads the tool list of each listed server whose tools it can read without signing in every 3 hours, and records added and removed tools, changed descriptions, schemas and annotations after two reads agree. On 28 October 2026, 351 of the 1,125 listed servers had a watched tool list, and the history began on 6 October 2026. The newest changes across the directory are at recent changes, and the change history docs explain what counts as a change and what the history cannot show: tools a server lists only after sign-in or only to some clients, and a change undone between two checks. Sign in and press Follow on a listing to get an email when its tools or version change.

If the server you are debugging is public and not listed, suggest it with its URL, or run npx mcp-tc submit <url>.

FAQ

What is MCP Inspector and do I need to install it?

MCP Inspector is the reference developer tool for testing and debugging MCP servers, published as the npm package @modelcontextprotocol/inspector. It bundles a web UI, a scriptable CLI (--cli) and a terminal UI (--tui). You run it with npx and no install step; it needs Node 22.19.0 or newer. Pass it the same stdio command or --server-url your client uses, and it shows the JSON-RPC transcript, the HTTP layer and the server's stderr.

Why does my MCP server work in Inspector but not in my client?

The Inspector runs the server from your shell, with your working directory, your environment variables and your PATH. A client launches it from an undefined working directory with a limited set of environment variables, which the MCP debugging guide calls out as platform-dependent. Use absolute paths and an env block in the client config, confirm the runtime (npx, uvx, docker) is on the client's path, and compare the client's log with the Inspector's Console tab.

How do I see which protocol versions a server supports?

Send server/discover. The 2026-07-28 specification says servers must implement it, and the result lists supportedVersions along with capabilities and the server's self-reported name and version. If you ask for a version the server does not support, it answers HTTP 400 with error code -32022 and the supported versions in the error's data. A server that returns any other error, or nothing, is on the legacy era and expects an initialize handshake instead.

What does "Failed to connect" mean in Claude Code?

It means the connection attempt failed for a reason other than authentication, which has its own label; the Claude Code docs describe the detail shown next to it as the HTTP status or error code, plus any error text the server returned. Run claude mcp get <name> to read the Issue: line, or claude mcp list for the failure detail with credentials redacted. A rejected headers.Authorization you set yourself also shows as a failed connection. For a stdio server, select Reconnect in /mcp, since the first connection is not retried.

Can mcp.tc tell me why my server fails to connect?

Partly. npx mcp-tc check <url> reads your endpoint the way mcp.tc and clients do, reports the handshake, the sign-in challenge, the tool list and the server card, and exits 6 on errors or 5 when the server cannot be read at all. It does not predict whether the server will be listed. For a server already listed, the listing page shows whether its daily health check is failing, and the History tab shows tool changes mcp.tc's reads found.

Where should a stdio MCP server write its logs?

To stderr, and nowhere else. The stdio transport specification says the server must not write anything to stdout that is not a valid MCP message and may write UTF-8 log lines to stderr. Clients may capture stderr; the Inspector shows it in its Console tab, and the debugging guide says the host application captures it for stdio servers. Logging over the protocol with notifications/message is deprecated as of 2026-07-28, and a remote server's stderr is not captured by the client at all.

Fonti

  1. modelcontextprotocol.io/docs/tools/inspector
  2. modelcontextprotocol.io/docs/2026-07-28/tools/inspector/cli
  3. modelcontextprotocol.io/docs/2026-07-28/tools/inspector/configuration
  4. modelcontextprotocol.io/docs/2026-07-28/tools/inspector/web
  5. modelcontextprotocol.io/docs/2026-07-28/tools/inspector/protocol-eras
  6. modelcontextprotocol.io/docs/2026-07-28/tools/debugging
  7. modelcontextprotocol.io/specification/2026-07-28/basic/index
  8. modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http
  9. modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio
  10. modelcontextprotocol.io/specification/2026-07-28/server/discover
  11. code.claude.com/docs/en/mcp
  12. code.visualstudio.com/docs/agents/run/manage-mcp-servers
  13. cursor.com/docs/context/mcp
  14. github.com/mcptc/mcp-tc

Server da provare

Tutti i server
  • GitHub, verificato

    Strumenti per sviluppatori

    Accesso richiesto

    Lavora con repository, issue, pull request, workflow di Actions e ricerca nel codice di GitHub dal tuo assistente AI.

    mcp.tc/i/github
  • Accesso facoltativo

    Ottieni nel contesto del tuo assistente documentazione di librerie ed esempi di codice aggiornati e specifici per versione.

    mcp.tc/i/context7
  • Senza account

    Fai domande su qualsiasi repository GitHub pubblico e leggi la sua documentazione DeepWiki generata dall’AI.

    mcp.tc/i/deepwiki
Tutti gli articoli