From 62ce16d08f03f6ccc8f031c9b8a1b30f75ef98cc Mon Sep 17 00:00:00 2001 From: Ethan Dickson Date: Tue, 18 Aug 2026 05:09:31 +0000 Subject: [PATCH] fix(site/src/pages/AgentsPage): persist empty MCP selection --- .../AgentsPage/AgentChatPage.stories.tsx | 55 ++++++++++++++++++- site/src/pages/AgentsPage/AgentChatPage.tsx | 5 +- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/site/src/pages/AgentsPage/AgentChatPage.stories.tsx b/site/src/pages/AgentsPage/AgentChatPage.stories.tsx index cc6b3784b62df..d124f03114e8e 100644 --- a/site/src/pages/AgentsPage/AgentChatPage.stories.tsx +++ b/site/src/pages/AgentsPage/AgentChatPage.stories.tsx @@ -26,6 +26,7 @@ import { MockChat, MockChatMessage, MockChatQueuedMessage, + MockMCPServerConfig, } from "#/testHelpers/chatEntities"; import { MockChatModelConfig } from "#/testHelpers/chatModels"; import { @@ -255,7 +256,10 @@ const buildChatAuthorizationQuery = ( const buildQueries = ( chat: TypesGen.Chat, messagesData: TypesGen.ChatMessagesResponse, - opts?: { diffUrl?: string }, + opts?: { + diffUrl?: string; + mcpServers?: readonly TypesGen.MCPServerConfig[]; + }, ) => { const diffStatus: TypesGen.ChatDiffStatus = { chat_id: CHAT_ID, @@ -301,7 +305,7 @@ const buildQueries = ( }, { key: chatModelsKey, data: mockModelCatalog }, { key: chatModelConfigs().queryKey, data: mockModelConfigs }, - { key: mcpServersKey, data: [] }, + { key: mcpServersKey, data: opts?.mcpServers ?? [] }, buildChatAuthorizationQuery(chat, { canShareChat: { action: "share", @@ -3217,6 +3221,53 @@ export const SendResponseAfterChatSwitch: Story = { }, }; +export const RemoveLastMCPServer: Story = { + parameters: { + queries: buildQueries( + { + id: CHAT_ID, + ...baseChatFields, + title: "Remove last MCP server", + status: "waiting", + mcp_server_ids: [MockMCPServerConfig.id], + }, + { messages: [], queued_messages: [], has_more: false }, + { + diffUrl: undefined, + mcpServers: [MockMCPServerConfig], + }, + ), + }, + beforeEach: () => { + spyOn(API.experimental, "getUserSkills").mockResolvedValue([]); + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const sendSpy = spyOn( + API.experimental, + "createChatMessage", + ).mockResolvedValue({ queued: false }); + + await userEvent.click( + await canvas.findByRole("button", { name: "Remove MCP Server" }), + ); + const editor = await canvas.findByTestId("chat-message-input"); + await userEvent.click(editor); + await userEvent.type(editor, "Send without MCP tools"); + await userEvent.keyboard("{Enter}"); + + await waitFor(() => { + expect(sendSpy).toHaveBeenCalledTimes(1); + }); + expect(sendSpy).toHaveBeenCalledWith( + CHAT_ID, + expect.objectContaining({ + mcp_server_ids: [], + }), + ); + }, +}; + /** * The send flow renders the durable user row once the server accepts the * prompt, before the assistant turn produces any output. diff --git a/site/src/pages/AgentsPage/AgentChatPage.tsx b/site/src/pages/AgentsPage/AgentChatPage.tsx index da472f7d646b4..efe81b3a18504 100644 --- a/site/src/pages/AgentsPage/AgentChatPage.tsx +++ b/site/src/pages/AgentsPage/AgentChatPage.tsx @@ -1799,10 +1799,7 @@ const AgentChatPage: FC = () => { content, model_config_id: selectedModelConfigID, reasoning_effort: effectiveReasoningEffort, - mcp_server_ids: - effectiveMCPServerIds.length > 0 - ? [...effectiveMCPServerIds] - : undefined, + mcp_server_ids: [...effectiveMCPServerIds], ...(planModeSwitch !== undefined ? { plan_mode: