inspector/pr-screenshots
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Cliff Hall fe295396af
Extensions: advertised-extensions toggle in Server Settings (Phase 2 of #1633) (#1743)
* Extensions: advertised-extensions toggle in Server Settings (Phase 2 of #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

* Extensions: add #1739 proof screenshots (advertised-extensions toggle)

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

* Extensions: reconverge advertisedExtensions to no-override on default (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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 16:23:43 -04:00
..
advertised-ext-settings-tasks-off.png Extensions: advertised-extensions toggle in Server Settings (Phase 2 of #1633) (#1743) 2026-07-22 16:23:43 -04:00
advertised-ext-settings-tasks-on.png Extensions: advertised-extensions toggle in Server Settings (Phase 2 of #1633) (#1743) 2026-07-22 16:23:43 -04:00
advertised-ext-tools-tasks-off.png Extensions: advertised-extensions toggle in Server Settings (Phase 2 of #1633) (#1743) 2026-07-22 16:23:43 -04:00
advertised-ext-tools-tasks-on.png Extensions: advertised-extensions toggle in Server Settings (Phase 2 of #1633) (#1743) 2026-07-22 16:23:43 -04:00
logging-legacy-era.png Logging: per-request log level on modern servers (era fork) (#1629) (#1724) 2026-07-19 17:08:22 -04:00
logging-modern-era-control.png Logging: per-request log level on modern servers (era fork) (#1629) (#1724) 2026-07-19 17:08:22 -04:00
logging-modern-era-loglevel-stamp.png Logging: per-request log level on modern servers (era fork) (#1629) (#1724) 2026-07-19 17:08:22 -04:00
logging-modern-server-setting.png Logging: per-request log level on modern servers (era fork) (#1629) (#1724) 2026-07-19 17:08:22 -04:00
README.md Extensions: advertised-extensions toggle in Server Settings (Phase 2 of #1633) (#1743) 2026-07-22 16:23:43 -04:00
subscriptions-legacy-live-update.png Resources: subscriptions/listen model on modern servers (era fork) (#1630) (#1730) 2026-07-20 19:33:40 -04:00
subscriptions-legacy-resources-subscribe.png Resources: subscriptions/listen model on modern servers (era fork) (#1630) (#1730) 2026-07-20 19:33:40 -04:00
subscriptions-modern-header-badge.png Resources: subscriptions/listen model on modern servers (era fork) (#1630) (#1730) 2026-07-20 19:33:40 -04:00
subscriptions-modern-listen-acknowledged.png Resources: subscriptions/listen model on modern servers (era fork) (#1630) (#1730) 2026-07-20 19:33:40 -04:00
tasks-legacy-cancel-sticky.png Tasks: io.modelcontextprotocol/tasks extension on modern servers (era fork) (#1731) 2026-07-21 19:17:04 -04:00
tasks-legacy-run-as-task.png Tasks: io.modelcontextprotocol/tasks extension on modern servers (era fork) (#1731) 2026-07-21 19:17:04 -04:00
tasks-modern-completed.png Tasks: io.modelcontextprotocol/tasks extension on modern servers (era fork) (#1731) 2026-07-21 19:17:04 -04:00
tasks-modern-connected.png Tasks: io.modelcontextprotocol/tasks extension on modern servers (era fork) (#1731) 2026-07-21 19:17:04 -04:00
tasks-modern-input-completed.png Tasks: io.modelcontextprotocol/tasks extension on modern servers (era fork) (#1731) 2026-07-21 19:17:04 -04:00
tasks-modern-input-required.png Tasks: io.modelcontextprotocol/tasks extension on modern servers (era fork) (#1731) 2026-07-21 19:17:04 -04:00
tasks-modern-loop-cancelled.png Tasks: io.modelcontextprotocol/tasks extension on modern servers (era fork) (#1731) 2026-07-21 19:17:04 -04:00
xmcpheader-excluded-reason.png Tools: x-mcp-header annotation tooling + -32602 unknown-tool rendering (#1632) (#1735) 2026-07-22 11:42:54 -04:00
xmcpheader-excluded-tools.png Tools: x-mcp-header annotation tooling + -32602 unknown-tool rendering (#1632) (#1735) 2026-07-22 11:42:54 -04:00
xmcpheader-invalid-params.png Tools: x-mcp-header annotation tooling + -32602 unknown-tool rendering (#1632) (#1735) 2026-07-22 11:42:54 -04:00
xmcpheader-mirrored-headers.png Tools: x-mcp-header annotation tooling + -32602 unknown-tool rendering (#1632) (#1735) 2026-07-22 11:42:54 -04:00
xmcpheader-unknown-tool.png Tools: x-mcp-header annotation tooling + -32602 unknown-tool rendering (#1632) (#1735) 2026-07-22 11:42:54 -04:00

Advertised-extensions toggle (#1739) — proof screenshots

End-to-end verification of the advertised-extensions debugging knob against a real legacy HTTP test server (test-servers/configs/advertised-extensions-http.json on port 3220), driven in a real browser through the web client's remote-proxy transport. The server registers echo (always) and get_weather gated on the io.modelcontextprotocol/tasks extension (extensionGatedTools): the tool is enabled on notifications/initialized only when the connected client declared that extension.

Advertised Extensions — Tasks advertised (default)

Server Settings → Advertised Extensions (the new section). With no override, Tasks (io.modelcontextprotocol/tasks) is checked — the registry default — so the Inspector advertises it in its client capabilities.

Tools with Tasks advertised

Connected with Tasks advertised. The server sees the declared extension on initialized and enables the gated tool, so tools/list returns both echo and get_weather.

Advertised Extensions — Tasks unchecked

Unchecking Tasks writes the per-server advertisedExtensions override. The change takes effect on the next connect (as the section note says).

Tools with Tasks not advertised

After reconnecting, the client advertises no extensions, so the server never enables the gated tool — tools/list now returns only echo. The server's tool registration demonstrably changed based on what the client advertised, exactly the acceptance criterion for #1739.


x-mcp-header Tools tooling (#1632) — proof screenshots

End-to-end verification of the SEP-2243 x-mcp-header Tools tooling against a real modern (2026-07-28) HTTP test server (test-servers/configs/xmcpheader-modern-http.json on port 3120), driven in a real browser through the web client's remote-proxy transport.

Excluded tools in the sidebar

Connected with Protocol Era = Modern. invalid_header_tool is dropped from tools/list by the SDK (its x-mcp-header annotation is invalid), so the Inspector re-lists the raw list and surfaces it struck-through under an "Excluded (SEP-2243)" divider — showing why a tool vanished rather than silently omitting it.

Exclusion reason on hover

Hovering the excluded tool shows the exact scan reason: the header name "Bad Header" contains a space, so it is not a valid RFC 9110 token.

Mirrored request headers

get_weather's detail panel shows the "Mirrored request headers (SEP-2243)" section: its city argument mirrors to Mcp-Param-City, with the note that the SDK omits Mcp-Param-* on the browser transport.

Unknown tool -32602

Calling a tool the server no longer recognizes rejects with -32602 (SDK v2) instead of an isError result, and renders as an "Unknown Tool" error panel with a targeted hint (reproduced by swapping the sessionless server to one without echo while the cached list still showed it).

Invalid params -32602

-32602 is the generic Invalid params code, so a known tool rejected for bad arguments throws the same code as an unknown tool. The panel disambiguates from the message: a -32602 that does not name an unknown tool renders under "Invalid Parameters" (with a schema hint) rather than "Unknown Tool". Triggered live via the trigger_invalid_params tool, which returns a real -32602 JSON-RPC error whose message is not about a missing tool.


Tasks extension era fork (#1631) — proof screenshots

End-to-end verification of the Tasks era fork against two real test servers (test-servers/configs/tasks-modern-http.json on port 3222 and tasks-legacy-http.json on 3223), driven in a real browser through the web client's remote-proxy transport.

Modern era (2026-07-28, io.modelcontextprotocol/tasks extension)

Modern connected, Tasks tab present

Connected with Protocol Era = Modern (MCP 2026-07-28). The Tasks tab appears in the monitoring sidebar because the io.modelcontextprotocol/tasks extension was negotiated (it is empty until a task runs).

Modern task completed

Connected with Protocol Era = Modern (MCP 2026-07-28). The Tasks tab is gated on the negotiated io.modelcontextprotocol/tasks extension (not capabilities.tasks). Running modern_task with Run as task on issues a tools/call that returns a CreateTaskResult (resultType: "task"), then polls tasks/get (no tasks/list); the completed task inlines its result (no blocking tasks/result) — shown both in the Results panel and the Tasks card.

Modern input_required → tasks/update

modern_input_task moves to input_required: the tasks/get response's inputRequests map (visible in the task's Full Task Object) carries an embedded elicitation/create, surfaced through the same pending-request modal the MRTR path uses — note the accurate wording "your answer is submitted via a tasks/update request (SEP-2663), not a retry". Answering it sends tasks/update with the inputResponses, and the next poll completes the task:

Modern input task completed

Legacy era (2025-11-25, contrast — unchanged)

Legacy run-as-task

Connected with Protocol Era = Legacy. The Tasks tab is gated on capabilities.tasks; simple_task is taskSupport: "required" so Run as task is forced on. The legacy flow uses tasks/list to populate the list, tasks/get to poll, and the blocking tasks/result to fetch the payload ({ "message": "Task completed: no message", "taskId": … }). Note the legacy-only Logs tab (this server advertises logging), absent from the modern monitor set.

Notes

  • SDK v2 removed all tasks support and era-gates the tasks/* spec methods out of the 2026-07-28 era on both the client (outbound) and server (inbound), and its codec rejects a resultType: "task" result outright. So the Inspector drives the extension itself: the task-creation frame is rewritten at the transport into a CallToolResult carrying the handle (the true resultType: "task" frame is still logged to the Protocol/Network tabs), and tasks/get / tasks/update / tasks/cancel ride a raw-wire request channel that carries the full modern envelope and is consumed by the transport before the SDK Client sees it. The test server serves tasks/* from an Express interceptor ahead of the SDK handler (the SDK's modern leg would answer them -32601).
  • On modern, task creation is server-directed (SEP-2663): the client declares the extension once and any tool may return a task, so the Tools screen offers Run as task for every tool on a modern connection (rather than gating on the legacy per-tool taskSupport).