Extensions: advertised-extensions toggle in Server Settings (Phase 2 of #1633) - #1743
Conversation
#1633) Adds the debugging knob from #1633: users choose which extensions the Inspector advertises to a server, and a server may register different tools in response. Builds on Phase 1's registry + advertisedExtensions option (#1738). Settings + persistence (core): - InspectorServerSettings.advertisedExtensions + StoredMCPServer field, wired through serverList's read/write converters and INSPECTOR_FIELD_KEY_MAP (omit-when-empty, byte-stable round-trip). - validateSettings (remote PUT route): isBooleanRecord guard + carry a non-empty map; unknown/malformed rejected. - App.tsx threads savedSettings.advertisedExtensions into the client options. UI: - ServerSettingsForm renders an "Advertised Extensions" group of checkboxes driven by ADVERTISABLE_EXTENSIONS; a per-server override wins over the registry default. Modal folds a toggle into settings.advertisedExtensions. Test server + proof: - composable-test-server extensionGatedTools: a tool registered disabled and enabled on `initialized` iff the client declared the mapped extension (getClientCapabilities). Legacy stateful leg. Threaded through load-config/resolve-config; advertised-extensions-http.json showcase + README. - Integration test connects legacy with/without the tasks extension advertised and asserts the gated tool appears/disappears in tools/list — the acceptance criterion, proven end to end, not asserted. Tests: serverList round-trip (non-empty/absent/empty), ServerSettingsForm toggle rows, ServerSettingsModal fold, validateSettings accept/reject, and the integration gating test. npm run ci green (per-file ≥90 gate held). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5
|
@claude review |
|
Claude finished @cliffhall's task in 1m 27s —— View job Code Review — Advertised-extensions toggle (Phase 2 of #1633)
Overall this is a clean, well-scoped, and thoroughly-tested PR. The registry-as-source-of-truth pattern ( Observations (minor / optional)1. Toggling an override back to its default value persists a redundant entry. 2. Things I specifically checked and liked
Nice work — LGTM modulo the optional persistence-reconvergence nit above. |
End-to-end smoke test in the web client against the legacy advertised-extensions-http.json test server (port 3220): connecting with the Tasks extension advertised (default) lists echo + get_weather, unchecking the Advertised Extensions → Tasks toggle and reconnecting lists only echo — the server's tool registration changing on the client-declared extension. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5
… (review) Address Phase 2 review observation #1: toggling an extension back to its registry default now deletes the override key (and drops the whole map to undefined when it empties), so the on-disk `advertisedExtensions` reconverges to the byte-stable "no override" state instead of persisting a redundant `{ key: <default> }`. Matches the omit-when-default policy the other settings use. Only a value that differs from the default is persisted. Adds a modal test asserting the reconvergence (re-checking the sole disabling override drops advertisedExtensions to undefined). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5
|
Thanks for the thorough review! Addressed in bf3afe1:
Also added end-to-end proof screenshots to the PR description (four shots: settings toggle on/off × tools list with/without the gated
@claude review |
|
Claude finished @cliffhall's task in 43s —— View job Re-review — reconvergence fix (bf3afe1)
The reconvergence fix looks correct and well-implemented. LGTM. ✅
This exactly matches the Details I checked
Observation 2 (the Nothing further from me — the earlier review's sole actionable nit is resolved cleanly, with a test. 👍 |
Closes #1739
Phase 2 of #1633. Adds the advertised-extensions toggle — the core debugging knob of the tracking issue: users choose which extensions the Inspector advertises to a server, and a server may register different tools in response. Builds directly on Phase 1's registry +
advertisedExtensionsclient option (#1738, merged).What changed
Settings + persistence (core)
InspectorServerSettings.advertisedExtensionsand the matchingStoredMCPServerfield, wired throughserverList's read (storedFieldsToInspectorSettings) and write (inspectorSettingsToStoredFields) converters and the source-of-truthINSPECTOR_FIELD_KEY_MAP. Omit-when-empty on disk for a byte-stable round-trip.validateSettings(remote/api/serversPUT route): anisBooleanRecordguard rejects a malformed map; a valid non-empty map is carried, an empty one is dropped.App.tsxthreadssavedSettings.advertisedExtensionsinto theInspectorClientoptions (absent/empty → registry defaults).UI
ServerSettingsFormrenders an "Advertised Extensions" checkbox group driven byADVERTISABLE_EXTENSIONS; a per-server override wins over the registry default (mirrorsbuildClientExtensions). The change takes effect on the next connect (surfaced in the description).ServerSettingsModalfolds a toggle intosettings.advertisedExtensions.Test server + end-to-end proof
composable-test-servergainsextensionGatedTools: a named tool is registered disabled and enabled onnotifications/initializedonly when the connected client declared the mapped extension (getClientCapabilities().extensions). Legacy stateful leg (the modern per-request leg has no persistentoninitialized). Threaded throughload-config/resolve-config.test-servers/configs/advertised-extensions-http.jsonshowcase + README note:echoalways,get_weathergated onio.modelcontextprotocol/tasks.tools/list. This is the acceptance criterion ("demonstrably changes server tool registration"), proven end to end rather than asserted.Tests
serverListround-trip (non-empty / absent / empty map),ServerSettingsFormtoggle rows (default-checked, override-unchecks, click fires),ServerSettingsModalfold,validateSettingsaccept/reject/empty, and the integration gating test (3 cases).npm run cigreen — validate → coverage (per-file ≥90 gate held) → smoke → Storybook.Proof screenshots
End-to-end smoke test in the web client against the legacy
advertised-extensions-http.jsontest server (port 3220), which gatesget_weatheron theio.modelcontextprotocol/tasksextension. More detail inpr-screenshots/README.md.With Tasks advertised (default): the new toggle is on, and
tools/listreturnsecho+get_weather.Uncheck Tasks and reconnect: the client advertises no extensions, the server never enables the gated tool, and
tools/listreturns onlyecho.Notes
io.modelcontextprotocol/uiadvertisement and its likely cast land in Phase 3 (Extensions: Connection Info both eras + io.modelcontextprotocol/ui advertisement (Phase 3 of #1633) #1740), after which the ext-apps-v1-shim-removal follow-up gets filed (so it can enumerate every shim site).🤖 Generated with Claude Code
https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5