Merge pull request #1830 from modelcontextprotocol/chore/v2-golive

chore: replace main's tree with v2
This commit is contained in:
Cliff Hall 2026-07-27 23:25:08 -04:00 • committed by GitHub
commit 25106dcce4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
1216 changed files with 237687 additions and 45983 deletions

5
.claude/settings.json Normal file
View file

@ -0,0 +1,5 @@
{
"enabledPlugins": {
"playwright@claude-plugins-official": true
}
}

View file

@ -1,35 +1,38 @@
# Version control
# Keep the build context small and force a clean, in-container install/build.
# Host node_modules and build outputs are excluded so nothing stale or
# wrong-architecture is copied in — the builder stage runs its own
# `npm install && npm pack`.
.git
.gitignore
.github
# Node.js
# Installed deps (root + every client) — reinstalled in the image
node_modules
npm-debug.log
clients/*/node_modules
test-servers/node_modules
# Build artifacts
client/dist
client/build
server/dist
server/build
# Environment variables
.env
.env.local
.env.development
.env.test
.env.production
# Editor files
.vscode
.idea
# Logs
logs
*.log
# Testing
# Build outputs — rebuilt in the image
clients/*/build
clients/web/dist
test-servers/build
storybook-static
coverage
# Docker
Dockerfile
.dockerignore
# Docs/specs aren't referenced by the build — trim them from the context.
# (test-servers/ stays: `tsc -b` typechecks the integration tests that import
# the `@modelcontextprotocol/inspector-test-server` alias.)
specification
docs
# Packed tarballs (the image makes its own)
*.tgz
# Local / editor / env
.env
.env.*
.DS_Store
.vscode
.idea
.claude
.playwright-mcp
*.log

View file

1
.gitattributes vendored
View file

@ -1 +0,0 @@
package-lock.json linguist-generated=true

View file

@ -1,40 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ""
labels: ""
assignees: ""
---
**Inspector Version**
- [e.g. 0.16.5)
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
**Additional context**
Add any other context about the problem here.
**Version Consideration**
Inspector V2 is under development to address architectural and UX improvements. During this time, V1 contributions should focus on **bug fixes and MCP spec compliance**. See [CONTRIBUTING.md](../../CONTRIBUTING.md) for more details.

View file

@ -1,6 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View file

