diff --git a/clients/web/src/components/groups/ConnectionInfoContent/ConnectionInfoContent.test.tsx b/clients/web/src/components/groups/ConnectionInfoContent/ConnectionInfoContent.test.tsx index 9320fa21..51565697 100644 --- a/clients/web/src/components/groups/ConnectionInfoContent/ConnectionInfoContent.test.tsx +++ b/clients/web/src/components/groups/ConnectionInfoContent/ConnectionInfoContent.test.tsx @@ -216,7 +216,9 @@ describe("ConnectionInfoContent", () => { protocolEra="legacy" />, ); - expect(screen.getByText("Advertised Extensions")).toBeInTheDocument(); + expect( + screen.getByText("Client Advertised Extensions"), + ).toBeInTheDocument(); expect( screen.getByText( "io.modelcontextprotocol/tasks, io.modelcontextprotocol/ui", @@ -234,7 +236,9 @@ describe("ConnectionInfoContent", () => { />, ); expect(screen.getByText("Server Extensions")).toBeInTheDocument(); - expect(screen.getByText("Advertised Extensions")).toBeInTheDocument(); + expect( + screen.getByText("Client Advertised Extensions"), + ).toBeInTheDocument(); // Exactly two em dashes: the two extension sections (the server version is // present in the fixture, so it does not em-dash). expect(screen.getAllByText("—")).toHaveLength(2); diff --git a/clients/web/src/components/groups/ConnectionInfoContent/ConnectionInfoContent.tsx b/clients/web/src/components/groups/ConnectionInfoContent/ConnectionInfoContent.tsx index 66a8e0af..f1dfbd35 100644 --- a/clients/web/src/components/groups/ConnectionInfoContent/ConnectionInfoContent.tsx +++ b/clients/web/src/components/groups/ConnectionInfoContent/ConnectionInfoContent.tsx @@ -260,7 +260,7 @@ export function ConnectionInfoContent({ {formatExtensions(capabilities.extensions)} - Advertised Extensions + Client Advertised Extensions {formatExtensions(clientCapabilities.extensions)} diff --git a/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.stories.tsx b/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.stories.tsx index 5fc898ae..f0db4756 100644 --- a/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.stories.tsx +++ b/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.stories.tsx @@ -233,6 +233,19 @@ export const WithHeaders: Story = { }, }; +export const AdvertisedExtensions: Story = { + args: { + // Expand the standalone Advertised Extensions section so its checkboxes are + // documented visually. A per-server override disables one extension, showing + // both the default-on and toggled-off states side by side. + expandedSections: ["extensions"], + settings: { + ...defaultSettings, + advertisedExtensions: { "io.modelcontextprotocol/tasks": false }, + }, + }, +}; + export const WithOAuth: Story = { args: { settings: { diff --git a/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.test.tsx b/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.test.tsx index 7351ca48..8a6f81c1 100644 --- a/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.test.tsx +++ b/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.test.tsx @@ -458,9 +458,13 @@ describe("ServerSettingsForm", () => { , ); + // Advertised Extensions is now its own accordion section (#1747). + expect( + screen.getByRole("button", { name: "Advertised Extensions" }), + ).toBeInTheDocument(); const tasks = screen.getByRole("checkbox", { name: /Tasks \(io\.modelcontextprotocol\/tasks\)/, }); @@ -476,7 +480,7 @@ describe("ServerSettingsForm", () => { ...emptySettings, advertisedExtensions: { "io.modelcontextprotocol/tasks": false }, }} - expandedSections={["options"]} + expandedSections={["extensions"]} />, ); expect( @@ -494,7 +498,7 @@ describe("ServerSettingsForm", () => { {...baseHandlers} onAdvertisedExtensionChange={onAdvertisedExtensionChange} settings={emptySettings} - expandedSections={["options"]} + expandedSections={["extensions"]} />, ); // Default is checked; clicking flips it to unadvertised. diff --git a/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.tsx b/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.tsx index 55c88970..de582f29 100644 --- a/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.tsx +++ b/clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.tsx @@ -44,6 +44,7 @@ function isExtensionAdvertised( export type ServerSettingsSection = | "options" + | "extensions" | "environment" | "headers" | "metadata" @@ -401,34 +402,6 @@ export function ServerSettingsForm({ checked={settings.paginatedLists ?? false} onChange={(e) => onPaginatedListsChange(e.currentTarget.checked)} /> - - - Advertised Extensions - - - Which extensions the Inspector declares to this server in its - client capabilities. A server may register different tools - depending on what the client advertises — toggle these to debug - that. Takes effect on the next connect. - - {ADVERTISABLE_EXTENSIONS.map((ext) => ( - - onAdvertisedExtensionChange( - ext.key, - e.currentTarget.checked, - ) - } - /> - ))} - + + Advertised Extensions + + + + Which extensions the Inspector declares to this server in its + client capabilities. A server may register different tools + depending on what the client advertises — toggle these to debug + that. Takes effect on the next connect. + + {ADVERTISABLE_EXTENSIONS.map((ext) => ( + + onAdvertisedExtensionChange(ext.key, e.currentTarget.checked) + } + /> + ))} + + + + {isStdio ? ( Environment Variables diff --git a/clients/web/src/components/groups/ServerSettingsModal/ServerSettingsModal.test.tsx b/clients/web/src/components/groups/ServerSettingsModal/ServerSettingsModal.test.tsx index c0c51aab..ac68ef1e 100644 --- a/clients/web/src/components/groups/ServerSettingsModal/ServerSettingsModal.test.tsx +++ b/clients/web/src/components/groups/ServerSettingsModal/ServerSettingsModal.test.tsx @@ -175,8 +175,11 @@ describe("ServerSettingsModal", () => { onSettingsChange={onSettingsChange} />, ); - // The Options section is expanded by default; Tasks is checked (registry - // default), so clicking it toggles the override off. + // Advertised Extensions is its own accordion section (#1747), collapsed by + // default — open it, then toggle Tasks (checked by the registry default) off. + await user.click( + screen.getByRole("button", { name: "Advertised Extensions" }), + ); await user.click( screen.getByRole("checkbox", { name: /Tasks \(io\.modelcontextprotocol\/tasks\)/, @@ -207,6 +210,10 @@ describe("ServerSettingsModal", () => { onSettingsChange={onSettingsChange} />, ); + // Open the Advertised Extensions section (#1747), then re-check Tasks. + await user.click( + screen.getByRole("button", { name: "Advertised Extensions" }), + ); await user.click( screen.getByRole("checkbox", { name: /Tasks \(io\.modelcontextprotocol\/tasks\)/, diff --git a/clients/web/src/components/groups/ServerSettingsModal/ServerSettingsModal.tsx b/clients/web/src/components/groups/ServerSettingsModal/ServerSettingsModal.tsx index f6f28671..e91d43c8 100644 --- a/clients/web/src/components/groups/ServerSettingsModal/ServerSettingsModal.tsx +++ b/clients/web/src/components/groups/ServerSettingsModal/ServerSettingsModal.tsx @@ -26,6 +26,7 @@ function allSectionsFor( ): ServerSettingsSection[] { return [ "options", + "extensions", ...(isStdio ? (["environment"] as const) : []), "headers", "metadata", diff --git a/pr-screenshots/adv-ext-own-section-conninfo.png b/pr-screenshots/adv-ext-own-section-conninfo.png new file mode 100644 index 00000000..3e9bccc1 Binary files /dev/null and b/pr-screenshots/adv-ext-own-section-conninfo.png differ diff --git a/pr-screenshots/adv-ext-own-section.png b/pr-screenshots/adv-ext-own-section.png new file mode 100644 index 00000000..c42945f1 Binary files /dev/null and b/pr-screenshots/adv-ext-own-section.png differ