From fad7e411e13a00210bd2edc11421bd4d0a449966 Mon Sep 17 00:00:00 2001 From: Chris Volzer Date: Thu, 9 Apr 2026 16:57:27 -0400 Subject: [PATCH 1/3] fix: disable mcp servers from local config for codex --- .../agent/src/adapters/codex/codex-agent.ts | 9 +++-- packages/agent/src/adapters/codex/settings.ts | 36 +++++++++---------- packages/agent/src/adapters/codex/spawn.ts | 20 +++++++++++ 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/packages/agent/src/adapters/codex/codex-agent.ts b/packages/agent/src/adapters/codex/codex-agent.ts index f52194b3d..77b618a64 100644 --- a/packages/agent/src/adapters/codex/codex-agent.ts +++ b/packages/agent/src/adapters/codex/codex-agent.ts @@ -108,9 +108,15 @@ export class CodexAcpAgent extends BaseAcpAgent { super(client); this.logger = new Logger({ debug: true, prefix: "[CodexAcpAgent]" }); + // Load user codex settings before spawning so spawnCodexProcess can + // filter out any [mcp_servers.*] entries from ~/.codex/config.toml. + const cwd = options.codexProcessOptions.cwd ?? process.cwd(); + const settingsManager = new CodexSettingsManager(cwd); + // Spawn the codex-acp subprocess this.codexProcess = spawnCodexProcess({ ...options.codexProcessOptions, + settings: settingsManager.getSettings(), logger: this.logger, processCallbacks: options.processCallbacks, }); @@ -120,9 +126,6 @@ export class CodexAcpAgent extends BaseAcpAgent { const codexWritable = nodeWritableToWebWritable(this.codexProcess.stdin); const codexStream = ndJsonStream(codexWritable, codexReadable); - // Set up session with CodexSettingsManager - const cwd = options.codexProcessOptions.cwd ?? process.cwd(); - const settingsManager = new CodexSettingsManager(cwd); const abortController = new AbortController(); this.session = { abortController, diff --git a/packages/agent/src/adapters/codex/settings.ts b/packages/agent/src/adapters/codex/settings.ts index 7493df02e..ff3e20b10 100644 --- a/packages/agent/src/adapters/codex/settings.ts +++ b/packages/agent/src/adapters/codex/settings.ts @@ -13,6 +13,8 @@ export interface CodexSettings { personality?: string; modelReasoningEffort?: string; trustLevel?: string; + // Names of every `[mcp_servers.]` section declared in the user's config.toml + mcpServerNames: string[]; } /** @@ -24,32 +26,29 @@ export interface CodexSettings { */ export class CodexSettingsManager { private cwd: string; - private settings: CodexSettings = {}; - private initialized = false; + private settings: CodexSettings = { mcpServerNames: [] }; constructor(cwd: string) { this.cwd = cwd; + this.loadSettings(); } async initialize(): Promise { - if (this.initialized) { - return; - } - await this.loadSettings(); - this.initialized = true; + // No-op: settings are loaded in the constructor. Kept async to + // satisfy the BaseSettingsManager interface. } private getConfigPath(): string { return path.join(os.homedir(), ".codex", "config.toml"); } - private async loadSettings(): Promise { + private loadSettings(): void { const configPath = this.getConfigPath(); try { - const content = await fs.promises.readFile(configPath, "utf-8"); + const content = fs.readFileSync(configPath, "utf-8"); this.settings = parseCodexToml(content, this.cwd); } catch { - this.settings = {}; + this.settings = { mcpServerNames: [] }; } } @@ -62,17 +61,13 @@ export class CodexSettingsManager { } async setCwd(cwd: string): Promise { - if (this.cwd === cwd) { - return; - } - this.dispose(); + if (this.cwd === cwd) return; this.cwd = cwd; - this.initialized = false; - await this.initialize(); + this.loadSettings(); } dispose(): void { - this.initialized = false; + // No-op: no resources to release. Kept async to satisfy the BaseSettingsManager interface. } } @@ -82,7 +77,8 @@ export class CodexSettingsManager { * Does NOT handle full TOML spec — only what codex config uses. */ function parseCodexToml(content: string, cwd: string): CodexSettings { - const settings: CodexSettings = {}; + const settings: CodexSettings = { mcpServerNames: [] }; + const mcpServerNames = new Set(); let currentSection = ""; for (const line of content.split("\n")) { @@ -93,6 +89,9 @@ function parseCodexToml(content: string, cwd: string): CodexSettings { const sectionMatch = trimmed.match(/^\[(.+)\]$/); if (sectionMatch) { currentSection = sectionMatch[1] ?? ""; + if (currentSection.startsWith("mcp_servers.")) { + mcpServerNames.add(currentSection.slice("mcp_servers.".length)); + } continue; } @@ -123,5 +122,6 @@ function parseCodexToml(content: string, cwd: string): CodexSettings { } } + settings.mcpServerNames = Array.from(mcpServerNames); return settings; } diff --git a/packages/agent/src/adapters/codex/spawn.ts b/packages/agent/src/adapters/codex/spawn.ts index 3bc0b53e6..29c34ba73 100644 --- a/packages/agent/src/adapters/codex/spawn.ts +++ b/packages/agent/src/adapters/codex/spawn.ts @@ -4,6 +4,7 @@ import { delimiter, dirname } from "node:path"; import type { Readable, Writable } from "node:stream"; import type { ProcessSpawnedCallback } from "../../types"; import { Logger } from "../../utils/logger"; +import type { CodexSettings } from "./settings"; export interface CodexProcessOptions { cwd?: string; @@ -14,6 +15,7 @@ export interface CodexProcessOptions { binaryPath?: string; logger?: Logger; processCallbacks?: ProcessSpawnedCallback; + settings?: CodexSettings; } export interface CodexProcess { @@ -28,6 +30,24 @@ function buildConfigArgs(options: CodexProcessOptions): string[] { args.push("-c", `features.remote_models=false`); + // Disable the user's local MCPs one-by-one so Codex only uses the MCPs we + // provide via ACP. We can't use `-c mcp_servers={}` because that makes Codex + // ignore MCPs entirely, including the ones we inject later. + for (const name of options.settings?.mcpServerNames ?? []) { + args.push("-c", `mcp_servers.${name}.enabled=false`); + } + + // TEMPORARY DEBUG: PostHog LLM gateway /v1/models is returning + // "truncation_policy": {"mode":"bytes","limit":0} + // for every model, which codex-rs interprets as "replace every MCP tool + // output with the placeholder `…N chars truncated…`". This erases tool + // results before the model sees them and causes hallucinations. + // + // This override raises tool_output_token_limit to an effectively unbounded + // value to verify that truncation is the cause. REVERT once the gateway + // fix ships. See investigation in chat on 2026-04-09. + args.push("-c", `tool_output_token_limit=2000000`); + if (options.apiBaseUrl) { args.push("-c", `model_provider="posthog"`); args.push("-c", `model_providers.posthog.name="PostHog Gateway"`); From 1af4c6160498e4a9552ab1e9f344481fad865692 Mon Sep 17 00:00:00 2001 From: Chris Volzer Date: Thu, 9 Apr 2026 16:57:55 -0400 Subject: [PATCH 2/3] chore: remove temp fix --- packages/agent/src/adapters/codex/spawn.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/agent/src/adapters/codex/spawn.ts b/packages/agent/src/adapters/codex/spawn.ts index 29c34ba73..fd4777572 100644 --- a/packages/agent/src/adapters/codex/spawn.ts +++ b/packages/agent/src/adapters/codex/spawn.ts @@ -37,17 +37,6 @@ function buildConfigArgs(options: CodexProcessOptions): string[] { args.push("-c", `mcp_servers.${name}.enabled=false`); } - // TEMPORARY DEBUG: PostHog LLM gateway /v1/models is returning - // "truncation_policy": {"mode":"bytes","limit":0} - // for every model, which codex-rs interprets as "replace every MCP tool - // output with the placeholder `…N chars truncated…`". This erases tool - // results before the model sees them and causes hallucinations. - // - // This override raises tool_output_token_limit to an effectively unbounded - // value to verify that truncation is the cause. REVERT once the gateway - // fix ships. See investigation in chat on 2026-04-09. - args.push("-c", `tool_output_token_limit=2000000`); - if (options.apiBaseUrl) { args.push("-c", `model_provider="posthog"`); args.push("-c", `model_providers.posthog.name="PostHog Gateway"`); From bd9649972fac67c88ef03896eb408240c70d8f23 Mon Sep 17 00:00:00 2001 From: Chris Volzer Date: Thu, 9 Apr 2026 17:09:56 -0400 Subject: [PATCH 3/3] chore: change comment --- packages/agent/src/adapters/codex/settings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/agent/src/adapters/codex/settings.ts b/packages/agent/src/adapters/codex/settings.ts index ff3e20b10..5d1e0665c 100644 --- a/packages/agent/src/adapters/codex/settings.ts +++ b/packages/agent/src/adapters/codex/settings.ts @@ -67,7 +67,7 @@ export class CodexSettingsManager { } dispose(): void { - // No-op: no resources to release. Kept async to satisfy the BaseSettingsManager interface. + // No-op: no resources to release. Kept to satisfy the BaseSettingsManager interface. } }