@ -1,57 +1,34 @@
## Summary
<!--
⚠️ Before you open this pull request, please read our contribution policy.
<!-- Provide a brief description of what this PR does -->
We accept ISSUES, NOT PULL REQUESTS from external contributors.
> **Note:** Inspector V2 is under development to address architectural and UX improvements. During this time, V1 contributions should focus on **bug fixes and MCP spec compliance**. See [CONTRIBUTING.md](../CONTRIBUTING.md) for more details.
Design and implementation are done by the maintainers through a
prompt-driven workflow (see AGENTS.md). External source PRs will not be
merged — they have to be reverse-engineered to fit our component/theme
conventions and coverage gates, so it's faster for us to re-derive the
change from your intent.
## Type of Change
If you've found a bug or want a feature:
→ Open an issue instead, labeled for the version you're targeting
(`v1` for `v1/main`, `v2` for `main`).
<!-- Mark the relevant option with an "x" -->
If you've already built the change locally:
→ Open an issue and share the PROMPT(S) you used to generate it, not a
diff. We'll reproduce it through our own workflow.
- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Documentation update
- [ ] Refactoring (no functional changes)
- [ ] Test updates
- [ ] Build/CI improvements
Full policy: https://github.com/modelcontextprotocol/inspector/blob/main/CONTRIBUTORS.md
## Changes Made
Maintainers: delete this template body and describe your change normally.
-->
<!-- Describe the changes in detail. Include screenshots/recordings if applicable -->
## Related Issues
<!-- Link to related issues using #issue_number or "Fixes #issue_number" -->
## Testing
<!-- Describe how you tested these changes, where applicable -->
- [ ] Tested in UI mode
- [ ] Tested in CLI mode
- [ ] Tested with STDIO transport
- [ ] Tested with SSE transport
- [ ] Tested with Streamable HTTP transport
- [ ] Added/updated automated tests
- [ ] Manual testing performed
### Test Results and/or Instructions
<!-- Provide steps for reviewers to test your changes -->
Screenshots are encouraged to share your testing results for this change.
## Checklist
- [ ] Code follows the style guidelines (ran `npm run prettier-fix`)
- [ ] Self-review completed
- [ ] Code is commented where necessary
- [ ] Documentation updated (README, comments, etc.)
## Breaking Changes
<!-- If this is a breaking change, describe the impact and migration path -->
## Additional Context
<!-- Add any other context, screenshots, or information about the PR here -->
> **Heads up:** this repository accepts **issues, not pull requests** from
> external contributors. Please read [`CONTRIBUTORS.md`](../blob/main/CONTRIBUTORS.md)
> before continuing. If you're an external contributor, open an issue (and
> share the prompt you used, if you've already built the change) rather than
> this PR.
>
> Want to work on the Inspector with us directly? Come say hello in
> **`#inspector-dev`** on the
> [MCP Contributor Discord](https://discord.gg/6CSzBmMkjX) — we're happy to
> scope work with you.

View file

@ -1,93 +0,0 @@
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
claude:
if: |
(
(github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@claude') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) ||
(github.event_name == 'pull_request_review_comment' &&
contains(github.event.comment.body, '@claude') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) ||
(github.event_name == 'pull_request_review' &&
contains(github.event.review.body, '@claude') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)) ||
(github.event_name == 'issues' &&
(contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.issue.author_association))
)
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
actions: read
steps:
- name: Get PR details
if: |
(github.event_name == 'issue_comment' && github.event.issue.pull_request) ||
github.event_name == 'pull_request_review_comment' ||
github.event_name == 'pull_request_review'
id: pr
uses: actions/github-script@v8
with:
script: |
let prNumber;
if (context.eventName === 'issue_comment') {
prNumber = context.issue.number;
} else {
prNumber = context.payload.pull_request.number;
}
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
core.setOutput('sha', pr.data.head.sha);
core.setOutput('repo', pr.data.head.repo.full_name);
- name: Checkout PR branch
if: steps.pr.outcome == 'success'
uses: actions/checkout@v6
with:
ref: ${{ steps.pr.outputs.sha }}
repository: ${{ steps.pr.outputs.repo }}
fetch-depth: 0
- name: Checkout repository
if: steps.pr.outcome != 'success'
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
# Allow Claude to read CI results on PRs
additional_permissions: |
actions: read
# Trigger when assigned to an issue
assignee_trigger: "claude"
claude_args: |
--mcp-config .mcp.json
--allowedTools "Bash,mcp__mcp-docs"
--append-system-prompt "If posting a comment to GitHub, give a concise summary of the comment at the top and put all the details in a <details> block. When working on MCP-related code or reviewing MCP-related changes, use the mcp-docs MCP server to look up the latest protocol documentation. For schema details, reference https://github.com/modelcontextprotocol/modelcontextprotocol/tree/main/schema which contains versioned schemas in JSON (schema.json) and TypeScript (schema.ts) formats."

View file

@ -1,38 +0,0 @@
name: CLI Tests
on:
push:
paths:
- "cli/**"
pull_request:
paths:
- "cli/**"
jobs:
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./cli
steps:
- uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version-file: package.json
cache: npm
- name: Install dependencies
run: |
cd ..
npm ci --ignore-scripts
- name: Build CLI
run: npm run build
- name: Run tests
run: npm test
env:
NPM_CONFIG_YES: true
CI: true

View file

@ -1,78 +0,0 @@
name: Playwright Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
# Installing Playwright dependencies can take quite awhile, and also depends on GitHub CI load.
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libwoff1
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
id: setup_node
with:
node-version-file: package.json
cache: npm
# Cache Playwright browsers
- name: Cache Playwright browsers
id: cache-playwright
uses: actions/cache@v5
with:
path: ~/.cache/ms-playwright # The default Playwright cache path
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }} # Cache key based on OS and package-lock.json
restore-keys: |
${{ runner.os }}-playwright-
- name: Install dependencies
run: npm ci
- name: Install Playwright dependencies
run: npx playwright install-deps
- name: Install Playwright and browsers unless cached
run: npx playwright install --with-deps
if: steps.cache-playwright.outputs.cache-hit != 'true'
- name: Run Playwright tests
id: playwright-tests
run: npm run test:e2e
- name: Upload Playwright Report and Screenshots
uses: actions/upload-artifact@v7
if: steps.playwright-tests.conclusion != 'skipped'
with:
name: playwright-report
path: |
client/playwright-report/
client/test-results/
client/results.json
retention-days: 2
- name: Publish Playwright Test Summary
uses: daun/playwright-report-summary@v3
if: steps.playwright-tests.conclusion != 'skipped'
with:
create-comment: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
report-file: client/results.json
comment-title: "🎭 Playwright E2E Test Results"
job-summary: true
icon-style: "emojis"
custom-info: |
**Test Environment:** Ubuntu Latest, Node.js ${{ steps.setup_node.outputs.node-version }}
**Browsers:** Chromium, Firefox
📊 [View Detailed HTML Report](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) (download artifacts)
test-command: "npm run test:e2e"

View file

@ -1,9 +1,10 @@
name: Run install, format, lint, build, and test on every push
on:
push:
branches:
- main
pull_request:
# A published GitHub release triggers the `publish` job below. The release's
# target commit determines which workflow runs — so this only publishes when a
# release is cut from a commit that carries this (v2) workflow.
release:
types: [published]
@ -12,63 +13,161 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Checkout code
uses: actions/checkout@v6
- uses: actions/setup-node@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: package.json
cache: npm
node-version: '22.x'
cache: 'npm'
# Working around https://github.com/npm/cli/issues/4828
# - run: npm ci
- run: npm install --no-package-lock
- name: Install dependencies (root + all clients)
# The root postinstall (scripts/install-clients.mjs) cascades
# `npm install` into clients/web, clients/cli, clients/tui, and
# clients/launcher, so this single step sets up every client.
run: npm install
- name: Check formatting
run: npm run prettier-check
- name: Validate (coverage guards, format, lint, typecheck, build, fast tests)
# Runs the two coverage guards first (verify:format-coverage +
# verify:typecheck-coverage), then validate:core, then each client's
# self-validation: format:check + lint + typecheck + build + test (no
# coverage instrumentation — fast). This also builds every client bundle
# (web dist, cli/tui/launcher) that the smokes below need. The heavier
# per-file coverage gate runs in its own step below. Unit tests run in
# both steps (fast here, instrumented under coverage); the double unit
# run is an accepted trade-off for keeping this fast build step intact.
# A future optimization could split coverage into per-client parallel
# jobs, but that's a larger restructure and deliberately out of scope.
run: npm run validate
- name: Check version consistency
run: npm run check-version
- name: Enforce per-file coverage gate (≥90% on all four dimensions)
# CI-ENFORCED coverage gate (#1550): runs `npm run coverage`, which
# chains every client's `test:coverage` (v8-instrumented) and fails the
# job if ANY file drops below 90% on lines, statements, functions, or
# branches. This is the whole point of the step — a PR that regresses
# coverage below the threshold now blocks merge instead of relying on a
# contributor remembering to run the gate locally.
#
# This also covers the web integration project: web's `test:coverage`
# runs `--project=unit --project=integration --coverage`, so the former
# standalone `Run web integration tests` step was removed to avoid
# running the integration suite twice.
run: npm run coverage
- name: Check linting
working-directory: ./client
run: npm run lint
- name: Verify the browser-externalized-builtin build gate (#1769)
# Runs a real `vite build` with a Node built-in forced into the browser
# graph and asserts the build FAILS via the #1769 gate. The unit tests
# cover the detection logic against a captured message; only this real
# build catches the risk the issue calls out — that the Vite warning
# phrasing drifts across releases, silently disabling the message-keyed
# gate. It restores the mutated entry afterward (see the script).
run: npm run verify:build-gate
- name: Run client tests
working-directory: ./client
run: npm test
# Playwright chromium is installed BEFORE the smokes because
# `smoke:web:browser` (the headless-browser boot smoke, #1615) drives the
# prod web bundle in chromium — restoring/installing it here lets that
# smoke reuse the cache instead of downloading its own copy. The Storybook
# step below reuses the same install.
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('clients/web/package-lock.json') }}
- run: npm run build
- name: Install Playwright browsers
working-directory: ./clients/web
run: npx playwright install --with-deps chromium
- name: Run cross-client smokes
# End-to-end smokes through the built launcher (--help dispatch + prod
# CLI/web). Not part of any client's `validate`: it needs the
# cli/tui/launcher bundles, which `validate` above already built
# (smoke:web builds clients/web/dist on demand — #1486). smoke:web:browser
# boots the prod web bundle in headless chromium (#1615). smoke:tui
# self-skips here — the Ink TUI needs a real TTY (raw mode) that headless
# CI lacks, so its boot/render check is local-only.
run: npm run smoke
- name: Run Storybook play-function tests
working-directory: ./clients/web
run: npm run test:storybook
# Publish the single `@modelcontextprotocol/inspector` package to npm on a
# published GitHub release. v2 is not an npm workspace, so there is no
# `publish-all` / `--workspaces` (v1) — just one `npm publish`, whose `prepack`
# (`npm run build`) builds every client bundle into the `files` allowlist.
# `pack:verify` runs first as the pre-publish gate: it builds, packs the real
# tarball, installs it into a clean throwaway consumer, and drives the
# installed `mcp-inspector` bin (web/cli/tui) end to end — so a broken package
# is caught before it reaches npm rather than after.
publish:
runs-on: ubuntu-latest
if: github.event_name == 'release'
environment: release
needs: build
# Serialize publishes so two releases cut in quick succession can't run
# overlapping `npm publish`es. Never cancel an in-flight publish.
concurrency:
group: publish-npm
cancel-in-progress: false
permissions:
contents: read
# Required for npm provenance (`--provenance` mints a signed attestation
# via GitHub's OIDC token). The repo is public, so provenance is available.
id-token: write
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
- name: Checkout code
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: package.json
cache: npm
registry-url: "https://registry.npmjs.org"
node-version: '22.x'
cache: 'npm'
registry-url: 'https://registry.npmjs.org'
# Working around https://github.com/npm/cli/issues/4828
# - run: npm ci
- run: npm install --no-package-lock
# OIDC trusted publishing requires npm >=11.5.1; Node 22's bundled npm is 10.x.
- name: Ensure npm CLI supports OIDC trusted publishing
run: npm install -g npm@^11.5.1
- run: npm run publish-all
- name: Assert release tag matches package version
# `npm publish` ships whatever `version` is in the root package.json,
# regardless of the release's tag. Fail fast (before the heavy install /
# pack:verify) if they disagree — e.g. a release drafted without running
# `npm version`, or cut from the wrong commit — since publishing is
# irreversible. Tolerates the conventional leading `v` (npm version tags
# as `vX.Y.Z`). The tag arrives via `env:` (not spliced into the script)
# to avoid the script-injection surface of interpolating `${{ }}` into a
# `run:` block.
env:
NPM_CONFIG_PROVENANCE: "true"
TAG: ${{ github.event.release.tag_name }}
run: |
PKG="$(node -p "require('./package.json').version")"
if [ "${TAG#v}" != "$PKG" ]; then
echo "Release tag '$TAG' does not match package.json version '$PKG'"
exit 1
fi
- name: Install dependencies (root + all clients)
run: npm install
- name: Verify the publishable tarball end to end
# Builds, `npm pack`s, installs the tarball into a clean consumer, and
# drives the installed bin. Needs registry access to pull the tarball's
# runtime deps — available here. `smoke:tui` inside it self-skips on CI.
run: npm run pack:verify
- name: Publish to npm (single package, with provenance)
# `prepack` (`npm run build`) rebuilds the client bundles into the tarball.
# The build runs three times on this path (build job → pack:verify →
# prepack); the redundancy is intentional — each is a clean-tree rebuild
# and the `prepack` one is what actually populates the published tarball,
# so don't "optimize" it away.
run: npm publish --access public --provenance
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# Build and push the multi-arch container image to GHCR on a published
# release. The image installs the packed tarball (`Dockerfile`) so it ships
# the same artifact as npm. Independent of the npm `publish` job (both gated on
# the release event) — a container failure doesn't block the npm publish.
publish-github-container-registry:
runs-on: ubuntu-latest
if: github.event_name == 'release'
@ -80,7 +179,8 @@ jobs:
attestations: write
id-token: write
steps:
- uses: actions/checkout@v6
- name: Checkout code
uses: actions/checkout@v6
- name: Log in to the Container registry
uses: docker/login-action@v4
@ -94,6 +194,14 @@ jobs:
uses: docker/metadata-action@v6
with:
images: ghcr.io/${{ github.repository }}
# Be explicit rather than relying on `flavor.latest=auto`: on a release
# cut both the version tags and `latest` land, so the README's bare
# `ghcr.io/…/inspector` (implicit `:latest`) never 404s.
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
flavor: |
latest=true
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

