Discover / Development

MCP Inspector

by modelcontextprotocolTypeScript

Developer tool to inspect and test Model Context Protocol servers.

Toolactive

Maturity: active because commit 1d ago, latest release 2.0.0. Derived from release and commit history, not a rating.

Stars
11k
Forks
1.5k
Downloads / mo
Last commit
2026-08-02
License
Open issues
58

Market and trust evidence

Edition not yet matched

No exact skills.sh identity match is available for this repository. Repository adoption and freshness remain visible above; install momentum is not inferred.

Trust analysis is a screening signal, not a security warranty. Read the ranking and trust methodology.

In practice

Written by AI from this repository’s README · high confidence

Provides Web, CLI, and TUI clients to inspect and debug MCP servers effectively.

Use it when

Use to test and validate MCP servers during development.

Not the right pick when

Not a production client for end users.

Capabilities

  • Web single-page app
  • Scriptable CLI
  • Interactive TUI

Requirements

  • Node >= 22.19.0

Cost: Free and open source

Video walkthroughs

Third-party YouTube uploads matched to this tool by title, channel and repository name on 2026-08-03. Not made, reviewed or endorsed by SkillPilot. View counts and publish months are as of the match date and the month is approximate. Nothing loads from YouTube until you press play.

What the repository ships

Ships CLAUDE.mdHas docsDocker imageSecurity policyCI configured

Detected from the actual files in the repository root.

Latest release 2.0.0

Published 2026-07-28

The v2 Inspector is now the default release.


npx @modelcontextprotocol/inspector          # web UI
npx @modelcontextprotocol/inspector --cli    # CLI
npx @modelcontextprotocol/inspector --tui    # TUI

What's new

v2 ships as a single package with three clients — a Vite + React + Mantine web UI, a scriptable CLI, and an Ink-based TUI — over a shared @inspector/core runtime, so all three behave identically.

Upgrading from v1

  • Node >= 22.19.0 is now required (was >= 22.7.5).
  • CLI flags changed substantially. In particular --config now means a read-only session file; --catalog is the writable server list. See MCP server configuration.
  • The v1 sub-packages (inspector-client, inspector-server, inspector-cli) are deprecated and not part of v2 — v2 publishes a single package.

v1

v1 is deprecated and receives security fixes only, published under the v1-latest tag:


npm i @modelcontextprotocol/inspector@v1-latest

Tags

README

MCP Inspector

A developer tool for inspecting Model Context Protocol (MCP) servers. It ships as a single package, @modelcontextprotocol/inspector, that provides three ways to inspect a server:

  • Web — a Vite + React + Mantine single-page app with a Node backend.
  • CLI — a scriptable command-line client for automation, CI, and fast agent feedback loops.
  • TUI — an interactive terminal UI built with Ink.

All three run through one global mcp-inspector binary:


npx @modelcontextprotocol/inspector          # web UI (default)
npx @modelcontextprotocol/inspector --cli    # CLI
npx @modelcontextprotocol/inspector --tui    # TUI

Repo status. This is the v2 line of the Inspector (branch v2/main). The main branch is the legacy v1 implementation (bug fixes only). v2 will eventually replace main. See AGENTS.md for branch/board conventions.

Project layout

