Files
coder/site/permissions.json
T
Michael Suchacz 24b83dc727 feat: add organization picker to MCP server settings pages (#28150)
Adds an organization picker to the MCP server settings pages so
multi-org deployments can manage every organization's MCP servers
through the UI, not just the default organization's. Closes CODAGT-714
(scoped to MCP servers only; model configs stay deployment-wide until
CODAGT-709 lands).

## Stack Context

Top of the CODAGT-711/717/712/806 stack: MCP server configs are
org-scoped with RBAC, audit logging, per-config ACLs, and owner-scoped
user tokens. This layer makes the admin UI org-aware, resolving the
"default org only" limitation documented in the bottom PR.

## Summary

- The MCP servers list and add pages resolve the working organization
from an `org` search param (falling back to the default org), and render
an organization picker built on the existing `OrganizationAutocomplete`.
The picker only appears when more than one organization is visible, so
single-org deployments see no change.
- Selecting an organization rewrites the search param, refetches the
list for that org, and threads through to the add page so creation posts
to the selected organization.
- The update page now loads the server by ID (new organization-scoped
`GET /api/experimental/organizations/{organization}/mcp-servers/{id}`
frontend binding) instead of listing the default org and searching
client-side, so servers from any organization can be edited. Post-save
navigation returns to the owning organization's list via the server's
`organization_id`.
- Removes the now-unused `getDefaultOrganizationId` helper.
- Review hardening: organization display labels are disambiguated with
the unique org name when effective display names collide (picker
options, trigger text, and accessible name). Access is no longer
restricted to deployment admins: the pages, sidebar item, and nav entry
accept org-scoped `mcp_server_config` permissions, the picker lists only
organizations the user can view, content and affordances (add, edit,
delete) are gated on the selected organization's permissions, and
deployment admins keep full access everywhere.

## Testing

Storybook interaction stories cover: picker hidden with one org,
switching orgs refetches and swaps list contents, add posting to the
URL-selected org, add posting after an in-form org switch (asserting
typed form state survives the switch), and update loading by ID.
Red-green verified by breaking the search-param resolution and observing
the new stories fail.

> Mux acted on Mike's behalf for this PR.
2026-08-19 19:46:23 +00:00

159 lines
3.9 KiB
JSON

{
"viewAllUsers": {
"object": { "resource_type": "user" },
"action": "read"
},
"updateUsers": {
"object": { "resource_type": "user" },
"action": "update"
},
"createUser": {
"object": { "resource_type": "user" },
"action": "create"
},
"createTemplates": {
"object": { "resource_type": "template", "any_org": true },
"action": "create"
},
"createWorkspace": {
"object": {
"resource_type": "workspace",
"any_org": true,
"owner_id": "me"
},
"action": "create"
},
"updateTemplates": {
"object": { "resource_type": "template" },
"action": "update"
},
"deleteTemplates": {
"object": { "resource_type": "template" },
"action": "delete"
},
"viewDeploymentConfig": {
"object": { "resource_type": "deployment_config" },
"action": "read"
},
"editDeploymentConfig": {
"object": { "resource_type": "deployment_config" },
"action": "update"
},
"viewDeploymentStats": {
"object": { "resource_type": "deployment_stats" },
"action": "read"
},
"readWorkspaceProxies": {
"object": { "resource_type": "workspace_proxy" },
"action": "read"
},
"editWorkspaceProxies": {
"object": { "resource_type": "workspace_proxy" },
"action": "create"
},
"createOrganization": {
"object": { "resource_type": "organization" },
"action": "create"
},
"viewAnyGroup": {
"object": { "resource_type": "group" },
"action": "read"
},
"createGroup": {
"object": { "resource_type": "group" },
"action": "create"
},
"viewAllLicenses": {
"object": { "resource_type": "license" },
"action": "read"
},
"viewNotificationTemplate": {
"object": { "resource_type": "notification_template" },
"action": "read"
},
"viewOrganizationIDPSyncSettings": {
"object": { "resource_type": "idpsync_settings" },
"action": "read"
},
"viewAnyMembers": {
"object": { "resource_type": "organization_member", "any_org": true },
"action": "read"
},
"editAnyGroups": {
"object": { "resource_type": "group", "any_org": true },
"action": "update"
},
"assignAnyRoles": {
"object": { "resource_type": "assign_org_role", "any_org": true },
"action": "assign"
},
"viewAnyIdpSyncSettings": {
"object": { "resource_type": "idpsync_settings", "any_org": true },
"action": "read"
},
"viewAnyMCPServerConfigs": {
"object": { "resource_type": "mcp_server_config", "any_org": true },
"action": "read"
},
"createAnyMCPServerConfig": {
"object": { "resource_type": "mcp_server_config", "any_org": true },
"action": "create"
},
"updateAnyMCPServerConfig": {
"object": { "resource_type": "mcp_server_config", "any_org": true },
"action": "update"
},
"deleteAnyMCPServerConfig": {
"object": { "resource_type": "mcp_server_config", "any_org": true },
"action": "delete"
},
"editAnySettings": {
"object": { "resource_type": "organization", "any_org": true },
"action": "update"
},
"viewAnyAuditLog": {
"object": { "resource_type": "audit_log", "any_org": true },
"action": "read"
},
"viewAnyConnectionLog": {
"object": { "resource_type": "connection_log", "any_org": true },
"action": "read"
},
"viewDebugInfo": {
"object": { "resource_type": "debug_info" },
"action": "read"
},
"viewAnyAIBridgeInterception": {
"object": { "resource_type": "aibridge_interception", "any_org": true },
"action": "read"
},
"viewAnyAIProvider": {
"object": { "resource_type": "ai_provider" },
"action": "read"
},
"viewAIGatewayKeys": {
"object": { "resource_type": "ai_gateway_key" },
"action": "read"
},
"createOAuth2App": {
"object": { "resource_type": "oauth2_app" },
"action": "create"
},
"editOAuth2App": {
"object": { "resource_type": "oauth2_app" },
"action": "update"
},
"deleteOAuth2App": {
"object": { "resource_type": "oauth2_app" },
"action": "delete"
},
"viewOAuth2AppSecrets": {
"object": { "resource_type": "oauth2_app_secret" },
"action": "read"
},
"createChat": {
"object": { "resource_type": "chat", "any_org": true, "owner_id": "me" },
"action": "create"
}
}