46
.gitignore vendored
View file

@ -1,21 +1,27 @@
.DS_Store
.vscode
.idea
node_modules/
*-workspace/
server/build
client/dist
client/tsconfig.app.tsbuildinfo
client/tsconfig.node.tsbuildinfo
cli/build
test-output
tool-test-output
metadata-test-output
# symlinked by `npm run link:sdk`:
sdk
client/playwright-report/
client/results.json
client/test-results/
client/e2e/test-results/
mcp.json
.claude/settings.local.json
.vscode
.DS_Store
.claude/
node_modules
dist
clients/web/dist
clients/**/build
clients/**/coverage
test-servers/build
# TypeScript incremental build cache (written by `tsc -b`); web routes its own
# into node_modules/.tmp via tsBuildInfoFile, but a stray `tsc -b` elsewhere
# drops one next to the tsconfig — never source.
*.tsbuildinfo
.env
/.playwright-mcp/
# Local debugging artifacts dropped at the repo root (e.g. attached to
# Claude Code conversations): screenshots, exported Inspector history dumps,
# and ad-hoc registry/client config fixtures used for manual import testing.
# Should never be part of the source tree.
/*.png
/inspector-history-*.json
/inspector-network-*.json
/*.server.json
/configs/
pr-screenshots

View file

@ -1,2 +0,0 @@
npx lint-staged
git update-index --again

View file

@ -1,8 +0,0 @@
{
"mcpServers": {
"mcp-docs": {
"type": "http",
"url": "https://modelcontextprotocol.io/mcp"
}
}
}

View file

@ -1 +0,0 @@
22.x.x

12
.npmignore Normal file
View file

@ -0,0 +1,12 @@
# npm pack uses .npmignore instead of .gitignore when this file exists.
# Built artifacts are whitelisted via package.json "files".
node_modules
.env
.idea
.vscode
.DS_Store
.claude/
*.log
coverage
storybook-static

2
.npmrc
View file

@ -1,2 +0,0 @@
registry="https://registry.npmjs.org/"
@modelcontextprotocol:registry="https://registry.npmjs.org/"

View file

@ -1,6 +0,0 @@
packages
server/build
CODE_OF_CONDUCT.md
SECURITY.md
mcp.json
.claude/settings.local.json

View file

370
AGENTS.md

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show more