feat: add group and user ACLs to MCP server configs (#27944)

Adds group and user ACLs to org-scoped MCP server configs so
organizations can restrict specific MCP servers to subsets of members,
mirroring the template ACL pattern.

## Summary

- Migration adds `group_acl`/`user_acl` JSONB columns (nested `{"<id>":
{"permissions": [...]}}` shape) and seeds every existing config with its
organization's Everyone group read entry (the Everyone group ID equals
the org ID), so member access is unchanged by default. Creation seeds
the same entry.
- The blanket org-member read grant from the base PR is replaced by ACL
evaluation: Rego requires org membership for every ACL grant, and
`GetAuthorizedMCPServerConfigs` compiles ACL-aware SQL filters.
- New `ActionShare` (org admins) gates `GET|PATCH
/api/experimental/organizations/{organization}/mcp-servers/{mcpserverconfig}/acl`
(nested under the organization like the rest of the config surface).
PATCH validates principals against the config's organization, merges
sparse updates under a row lock, stamps `updated_by`/`updated_at`, and
is audited as a Write with `Old` captured before authorization. A config
deleted concurrently between the middleware fetch and the locked
re-fetch is concealed as 404, matching the update and delete handlers.
ACL columns are tracked in the audit table.
- ACL management is available in all editions (no enterprise
entitlement), documented in the MCP servers page. Revoking an ACL does
not retro-strip already-selected configs from existing chats; new
selection is blocked at chat create.
- Force On respects the ACL: the forced set is loaded as the chat owner,
so a `force_on` server whose ACL denies the owner never attaches at
create, send, or generation time.
- No rolling-upgrade machinery: upgrades run in scheduled maintenance
downtime, so the migration only backfills existing rows; the API sets
the Everyone read grant explicitly on every insert.

Stacked on #27943. Part of the MCP org-separation stack.

Closes https://linear.app/codercom/issue/CODAGT-712

UAT: verified on a dogfood instance with two members and a custom group:
Everyone-seed default visibility, group grant with Everyone removal
(non-member loses list/fetch/selection), foreign-principal rejection,
non-admin share denial (audited 403 / concealed 404), user_acl restore,
and audited ACL diffs.

> Mux (AI agent) authored this PR on Mike's behalf.

