feat(mcp): add resource group scopes with permission inheritance

This commit is contained in:
二丫讲梵 authored and GitHub committed 2026-09-07 02:18:28 +08:00
1 parent 2eaf7f9914
commit 691ecd084b
31 files changed
+2398 -1047

No files matched your search

@@ -493,8 +493,10 @@ describe("normalizeMcpGlobalPolicy", () => {
readOnly: false,
allowDangerousSql: false,
allowedConnectionIds: null,
allowedGroupIds: [],
allowedToolNames: null,
connectionPolicies: [],
groupPolicies: [],
configured: false,
queryTimeoutSecs: null,
});
@@ -512,8 +514,10 @@ describe("normalizeMcpGlobalPolicy", () => {
readOnly: true,
allowDangerousSql: true,
allowedConnectionIds: ["connection-1", "connection-2"],
allowedGroupIds: [],
allowedToolNames: null,
connectionPolicies: [],
groupPolicies: [],
configured: true,
queryTimeoutSecs: null,
});
@@ -811,8 +815,10 @@ describe("settingsStore MCP policy persistence", () => {
readOnly: true,
allowDangerousSql: false,
allowedConnectionIds: ["connection-1"],
allowedGroupIds: [],
allowedToolNames: null,
connectionPolicies: [],
groupPolicies: [],
configured: true,
queryTimeoutSecs: null,
};
@@ -826,8 +832,10 @@ describe("settingsStore MCP policy persistence", () => {
readOnly: false,
allowDangerousSql: false,
allowedConnectionIds: [],
allowedGroupIds: [],
allowedToolNames: null,
connectionPolicies: [],
groupPolicies: [],
configured: true,
queryTimeoutSecs: null,
});
+29
View File
@@ -53,13 +53,21 @@ export interface McpGlobalPolicy {
readOnly: boolean;
allowDangerousSql: boolean;
allowedConnectionIds: string[] | null;
allowedGroupIds: string[];
allowedToolNames: string[] | null;
connectionPolicies: McpConnectionPolicy[];
groupPolicies: McpGroupPolicy[];
configured: boolean;
/** MCP query timeout override in seconds. null/undefined = inherit the connection; 0 = no limit. */
queryTimeoutSecs: number | null;
}
export interface McpGroupPolicy {
groupId: string;
readOnly: boolean;
allowDangerousSql: boolean;
}
export interface McpConnectionPolicy {
connectionId: string;
readOnly: boolean;
@@ -113,14 +121,17 @@ export const DEFAULT_MCP_GLOBAL_POLICY: McpGlobalPolicy = {
readOnly: false,
allowDangerousSql: false,
allowedConnectionIds: null,
allowedGroupIds: [],
allowedToolNames: null,
connectionPolicies: [],
groupPolicies: [],
configured: false,
queryTimeoutSecs: null,
};
export function normalizeMcpGlobalPolicy(policy: Partial<McpGlobalPolicy> | null | undefined): McpGlobalPolicy {
const allowedConnectionIds = policy?.allowedConnectionIds === null || policy?.allowedConnectionIds === undefined ? null : [...new Set(policy.allowedConnectionIds.filter((id): id is string => typeof id === "string" && id.trim().length > 0).map((id) => id.trim()))];
const allowedGroupIds = allowedConnectionIds === null ? [] : [...new Set((policy?.allowedGroupIds ?? []).filter((id): id is string => typeof id === "string" && id.trim().length > 0).map((id) => id.trim()))];
const allowedToolNames = policy?.allowedToolNames === null || policy?.allowedToolNames === undefined ? null : [...new Set(policy.allowedToolNames.filter((name): name is string => typeof name === "string" && name.trim().length > 0).map((name) => name.trim()))];
const connectionPolicies = Object.values(
(policy?.connectionPolicies ?? []).reduce<Record<string, McpConnectionPolicy>>((rules, rule) => {
@@ -156,6 +167,20 @@ export function normalizeMcpGlobalPolicy(policy: Partial<McpGlobalPolicy> | null
return rules;
}, {}),
);
const groupPolicies = Object.values(
(policy?.groupPolicies ?? []).reduce<Record<string, McpGroupPolicy>>((rules, rule) => {
if (!rule || typeof rule.groupId !== "string" || !rule.groupId.trim()) return rules;
const groupId = rule.groupId.trim();
const current = rules[groupId];
const readOnly = current?.readOnly === true || rule.readOnly === true;
rules[groupId] = {
groupId,
readOnly,
allowDangerousSql: !readOnly && (current ? current.allowDangerousSql && rule.allowDangerousSql === true : rule.allowDangerousSql === true),
};
return rules;
}, {}),
);
// null / undefined / non-positive => null (inherit connection). 0 is preserved
// as an explicit "no limit" only here; the UI maps "no limit" <=> 0 and
// "inherit" <=> null.
@@ -164,8 +189,10 @@ export function normalizeMcpGlobalPolicy(policy: Partial<McpGlobalPolicy> | null
readOnly: policy?.readOnly === true,
allowDangerousSql: policy?.allowDangerousSql === true,
allowedConnectionIds,
allowedGroupIds,
allowedToolNames,
connectionPolicies,
groupPolicies,
configured: policy?.configured === true,
queryTimeoutSecs,
};
@@ -1783,8 +1810,10 @@ export const useSettingsStore = defineStore("settings", () => {
readOnly: next.readOnly,
allowDangerousSql: next.allowDangerousSql,
allowedConnectionIds: next.allowedConnectionIds,
allowedGroupIds: next.allowedGroupIds,
allowedToolNames: next.allowedToolNames,
connectionPolicies: next.connectionPolicies,
groupPolicies: next.groupPolicies,
queryTimeoutSecs: next.queryTimeoutSecs,
});
} catch (error) {