* Extensions: Connection Info both eras + io.modelcontextprotocol/ui advertisement (Phase 3 of #1633)
Completes the Extensions surfacing and advertises the MCP Apps UI extension.
core/mcp/extensions.ts:
- Add UI_EXTENSION_KEY ("io.modelcontextprotocol/ui") and MCP_APP_MIME_TYPE
("text/html;profile=mcp-app") — mirrors of ext-apps' EXTENSION_ID /
RESOURCE_MIME_TYPE (hardcoded: the constants live on the package's /server
subpath or an extensionless re-export that doesn't resolve under NodeNext).
- Registry entries gain an optional `advertisement` value; the builder stamps
it (default {}). Add the `ui` entry, default-advertised with
`{ mimeTypes: ["text/html;profile=mcp-app"] }` — the Inspector always renders
App tools. No ext-apps cast needed: the extensions value type is `object`.
ConnectionInfoContent:
- Source server extensions from the negotiated `capabilities.extensions`
(getServerCapabilities, era-transparent) instead of the modern-only
discoverResult, so a LEGACY server advertising extensions renders them too.
- Add a two-column "Server Extensions" / "Advertised Extensions" section (the
Inspector's own advertised map), mirroring the server/client capability
columns. Drop the now-redundant Extensions row from the modern Discovery
section (Supported versions stays).
Tests: extensions.test.ts covers the ui entry + advertisement value and the
per-extension enable/disable; ConnectionInfoContent.test.tsx covers legacy
server extensions (no discovery), the advertised-extensions column, and the
em-dash empty states. npm run ci green (the one InspectorView localStorage
failure is a known flake, passes on re-run).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5
* Extensions: address Phase 3 review (mime drift-guard, story, exact em-dashes)
- extensions-mimetype.test.ts (integration/node): assert MCP_APP_MIME_TYPE
equals ext-apps' real RESOURCE_MIME_TYPE (imported) and that the client
advertises it — a genuine drift guard, replacing the tautological literal
check in the unit test (which now just asserts the type).
- ConnectionInfoContent Modern story: carry the tasks extension on
initializeResult.capabilities too, so the Server Extensions row demonstrates
it (the row now reads negotiated server capabilities, not discoverResult).
- Tighten the em-dash assertions from ">= N" to exact counts (3/3/2) now that
the two extension sections em-dash by default.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5
* Extensions: drift-guard UI_EXTENSION_KEY against ext-apps EXTENSION_ID (review)
Address the Phase 3 re-review nit: the extension id was the other half of the
same drift risk (a server keys its Apps lookup on it). Import ext-apps'
EXTENSION_ID from the /server subpath in the node integration test (fine there;
the browser build is what avoids /server) and assert UI_EXTENSION_KEY === it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5
* Extensions: clone the registry advertisement so builds never alias it (review)
Address the Phase 3 re-review's optional defensive nit: buildClientExtensions
returned the same object reference as the ADVERTISABLE_EXTENSIONS entry for the
ui advertisement, so an in-place mutation of a stamped value (e.g.
extensions[ui].mimeTypes) could corrupt the registry for later connections.
structuredClone the advertisement on stamp; add a test asserting a mutated
build doesn't leak into the next one. Nothing mutates it today — purely
defensive.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5
* Extensions: add #1740 Connection Info proof screenshots
End-to-end smoke test in the web client against the legacy
advertised-extensions-http.json server: the Connection Info modal shows the new
era-transparent Server Extensions / Advertised Extensions section, with
Advertised Extensions listing io.modelcontextprotocol/tasks + io.modelcontextprotocol/ui
(the new ui advertisement), and only ui after toggling Tasks off and reconnecting.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>