<!-- mux-attribution: model=claude-fable-5 thinking=high -->
This commit is contained in:
Michael Suchacz
2026-08-19 19:25:18 +00:00
committed by GitHub
parent 299e72ad30
commit 7ca7c30f40
46 changed files with 2114 additions and 132 deletions
+2
View File
@@ -43,7 +43,9 @@ const (
CheckGroupsChatSpendLimitMicrosCheck CheckConstraint = "groups_chat_spend_limit_micros_check" // groups
CheckMcpServerConfigsAuthTypeCheck CheckConstraint = "mcp_server_configs_auth_type_check" // mcp_server_configs
CheckMcpServerConfigsAvailabilityCheck CheckConstraint = "mcp_server_configs_availability_check" // mcp_server_configs
CheckMcpServerConfigsGroupAclIsObject CheckConstraint = "mcp_server_configs_group_acl_is_object" // mcp_server_configs
CheckMcpServerConfigsTransportCheck CheckConstraint = "mcp_server_configs_transport_check" // mcp_server_configs
CheckMcpServerConfigsUserAclIsObject CheckConstraint = "mcp_server_configs_user_acl_is_object" // mcp_server_configs
CheckOauth2ProviderAppCodesScopeNotEmpty CheckConstraint = "oauth2_provider_app_codes_scope_not_empty" // oauth2_provider_app_codes
CheckOauth2ProviderAppTokensScopeNotEmpty CheckConstraint = "oauth2_provider_app_tokens_scope_not_empty" // oauth2_provider_app_tokens
CheckOauth2ProviderAppsClientTypeCheck CheckConstraint = "oauth2_provider_apps_client_type_check" // oauth2_provider_apps
+7
View File
@@ -7677,6 +7677,13 @@ func (q *querier) UpdateMCPServerConfig(ctx context.Context, arg database.Update
return q.db.UpdateMCPServerConfig(ctx, arg)
}
func (q *querier) UpdateMCPServerConfigACLByID(ctx context.Context, arg database.UpdateMCPServerConfigACLByIDParams) error {
fetch := func(ctx context.Context, arg database.UpdateMCPServerConfigACLByIDParams) (database.MCPServerConfig, error) {
return q.db.GetMCPServerConfigByID(ctx, arg.ID)
}
return fetchAndExec(q.log, q.auth, policy.ActionShare, fetch, q.db.UpdateMCPServerConfigACLByID)(ctx, arg)
}
func (q *querier) UpdateMCPServerUserTokenFromRefresh(ctx context.Context, arg database.UpdateMCPServerUserTokenFromRefreshParams) (database.MCPServerUserToken, error) {
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceDeploymentConfig); err != nil {
return database.MCPServerUserToken{}, err
+7
View File
@@ -1735,6 +1735,13 @@ func (s *MethodTestSuite) TestChats() {
dbm.EXPECT().InsertMCPServerConfig(gomock.Any(), arg).Return(config, nil).AnyTimes()
check.Args(arg).Asserts(rbac.ResourceMCPServerConfig.InOrg(arg.OrganizationID), policy.ActionCreate).Returns(config)
}))
s.Run("UpdateMCPServerConfigACLByID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
config := testutil.Fake(s.T(), faker, database.MCPServerConfig{})
arg := database.UpdateMCPServerConfigACLByIDParams{ID: config.ID, UpdatedBy: uuid.New()}
dbm.EXPECT().GetMCPServerConfigByID(gomock.Any(), config.ID).Return(config, nil).AnyTimes()
dbm.EXPECT().UpdateMCPServerConfigACLByID(gomock.Any(), arg).Return(nil).AnyTimes()
check.Args(arg).Asserts(config, policy.ActionShare)
}))
s.Run("UpdateChatMCPServerIDs", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
chat := testutil.Fake(s.T(), faker, database.Chat{})
arg := database.UpdateChatMCPServerIDsParams{
+13
View File
@@ -347,6 +347,17 @@ func MCPServerConfig(t testing.TB, db database.Store, seed database.MCPServerCon
updatedBy = createdBy
}
groupACL := seed.GroupACL
if groupACL == nil {
groupACL = database.ChatACL{
organizationID.String(): {Permissions: []policy.Action{policy.ActionRead}},
}
}
userACL := seed.UserACL
if userACL == nil {
userACL = database.ChatACL{}
}
cfg, err := db.InsertMCPServerConfig(genCtx, database.InsertMCPServerConfigParams{
ID: takeFirst(seed.ID, uuid.New()),
OrganizationID: organizationID,
@@ -376,6 +387,8 @@ func MCPServerConfig(t testing.TB, db database.Store, seed database.MCPServerCon
ModelIntent: seed.ModelIntent,
AllowInPlanMode: seed.AllowInPlanMode,
ForwardCoderHeaders: seed.ForwardCoderHeaders,
GroupACL: groupACL,
UserACL: userACL,
CreatedBy: createdBy,
UpdatedBy: updatedBy,
})
+8
View File
@@ -5449,6 +5449,14 @@ func (m queryMetricsStore) UpdateMCPServerConfig(ctx context.Context, arg databa
return r0, r1
}
func (m queryMetricsStore) UpdateMCPServerConfigACLByID(ctx context.Context, arg database.UpdateMCPServerConfigACLByIDParams) error {
start := time.Now()
r0 := m.s.UpdateMCPServerConfigACLByID(ctx, arg)
m.queryLatencies.WithLabelValues("UpdateMCPServerConfigACLByID").Observe(time.Since(start).Seconds())
m.queryCounts.WithLabelValues(httpmw.ExtractHTTPRoute(ctx), httpmw.ExtractHTTPMethod(ctx), "UpdateMCPServerConfigACLByID").Inc()
return r0
}
func (m queryMetricsStore) UpdateMCPServerUserTokenFromRefresh(ctx context.Context, arg database.UpdateMCPServerUserTokenFromRefreshParams) (database.MCPServerUserToken, error) {
start := time.Now()
r0, r1 := m.s.UpdateMCPServerUserTokenFromRefresh(ctx, arg)
+14
View File
@@ -10310,6 +10310,20 @@ func (mr *MockStoreMockRecorder) UpdateMCPServerConfig(ctx, arg any) *gomock.Cal
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateMCPServerConfig", reflect.TypeOf((*MockStore)(nil).UpdateMCPServerConfig), ctx, arg)
}
// UpdateMCPServerConfigACLByID mocks base method.
func (m *MockStore) UpdateMCPServerConfigACLByID(ctx context.Context, arg database.UpdateMCPServerConfigACLByIDParams) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateMCPServerConfigACLByID", ctx, arg)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateMCPServerConfigACLByID indicates an expected call of UpdateMCPServerConfigACLByID.
func (mr *MockStoreMockRecorder) UpdateMCPServerConfigACLByID(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateMCPServerConfigACLByID", reflect.TypeOf((*MockStore)(nil).UpdateMCPServerConfigACLByID), ctx, arg)
}
// UpdateMCPServerUserTokenFromRefresh mocks base method.
func (m *MockStore) UpdateMCPServerUserTokenFromRefresh(ctx context.Context, arg database.UpdateMCPServerUserTokenFromRefreshParams) (database.MCPServerUserToken, error) {
m.ctrl.T.Helper()
+7 -2
View File
@@ -278,7 +278,8 @@ CREATE TYPE api_key_scope AS ENUM (
'mcp_server_config:create',
'mcp_server_config:read',
'mcp_server_config:update',
'mcp_server_config:delete'
'mcp_server_config:delete',
'mcp_server_config:share'
);
CREATE TYPE app_sharing_level AS ENUM (
@@ -2521,9 +2522,13 @@ CREATE TABLE mcp_server_configs (
forward_coder_headers boolean DEFAULT false NOT NULL,
oauth2_revocation_url text DEFAULT ''::text NOT NULL,
organization_id uuid NOT NULL,
group_acl jsonb DEFAULT '{}'::jsonb NOT NULL,
user_acl jsonb DEFAULT '{}'::jsonb NOT NULL,
CONSTRAINT mcp_server_configs_auth_type_check CHECK ((auth_type = ANY (ARRAY['none'::text, 'oauth2'::text, 'api_key'::text, 'custom_headers'::text, 'user_oidc'::text]))),
CONSTRAINT mcp_server_configs_availability_check CHECK ((availability = ANY (ARRAY['force_on'::text, 'default_on'::text, 'default_off'::text]))),
CONSTRAINT mcp_server_configs_transport_check CHECK ((transport = ANY (ARRAY['streamable_http'::text, 'sse'::text])))
CONSTRAINT mcp_server_configs_group_acl_is_object CHECK ((jsonb_typeof(group_acl) = 'object'::text)),
CONSTRAINT mcp_server_configs_transport_check CHECK ((transport = ANY (ARRAY['streamable_http'::text, 'sse'::text]))),
CONSTRAINT mcp_server_configs_user_acl_is_object CHECK ((jsonb_typeof(user_acl) = 'object'::text))
);
CREATE TABLE mcp_server_user_tokens (
@@ -0,0 +1,6 @@
ALTER TABLE mcp_server_configs
DROP COLUMN group_acl,
DROP COLUMN user_acl;
-- Enum values cannot be removed safely from api_key_scope, so the
-- share scope added by the up migration stays.
@@ -0,0 +1,13 @@
ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'mcp_server_config:share';
ALTER TABLE mcp_server_configs
ADD COLUMN group_acl JSONB NOT NULL DEFAULT '{}'::JSONB,
ADD COLUMN user_acl JSONB NOT NULL DEFAULT '{}'::JSONB,
ADD CONSTRAINT mcp_server_configs_group_acl_is_object CHECK (jsonb_typeof(group_acl) = 'object'),
ADD CONSTRAINT mcp_server_configs_user_acl_is_object CHECK (jsonb_typeof(user_acl) = 'object');
UPDATE mcp_server_configs
SET group_acl = jsonb_build_object(
organization_id::text,
jsonb_build_object('permissions', jsonb_build_array('read'))
);
@@ -3239,3 +3239,93 @@ func TestMigration000574MCPServerConfigsOrganizationID(t *testing.T) {
require.NoError(t, err)
require.Zero(t, danglingIDs)
}
func TestMigration000576MCPServerConfigACL(t *testing.T) {
t.Parallel()
const priorMigrationVersion = 575
sqlDB := testSQLDB(t)
next, err := migrations.Stepper(sqlDB)
require.NoError(t, err)
for {
version, more, err := next()
require.NoError(t, err)
if !more {
t.Fatalf("migration %d not found", priorMigrationVersion)
}
if version == priorMigrationVersion {
break
}
}
ctx := testutil.Context(t, testutil.WaitSuperLong)
now := time.Now().UTC().Truncate(time.Microsecond)
var defaultOrgID uuid.UUID
err = sqlDB.QueryRowContext(ctx, `SELECT id FROM organizations WHERE is_default = true`).Scan(&defaultOrgID)
require.NoError(t, err)
orgID := uuid.New()
_, err = sqlDB.ExecContext(ctx, `
INSERT INTO organizations (
id, name, display_name, description, icon, created_at, updated_at,
is_default, deleted, default_org_member_roles
) VALUES ($1, 'migration-570-org', 'Migration 570 Org', '', '', $2, $2, false, false, '{}')
`, orgID, now)
require.NoError(t, err)
configIDs := []uuid.UUID{uuid.New(), uuid.New()}
orgIDs := []uuid.UUID{defaultOrgID, orgID}
for i, configID := range configIDs {
_, err = sqlDB.ExecContext(ctx, `
INSERT INTO mcp_server_configs (
id, organization_id, display_name, slug, description, url, auth_type,
availability, enabled, created_at, updated_at
) VALUES ($1, $2, $3, $4, 'unchanged', $5, 'none', 'default_on', true, $6, $6)
`, configID, orgIDs[i], fmt.Sprintf("Migration 570 Config %d", i), fmt.Sprintf("migration-570-config-%d", i), fmt.Sprintf("https://mcp.example.com/%d", i), now)
require.NoError(t, err)
}
version, _, err := next()
require.NoError(t, err)
require.EqualValues(t, 576, version)
for i, configID := range configIDs {
var displayName, description string
var enabled bool
var groupACL, userACL string
err = sqlDB.QueryRowContext(ctx, `
SELECT display_name, description, enabled, group_acl::text, user_acl::text
FROM mcp_server_configs WHERE id = $1
`, configID).Scan(&displayName, &description, &enabled, &groupACL, &userACL)
require.NoError(t, err)
require.Equal(t, fmt.Sprintf("Migration 570 Config %d", i), displayName)
require.Equal(t, "unchanged", description)
require.True(t, enabled)
require.JSONEq(t, fmt.Sprintf(`{%q:{"permissions":["read"]}}`, orgIDs[i].String()), groupACL)
require.JSONEq(t, `{}`, userACL)
}
for _, column := range []string{"group_acl", "user_acl"} {
var defaultValue string
err = sqlDB.QueryRowContext(ctx, `
SELECT column_default FROM information_schema.columns
WHERE table_name = 'mcp_server_configs' AND column_name = $1
`, column).Scan(&defaultValue)
require.NoError(t, err)
require.Equal(t, "'{}'::jsonb", defaultValue)
}
downSQL, err := os.ReadFile("000576_mcp_server_config_acl.down.sql")
require.NoError(t, err)
_, err = sqlDB.ExecContext(ctx, string(downSQL))
require.NoError(t, err)
var aclColumns int
err = sqlDB.QueryRowContext(ctx, `
SELECT COUNT(*) FROM information_schema.columns
WHERE table_name = 'mcp_server_configs' AND column_name IN ('group_acl', 'user_acl')
`).Scan(&aclColumns)
require.NoError(t, err)
require.Zero(t, aclColumns)
}
@@ -0,0 +1,17 @@
INSERT INTO mcp_server_configs (
id,
organization_id,
display_name,
slug,
url,
auth_type,
group_acl
) VALUES (
'f5690000-0000-4000-8000-000000000001',
'f5610000-0000-4000-8000-000000000001',
'Fixture MCP ACL Server',
'fixture-mcp-acl-server',
'https://mcp.example.com/acl',
'none',
'{"f5610000-0000-4000-8000-000000000001":{"permissions":["read"]}}'::JSONB
);
+3 -1
View File
@@ -230,7 +230,9 @@ func (c Chat) RBACObject() rbac.Object {
func (m MCPServerConfig) RBACObject() rbac.Object {
return rbac.ResourceMCPServerConfig.
WithID(m.ID).
InOrg(m.OrganizationID)
InOrg(m.OrganizationID).
WithGroupACL(m.GroupACL.RBACACL()).
WithACLUserList(m.UserACL.RBACACL())
}
func (c Chat) IsSubChat() bool {
+3 -1
View File
@@ -1207,7 +1207,7 @@ type mcpServerConfigQuerier interface {
func (q *sqlQuerier) GetAuthorizedMCPServerConfigs(ctx context.Context, organizationID uuid.UUID, prepared rbac.PreparedAuthorized) ([]MCPServerConfig, error) {
authorizedFilter, err := prepared.CompileToSQL(ctx, regosql.ConvertConfig{
VariableConverter: regosql.MCPServerConfigNoACLConverter(),
VariableConverter: regosql.MCPServerConfigConverter(),
})
if err != nil {
return nil, xerrors.Errorf("compile authorized filter: %w", err)
@@ -1261,6 +1261,8 @@ func (q *sqlQuerier) GetAuthorizedMCPServerConfigs(ctx context.Context, organiza
&i.ForwardCoderHeaders,
&i.OAuth2RevocationURL,
&i.OrganizationID,
&i.GroupACL,
&i.UserACL,
); err != nil {
return nil, err
}
+6 -1
View File
@@ -470,6 +470,7 @@ const (
ApiKeyScopeMcpServerConfigRead APIKeyScope = "mcp_server_config:read"
ApiKeyScopeMcpServerConfigUpdate APIKeyScope = "mcp_server_config:update"
ApiKeyScopeMcpServerConfigDelete APIKeyScope = "mcp_server_config:delete"
ApiKeyScopeMcpServerConfigShare APIKeyScope = "mcp_server_config:share"
)
func (e *APIKeyScope) Scan(src interface{}) error {
@@ -749,7 +750,8 @@ func (e APIKeyScope) Valid() bool {
ApiKeyScopeMcpServerConfigCreate,
ApiKeyScopeMcpServerConfigRead,
ApiKeyScopeMcpServerConfigUpdate,
ApiKeyScopeMcpServerConfigDelete:
ApiKeyScopeMcpServerConfigDelete,
ApiKeyScopeMcpServerConfigShare:
return true
}
return false
@@ -998,6 +1000,7 @@ func AllAPIKeyScopeValues() []APIKeyScope {
ApiKeyScopeMcpServerConfigRead,
ApiKeyScopeMcpServerConfigUpdate,
ApiKeyScopeMcpServerConfigDelete,
ApiKeyScopeMcpServerConfigShare,
}
}
@@ -5474,6 +5477,8 @@ type MCPServerConfig struct {
ForwardCoderHeaders bool `db:"forward_coder_headers" json:"forward_coder_headers"`
OAuth2RevocationURL string `db:"oauth2_revocation_url" json:"oauth2_revocation_url"`
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
GroupACL ChatACL `db:"group_acl" json:"group_acl"`
UserACL ChatACL `db:"user_acl" json:"user_acl"`
}
type MCPServerUserToken struct {
+1
View File
@@ -1505,6 +1505,7 @@ type sqlcQuerier interface {
UpdateInactiveUsersToDormant(ctx context.Context, arg UpdateInactiveUsersToDormantParams) ([]UpdateInactiveUsersToDormantRow, error)
UpdateInboxNotificationReadStatus(ctx context.Context, arg UpdateInboxNotificationReadStatusParams) error
UpdateMCPServerConfig(ctx context.Context, arg UpdateMCPServerConfigParams) (MCPServerConfig, error)
UpdateMCPServerConfigACLByID(ctx context.Context, arg UpdateMCPServerConfigACLByIDParams) error
// Refresh persistence must not recreate a token deleted by disconnect.
// The optimistic lock also prevents stale refreshes from replacing newer tokens.
UpdateMCPServerUserTokenFromRefresh(ctx context.Context, arg UpdateMCPServerUserTokenFromRefreshParams) (MCPServerUserToken, error)
+65 -11
View File
@@ -17147,7 +17147,7 @@ func (q *sqlQuerier) DeleteMCPServerUserTokensByConfigID(ctx context.Context, mc
const getEnabledMCPServerConfigsByOrganization = `-- name: GetEnabledMCPServerConfigsByOrganization :many
SELECT
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id, group_acl, user_acl
FROM
mcp_server_configs
WHERE
@@ -17199,6 +17199,8 @@ func (q *sqlQuerier) GetEnabledMCPServerConfigsByOrganization(ctx context.Contex
&i.ForwardCoderHeaders,
&i.OAuth2RevocationURL,
&i.OrganizationID,
&i.GroupACL,
&i.UserACL,
); err != nil {
return nil, err
}
@@ -17215,7 +17217,7 @@ func (q *sqlQuerier) GetEnabledMCPServerConfigsByOrganization(ctx context.Contex
const getEnabledMCPServerConfigsByOrganizationAndIDs = `-- name: GetEnabledMCPServerConfigsByOrganizationAndIDs :many
SELECT
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id, group_acl, user_acl
FROM
mcp_server_configs
WHERE
@@ -17273,6 +17275,8 @@ func (q *sqlQuerier) GetEnabledMCPServerConfigsByOrganizationAndIDs(ctx context.
&i.ForwardCoderHeaders,
&i.OAuth2RevocationURL,
&i.OrganizationID,
&i.GroupACL,
&i.UserACL,
); err != nil {
return nil, err
}
@@ -17289,7 +17293,7 @@ func (q *sqlQuerier) GetEnabledMCPServerConfigsByOrganizationAndIDs(ctx context.
const getForcedMCPServerConfigsByOrganization = `-- name: GetForcedMCPServerConfigsByOrganization :many
SELECT
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id, group_acl, user_acl
FROM
mcp_server_configs
WHERE
@@ -17342,6 +17346,8 @@ func (q *sqlQuerier) GetForcedMCPServerConfigsByOrganization(ctx context.Context
&i.ForwardCoderHeaders,
&i.OAuth2RevocationURL,
&i.OrganizationID,
&i.GroupACL,
&i.UserACL,
); err != nil {
return nil, err
}
@@ -17358,7 +17364,7 @@ func (q *sqlQuerier) GetForcedMCPServerConfigsByOrganization(ctx context.Context
const getMCPServerConfigByID = `-- name: GetMCPServerConfigByID :one
SELECT
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id, group_acl, user_acl
FROM
mcp_server_configs
WHERE
@@ -17401,13 +17407,15 @@ func (q *sqlQuerier) GetMCPServerConfigByID(ctx context.Context, id uuid.UUID) (
&i.ForwardCoderHeaders,
&i.OAuth2RevocationURL,
&i.OrganizationID,
&i.GroupACL,
&i.UserACL,
)
return i, err
}
const getMCPServerConfigByIDForUpdate = `-- name: GetMCPServerConfigByIDForUpdate :one
SELECT
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id, group_acl, user_acl
FROM
mcp_server_configs
WHERE
@@ -17451,13 +17459,15 @@ func (q *sqlQuerier) GetMCPServerConfigByIDForUpdate(ctx context.Context, id uui
&i.ForwardCoderHeaders,
&i.OAuth2RevocationURL,
&i.OrganizationID,
&i.GroupACL,
&i.UserACL,
)
return i, err
}
const getMCPServerConfigByOrganizationAndSlug = `-- name: GetMCPServerConfigByOrganizationAndSlug :one
SELECT
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id, group_acl, user_acl
FROM
mcp_server_configs
WHERE
@@ -17506,13 +17516,15 @@ func (q *sqlQuerier) GetMCPServerConfigByOrganizationAndSlug(ctx context.Context
&i.ForwardCoderHeaders,
&i.OAuth2RevocationURL,
&i.OrganizationID,
&i.GroupACL,
&i.UserACL,
)
return i, err
}
const getMCPServerConfigsByOrganization = `-- name: GetMCPServerConfigsByOrganization :many
SELECT
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id, group_acl, user_acl
FROM
mcp_server_configs
WHERE
@@ -17565,6 +17577,8 @@ func (q *sqlQuerier) GetMCPServerConfigsByOrganization(ctx context.Context, orga
&i.ForwardCoderHeaders,
&i.OAuth2RevocationURL,
&i.OrganizationID,
&i.GroupACL,
&i.UserACL,
); err != nil {
return nil, err
}
@@ -17689,6 +17703,8 @@ INSERT INTO mcp_server_configs (
model_intent,
allow_in_plan_mode,
forward_coder_headers,
group_acl,
user_acl,
created_by,
updated_by
) VALUES (
@@ -17720,11 +17736,13 @@ INSERT INTO mcp_server_configs (
$26::boolean,
$27::boolean,
$28::boolean,
$29::uuid,
$30::uuid
$29,
$30,
$31::uuid,
$32::uuid
)
RETURNING
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id, group_acl, user_acl
`
type InsertMCPServerConfigParams struct {
@@ -17756,6 +17774,8 @@ type InsertMCPServerConfigParams struct {
ModelIntent bool `db:"model_intent" json:"model_intent"`
AllowInPlanMode bool `db:"allow_in_plan_mode" json:"allow_in_plan_mode"`
ForwardCoderHeaders bool `db:"forward_coder_headers" json:"forward_coder_headers"`
GroupACL ChatACL `db:"group_acl" json:"group_acl"`
UserACL ChatACL `db:"user_acl" json:"user_acl"`
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
UpdatedBy uuid.UUID `db:"updated_by" json:"updated_by"`
}
@@ -17790,6 +17810,8 @@ func (q *sqlQuerier) InsertMCPServerConfig(ctx context.Context, arg InsertMCPSer
arg.ModelIntent,
arg.AllowInPlanMode,
arg.ForwardCoderHeaders,
arg.GroupACL,
arg.UserACL,
arg.CreatedBy,
arg.UpdatedBy,
)
@@ -17827,6 +17849,8 @@ func (q *sqlQuerier) InsertMCPServerConfig(ctx context.Context, arg InsertMCPSer
&i.ForwardCoderHeaders,
&i.OAuth2RevocationURL,
&i.OrganizationID,
&i.GroupACL,
&i.UserACL,
)
return i, err
}
@@ -17914,7 +17938,7 @@ SET
WHERE
id = $28::uuid
RETURNING
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id
id, display_name, slug, description, icon_url, transport, url, auth_type, oauth2_client_id, oauth2_client_secret, oauth2_client_secret_key_id, oauth2_auth_url, oauth2_token_url, oauth2_scopes, api_key_header, api_key_value, api_key_value_key_id, custom_headers, custom_headers_key_id, tool_allow_list, tool_deny_list, availability, enabled, created_by, updated_by, created_at, updated_at, model_intent, allow_in_plan_mode, forward_coder_headers, oauth2_revocation_url, organization_id, group_acl, user_acl
`
type UpdateMCPServerConfigParams struct {
@@ -18013,10 +18037,40 @@ func (q *sqlQuerier) UpdateMCPServerConfig(ctx context.Context, arg UpdateMCPSer
&i.ForwardCoderHeaders,
&i.OAuth2RevocationURL,
&i.OrganizationID,
&i.GroupACL,
&i.UserACL,
)
return i, err
}
const updateMCPServerConfigACLByID = `-- name: UpdateMCPServerConfigACLByID :exec
UPDATE mcp_server_configs
SET
group_acl = $1,
user_acl = $2,
updated_by = $3::uuid,
updated_at = NOW()
WHERE
id = $4::uuid
`
type UpdateMCPServerConfigACLByIDParams struct {
GroupACL ChatACL `db:"group_acl" json:"group_acl"`
UserACL ChatACL `db:"user_acl" json:"user_acl"`
UpdatedBy uuid.UUID `db:"updated_by" json:"updated_by"`
ID uuid.UUID `db:"id" json:"id"`
}
func (q *sqlQuerier) UpdateMCPServerConfigACLByID(ctx context.Context, arg UpdateMCPServerConfigACLByIDParams) error {
_, err := q.db.ExecContext(ctx, updateMCPServerConfigACLByID,
arg.GroupACL,
arg.UserACL,
arg.UpdatedBy,
arg.ID,
)
return err
}
const updateMCPServerUserTokenFromRefresh = `-- name: UpdateMCPServerUserTokenFromRefresh :one
UPDATE mcp_server_user_tokens
SET
@@ -101,6 +101,8 @@ INSERT INTO mcp_server_configs (
model_intent,
allow_in_plan_mode,
forward_coder_headers,
group_acl,
user_acl,
created_by,
updated_by
) VALUES (
@@ -132,6 +134,8 @@ INSERT INTO mcp_server_configs (
@model_intent::boolean,
@allow_in_plan_mode::boolean,
@forward_coder_headers::boolean,
@group_acl,
@user_acl,
@created_by::uuid,
@updated_by::uuid
)
@@ -175,6 +179,16 @@ WHERE
RETURNING
*;
-- name: UpdateMCPServerConfigACLByID :exec
UPDATE mcp_server_configs
SET
group_acl = @group_acl,
user_acl = @user_acl,
updated_by = @updated_by::uuid,
updated_at = NOW()
WHERE
id = @id::uuid;
-- name: DeleteMCPServerConfigByID :exec
DELETE FROM
mcp_server_configs
+6
View File
@@ -83,6 +83,12 @@ sql:
- column: "chats.group_acl"
go_type:
type: "ChatACL"
- column: "mcp_server_configs.user_acl"
go_type:
type: "ChatACL"
- column: "mcp_server_configs.group_acl"
go_type:
type: "ChatACL"
- column: "chats_expanded.user_acl"
go_type:
type: "ChatACL"