MCP Inspector: Turning Server Connections, Tools, and OAuth into a Verifiable Debugging Loop
MCP Inspector: Turning Server Connections, Tools, and OAuth into a Verifiable Debugging Loop
Problems with an MCP Server are rarely limited to whether the process starts. The server may fail during initialize because of a protocol mismatch, connect successfully but expose the wrong tools, or stall at OAuth when the target is a remote HTTP service. In CI, a human-readable banner mixed into stdout can even break the JSON parser used by the next step. As MCP becomes the tool boundary for AI Agents, these cases cannot be judged by opening a web page and clicking around once.
I chose modelcontextprotocol/inspector because it treats MCP Server inspection as a real developer tool rather than a demo UI. The official repository's v2 line exposes Web, CLI, and TUI interfaces through one mcp-inspector binary. Its CLI can emit machine-readable JSON for shell scripts, CI jobs, and smoke tests. Its value is therefore not only that it shows a tool list, but that it turns connection, capability negotiation, tool calls, OAuth, and failure states into repeatable verification steps.
This article is based on the official MCP Inspector repository, README, CLI documentation, MCP server configuration guide, and shell smoke-testing guide. Repository facts were checked on September 11, 2026. Versions, command-line flags, and MCP SDK behavior can change, so use the official documentation for production work.
The short version: it makes MCP verifiable
MCP Inspector belongs in the middle of the MCP Server development lifecycle. It does not replace unit tests or a formal conformance suite. It fills the gap between "the Server process runs" and "an Agent can use it reliably."
I see four main layers of use:
1. Fast diagnosis: connect to a local or remote Server in the Web interface and inspect initialization, tools, resources, prompts, and events.
2. Interactive exploration: use the TUI from a terminal without switching to a browser for every small change.
3. Automated verification: run initialize, tools/list, or tools/call with the CLI and let a shell script and jq evaluate the result.
4. A release gate: compose connect, list, call, and assert into a smoke job that runs after every commit or deployment.
This positioning matters. If you only need a one-time manual demonstration, the Web interface may be enough. If the team needs to know whether a Server still works after an SDK upgrade, schema change, or OAuth provider change, the CLI's repeatability is the important part.
Why Web, CLI, and TUI share one Inspector
The official README separates the Inspector into Web, CLI, TUI, and launcher clients, with shared code in core. The Web client is a Vite, React, Mantine, and Node backend application. The CLI is a scriptable client for automation, CI, and fast Agent feedback loops. The TUI uses Ink and React for an interactive terminal experience. All three are dispatched through the same mcp-inspector entry point.
The design reflects a useful engineering rule: interfaces can differ, but verification semantics should not be reinvented for every interface. Web is good for human exploration, CLI is good for programmatic assertions, and TUI is good for fast terminal-based debugging. If they share connection settings, transports, and core parsing logic, the team is less likely to see a browser success that cannot be reproduced in CI.
Shared core does not mean that every flag behaves identically. The official configuration guide calls out differences involving --header, --transport stdio, and the -- separator. I would not copy a command that works in Web directly into CI. Read the documentation for the specific client and then fix the smallest verifiable command in the workflow.
What each interface is for
Web: inspect complete state and explore an unknown Server
Web is the natural starting point for a new Server or for inspecting tool schemas, resources, prompts, and MCP App behavior. It turns protocol interaction into visible state, so you can quickly see what the Server provides and whether a tool's input schema matches the client expectation.
It is also useful for exploratory debugging: connect, inspect serverInfo and capabilities, list tools, and try one safe read operation. Its strength, however, is interaction speed rather than replayability. A second engineer may not know exactly which buttons were pressed, which headers were used, or whether an error was intermittent.
TUI: keep interactive testing in the terminal
The TUI brings interactive inspection back to the terminal. This is convenient for SSH, tmux, and remote development environments. It can serve as the bridge between a CLI probe and deeper Web debugging.
It is still a human-facing interface. When another program or CI needs the result, use the CLI's --format json instead of parsing terminal layout.
CLI: connect the Inspector to engineering workflows
The CLI is the most useful part for an automated pipeline. The official documentation describes it as connect, execute one --method, and disconnect. It supports tools, resources, and prompts, and it can inspect catalog entries with servers/list and servers/show without connecting.
A minimal local Server check is:
npx @modelcontextprotocol/inspector --cli node build/index.js --method initialize
This does not invoke a business tool. It completes the MCP handshake, prints serverInfo, protocolVersion, capabilities, and instructions, then disconnects. For a smoke test, it is a strong first probe: inexpensive, but sufficient to confirm that the target is alive and actually speaks MCP.
From initialize to tools/call: a repeatable verification path
I recommend four steps from shallow to deep instead of immediately calling the most complicated tool.
Step one: verify the connection and protocol
A stdio Server is specified as the Inspector target command. A remote Server can use HTTP or SSE. A Streamable HTTP example is:
npx @modelcontextprotocol/inspector --cli \\
--transport http --server-url https://example.com/mcp --method initialize
For SSE:
npx @modelcontextprotocol/inspector --cli \\
--transport sse --server-url https://example.com/sse --method initialize
This step answers only whether the handshake works. It does not prove that tools are correct or that the permission model is complete. A zero exit code is not proof that the entire product workflow passed.
Step two: list capabilities and detect contract drift
List tools, resources, or prompts:
npx @modelcontextprotocol/inspector --cli node build/index.js \\
--method tools/list --format json
--format json is essential. The official smoke-testing guide says that the default output is human-readable text. Any result consumed by a script should explicitly request JSON. A normal method envelope contains result, and some cases also contain appInfo or schemaFindings. A consumer should not assume every response has the same fixed set of keys.
To assert that a tool exists:
npx @modelcontextprotocol/inspector --cli node build/index.js \\
--method tools/list --format json \\
| jq -e '.result.tools | map(.name) | index("my_tool")' > /dev/null
The important engineering idea is not jq; it is turning a tool contract into a condition that fails the job. If a tool disappears, the response shape changes, or the test points at the wrong environment, CI should fail clearly rather than leave an apparently successful log.
Step three: call one controlled tool
After the capability list matches expectations, call one tool:
npx @modelcontextprotocol/inspector --cli node build/index.js \\
--method tools/call \\
--tool-name mytool \\
--tool-arg key=value \\
--tool-arg another=value2 \\
--format json
For nested JSON, pass the value as one --tool-arg:
--tool-arg 'options={"format": "json", "max_tokens": 100}'
I treat the choice of smoke-test tool as a security decision. Prefer read-only, idempotent tools with no external side effects, such as a version, health, or fixed-fixture check. Do not call a delete, email, database-write, or cloud-mutation tool on every CI run merely to prove that tools/call works.
Step four: use an independent process for each assertion
The official smoke-testing guide recommends one Inspector process per assertion. Each step then has clear stdout, stderr, and an exit code, making it easier to locate whether connect, list, or call failed. This is not a full conformance suite; it is a quick health check suitable for every commit or deployment.
The failure boundaries are straightforward:
- If
initializefails, inspect the target, transport, Node version, and timeout. - If
tools/listfails, check whether the Server declares capabilities correctly and whether the output is actually JSON. - If
tools/callfails, check the tool name, schema, argument types, and Server exception. - If only an App probe fails, inspect the
appInforesponse shape instead of blindly reading.result.
`--config` and `--catalog`: similar names, different ownership
Inspector v2 separates two kinds of Server configuration. --catalog is the Inspector-managed Server list and may be written. If it does not exist, the CLI and TUI seed an empty catalog. --config is a read-only session file; a missing file is an error, and the Inspector does not create or modify it. The two options are mutually exclusive and cannot be combined with an ad hoc target.
The distinction is useful for teams:
- Use
--catalogfor your own local working set. - Use
--configin CI when the repository supplies a fixed session file and the test must not silently modify it. - Use an ad hoc target for a temporary command or URL.
For example:
npx @modelcontextprotocol/inspector --cli \\
--config ./mcp.json --server my-server \\
--method initialize
Target ordering is another common trap. The CLI treats the first run of non-dash tokens as the target, so the target must come before Inspector flags:
# Correct
npx @modelcontextprotocol/inspector --cli node build/index.js --method tools/list
# Easy to run against the wrong source
npx @modelcontextprotocol/inspector --cli --method tools/list node build/index.js
The second form may not fail. node build/index.js can be discarded and the Inspector can fall back to the catalog. A command that succeeds against the wrong Server is more dangerous than an explicit error, so I would include target ordering and source selection in code review checklists.
The `--` separator and timeout: two CI details
When a stdio Server has flags of its own, the boundary between Inspector arguments and target arguments must be explicit. Under the CLI, the -- split differs from Web and TUI: the target command comes first and the remaining Inspector options come after the separator.
For example:
npx @modelcontextprotocol/inspector --cli \\
node build/index.js --config ./server.conf -- --method tools/list
Verify the direction against the documentation for the client you are using. Copying a Web example into the CLI can make --config land on the wrong side of the boundary.
Timeouts matter too. The official documentation says that --connect-timeout defaults to 15000 milliseconds for ad hoc targets and --server-url; setting it to 0 disables the timeout. A CI job should not disable this protection. A black-holed remote host should fail the probe instead of making the runner wait until the job's own hard limit kills it.
OAuth and remote Servers: login success is not the test
Remote MCP connections can involve transport, OAuth discovery, authorization, token storage, and refresh. The CLI documentation says that a Server loaded from a catalog or config can carry headers, connection and request timeouts, OAuth settings, and roots. A temporary --header can override a header for that run without changing the other settings in the file.
Two points deserve emphasis. First, a configuration file should never put secrets directly into a repository. A read-only --config file is protected from Inspector writes, but read-only does not make its contents safe. Second, OAuth success should be an observable test step: verify discovery, authorization, token use, and then MCP initialize and tools/list. Do not stop at seeing a consent screen in a browser.
For non-interactive CI, use a test authorization environment and manage token lifetime explicitly. If authorization is missing, fail quickly. Never write a real user's account details or long-lived token to the log.
MCP App response shapes: do not assume `result` always exists
Inspector v2 has a dedicated probe for MCP Apps. The smoke-testing guide explains that normal JSON envelopes generally contain result and may also contain appInfo and schemaFindings. The --app-info probe is different: it can return only appInfo and no result.
This is a classic integration error. A consumer that always reads .result will reject a valid --app-info response. A consumer that only accepts appInfo can mishandle the NDJSON behavior of tools/list --app-info. Inspect the keys and treat the exit code and JSON fields as separate signals.
The broader lesson is that tool usability includes an output contract that downstream programs can understand. When humans, CI, and Agents all use the same Server, envelope differences belong in both documentation and tests.
Installation and the first verifiable task
The official v2 README requires Node >=22.19.0. If you only consume the published package, use npx. If you develop the Inspector itself, run npm install at the repository root and then npm run build. The v2 repository is not an npm workspace: every clients/* directory has its own package.json and node_modules, while root scripts chain the Web, CLI, TUI, and launcher builds.
I would start in this order.
1. Check the environment
node --version
npx --version
jq --version
If Node is below the official floor, upgrade it first. Do not confuse later ESM, undici, or bundling errors with MCP Server failures. In CI, do not let npx drift to a different version on each day. Pin an exact package version:
npx --yes @modelcontextprotocol/[email protected] --cli node build/index.js --method initialize
--yes avoids a first-run prompt, while the exact version keeps the same commit from testing against a different Inspector later.
2. Run a connect-only probe
npx --yes @modelcontextprotocol/[email protected] \\
--cli node build/index.js --method initialize
If this fails, do not jump to tools/call. Check that the target command starts independently, that a stdio Server does not write non-protocol logs to stdout, that the remote URL matches the transport, and that the connect timeout is reasonable.
3. Turn the result into a CI assertion
npx --yes @modelcontextprotocol/[email protected] \\
--cli node build/index.js --method tools/list --format json \\
| jq -e '.result.tools | length > 0' > /dev/null
This is only an example. A real project should assert the tool names, input schema, or resources that it truly depends on rather than merely checking that the tools array is non-empty.
4. Add a safe tools/call
npx --yes @modelcontextprotocol/[email protected] \\
--cli node build/index.js \\
--method tools/call --tool-name health_check \\
--format json \\
| jq -e '.result' > /dev/null
After these four steps, the Inspector has moved from a debugging screen to an executable Server contract.
What it does not solve
MCP Inspector is useful, but it is not a universal test tool.
First, it cannot prove that business logic is correct. tools/list proves that a capability is declared, and a successful tools/call does not prove that the data satisfies product rules. The Server still needs unit, integration, and domain-level assertions.
Second, it is not a complete security audit tool. Inspector helps inspect headers, OAuth, roots, and tool behavior, but the deployment team still owns permissions, least privilege, secret handling, audit logs, and supply-chain risk. A stdio Server that can execute local commands or read files must not be trusted merely because Inspector connected successfully.
Third, it cannot remove transport and environment differences. Node versions, proxies, DNS, TLS, container networking, OAuth providers, and Server startup output can differ between local and production. Inspector makes failures clearer; it does not create production parity for you.
Fourth, Web success cannot replace CI. A person clicking a button proves only that one operation worked at one moment. Team confidence requires fixed versions, fixed configuration, bounded timeouts, and exit codes that can be evaluated automatically.
How I would add it to a team workflow
For a team starting with MCP, I would build a small verification matrix:
- On every pull request: initialize and tools/list for a local stdio Server.
- On every deployment: initialize, required-tool existence, and one read-only tools/call for the remote HTTP or SSE Server.
- On every OAuth configuration change: discovery, authorization, token use, and the following MCP method.
- On every Inspector or MCP SDK upgrade: rerun the same smoke tests with a pinned version and inspect exit codes and JSON envelopes.
The test scripts should follow three rules:
1. Keep results on stdout and diagnostics on stderr. Do not merge them with 2>&1 before sending the stream to jq.
2. Run each assertion independently so the failure boundary remains clear.
3. Never print API keys, cookies, OAuth tokens, or complete sensitive headers to the log.
The goal is not to add one more tool. It is to turn an MCP Server from "an Agent seems able to use it" into "we know which contract has been verified."
Final assessment: an observable test surface for MCP
The most important part of MCP Inspector is not merely that it has Web, CLI, and TUI. It puts different users of protocol interaction into one coherent toolchain: people explore in Web, developers debug in TUI, CI asserts with CLI, and Agent developers can feed tool results into their own loops.
If your MCP Server is still at the stage where "it connects" counts as success, start with initialize, tools/list, and one read-only tools/call. If you already face OAuth, proxy, MCP App, roots, or configuration drift, write those boundaries as repeatable tests.
Inspector is best for teams that already have an MCP Server, or are about to connect MCP to an AI Agent, and are willing to turn debugging experience into automation. For a one-time manual demo, Web may be enough. Once the Server is continuously deployed and used by more than one person, a CLI smoke test should not be an afterthought.
References