- TypeScript 90.8%
- JavaScript 8.8%
- CSS 0.2%
- HTML 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Two unrelated things, both touching the same security notes.
## Round 6 findings
1. The credential scan ran too late to be a backstop. The analysis was
uploaded as an artifact and only scanned in the posting job — but this
repo is public, so an artifact holding a verbatim credential is
downloadable for its whole retention window. Refusing to POST text
that has already left the job refuses nothing. The scan now gates the
WRITE, in the same step that writes `analysis.md` (not two steps: a
failure between a passing scan and a separate write would leave the
file for the upload to collect), and the upload is gated on
`hashFiles('analysis.md')`. The posting job scans again, since the
artifact is the boundary and each side should check what it handles.
2. The permissions test failed open on the input it existed to catch.
GitHub accepts the shorthand `permissions: write-all`, and
`Object.entries("write-all")` iterates the string's CHARACTERS — so
the scan for a `write` value found nothing and the test passed green
while the model held every scope. It now rejects a non-mapping
outright and asserts the exact value.
3. (Suppressed.) The security prose in AGENTS.md still described the
same-job, environment-variable handoff that two rounds had already
replaced. Rewritten around the two boundaries the write-up actually
crosses now. Worth noting the pattern rather than just the instance:
this was the third round running in which I changed the mechanism and
left the prose describing the previous one, and stale security prose
is worse than none — the next person preserves properties the code no
longer has.
## Closing #2269
Filed during round 3 to replace the long-lived ANTHROPIC_API_KEY with
workload identity federation. Closed as not planned, because the threat
model behind it does not hold.
Every round escalated on "the model reads UNTRUSTED upstream release
notes" and I accepted that framing without checking it. Both upstreams
this sweep watches — modelcontextprotocol/typescript-sdk and
modelcontextprotocol/ext-apps — are in this repository's own org, with
release notes written by the same maintainer group. That is first-party
content, and anyone able to plant an injection in it already holds
release rights here.
Federation was reachable, so this is a judgement rather than a
capitulation: issuers and rules are creatable via
`client.beta.organization.federation.*`, and for GitHub Actions the
issuer is the standard token.actions.githubusercontent.com with JWKS
discovery. But those endpoints reject plain API keys and need an
`org:admin` OAuth token, making it org-admin work on the Anthropic
organization — disproportionate against our own changelogs.
The assessment is recorded rather than deleted. AGENTS.md and the
workflow comment now state the residual channel AND what makes it
acceptable, so pointing this at an upstream outside the org, or at
third-party content, is a documented trigger to re-open the question.
Mutation-checked, each failing a different set:
permissions: write-all on analyze -> no model runs in a job that can write
upload re-gated on structured_output -> the scan-ordering test
62 tests in this file; `npm run local:gate` green end to end.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019JWUZxLDnPgLQzjBrtk1x9
Signed-off-by: cliffhall <cliff@futurescale.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 |
| 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.