v2 is not an npm workspace. Each client under clients/* keeps its own package.json and node_modules; shared code lives in core/ and is consumed via a @inspector/core build-time alias (no package.json of its own). A single npm install at the root cascades installs into every client (see Setup).


inspector/
├── clients/
│   ├── web/          # Web client (Vite + React + Mantine). src/ = browser app; server/ = Node dev/prod backend
│   ├── cli/          # CLI client (tsup bundle, @inspector/core alias)
│   ├── tui/          # TUI client (Ink + React, tsup bundle)
│   └── launcher/     # Shared launcher — provides the `mcp-inspector` bin, dispatches to web/cli/tui
├── core/             # Shared code consumed via the `@inspector/core` alias (no package.json)
│   ├── auth/         # OAuth: providers, discovery, storage, mid-session recovery (browser/node/remote backends)
│   ├── json/         # JSON + parameter/argument conversion utilities
│   ├── logging/      # Silent pino logger singleton
│   ├── mcp/          # InspectorClient runtime, state stores, transports, config import
│   ├── node/         # Node-only shared helpers: version reader, hostUrl (host normalize/canonicalize + all-interfaces/loopback detection)
│   ├── react/        # React hooks over the state stores
│   └── storage/      # File I/O helpers for the OAuth persist backends
├── test-servers/     # Composable MCP test servers + fixtures used by integration tests
├── scripts/          # Root build/verify tooling (install cascade, smokes, verify-build-gate, verify-format-coverage, pack:verify)
├── specification/    # Design/build specifications
├── AGENTS.md         # Contribution rules for agents AND humans (see below)
└── README.md         # You are here

Each client has its own README with client-specific detail:

web · cli · tui · launcher.

Task-oriented guides live under docs/:

  • MCP server configuration — which server(s) the Inspector connects to: --catalog vs. --config, ad-hoc targets, the -- separator, the file format and its Inspector-specific per-server fields. Shared by all three clients; the cli and tui READMEs delegate their server-options sections to it.
  • Reviewing an MCP App — the CLI-first → one-shot-web recipe for automated App-tool review: --app-info probe → deep-link navigate → rendered widget, plus OAuth handoff and proxy support.
  • Launcher and config consolidation — why the launcher runs a client in-process rather than spawning it, and how the shared config processor fits in.

Setup

Requires Node >=22.19.0.


npm install     # root install; postinstall cascades into every client
  • Fresh clone: run npm install at the repo root.
  • After a pull that changes a client's dependencies: re-run npm install at the root to re-sync every client.

The cascade (scripts/install-clients.mjs) is dev-only — it exits early when the package is installed as a dependency, and the published tarball ships only each client's build/, so end users are unaffected. Set INSPECTOR_SKIP_CLIENT_INSTALL=1 to skip it.

Running during development

For day-to-day web iteration, run Vite directly from the web client (fast HMR, no launcher build needed):


cd clients/web && npm run dev

The launcher-driven scripts below run the built launcher, so build first (npm run build):


npm run web        # prod web launcher against clients/web/dist
npm run web:dev    # web launcher in --dev mode (Vite)

The @inspector/core shared package

Shared code architecture: the four clients over the @inspector/core shared package

core/ holds the logic shared by all three clients so that web, CLI, and TUI behave identically. Its entry point is the InspectorClient class (core/mcp/), which owns the connection to an MCP server, the request/response lifecycle, and a set of state stores; core/react/ exposes React hooks over those stores that both the web and TUI (Ink) React trees consume. OAuth (core/auth/) is factored into isomorphic logic plus browser/node/remote backends so the same flows work in the browser, in Node, and against a remote backend.

core/ intentionally has no package.json — it is not published on its own. Each client bundles it in via a @inspector/core alias:

  • CLI / TUI: esbuildOptions.alias in their tsup.config.ts maps @inspector/core → the repo core/ directory, and noExternal: [/^@inspector\/core/] inlines it into the bundle.
  • Web: the same alias in clients/web/vite.config.ts for the browser app and the Node backend runner.

Publishing core/ as its own package (e.g. for third parties to build on) is deliberately deferred — see issue #1636.

Web client: "dumb components" + Storybook

The v2 web client is built from presentational ("dumb") components — they accept data and callbacks as props and contain only display logic, with no direct data fetching or client state. State comes from the @inspector/core hooks, wired in near the top of the tree. This keeps components isolated, testable, and documentable.

That approach is what makes Storybook first-class here: every screen and element component has a *.stories.tsx file (96+ stories) that renders it against fixture props. Storybook play functions double as interaction tests, run headless in CI (npm run ci:storybook, Chromium via Playwright).

Styling follows a strict Mantine-first convention (theme variants and component props over CSS classes, --inspector-* CSS custom properties over raw color literals). The full rules live in AGENTS.md under React instructions — read them before touching web UI. Element components live in clients/web/src/components/elements/; theme variants in clients/web/src/theme/.

Test servers

test-servers/ provides composable MCP servers used by the integration and smoke suites, so tests exercise a real server over a real transport instead of mocks. A server is assembled from presets (fixture factories in test-servers/src/preset-registry.ts — tools, resources, prompts, tasks, elicitation, sampling, OAuth, …) and can be driven two ways:

  • In-process — import the factories (createTestServerHttp, createEchoTool, …) and run the server inside the test's event loop (used by the HTTP integration paths).
  • As a subprocesstest-servers/build/test-server-stdio.js is spawned as a real stdio child (used by the CLI smoke and stdio integration tests).

Configure a server declaratively with a JSON config (see test-servers/configs/*.json) selecting presets, then load it via --config. Because the servers are spawned as real subprocesses, the build output must exist first:


npm run test-servers:build   # (from clients/web) → tsc -p test-servers, emits test-servers/build/

The Vite alias @modelcontextprotocol/inspector-test-server (in clients/web/vite.config.ts) points at test-servers/build/index.js so getTestMcpServerPath() resolves to a real .js path.

Serving the modern protocol era

A streamable-HTTP server can also serve the modern (2026-07-28) protocol era via the SDK's createMcpHandler:

  • Set transport.modern in the JSON config — true for dual-era stateless serving, or { "legacy": "reject" } for modern-only strict.
  • Or pass modern on the ServerConfig for an in-process createTestServerHttp.

This is what lets an Inspector connection negotiating protocolEra: "auto" | "modern" reach the modern leg (populated server/discover, sessionless). See test-servers/configs/modern-http.json.

Showcase configs

Each config below is a ready-made server for exercising one feature by hand. Load one with --config, and unless noted, connect with Protocol Era = Modern.

| Config | Demonstrates | Issue |

| ----------------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------- |

| modern-mrtr-http.json | A single MRTR round-trip | — |

| mrtr-showcase-http.json | Every MRTR preset in one server | — |

| modern-network-http.json | Network tab: Mcp-* headers + error taxonomy | #1628 |

| xmcpheader-modern-http.json | Tools tab: x-mcp-header mirroring and exclusions | #1632 |

| pagination-http.json | Page-by-page list fetching | #1721 |

| advertised-extensions-http.json | Tool registration gated on advertised extensions | #1739 |

| logging-{legacy,modern}-http.json | Logging, both eras | #1629 |

| subscriptions-{legacy,modern}-http.json | Resource subscriptions, both eras | #1630 |

| tasks-{legacy,modern}-http.json | Tasks, both eras | #1631 |

MRTR

modern-mrtr-http.json serves the mrtr_confirm tool (preset mrtr_confirm, createMrtrTool) over the modern leg. Its handler returns inputRequired(...) embedding a form elicitation, so invoking it produces a real round-trip: input_required → the client fulfils the embedded elicitation and retries with a new id → complete.

The Inspector drives MRTR manually (inputRequired: { autoFulfill: false }), so the embedded elicitation pauses at the pending-request modal (tagged "input_required") for you to answer, then the retry completes. Useful for eyeballing both that pending-request UX and the Protocol view's MRTR conversation grouping.

mrtr-showcase-http.json bundles every MRTR preset in one server:

| Preset | Behavior |

| --------------- | ------------------------------------------------------------------------------ |

| mrtr_confirm | Single round |

| mrtr_two_step | Two elicitation rounds via requestState |

| mrtr_sample | Embedded sampling → the Sampling panel |

| mrtr_roots | Embedded roots/list, auto-answered silently from configured roots (no modal) |

| mrtr_edge | An inputRequests-only round, then a requestState-only round |

| mrtr_loop | Never completes → trips the MRTR_MAX_ROUNDS bound |

The legacy collect_elicitation preset calls server.elicitInput, which errors on the 2026-07-28 leg — server→client requests aren't allowed there. MRTR is the modern replacement.

Network tab — standardized headers and error taxonomy

modern-network-http.json covers SEP-2243 / SEP-2575. It serves a get_weather tool whose city argument carries an x-mcp-header: "City" annotation, so a modern client mirrors it to Mcp-Param-City.

It also serves four trigger_* tools that the modern leg's spec-error injector (transport.modern.injectSpecErrors: true) answers with a real HTTP status plus JSON-RPC error body:

| Tool | Response |

| ----------------------------- | ---------------------------------------- |

| trigger_header_mismatch | 400 / -32020 |

| trigger_missing_capability | 400 / -32021 |

| trigger_unsupported_version | 400 / -32022 (with data.supported) |

| trigger_method_not_found | 404 / -32601 |

Open the Network tab to see the mirrored Mcp-* headers highlighted, sentinel values decoded, and each error rendered distinctly.

**Mcp-Param-* mirroring is skipped by the SDK in the browser (detectProbeEnvironment() !== "browser"). So calling get_weather from the

Truncated. Read the full README on GitHub ↗

Related tools