- TypeScript 90.8%
- JavaScript 8.8%
- CSS 0.2%
- HTML 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
* chore: land the #2247 round-9 review findings on v2/main Copilot filed a ninth review round on #2247 after it had merged, so none of it reached v2/main. All five findings are addressed here. 1. The testing -> test-servers hand-off delivered the wrong half of the procedure. test-servers documented only the two-process manual path (server-composable.js --config <name>.json plus a second Inspector process), but an integration test builds the server in-process from the @modelcontextprotocol/inspector-test-server API and owns its lifecycle. Adds a "Two ways to use a fixture — pick the right one first" section with the in-process recipe, the four mechanics that bite (one barrel, start/stop in afterEach, read started.url, era is a constructor option), and a pointer to the reference test; renames "Run one" to "Run one by hand (two processes)" so the manual path names itself. testing now says in the connecting bullet that an automated test does NOT spawn. 2. testing's heading asked "does the test need a real server?", which its own hand-rolled-server exception contradicts. It now asks whether the test uses a test-servers/ fixture. 3. "imports" was too broad a dependency test — test-server-scope.test.ts imports the package to unit-test scope middleware as a pure function and never starts a server. The condition is now "starts, spawns, or configures", with that test named as the counterexample. 4. docs/skill-authoring.md attributed the 33% -> 100% rise to imperative wording and placement independently. The #2247 edit changed both at once, so only the combination is established; the split into two levers is now labelled the plausible mechanism, not a measured result. 5. The CHAIN_THRESHOLD comment generalised "a well-shaped pointer clears 0.8" from one two-case run of that same multi-variable edit. It now reads as an existence proof about the ceiling, not a property of pointers in general. Also records the headline lesson where it can be found again: a green hand-off number proves skill B loaded, never that B answered the question — in AGENTS.md's chain-case rules and in the skill-authoring checklist. Docs, skill bodies and one comment only; no runtime code changes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018zwYWanPhvgu6wiKoeGg4N Signed-off-by: cliffhall <cliff@futurescale.com> * fix: address Copilot review round 1 on #2264 The new section claimed two shapes and there are three — the automated stdio path was missing, and it is the repo's established pattern (getTestMcpServerCommand() into a stdio transport, used by five web integration files and the whole CLI suite). Telling callers an automated test "does not spawn" told them not to use it. - test-servers: "Two ways" -> "Three ways", with a table and a subsection for the spawned-stdio shape — the transport owns the child (disconnect, not stop()), no config can be selected because that entry point runs the stdio default, and it is still the build. Names a reference test for it. - test-servers: the build is no longer scoped to the manual path. All three shapes resolve test-servers/build/ — two through the barrel alias, one by running the emitted .js — so the staleness hazard is called out as applying to every shape, and `Build first` no longer opens by claiming the only reason is subprocess spawning. - testing: the "does not spawn" instruction is replaced by the two automated shapes and when to pick each. What they share, and what the hand-off actually needed to say, is that neither picks a showcase config. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018zwYWanPhvgu6wiKoeGg4N Signed-off-by: cliffhall <cliff@futurescale.com> * fix: address Copilot review round 2 on #2264 Round 1 fixed the missing stdio shape but kept the wrong axis. Cutting the taxonomy by "automated vs by hand" excluded the config-driven smokes — smoke-web-elicitation.mjs spawns server-composable.js --config directly, and lib/mcp-app-flow.mjs does it for smoke:web:app, smoke:web:tabs and pack:verify. Those are automated AND need every bit of the config and protocol-era guidance a person at two terminals does, so the skill was routing their authors away from it. - test-servers: the cut is now how the SERVER IS STOOD UP, stated as such. Third shape is "spawned composable HTTP", whose consumers are the smokes, pack:verify, and a person by hand — the config/era guidance belongs to the shape, whoever starts it. Table gains a Consumers column and loses the Who column that caused this. - test-servers: the stale "an automated test builds the server in-process instead" line under `Run one by hand` is gone (suppressed comment); that heading is now the same shape driven by a person. - testing: routes by what is driving — integration/CLI test to in-process HTTP, stdio-is-the-point to spawned stdio, and a smoke to the composable-config path with the era guidance it actually needs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018zwYWanPhvgu6wiKoeGg4N Signed-off-by: cliffhall <cliff@futurescale.com> * fix: address Copilot review round 3 on #2264 Round 2 replaced one wrong axis with a narrower one: it routed "a smoke" wholesale to the config-driven composable path, and smoke:cli does not use it. smoke-cli.mjs starts an in-process createTestServerHttp for the header round-trip (so it can read back what the CLI sent) and writes the built stdio entry into a --catalog for the connect checks; smoke:tui uses only the latter. Neither picks a config. - test-servers: consumers filled in per row — in-process HTTP gains CLI tests and smoke:cli, spawned stdio gains smoke:cli and smoke:tui, and the composable row is narrowed to the WEB smokes. A warning states the point directly: "a smoke" is not a shape, pick by the row. - test-servers: the stdio shape now covers naming the built entry in a catalog without connecting, which is what those two smokes do. - testing: same narrowing, plus the reason spelled out so the word "smoke" stops being a routing key. - testing: the dependency criterion said "starts, spawns, or configures", which excluded the build-only smoke:tui case documented directly above it — the skill both required and rejected the hand-off for it (suppressed comment). It now reads "starts, spawns, configures, or hands a built entry to the subject under test". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018zwYWanPhvgu6wiKoeGg4N Signed-off-by: cliffhall <cliff@futurescale.com> --------- Signed-off-by: cliffhall <cliff@futurescale.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
| .claude | ||
| .github | ||
| clients | ||
| core | ||
| docs | ||
| scripts | ||
| specification | ||
| test-servers | ||
| .dockerignore | ||
| .gitattributes | ||
| .gitignore | ||
| .mcp.json | ||
| .npmignore | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| CODE_OF_CONDUCT.md | ||
| CONTRIBUTING.md | ||
| Dockerfile | ||
| eslint.config.js | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| SECURITY.md | ||
| tsconfig.base.json | ||
| tsconfig.lint.json | ||
| vitest.shared.mts | ||
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
Upgrading from v1? Read the v1 → v2 migration guide — CLI flags, the new
--configvs.--catalogsplit, the Node engine bump, and what no longer ships.
Repo status. This is the v2 line of the Inspector. Active development happens on
v2/main(the develop branch — all v2 PRs target it), which is merged intomainat milestone releases;mainis the default branch and holds the latest released v2, published to the npmlatesttag. The legacy v1 line lives onv1/main— security fixes only, published straight from that branch to the npmv1-latesttag (npx @modelcontextprotocol/inspector@v1-latest). SeeAGENTS.mdfor branch/board conventions.
Quick start (development)
Requires Node >=22.19.0.
npm install # at the repo root; postinstall cascades into every client
npm run build # web → cli → tui → launcher
For day-to-day web iteration, run Vite directly — fast HMR, no launcher build needed:
cd clients/web && npm run dev
The launcher-driven scripts run the built launcher, so build first:
npm run web # prod web launcher against clients/web/dist
npm run web:dev # web launcher in --dev mode (Vite)
v2 is not an npm workspace — each client under clients/* keeps its own package.json and node_modules, and shared code lives in core/, consumed via a @inspector/core build-time alias. Every runtime dependency core/ imports is declared once, in the repo-root package.json, and each client declares only what that client alone consumes — its UI stack, its bundler-inlined packages, its dev tooling — which leaves clients/cli and clients/launcher with no runtime dependencies of their own. What that means for adding a dependency (root vs. client, dependencies vs. devDependencies, and the bundler external lists) is in the local-dev skill.
Project layout
inspector/
├── clients/
│ ├── web/ Web client (Vite + React + Mantine). src/ = browser app; server/ = Node 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)
├── test-servers/ Composable MCP test servers + fixtures used by integration and smoke tests
├── scripts/ Root build/verify tooling (install cascade, smokes, the verify:* guards)
│ and repo automation run from CI (the dependency, Dependabot-alert and SDK sweeps)
├── docs/ Task-oriented guides — see below
├── specification/ Design/build specifications
├── .claude/skills/ Agent skills: the repo's procedures, invokable by name
├── AGENTS.md Contribution rules for agents AND humans
└── README.md You are here
Each client has its own README with client-specific detail: web · cli · tui · launcher.
Documentation
| Guide | Covers |
|---|---|
| Architecture | The @inspector/core shared package, and the web client's "dumb components" + Storybook approach |
| Testing and the quality gate | What each validate / coverage / smoke / verify:* script covers, the GitHub-CI-vs-local-gate split, and the supported browsers |
| Writing a skill | How to write a skill description that actually fires, and eval cases that measure it — the case shapes that work, and the tuning loop |
| Test servers | The composable test servers and the showcase config for every feature — what to run, what to click, and what the broken build did |
| Publishing | What ships in the tarball, the packaging invariants, and pack:verify |
| Docker | Running the container image — ports, volumes, and where secrets go |
| Migrating from v1 to v2 | CLI flag mapping, --config vs. --catalog, the Node engine bump, env-var renames |
| MCP server configuration | Which server(s) the Inspector connects to, and the config file format |
| Reviewing an MCP App | The CLI-first → one-shot-web recipe for automated App-tool review |
| Smoke-testing an MCP server | The connect → list → call → assert workflow for a shell or CI job: --format json + jq, the exit-code map, and keeping OAuth non-interactive |
| Launcher and config consolidation | Why the launcher runs a client in-process rather than spawning it |
Testing and the quality gate
Each client self-validates from its own folder; the root scripts chain them. There is no aggregate root test script.
npm run validate # fast inner loop: format:check + lint + typecheck + build + unit tests
npm run coverage # the per-file ≥90% gate (lines/statements/functions/branches)
npm run local:gate # MANDATORY before pushing — a strict superset of GitHub CI
npm run local:gate chains every check below, plus the smokes and the Storybook tests. Testing and the quality gate owns the stage list and says what each one covers and why two are local-only; AGENTS.md holds the testing rules themselves.
Contributing — AGENTS.md, CLAUDE.md, and the skills
AGENTS.md is the contract for changing this codebase, and it applies to humans and AI agents alike. It is not agent-only boilerplate — it holds the project's real rules: the version/label conventions, the TypeScript and Mantine/React standards, the testing and coverage requirements, and the mandatory pre-push gate. Read it before making changes, and keep it up to date when you change structure, tooling, or rules.
The repo's procedures — multi-step recipes with commands and live IDs — live in .claude/skills/ instead, one directory per procedure, so they are loaded only when the task calls for them. They are ordinary committed Markdown: an agent that doesn't understand skills can read them, and AGENTS.md carries an index of what exists. Claude Code users invoke one by name (/release, /issue-triage, …).
CLAUDE.md is the entry point Claude Code loads automatically; it includes AGENTS.md, so agents and humans work from the same source of truth. If you use a different agent that reads AGENTS.md, you get the same rules.
A key rule worth surfacing here: all work is issue-driven. Before starting, find or create a tracking issue on the v2 project board; open PRs against v2/main with Closes #<issue>. External contributions are accepted as issues, not pull requests — see CONTRIBUTING.md.
License
MIT.