mirror of
https://github.com/coder/coder.git
synced 2026-10-31 11:02:50 +08:00
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:
Generated
+2
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
Generated
+14
@@ -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()
|
||||
|
||||
Generated
+7
-2
@@ -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)
|
||||
}
|
||||
|
||||
+17
@@ -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
|
||||
);
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Generated
+6
-1
@@ -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 {
|
||||
|
||||
Generated
+1
@@ -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)
|
||||
|
||||
Generated
+65
-11
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user