Carved out from the "did not solve" list of #1452 (port of CLI/TUI/launcher to v2).
Problem
When the web client is launched via the launcher with --config <path> (or an ad-hoc server target), runWeb (clients/web/server/run-web.ts) resolved a single server config and passed it to the backend as the legacy initialMcpConfig — the one-shot initial connection. It did not point the web backend at the config file as a persistent catalog source: there was no mcpConfigPath plumbed into the backend, and the web UI kept using its default catalog.
So mcp-inspector --web --config foo.json did not make the web UI load or switch to the catalog in foo.json; it only seeded one connection (and that seed was inert — the v2 UI never read it).
Resolution (implemented in #1496)
Implemented the catalog vs. read-only session model from specification/v2_catalog_launch_config.md, which deliberately splits the writable catalog flag from the read-only session flag so a foreign config passed at launch (e.g. claude_desktop_config.json) is never silently rewritten.
Precedence decision: --config does not merge with or replace the contents of the default catalog. Instead the launcher selects the active source the backend serves, and a session-wide writable flag:
| Launch |
Server-list source |
writable |
UI |
mcp-inspector --web |
default catalog ~/.mcp-inspector/mcp.json |
true |
full CRUD |
--catalog <path> (or MCP_CATALOG_PATH) |
that file as the active writable catalog (seed-if-missing / CRUD / file-watch) |
true |
full CRUD |
--config <path> |
that file as a read-only session — served but never written, seeded, or plaintext-secret-migrated |
false |
shown; CRUD hidden; read-only banner |
ad-hoc --server-url/command (+ --header) |
one server held in memory (no file written) |
false |
shown; connects with headers; CRUD hidden |
--catalog/--config are mutually exclusive; neither combines with an ad-hoc target or --header; --header requires an ad-hoc HTTP/SSE server. Every illegal combination exits with a clear error (this also closes the #1483 --header warn-only no-op).
How it works:
mcpConfigPath (writable catalog / read-only session file) and initialServers (in-memory ad-hoc list) are threaded runWeb → web-server-config.ts → both createRemoteApp call sites, with a writable flag.
- The backend (
core/mcp/remote/node/server.ts) serves the chosen source from GET /api/servers, rejects all mutations with 403 when read-only, skips seed + plaintext-secret migration on read-only reads, and exposes writable on GET /api/config. The existing mcp.json file watcher is reused (a read-only --config file still broadcasts external edits; in-memory ad-hoc lists are not watched).
- The web UI reads
writable via the new useServerListWritable hook and hides add/edit/clone/remove/reorder/settings, showing a read-only banner.
Acceptance criteria
Out of scope (separate issues)
--server selection / defaultServerId + auto-connect (#1183), catalog import (#1348/#1435), and the CLI/TUI resolveServerList + writable unification (#1482/#1432).
Carved out from the "did not solve" list of #1452 (port of CLI/TUI/launcher to v2).
Problem
When the web client is launched via the launcher with
--config <path>(or an ad-hoc server target),runWeb(clients/web/server/run-web.ts) resolved a single server config and passed it to the backend as the legacyinitialMcpConfig— the one-shot initial connection. It did not point the web backend at the config file as a persistent catalog source: there was nomcpConfigPathplumbed into the backend, and the web UI kept using its default catalog.So
mcp-inspector --web --config foo.jsondid not make the web UI load or switch to the catalog infoo.json; it only seeded one connection (and that seed was inert — the v2 UI never read it).Resolution (implemented in #1496)
Implemented the catalog vs. read-only session model from
specification/v2_catalog_launch_config.md, which deliberately splits the writable catalog flag from the read-only session flag so a foreign config passed at launch (e.g.claude_desktop_config.json) is never silently rewritten.Precedence decision:
--configdoes not merge with or replace the contents of the default catalog. Instead the launcher selects the active source the backend serves, and a session-widewritableflag:writablemcp-inspector --web~/.mcp-inspector/mcp.json--catalog <path>(orMCP_CATALOG_PATH)--config <path>--server-url/command (+--header)--catalog/--configare mutually exclusive; neither combines with an ad-hoc target or--header;--headerrequires an ad-hoc HTTP/SSE server. Every illegal combination exits with a clear error (this also closes the #1483--headerwarn-only no-op).How it works:
mcpConfigPath(writable catalog / read-only session file) andinitialServers(in-memory ad-hoc list) are threadedrunWeb→web-server-config.ts→ bothcreateRemoteAppcall sites, with awritableflag.core/mcp/remote/node/server.ts) serves the chosen source fromGET /api/servers, rejects all mutations with 403 when read-only, skips seed + plaintext-secret migration on read-only reads, and exposeswritableonGET /api/config. The existing mcp.json file watcher is reused (a read-only--configfile still broadcasts external edits; in-memory ad-hoc lists are not watched).writablevia the newuseServerListWritablehook and hides add/edit/clone/remove/reorder/settings, showing a read-only banner.Acceptance criteria
mcp-inspector --web --config <path>makes the web UI's server list reflect the catalog in<path>(read-only;--catalog <path>for a writable catalog).mcpConfigPath) / in-memory list (initialServers) rather than onlyinitialMcpConfig./api/configwritable;useServerListWritable; UI gating).Out of scope (separate issues)
--serverselection /defaultServerId+ auto-connect (#1183), catalog import (#1348/#1435), and the CLI/TUIresolveServerList+ writable unification (#1482/#1432).