feat: add per-project MCP config overrides (#5406)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
This commit is contained in:
Jake Nelson
2026-01-03 18:15:37 +11:00
committed by GitHub
parent da6df3d432
commit 5c5e636030
3 changed files with 71 additions and 15 deletions

View File

@@ -135,6 +135,11 @@ export namespace MCP {
// Prompt cache types
type PromptInfo = Awaited<ReturnType<MCPClient["listPrompts"]>>["prompts"][number]
type McpEntry = NonNullable<Config.Info["mcp"]>[string]
function isMcpConfigured(entry: McpEntry): entry is Config.Mcp {
return typeof entry === "object" && entry !== null && "type" in entry
}
const state = Instance.state(
async () => {
const cfg = await Config.get()
@@ -144,6 +149,11 @@ export namespace MCP {
await Promise.all(
Object.entries(config).map(async ([key, mcp]) => {
if (!isMcpConfigured(mcp)) {
log.error("Ignoring MCP config entry without type", { key })
return
}
// If disabled by config, mark as disabled without trying to connect
if (mcp.enabled === false) {
status[key] = { status: "disabled" }
@@ -237,6 +247,7 @@ export namespace MCP {
status: { status: "disabled" as const },
}
}
log.info("found", { key, type: mcp.type })
let mcpClient: MCPClient | undefined
let status: Status | undefined = undefined
@@ -434,8 +445,9 @@ export namespace MCP {
const config = cfg.mcp ?? {}
const result: Record<string, Status> = {}
// Include all MCPs from config, not just connected ones
for (const key of Object.keys(config)) {
// Include all configured MCPs from config, not just connected ones
for (const [key, mcp] of Object.entries(config)) {
if (!isMcpConfigured(mcp)) continue
result[key] = s.status[key] ?? { status: "disabled" }
}
@@ -455,6 +467,11 @@ export namespace MCP {
return
}
if (!isMcpConfigured(mcp)) {
log.error("Ignoring MCP connect request for config without type", { name })
return
}
const result = await create(name, { ...mcp, enabled: true })
if (!result) {
@@ -579,6 +596,10 @@ export namespace MCP {
throw new Error(`MCP server not found: ${mcpName}`)
}
if (!isMcpConfigured(mcpConfig)) {
throw new Error(`MCP server ${mcpName} is disabled or missing configuration`)
}
if (mcpConfig.type !== "remote") {
throw new Error(`MCP server ${mcpName} is not a remote server`)
}
@@ -705,6 +726,10 @@ export namespace MCP {
throw new Error(`MCP server not found: ${mcpName}`)
}
if (!isMcpConfigured(mcpConfig)) {
throw new Error(`MCP server ${mcpName} is disabled or missing configuration`)
}
// Re-add the MCP server to establish connection
pendingOAuthTransports.delete(mcpName)
const result = await add(mcpName, mcpConfig)
@@ -737,7 +762,9 @@ export namespace MCP {
export async function supportsOAuth(mcpName: string): Promise<boolean> {
const cfg = await Config.get()
const mcpConfig = cfg.mcp?.[mcpName]
return mcpConfig?.type === "remote" && mcpConfig.oauth !== false
if (!mcpConfig) return false
if (!isMcpConfigured(mcpConfig)) return false
return mcpConfig.type === "remote" && mcpConfig.oauth !== false
}
/**