Skip to content

feat: allow sharing MCP servers with users and groups (#28593) - #28686

Merged
mtojek merged 16 commits into
release/2.37from
backport/28593-to-2.37
Aug 27, 2026
Merged

feat: allow sharing MCP servers with users and groups (#28593)#28686
mtojek merged 16 commits into
release/2.37from
backport/28593-to-2.37

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Backport of #28593 to release/2.37, cherry-picked with git cherry-pick -x. Part of the post-2.37 backport stack rooted at #28683; the stack merges bottom-up, so this lands after its parent PR.

Applied cleanly on top of #28688; no adaptations. Also includes the 1-line test fix #28657 (expect the v2 MCP ACL path): on main it landed as a standalone base fix, and without it 2.37's pre-existing api.test.ts assertion still expects the experimental path that this PR's api.ts change retires.

Xum acted on Mike's behalf.

…s retryable errors (#28470)

## Problem

When Gemini's OpenAI-compatible endpoint rejects a model-generated
function call server-side, it ends the SSE stream cleanly with the
nonstandard finish reason `function_call_filter:
MALFORMED_FUNCTION_CALL` after streaming only thought summaries; the
rejected call never reaches the wire. chatd treated this as a normal
completion: fantasy maps the unrecognized finish reason to `unknown`,
the reasoning block never closes (the only non-thought delta is the
`</thought>` marker, which the transport seam strips to an empty string,
and the openaicompat hook only ends reasoning on a non-empty content
delta), so the step accumulates no content and the generation loop
finishes the turn as complete. The user sees the model think for ~40
seconds and then nothing: no assistant message, no `last_error`, chat
status `waiting`. Observed twice in a row in production on
gemini-3.7-flash, with "Resume" reproducing it identically.

## Fix

Two independent layers:

- `coderd/x/googleopenai`: the stream rewrite now converts any chunk
whose `finish_reason` starts with `function_call_filter` into an
OpenAI-style SSE `{"error": ...}` event embedding the raw reason.
openai-go turns error-bearing events into stream errors, so the failure
rides the existing stream-error path instead of ending the stream
cleanly.
- `coderd/x/chatd/chaterror`: classifies that injected error as
retryable (kind `generic`, provider `google`) with a clear user-facing
message, so the existing generation retry machinery re-runs the step and
persists a `last_error` if retries exhaust.
- `coderd/x/chatd/chatloop`: provider-agnostic guard: a step that
produced no user-visible content and no tool calls under a finish reason
of `unknown`, `error`, `other`, or `tool-calls` (a tool-calls finish
that delivered zero calls) now returns a retryable error instead of
silently completing the turn. `stop` and `length` finishes keep their
existing semantics.

Tests cover the seam rewrite (live-capture SSE shape plus standard
finish reason passthrough), the new classification, and the chatloop
guard (error cases plus preserved stop, length, text, and tool-call
behavior). Each layer was red-green verified independently.

Remote dogfood UAT ran against this exact commit: normal reasoning and
tool-call chats on a real model complete cleanly with no spurious guard
errors and no retry loops. The Google-side failure itself is not
deterministically triggerable against live Gemini and is owned by the
unit tests.

> Xum acted on Mike's (@ibetitsmike) behalf.

<!-- xum-attribution: model=claude-opus, thinking=enabled -->

(cherry picked from commit a48aedd)
## 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 -->

(cherry picked from commit b6d7653)
…edia stub (#28460)

Follow-up to review feedback on #28387.

That PR added three hooks for one feature (`useIsBelowLgViewport`,
`useIsBelowMdViewport`, and the local single-use
`useRightPanelNarrowSuppression`) and stubbed `window.matchMedia` in
tests with `Object.defineProperty`.

- Replace the two single-purpose viewport hooks with one generic
`useMediaQuery(query)`. Callers pass the shared Tailwind-aligned query
constants from `utils/mobile.ts`. The one new hook replaces the two
deleted ones (net -1).
- Inline `useRightPanelNarrowSuppression` into `AgentChatPage`, its only
consumer, and drop its `renderHook` unit suite. The behavior stays
covered by the narrow-viewport stories; the widening-restore case moved
into the `NarrowingSuppressesExpandedPanel` play function.
- Rework `testHelpers/matchMedia.ts` to install the stub with `spyOn`
from `storybook/test` instead of `Object.defineProperty`. The helper is
story-only now (stories run in real Chromium; jsdom has no
`matchMedia`), so any future unit test needing a stub should use
`vi.stubGlobal` directly.
- Encode the feedback in the canonical FE contract so it gets caught
during development: `.claude/docs/FRONTEND_PATTERNS.md` now bans new
React hooks when an existing hook, a plain function, or component state
suffices (FE3) and bans replacing browser globals with
`Object.defineProperty` in tests or stories (FE9: `vi.stubGlobal` /
`spyOn`), and notes that `renderHook` suites for stateful UI hooks
belong in the consuming component's story (FE1). The `frontend-review`
skill checklist flags all three. `site/AGENTS.md` is unchanged since it
already defers to the patterns doc.

Validation: `pnpm check`, `pnpm format:check`, `pnpm lint` (biome,
types, knip, circular deps, compiler check), `AgentChatPage.test.ts` (70
passed), story runs for `AgentChatPage.stories.tsx` and
`WorkspacePill.stories.tsx` (49 passed in Chromium).

> Xum acted on Mike's behalf (@ibetitsmike).

<!-- xum-attribution: model=claude-opus-4-6 thinking=high -->

(cherry picked from commit 3c32408)
… guidance (#28476)

Broad `find_tools` queries such as "linear issues" saturated the hard
20-match cap on every call: a large server's name token-matches every
one of its tools (+8 name, +1 server), so ranking was decided by a term
carrying no discriminating information and the model got 20 activations
per search regardless of intent.

Three changes, mirroring what makes xum's `tool_catalog_search` behave
well:

- **Lower default with a `limit` argument.** Keyword matches default to
10 per call; the new optional `limit` raises that up to the existing
hard cap of 20 (non-positive values fall back to the default). Exact
`names` are explicit activation requests and bypass the limit up to the
hard cap, so naming 15 tools still activates all 15.
- **Coverage-first ranking.** Keyword matches sort by distinct query
terms matched before raw score, so a query like "linear issues" ranks
tools matching both terms above the dozens matching only the server
name.
- **Model guidance.** `queries` and `names` now carry schema
descriptions (capability keywords and what they are matched against;
exact-name activation), and the tool description opens by explaining
what deferral means, that matches become callable on the next step, and
that a `"server: terms"` prefix scopes a query to one server.

An earlier revision also inferred a server scope from unprefixed query
words ("linear issues" behaving like "linear: issues"). Review kept
surfacing edge cases in that inference, and coverage-first ranking
already resolves the original saturation complaint, so it was dropped in
favor of the explicit prefix.

The hard cap stays at 20 so the persisted result keeps fitting under the
generic tool-result truncation budget that protects activation-recovery
JSON. Budget and reservation accounting are unchanged; the frontend
renderer ignores unknown argument fields, so no `site/` change is
needed.

> [!NOTE]
> Xum acted on @ibetitsmike's behalf in this pull request.
<!-- xum-attribution: model=claude-opus-4-6 thinking=high -->

(cherry picked from commit e244cac)
… session cleanup (#28400)

## Problem

During the Aug 19 dev.coder.com incident, chats stalled for up to ~15
minutes per turn. chatd reconnects to every configured MCP server on
every generation step, and one configured server
(`registry.coder.com/mcp`) was black-holing requests from the
deployment's egress IPs: TCP/requests were silently dropped, and each
connect attempt hung until the kernel gave up (~125s), far past the
nominal 10s connect budget.

The budget does not hold because go-sdk v1.7.0 detaches the context
inside `StreamableClientTransport.Connect`, and its error paths block on
HTTP work bound to that detached context. Reproduced in a test: a bare
`Connect` with a 2s deadline against a black-holed server returns after
**12s**. Step-end session cleanup (`session.Close()`) runs synchronously
in the generation loop and blocks on the same detached requests, so a
server that wedges mid-turn stalls every step boundary too.

## Changes

- **Enforce the connect budget externally** (`connectOne`): run
`Connect` + `ListTools` in a goroutine and select on the budget context.
On timeout, abandon the goroutine and leave a reaper that drains its
late result and closes any session that still materialized, so nothing
leaks and the caller returns within the budget.
- **Stop using bare `http.DefaultTransport`**: MCP traffic now rides a
cloned transport with a 5s dial timeout (converts SYN black-holes into
fast errors) and a 60s `ResponseHeaderTimeout`. `http.Client.Timeout`
stays unset so long-lived SSE streams are unaffected.
- **Close sessions in detached goroutines during cleanup**
(`ConnectAll`'s cleanup func): the sessions are discarded regardless,
and a wedged `Close` (DELETE bound to the SDK's detached context) must
not stall the generation loop at step boundaries.

One deliberate deviation from the incident plan: `ResponseHeaderTimeout`
is 60s (matching `toolCallTimeout`) instead of ~10s. The same HTTP
client serves tool-call POSTs, and a JSON-response MCP server sends no
headers until the tool finishes, so a 10s bound would falsely kill
legitimate 10-60s tools that fit today's tool-call budget. The real 10s
connect budget is enforced by the external select, not the transport.

## Tests

- Acceptance: with a black-holed server plus a healthy one configured,
`ConnectAll` returns within the budget and the healthy server's tools
are present; closing the black-holed connections makes the reaper exit
(red without the fix: 1s budget took 11s).
- A slow-but-alive server (300ms/request) still connects.
- A server that only responds after the budget: `ConnectAll` returns
promptly, the late result is reaped.
- Cleanup returns promptly while the session-teardown DELETE is wedged
server-side, and the teardown still happens in the background (red
without the fix: cleanup blocked 60s).
- Transport guard test pinning the dial/response-header bounds.

`go test ./coderd/x/chatd/...` passes (including goleak in `chatd`).

Part of the MCP connect-stall incident follow-up; observability (connect
durations in logs/debug runs) comes in a stacked follow-up PR.

> 🤖 Mux authored this PR on Mike's behalf.

<!-- mux-attribution: model=anthropic:claude-opus-4-6 thinking=high -->

(cherry picked from commit cc958b7)
…of rejecting them (#28589)

Chat title generation asks the model for a title in 2-8 words and then
hard-rejects any response longer than 8 words
(`validateGeneratedTitle`). Quickgen pins temperature for repeatable
output, so a model that overshoots the budget for a given conversation
overshoots on every retry: the rename dialog's Generate button returns a
deterministic 500 (`generate manual title: generated title exceeded 8
words`) no matter how often it is clicked, and the automatic
first-message path silently leaves the chat on its fallback title. On
dev.coder.com this rejection fires 1-3 times a day; one chat took 13
consecutive manual failures on 2026-08-25 (14:22-14:27 UTC).

Truncate the normalized title to the 8-word budget in
`normalizeTitleOutput` instead of rejecting it, and keep the empty-title
validation. Both the automatic and manual title paths share this
normalization, so both are fixed.

> Xum (AI agent) authored this change and PR on Mike's behalf.

(cherry picked from commit 60b0313)
## Stack context

This is the base of a 3-PR stack promoting the chat API from
`/api/experimental` to `/api/v2`: server compatibility mounts (this PR),
codersdk promotion (#28497), and frontend path updates (#28498).

## Summary

Double-mount the stable chat and MCP handlers under `/api/v2` while
retaining the existing experimental routes for the one-release
compatibility window decided in CODAGT-921. CODAGT-922 tracks removing
the compatibility mounts.

The shared route builders preserve existing authentication and
middleware behavior. Experiment-gated, debug, tombstone, and legacy
default-organization model routes remain experimental-only. Signed file
URLs, external OAuth callback URLs, and mixed-version replica relays
also remain on the experimental prefix during the transition.

Update Swagger and the generated API reference for the promoted routes,
including the workspace lookup and a runnable raw-body chat file upload
example. Retain internal endpoints outside the published reference,
share chat-file rate limits across both prefixes, enable CORS for the v2
MCP routes, and cover dual mounts plus exclusions with compatibility
tests. Remote dogfood UAT passed for the promoted chat, model, MCP, and
file flows.

> [!NOTE]
> Xum acted on Mike's behalf in this pull request.
<!-- xum-attribution: model=claude-fable-5 thinking=high -->

(cherry picked from commit 351bb14)
## Stack context

This is the second PR in the 3-PR chat API promotion stack: server
compatibility mounts (#28496), codersdk promotion (this PR), and
frontend path updates (#28498).

## Summary

Move the promoted chat and MCP SDK methods from `ExperimentalClient` to
`Client` and update them to use `/api/v2`. Methods for routes that
remain experimental stay on `ExperimentalClient`.

Update in-repository callers and generated types. The multi-replica chat
stream relay dials `/api/v2` directly: mixed-version replica sets are
not a supported upgrade path, so no experimental-path fallback is kept
(per review). Remote dogfood UAT passed for the composed stack.

> [!NOTE]
> Xum acted on Mike's behalf in this pull request.
<!-- xum-attribution: model=claude-fable-5 thinking=high -->

(cherry picked from commit 973d5a4)
## Stack context

This is the final PR in the 3-PR chat API promotion stack: server
compatibility mounts (#28496), codersdk promotion (#28497), and frontend
path updates (this PR).

## Summary

Switch promoted frontend chat and MCP REST and WebSocket calls to
`/api/v2`. Debug runs, virtual desktop streaming, advisor, and
computer-use provider routes remain on `/api/experimental` because those
surfaces were not promoted.

Update the matching tests, stories, helpers, and end-to-end route
expectations. Remote dogfood UAT passed with chat traffic verified on
the v2 routes.

> [!NOTE]
> Xum acted on Mike's behalf in this pull request.
<!-- xum-attribution: model=claude-fable-5 thinking=high -->

(cherry picked from commit 7394d2c)
ethanndickson and others added 3 commits August 27, 2026 05:33
Repair the Storybook interaction and Pixel failures currently present on
`main`. The failures came from organization-scoped model changes leaving
stories with incomplete providers and query fixtures, product copy and
route changes leaving stale assertions, and several interaction tests
depending on implementation details or teardown timing.

PR #27960 introduced organization-scoped chat models and the following
regressions:

- `OrganizationModelsLayout / Switch Organization Preserves Auxiliary
Parameters`, `Invalid Requested Organization Falls Back To Default`,
`Invalid Requested Organization Denies Add`, `Duplicate Display Names
Are Disambiguated`, and `No Readable Organization Is Not Found`: the
stories only populated permission query keys for individual
organizations, while the accessible-organization lookup requests
authorization for all visible organization IDs together. The unmatched
`/api/v2/authcheck` request returned a Storybook proxy 502, so the
layout rendered an error instead of the intended picker, fallback,
denied, disambiguation, or not-found state. Add fixtures for the
combined organization-permission keys, preserve the intentionally denied
permission map, and return an explicit empty authorization result for
the no-readable-organization case.
- `ModelFormProviderConfig / Provider Config Open AI`, `Provider Config
Anthropic`, and `Provider Config Open AI Web Search`: `ModelForm` began
consuming `OrganizationModelsContext`, but these stories were not
wrapped in its provider and rendered the router error boundary. Add the
same organization-model context decorator used by the sibling model form
stories.
- `AgentChatPage / Queued For Capacity After Polling`: the story
retained a manually assembled chat-and-messages fixture after the page
gained organization-model, provider, workspace, prompt, diff, chat-list,
and authorization dependencies. Those missing queries prevented the
polling request from being reached. Replace the partial fixture list
with the shared `buildQueries()` setup.
- `DashboardLayout / Custom Organization Role Can Open Models`,
`DashboardLayout / ACL Readable Member Can Open Models`, and `NavbarView
/ For Member With Model Access`: these stories also landed in #27960 and
inherited Pixel's tablet-and-desktop matrix, but their play functions
exercise the desktop `Models` link. Pixel's 744px tablet viewport
renders that link inside the closed mobile menu, so the desktop query
always failed there. Restrict these authorization-to-navigation stories
to the desktop matrix; mobile Models navigation remains covered by the
dedicated `MobileMenu` story.

- `DeploymentSidebarView / Premium Tab Visible` and `Premium Tab
Hidden`: PR #28226 renamed the production navigation item from `Premium`
to `Trial Upgrade`, but added stories that still queried the old name.
Update both the positive and negative assertions so the hidden-state
story cannot pass while the real CTA is present.
- `PremiumPageView / No License`: PR #28226 changed the production
heading to `Start an unlimited 30-day Coder trial` while the story
asserted the previous Premium wording. Update the accessible heading
assertion to the rendered copy.
- `AgentChatPageView / Queued For Capacity Community Admin`: PR #28437
intentionally moved the trial CTA from `https://coder.com/trial` to the
internal `/deployment/premium` route, leaving the story's href assertion
stale. Update the expected route while retaining the link-name and
callout checks.

- `AgentCreateForm / MCP Servers Error Shows Alert And Disables Send`
and `MCP Servers Refetch Error Keeps Send Enabled`: the MCP coverage was
introduced in #27942. PR #28442 later added a second unconditional MCP
`ErrorAlert`, so a background refetch error appeared even when cached
MCP data remained usable. The refetch story also called
`refetchQueries()` without a key, which began refetching unrelated
active model queries as the form's query surface expanded and produced
unmatched API failures. Remove the duplicate unconditional alert,
refetch only the organization's MCP query, and use semantic alert and
heading assertions. Initial-load failures still disable Send, while
background failures with cached data keep Send enabled without replacing
the form with an error.

- `IconField / Open Picker`: PR #27674 changed this story to wait for
the `em-emoji-picker` custom element. That implementation-specific query
races the lazy-loaded picker chunk and violates the component's
observable contract. Keep the button state assertion and wait for the
visible dialog instead.
- `AgentChatPage / Slash Compact Command Submits` and `Slash Compact
Yields To Personal Skill`: the command story added in #27081 waited on
cmdk's `Commands` group heading, which is accessibility-hidden, while
the skill variant queried raw implementation text. Menu placement and
visibility are asynchronous, especially after the positioning changes in
Enter.
- `AgentChatPageView / Terminal Focus On Tab Switch`: the focus coverage
added in #24677 exposed an xterm teardown race rather than a product
navigation regression. xterm queues its initial viewport
synchronization, but Storybook could synchronously dispose the terminal
first, leaving the queued callback to read a cleared renderer and report
an unhandled error. Clear React state immediately, defer xterm disposal
by one timer turn, query the labeled terminal textbox semantically, and
remove the unnecessary empty WebSocket message fixture.

(cherry picked from commit 9b5f47e)
- make Coder Agents available to organization members without a separate
built-in role
- remove the obsolete role from backend and frontend role surfaces
- update authorization, UI, documentation, and regression coverage

This PR intentionally ships no migration so it backports cleanly across
diverged migration numbers. Stale `agents-access` grants may remain in
user role arrays and org default member roles; the retired name is
treated as a grant of nothing (role expansion drops it, assignment
validation ignores it, and the name stays reserved). A follow-up PR will
add the data cleanup migration.

- `make gen`
- `make lint`
- repository pre-commit checks
- targeted RBAC, migration, chat API, enterprise, site, Storybook, and
race tests
- `git diff --check`

Rolling back the deployment restores the previous behavior directly: no
data changed, and older binaries still resolve any lingering
`agents-access` grants.

> Mux created this pull request on Mike's behalf.

(cherry picked from commit 845790e)
## Summary

Adds the missing user-facing half of MCP server config ACLs: admins can
now share an MCP server with individual users and groups from the UI,
backed by a new permission-safe candidate-discovery endpoint.

## Problem

The MCP server config ACL backend already existed (share RBAC action,
hydrated `GET .../acl`, sparse `PATCH .../acl`), but there was no
frontend for it. There was also no way to populate a sharing
autocomplete without the generic organization member/group APIs, which
require `organization_member:read` and `group:read` and would wrongly
couple MCP sharing to the workspace-sharing mode (the same bug fixed for
chat models in #28542).

## Changes

Backend:

- New v2-only `GET
/api/v2/organizations/{organization}/mcp-servers/{mcpserverconfig}/acl/available`
returning `codersdk.ACLAvailable`; because this API is new, it is not
mounted under the experimental compatibility prefix. Gated on
`ActionShare` for the specific server config; performs bounded
org-scoped member/group lookups via `dbauthz.AsSystemRestricted`;
excludes system users; supports `q`, `limit`, `offset`, and `after_id`
with template/chat-model autocomplete semantics.
- Tests cover authorization (404 without share), search, pagination,
system-user exclusion, org scoping, and a share-only custom role under
all three workspace-sharing modes (`none`, `service_accounts`,
`everyone`).

Frontend:

- `shareMCPServerConfig` permission plumbing; the MCP servers list,
details page, and AI settings sidebar now admit share-only users (share
does not require update; share-only users cannot edit the server form).
- Share-only access follows the established permission contract: a
bare-share role manages sharing through the list and ACL endpoints (the
detail route still requires read, update, or delete, matching the
existing enterprise permission-matrix tests), and the disabled-config
gate now also admits the share permission so a sharer with read access
can open a disabled server. Top-level navigation (Admin settings menu
and the /ai/settings index redirect) discovers organization-level MCP
sharers and surfaces permission lookup failures instead of silently
falling back.
- "Share server" action on the MCP server edit page opening a sharing
dialog: hydrated ACL grants render from the `GET .../acl` response,
adds/removals are saved as sparse `PATCH` deltas (`"read"` / `""`).
- Principal autocomplete backed exclusively by the new `/acl/available`
endpoint; the sharing flow never calls the generic org member/group APIs
(Storybook enforces this by rejecting those API spies). A discovery
error surfaces under the autocomplete without hiding existing grants.
- Storybook interaction coverage for the dialog (hydrated rendering,
add/remove, sparse deltas, error/cancel/reopen paths, autocomplete
exclusion and failure) and share-only access to the page/form.

Dogfood UAT ran remotely against a dev instance and passed, including
verifying via the network log that candidate discovery only hits
`/acl/available`. The share-only custom role UI flow could not be
exercised there (no premium license on the dev instance); it is covered
by the backend permission-matrix tests.

> 🤖 This PR was authored by Xum (an AI coding agent) acting on Mike's
behalf.

(cherry picked from commit 35cbca0)
@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Docs preview

Check off each page once it's been reviewed. If a page changes in a later push, its checkbox clears automatically so it gets a fresh look. Pages not yet wired into the docs navigation aren't listed here.

@ibetitsmike
ibetitsmike changed the base branch from release/2.37 to backport/28186-to-2.37 August 27, 2026 05:44
@ibetitsmike ibetitsmike changed the title [CONFLICT] feat: allow sharing MCP servers with users and groups (#28593) feat: allow sharing MCP servers with users and groups (#28593) Aug 27, 2026
@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

👋 Hey @github-actions[bot]!

This PR is targeting the release/2.37 release branch, but its title does not start with fix: or fix(scope):.

Only bug fixes should be cherry-picked to release branches. If this is a bug fix, please update the PR title to match the conventional commit format:

fix: description of the bug fix
fix(scope): description of the bug fix

If this is not a bug fix, it likely should not target a release branch.

@coderagents

coderagents Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Documentation Check

Updates Needed

  • docs/ai-coder/agents/platform-controls/mcp-servers.md - Says members "open Server actions > Manage permissions", but after the merge of the UI-fixes backport (ba7e1844ac, fix: batch backport tracyjohnsonux UI fixes for Agents and Coder admin area to release/2.37 #28673) the MCP server edit page no longer has a Server actions dropdown. MCPServerFormHeader.tsx now renders a direct Manage permissions button (and a Delete button). Reword to match, e.g. "open the server and select Manage permissions".

    ⚠️ Previously resolved, but regressed: the merged UI-fixes backport removed the Server actions menu, so the docs mismatch the UI again.

  • docs/ai-coder/agents/platform-controls/organizations.md - Same "Server actions > Manage permissions" wording; the MCP servers UI now exposes a direct Manage permissions button. Align the wording.

    ⚠️ Previously resolved, but regressed by the same merged UI-fixes backport.

Already Covered

  • The merges pulled in the "Coder Agents User" role removal (fix(site/src): repair failing Storybook stories #28462). Its docs are updated in the same PR: getting-started.md drops the grant-role step, models.md explains model-access-based access, and glossary.md removes the role entry. No stale references to Coder Agents User / agents-access remain in docs/.

Note

The new .../mcp-servers/{mcpserverconfig}/acl/available endpoint is reflected in the auto-generated Swagger/API reference, which doc-check does not flag directly.


Automated review via Coder Agents

> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.

The MCP server ACL client uses the promoted `/api/v2` route, but its
path assertion still expected the experimental compatibility route.

Update the assertion to match the v2 endpoint and restore the JavaScript
test suite.

(cherry picked from commit 20ca63d)
mtojek added a commit that referenced this pull request Aug 27, 2026
Batch backport of ibetitsmike's PRs that merged into `main` after the
`release/2.37` branch was cut (merge-base `c275327fb72`, 2026-08-24).

## Included (9 cherry-picks, in order)

| PR | Title |
|----|-------|
| #28470 | fix(coderd/x): surface Gemini malformed-function-call stream
deaths as retryable errors |
| #28471 | fix: apply MCP server selection when editing a chat message |
| #28460 | refactor: consolidate viewport hooks and remove
defineProperty matchMedia stub |
| #28476 | feat(coderd/x/chatd/chattool): improve find_tools relevance
and model guidance |
| #28400 | fix(coderd/x/chatd/mcpclient): enforce MCP connect budget and
unblock session cleanup |
| #28589 | fix(coderd/x/chatd): truncate overlong generated chat titles
instead of rejecting them |
| #28496 | feat: mount chat API routes under /api/v2 |
| #28497 | feat: promote codersdk chat API methods to Client |
| #28498 | feat(site): use /api/v2 chat API paths |

All picks applied cleanly with `git cherry-pick -x` onto `release/2.37`.

## Excluded and follow-up backports

The remaining post-cut PRs are cherry-picked onto this PR as a GitHub
stack (#28692) that merges bottom-up, so the dependency order is
enforced by the PR bases:

| Stack order | Original PR | Backport PR | Notes |
|-------------|-------------|-------------|-------|
| 1 | #28462 (repair failing Storybook stories) | #28687 | One fixture
adaptation: 2.37's `OrganizationModelsContextValue` has no
`organizations` field |
| 2 | #28186 (enable Coder Agents for organization members) | #28688 |
One story-assertion conflict resolved to the picked regex; ships no
migration by design |
| 3 | #28593 (allow sharing MCP servers with users and groups) | #28686
| Clean pick on top of #28688, plus the 1-line test fix #28657 (expect
v2 MCP ACL path) |
| 4 | #28659 (point MCP server ACL msw handlers at v2 paths) | #28689 |
Clean pick on top of #28686 |

Intentionally skipped: #28587 (restore agents-access cleanup migration).
Release branches cannot take a migration unless its sequence number
matches main with no gap.

## Validation

- `go build ./...` and test-binary compilation for `./coderd/...
./codersdk/... ./enterprise/... ./site` pass
- `pnpm check` and `pnpm lint:types` pass
- Targeted Vitest on all touched test files: unit 281/281 pass;
Storybook 180/181 pass. The single failure (`AgentChatPage.stories.tsx`
> Queued For Capacity After Polling) reproduces identically on the
untouched `release/2.37` baseline, so it is pre-existing and unrelated.

> Xum acted on Mike's behalf.
<!-- xum-attribution: model=claude-fable-5 thinking=high -->
…2-to-2.37

# Conflicts:
#	site/src/pages/AISettingsPage/ModelsPage/components/ModelFormProviderConfig.stories.tsx
# Conflicts:
#	site/src/pages/AISettingsPage/MCPServersPage/UpdateMCPServerPage/UpdateMCPServerPageView.tsx
#	site/src/pages/AISettingsPage/MCPServersPage/components/MCPServerForm.tsx
#	site/src/pages/AISettingsPage/MCPServersPage/components/MCPServerFormHeader.tsx
Base automatically changed from backport/28186-to-2.37 to release/2.37 August 27, 2026 07:27
@mtojek
mtojek self-requested a review August 27, 2026 07:28
@ibetitsmike

Copy link
Copy Markdown
Collaborator

Heads-up for whoever lands this: the current head 8353315 already reconciles the #28673 release drift. The three conflicting MCP files (MCPServerForm.tsx, MCPServerFormHeader.tsx, UpdateMCPServerPageView.tsx) plus the two MCP stories files are resolved to origin/main's exact content (redesigned header plus sharing), verified byte-identical to main. Squash-merging as-is lands exactly the sharing feature.

A fresh cherry-pick restack of #28593 onto release/2.37 would re-hit the same conflicts; if you do restack, the resolution is: take origin/main's version of those five files.

Xum acted on ibetitsmike's behalf.

@mtojek
mtojek merged commit 8f45d55 into release/2.37 Aug 27, 2026
34 checks passed
@mtojek
mtojek deleted the backport/28593-to-2.37 branch August 27, 2026 07:36
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cherry-pick/v2.37 Cherry-pick PR targeting release/2.37

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants