mirror of
https://github.com/coder/coder.git
synced 2026-10-31 02:43:21 +08:00
fix: apply MCP server selection when editing a chat message (#28471)
## Problem
Editing a user message in an Agent chat silently dropped the MCP server
selection. The composer renders the MCP picker in edit mode and toggles
update local client state, so the picker displayed the new selection,
but the edit request omitted `mcp_server_ids` at every layer (frontend
request builder, `codersdk.EditChatMessageRequest`, the `PATCH
/chats/{chat}/messages/{message}` handler, and `chatd.EditMessage`). The
chat's persisted selection never changed and the regenerated turn ran
without the newly enabled MCP tools. Two dogfood users hit this within
hours; there is no error anywhere and the UI shows the opposite of the
server state.
## Changes
- `codersdk`: add `MCPServerIDs *[]uuid.UUID` to
`EditChatMessageRequest`, mirroring `CreateChatMessageRequest` (nil
preserves the current selection).
- `chatd`: extract the send path's MCP update block into one shared
`applyRequestedMCPServerIDs` helper (explore-subagent snapshot
immutability guard plus Force On enforcement, Cure53 CDM-02-010) and
call it from both `SendMessage` and `EditMessage`, so enforcement cannot
drift between the two paths.
- `coderd`: extract the send handler's request validation (dedupe,
enabled-in-organization check, persisted-ID exemption) into
`normalizeRequestedChatMCPServerIDs` and wire it into the edit handler,
which now threads the selection into `EditMessageOptions`.
- Frontend: the edit request now includes `mcp_server_ids:
[...effectiveMCPServerIds]`, exactly like the send path, making the
picker's displayed state real.
- `make gen` artifacts (swagger, API docs, `typesGenerated.ts`).
## Tests
Each layer is covered and was proven with independent red toggles
(removing one layer's wiring fails only that layer's tests):
- chatd (`TestEditMessage_MCPServerIDs`): edit applies a provided
selection, nil preserves it, an emptied list cannot remove a `force_on`
server, and explore subagent chats keep the spawn-time snapshot.
- API (`TestPatchChatMessage/MCPServerIDsApplied`,
`MCPServerIDsInvalidRejected`): persistence via the endpoint, omission
preserves, unknown IDs get the same 400 as the send path.
- Storybook (`EditAppliesMCPServerSelection`): toggling a server on
during an edit puts it in the edit request payload.
Note: the `AgentChatPage.stories.tsx` story "Queued For Capacity After
Polling" fails locally on current main as well (verified against the
main baseline with this branch's changes reverted); it is unrelated to
this diff.
Remote dogfood UAT ran on the exact head and passed, including proof
that the regenerated turn actually gains the newly enabled MCP server's
tools.
> 🤖 Xum acted on Mike's (@ibetitsmike) behalf. • Model:
`anthropic:claude-fable-5`
<!-- xum-attribution: model=anthropic:claude-fable-5 -->
This commit is contained in:
Generated
+3
@@ -2122,6 +2122,9 @@ Experimental: this endpoint is subject to change.
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"mcp_server_ids": [
|
||||
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
|
||||
],
|
||||
"model_config_id": "f5fb4d91-62ca-4377-9ee6-5d43ba00d205",
|
||||
"reasoning_effort": "string"
|
||||
}
|
||||
|
||||
Generated
+4
@@ -8680,6 +8680,9 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"mcp_server_ids": [
|
||||
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
|
||||
],
|
||||
"model_config_id": "f5fb4d91-62ca-4377-9ee6-5d43ba00d205",
|
||||
"reasoning_effort": "string"
|
||||
}
|
||||
@@ -8690,6 +8693,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|--------------------|-----------------------------------------------------------|----------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `content` | array of [codersdk.ChatInputPart](#codersdkchatinputpart) | false | | |
|
||||
| `mcp_server_ids` | array of string | false | | Mcp server ids when set, replaces the chat's MCP server selection before the replacement turn runs. When nil the current selection is preserved. |
|
||||
| `model_config_id` | string | false | | Model config ID when set, overrides the model used for the replacement user message and the assistant turn that follows. When nil the original message's model is preserved. |
|
||||
| `reasoning_effort` | string | false | | |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user