Skip to content

docs: add the v1 → v2 migration guide - #1960

Open
cliffhall wants to merge 5 commits into
v2/mainfrom
v2/docs/1822-migration-guide
Open

docs: add the v1 → v2 migration guide#1960
cliffhall wants to merge 5 commits into
v2/mainfrom
v2/docs/1822-migration-guide

Conversation

@cliffhall

Copy link
Copy Markdown
Member

Closes #1822

Adds docs/v1-to-v2-migration.md — the guide the deprecation notice needed somewhere to point at. Docs only; no source changes.

What it covers

  • CLI flag mapping. Every v1 CLI flag still exists in v2 and means the same thing — nothing was renamed or removed. The table says so explicitly (so a reader can stop worrying), then lists what v2 adds: --catalog, --cwd, --tool-args-json, --format, --app-info, --connect-timeout, and the OAuth/handoff flags v1 had no equivalent for.
  • --config vs --catalog, with before/after examples. This is the section the issue called out: both versions have a --config flag, both take an mcpServers file, and they don't mean the same thing. Also notes that a v1 file works unchanged (streamable-http still accepted, unknown fields like the exported note carried through) and that --server now selects only under --cli.
  • Node engine bump >=22.7.5>=22.19.0, and where the floor comes from.
  • What no longer ships — the -client / -server / -cli sub-packages, frozen at 1.0.1 and deprecated; v2 is a single tarball.

Plus the things that will otherwise read as "v2 broke my setup":

  • a tools/call returning isError: true now exits 5, where v1 exited 0 — CI && chains that silently continued past failing calls will start failing
  • under --cli the target must come first, or it is silently dropped in favor of the catalog
  • the -- separator is reversed under --cli relative to web/tui
  • the proxy is gone — one server on 6274, MCP_PROXY_AUTH_TOKENMCP_INSPECTOR_API_TOKEN, MCP_PROXY_FULL_ADDRESS removed, and SERVER_PORT repurposed as the MCP Apps sandbox port fallback
  • the v1 Configuration panel's settings are now per-server catalog fields (requestTimeout / connectionTimeout); MCP_REQUEST_MAX_TOTAL_TIMEOUT has no equivalent
  • web query params narrowed and gated: serverCommand / serverArgs are gone, autoConnect must match the session token
  • Docker: one port, and the wildcard-bind opt-in the image now sets

Linked from

  • root README — an "Upgrading from v1?" banner above the repo-status note, plus an entry in the docs/ guide list
  • clients/cli/README.md — a pointer for people arriving from the v1 CLI
  • docs/mcp-server-configuration.md — Related section
  • AGENTS.md — the docs/ tree entry

Remaining from the issue's checklist

The last task ("link it from the deprecation notice, the 2.0.0 release notes, and the docs site") is partly outside this branch and needs the file to exist on main first:

Happy to open the v1/main follow-up once this merges and the guide has a stable URL.

Verification

Docs-only, so no code gate applies (markdown is not in the format:check globs and verify-format-coverage's extension set is TS/JS only). Ran prettier --write over the touched files, and verified every relative link and cross-doc anchor in the new guide resolves.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SW1p8E2uiyyLx4RKwrwSrt

Closes #1822

Adds docs/v1-to-v2-migration.md — the map for users arriving from v1:

- CLI flag mapping (every v1 flag survives; lists what v2 adds)
- `--config` vs `--catalog` semantics with before/after examples
- Node engine bump (>=22.7.5 → >=22.19.0)
- what no longer ships (the three sub-packages; v2 is one tarball)
- the three behavior changes most likely to bite: exit code 5 on a
  failing tool call, target-must-come-first under --cli, and the
  reversed `--` separator
- env-var mapping (MCP_PROXY_AUTH_TOKEN → MCP_INSPECTOR_API_TOKEN,
  MCP_PROXY_FULL_ADDRESS removed, SERVER_PORT repurposed), the v1 UI
  config settings, web query params, and Docker

Linked from the root README (banner + docs list), the CLI README, and
docs/mcp-server-configuration.md; AGENTS.md's docs/ tree entry updated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SW1p8E2uiyyLx4RKwrwSrt
@cliffhall cliffhall added the v2 Issues and PRs for v2 label Aug 10, 2026
@cliffhall cliffhall linked an issue Aug 11, 2026 that may be closed by this pull request
5 tasks
@cliffhall
cliffhall requested a balanced review from Copilot August 11, 2026 00:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a v1-to-v2 migration guide and links it from relevant documentation.

Changes:

  • Documents CLI, configuration, environment, architecture, and Docker migration.
  • Adds migration-guide links across entry-point docs.
  • Updates project documentation listings.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
docs/v1-to-v2-migration.md Adds the migration guide.
README.md Promotes and lists the guide.
clients/cli/README.md Links v1 CLI users to it.
docs/mcp-server-configuration.md Adds a related-guide link.
AGENTS.md Adds the guide to the project tree.
Suppressed comments (1)

docs/v1-to-v2-migration.md:297

  • This one-port Docker recipe cannot support MCP Apps: the sandbox listener is dynamic inside the container and is not reachable through the sole 6274 mapping. Pin and publish MCP_SANDBOX_PORT in the migration example, or explicitly label the recipe as excluding the Apps tab.
# v2 — one port; the image already sets the wildcard-bind opt-in
docker run --rm -p 6274:6274 ghcr.io/modelcontextprotocol/inspector:latest

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/v1-to-v2-migration.md Outdated
Comment thread docs/v1-to-v2-migration.md Outdated
Comment thread docs/v1-to-v2-migration.md Outdated
Comment thread docs/v1-to-v2-migration.md Outdated
Comment thread docs/v1-to-v2-migration.md Outdated
- Sandbox port: the Apps tab needs a second, dynamic listener, so
  "no second port" was wrong for Docker/remote deployments. Qualify the
  architecture section, add a pinned-port Docker recipe, and add a
  troubleshooting entry.
- Node floor: npm only warns EBADENGINE unless engine-strict is set, so
  npx does not refuse to run on an older Node.
- v1 default list: the web UI persisted its list in localStorage; only
  the on-disk default catalog is new.
- The v1→v2 --server example needs --cli (and a --method) to select an
  entry; note there is no one-entry web equivalent.
- New behavior change #4: an ambiguous URL path (neither /mcp nor /sse)
  now errors instead of falling back to SSE.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFXDQBEjvjCEBhmYkmw79a

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Suppressed comments (2)

docs/v1-to-v2-migration.md:237

  • The CLI can pass leading-dash arguments to a stdio server: when -- is present, clients/cli/src/cli.ts:536-541 treats every token before it as targetArgs, including flags. This statement incorrectly sends users to a catalog; show the reversed placement instead.
So the web example above, run under `--cli`, would have `--config /etc/myserver.conf` consumed as the Inspector's read-only-session flag (and then rejected as a catalog/ad-hoc conflict). There is currently no way to pass a leading-dash argument through to a stdio server on the `--cli` command line — put it in the server entry's `args` in a catalog or config file instead.

docs/v1-to-v2-migration.md:257

  • The output is not byte-for-byte identical: v1 wrote JSON.stringify(result, null, 2) without a terminator, while v2's emitResult appends "\n". Scripts comparing raw stdout should be told about the added trailing newline rather than calling it exact.
Stdout is otherwise compatible: the default `text` format still pretty-prints the result as `JSON.stringify(result, null, 2)`, exactly as v1 did.

- `--` under --cli: everything before the separator IS forwarded to the
  target, flags included (cli.ts:536-541), so "no way to pass a
  leading-dash argument" was wrong. Show the correct placement instead
  of sending users to a catalog file.
- Stdout: v2's emitResult appends "\n" where v1's awaitableLog wrote the
  JSON with no terminator, so the output is not byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFXDQBEjvjCEBhmYkmw79a
@cliffhall

Copy link
Copy Markdown
Member Author

Round 2: no new inline comments, but both suppressed comments were correct and are now fixed in 908284d0.

  • -- under --cli (line 237) — verified against clients/cli/src/cli.ts:536-541: when a -- is present, targetArgs is scriptArgs.slice(0, dashDashIndex) verbatim, leading-dash tokens included. So the claim that there is "no way to pass a leading-dash argument through to a stdio server" was wrong, and sending readers to a catalog file was bad advice. Replaced with the correct placement — target and its flags before the --, Inspector options after — shown as a v1/v2 pair, plus a note that the -- is required whenever the server itself takes flags (without one the target is only the leading run of non-dash tokens).

  • Trailing newline (line 257) — verified: v2's emitResult writes JSON.stringify(result, null, 2) + "\n" (clients/cli/src/handlers/emit-result.ts:36), while v1 passed the string to awaitableLog with no terminator and its awaitableLog was a bare process.stdout.write (v1/main:cli/src/utils/awaitable-log.ts) — so v1 genuinely emitted no trailing newline. "Exactly as v1 did" overstated it; now calls out the one-byte difference and what it means for a script diffing raw stdout against a stored v1 fixture.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Suppressed comments (2)

docs/v1-to-v2-migration.md:131

  • This blanket rule has a documented web exception: run-web.ts excludes --transport stdio from its ad-hoc check, so web accepts and ignores it alongside --catalog/--config; only CLI/TUI reject every --transport. Qualify the rule so migrated web commands are not described as errors.
**Rules:** `--catalog` and `--config` are mutually exclusive, and neither combines with an ad-hoc target (a positional command, `--server-url`, or `--transport`). v1 silently preferred the config file; v2 tells you.

docs/v1-to-v2-migration.md:237

  • This newly documented CLI behavior contradicts the page linked throughout this PR: docs/mcp-server-configuration.md:102 says there is currently no way to pass a leading-dash argument through and recommends putting it in the file. The parser does place every pre--- token in targetArgs, so this guide is correct; update that existing section and example in the same PR so users do not receive opposite instructions.
So the web example above, run verbatim under `--cli`, would have `--config /etc/myserver.conf` consumed as the Inspector's read-only-session flag (and then rejected as a catalog/ad-hoc conflict). To pass a leading-dash argument through to a stdio server, put it **before** the `--` instead — everything on that side is forwarded to the target untouched, flags included:

- The "nothing combines with an ad-hoc target" rule has a web exception:
  run-web.ts:130 exempts `--transport stdio`, so web ignores it rather
  than rejecting. Only cli/tui reject every `--transport`.
- mcp-server-configuration.md still said a leading-dash argument cannot
  reach a stdio server under --cli, the opposite of what the migration
  guide now says. The parser puts every pre-`--` token in targetArgs, so
  the guide is right; corrected the older section to match.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFXDQBEjvjCEBhmYkmw79a
@cliffhall

Copy link
Copy Markdown
Member Author

Round 3: no new inline comments; both suppressed comments were correct and are fixed in 8c9cf402.

  • Ad-hoc rule vs. --transport stdio (line 131) — verified at clients/web/server/run-web.ts:130, where the ad-hoc predicate is (!!opts.transport && opts.transport !== "stdio"). So web exempts stdio and ignores it alongside --catalog/--config, while cli/tui reject every --transport. The blanket rule now carries that exception (mcp-server-configuration.md already documented it in the flags table — this closes the gap in the new guide).

  • Contradiction with mcp-server-configuration.md:102 — good catch, and the direction of the fix was the right call: the parser does place every pre--- token in targetArgs (cli.ts:540), which becomes target verbatim (cli.ts:843) and is split into command + args at core/mcp/node/config.ts:181-182. So the new guide is correct and the older section was wrong. Updated that section in this PR — it now shows the same corrected placement plus the note that the -- is required whenever the server itself takes flags, instead of sending users to a catalog file.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

docs/v1-to-v2-migration.md:336

  • The MCP Apps example likewise publishes both the authenticated backend and sandbox port on all host interfaces. Keep both mappings loopback-only so following the migration guide does not expose the Inspector to the local network by default.
  docker run --rm -p 6274:6274 -p 6280:6280 -e MCP_SANDBOX_PORT=6280 \
    ghcr.io/modelcontextprotocol/inspector:latest

docs/v1-to-v2-migration.md:273

  • The environment variable is not removed in v2: web-server-config.ts still falls back to MCP_PROXY_AUTH_TOKEN when MCP_INSPECTOR_API_TOKEN is unset, and this compatibility path has a dedicated test. Distinguish this deprecated fallback from the query parameter below, which really was replaced, so existing deployments know they continue to work while migrating.
| `MCP_PROXY_AUTH_TOKEN`   | **`MCP_INSPECTOR_API_TOKEN`**                                                 | Renamed. Guards `/api/*` via `x-mcp-remote-auth: Bearer <token>`; the browser also receives it injected into `index.html`, so a bare reload keeps working                              |

Comment thread docs/v1-to-v2-migration.md Outdated
…llback

- The v1 recipe published on 127.0.0.1 and the v2 one silently dropped
  that. Docker's -p binds host interfaces independently of the
  container's HOST, and a no-Origin request skips the allow-list
  (core/mcp/remote/node/server.ts:241), so the token is the only guard on
  a process-spawning backend. Restore the loopback prefix on both
  recipes and say why.
- MCP_PROXY_AUTH_TOKEN is not removed: web-server-config.ts:329 still
  falls back to it. Call it a deprecated fallback rather than a rename,
  and distinguish it from the query param, which has no fallback
  (App.tsx getAuthToken reads only the new name).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFXDQBEjvjCEBhmYkmw79a
@cliffhall

Copy link
Copy Markdown
Member Author

Round 4: one inline comment (answered on the thread) plus two suppressed ones — all three were correct, fixed in 4fe02bca.

  • Legacy auth-token env (line 273) — verified: clients/web/server/web-server-config.ts:329 still falls back to MCP_PROXY_AUTH_TOKEN when the new name is unset, with a dedicated test at web-server-config.test.ts:158. "Renamed" alone implied a hard break. The row now says the old name still works as a deprecated fallback, so an existing deployment keeps running through the migration — and explicitly distinguishes that from the ?MCP_PROXY_AUTH_TOKEN= query param, which really was replaced with no fallback (App.tsx getAuthToken() reads only API_SERVER_ENV_VARS.AUTH_TOKEN from the URL).

  • MCP Apps Docker example (line 336) — same loopback fix as the main recipe; both now use -p 127.0.0.1:….

One thing deliberately not changed here: the root README.md's Docker section also shows an unqualified -p 6274:6274. Same argument applies to it, but changing the project's recommended run command is a user-visible recommendation change rather than part of "add a migration guide", so I'd rather do it under its own issue than fold it into this PR. Filing that separately.

@cliffhall

Copy link
Copy Markdown
Member Author

Follow-up for the README's Docker recipe filed as #1964 (v2, v2.2.0, board #28 → Incoming / Medium).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@cliffhall

Copy link
Copy Markdown
Member Author

Round 1 — response to the five inline comments (20527dc1)

Posting this at PR level because all five threads went outdated the moment the fixes landed (the commits rewrote the exact lines the comments were anchored to), so GitHub hides the replies by default. Repeating them here so they're actually readable. All five findings were correct.

1. "No second port to expose" is wrong — the MCP Apps sandbox is a second listener (thread)
Confirmed; clients/web/README.md says so explicitly. Reworded the claim to be about the proxy port specifically ("nothing needs 6277 exposed"), and added a ⚠️ callout: the sandbox is a separate, dynamic listener the browser reaches directly, so Docker/remote/SSH deployments must pin MCP_SANDBOX_PORT and forward it. The Docker section gained a two-port recipe, plus a new troubleshooting entry ("The Apps tab is blank in Docker / over SSH").

2. npx does not refuse to run on an old Node (thread)
Correct — engines is advisory unless engine-strict=true; npm emits EBADENGINE and continues. Replaced "npx will refuse to run" with the accurate version: npm only warns, so an old Node fails later and obscurely — check node -v first.

3. "v1 started empty every time" contradicts the localStorage statement (thread)
Sloppy shorthand on my part — it meant "no default on-disk file", but reads as contradicting the localStorage line two sections up. Now: "v1 had no default file: the CLI started with nothing unless you passed --config, and the web UI's list lived in the browser's localStorage — per-browser, and invisible to the CLI."

4. The --server example isn't equivalent without --cli (thread)
The v2 line now reads --cli --config ./mcp.json --server everything --method tools/list, and the caveat below it explains why the mode flag appeared, that the web client warns and loads every entry, and that there is no one-entry web equivalent — you pick from the list after it loads.

5. [target...] isn't fully the same — ambiguous URL paths now throw (thread)
Confirmed against buildConfigFromOptions (core/mcp/node/config.ts:194-210): /mcp → streamable-http, /sse → sse, anything else throws Transport type not specified and could not be determined from URL. Added as behavior change #4 (the section intro now says four, not three) with the mapping table, the exact error text, the note that the match is an exact suffix so …/mcp/ is ambiguous too, and the scope — it applies to the CLI, TUI, and --web command lines alike (web catches it and exits 1), while the browser deep link is the one exception, defaulting to http (clients/web/src/utils/deepLink.ts:157-159). The [target...] row now points at both rules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Issues and PRs for v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

go-live 9/9: write the v1 to v2 migration guide

2 participants