feat(mcp): add streamable http server and fine-grained authorization

This commit is contained in:
二丫讲梵 authored and GitHub committed 2026-08-31 22:56:16 +08:00
1 parent f725c50b2c
commit f075caef21
47 files changed
+4960 -509

No files matched your search

@@ -432,6 +432,8 @@ describe("normalizeMcpGlobalPolicy", () => {
readOnly: false,
allowDangerousSql: false,
allowedConnectionIds: null,
allowedToolNames: null,
connectionPolicies: [],
configured: false,
queryTimeoutSecs: null,
});
@@ -449,6 +451,8 @@ describe("normalizeMcpGlobalPolicy", () => {
readOnly: true,
allowDangerousSql: true,
allowedConnectionIds: ["connection-1", "connection-2"],
allowedToolNames: null,
connectionPolicies: [],
configured: true,
queryTimeoutSecs: null,
});
@@ -675,6 +679,8 @@ describe("settingsStore MCP policy persistence", () => {
readOnly: true,
allowDangerousSql: false,
allowedConnectionIds: ["connection-1"],
allowedToolNames: null,
connectionPolicies: [],
configured: true,
queryTimeoutSecs: null,
};
@@ -688,6 +694,8 @@ describe("settingsStore MCP policy persistence", () => {
readOnly: false,
allowDangerousSql: false,
allowedConnectionIds: [],
allowedToolNames: null,
connectionPolicies: [],
configured: true,
queryTimeoutSecs: null,
});
+32
View File
@@ -50,11 +50,22 @@ export interface McpGlobalPolicy {
readOnly: boolean;
allowDangerousSql: boolean;
allowedConnectionIds: string[] | null;
allowedToolNames: string[] | null;
connectionPolicies: McpConnectionPolicy[];
configured: boolean;
/** MCP query timeout override in seconds. null/undefined = inherit the connection; 0 = no limit. */
queryTimeoutSecs: number | null;
}
export interface McpConnectionPolicy {
connectionId: string;
readOnly: boolean;
allowDangerousSql: boolean;
executionModeConfigured: boolean;
databaseScope: "all" | "selected" | "none";
allowedDatabases: string[];
}
export type DesktopIconTheme = "default" | "black";
export type InterfaceLayout = "separated" | "classic";
@@ -91,12 +102,29 @@ export const DEFAULT_MCP_GLOBAL_POLICY: McpGlobalPolicy = {
readOnly: false,
allowDangerousSql: false,
allowedConnectionIds: null,
allowedToolNames: null,
connectionPolicies: [],
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 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) => {
if (!rule || typeof rule.connectionId !== "string" || !rule.connectionId.trim()) return rules;
rules[rule.connectionId.trim()] = {
connectionId: rule.connectionId.trim(),
readOnly: rule.readOnly === true,
allowDangerousSql: rule.readOnly !== true && rule.allowDangerousSql === true,
executionModeConfigured: rule.executionModeConfigured !== false,
databaseScope: rule.databaseScope === "selected" || rule.databaseScope === "none" ? rule.databaseScope : "all",
allowedDatabases: rule.databaseScope === "selected" ? [...new Set((rule.allowedDatabases ?? []).filter((database): database is string => typeof database === "string" && database.trim().length > 0).map((database) => database.trim()))] : [],
};
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.
@@ -105,6 +133,8 @@ export function normalizeMcpGlobalPolicy(policy: Partial<McpGlobalPolicy> | null
readOnly: policy?.readOnly === true,
allowDangerousSql: policy?.allowDangerousSql === true,
allowedConnectionIds,
allowedToolNames,
connectionPolicies,
configured: policy?.configured === true,
queryTimeoutSecs,
};
@@ -1530,6 +1560,8 @@ export const useSettingsStore = defineStore("settings", () => {
readOnly: next.readOnly,
allowDangerousSql: next.allowDangerousSql,
allowedConnectionIds: next.allowedConnectionIds,
allowedToolNames: next.allowedToolNames,
connectionPolicies: next.connectionPolicies,
queryTimeoutSecs: next.queryTimeoutSecs,
});
} catch (error) {