Skip to content

Commit 1ad3c26

Browse files
authored
fix(mcp-store): disable MCPs from local config file (#1601)
1 parent 817e5e0 commit 1ad3c26

3 files changed

Lines changed: 33 additions & 21 deletions

File tree

packages/agent/src/adapters/codex/codex-agent.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,15 @@ export class CodexAcpAgent extends BaseAcpAgent {
108108
super(client);
109109
this.logger = new Logger({ debug: true, prefix: "[CodexAcpAgent]" });
110110

111+
// Load user codex settings before spawning so spawnCodexProcess can
112+
// filter out any [mcp_servers.*] entries from ~/.codex/config.toml.
113+
const cwd = options.codexProcessOptions.cwd ?? process.cwd();
114+
const settingsManager = new CodexSettingsManager(cwd);
115+
111116
// Spawn the codex-acp subprocess
112117
this.codexProcess = spawnCodexProcess({
113118
...options.codexProcessOptions,
119+
settings: settingsManager.getSettings(),
114120
logger: this.logger,
115121
processCallbacks: options.processCallbacks,
116122
});
@@ -120,9 +126,6 @@ export class CodexAcpAgent extends BaseAcpAgent {
120126
const codexWritable = nodeWritableToWebWritable(this.codexProcess.stdin);
121127
const codexStream = ndJsonStream(codexWritable, codexReadable);
122128

123-
// Set up session with CodexSettingsManager
124-
const cwd = options.codexProcessOptions.cwd ?? process.cwd();
125-
const settingsManager = new CodexSettingsManager(cwd);
126129
const abortController = new AbortController();
127130
this.session = {
128131
abortController,

packages/agent/src/adapters/codex/settings.ts

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export interface CodexSettings {
1313
personality?: string;
1414
modelReasoningEffort?: string;
1515
trustLevel?: string;
16+
// Names of every `[mcp_servers.<name>]` section declared in the user's config.toml
17+
mcpServerNames: string[];
1618
}
1719

1820
/**
@@ -24,32 +26,29 @@ export interface CodexSettings {
2426
*/
2527
export class CodexSettingsManager {
2628
private cwd: string;
27-
private settings: CodexSettings = {};
28-
private initialized = false;
29+
private settings: CodexSettings = { mcpServerNames: [] };
2930

3031
constructor(cwd: string) {
3132
this.cwd = cwd;
33+
this.loadSettings();
3234
}
3335

3436
async initialize(): Promise<void> {
35-
if (this.initialized) {
36-
return;
37-
}
38-
await this.loadSettings();
39-
this.initialized = true;
37+
// No-op: settings are loaded in the constructor. Kept async to
38+
// satisfy the BaseSettingsManager interface.
4039
}
4140

4241
private getConfigPath(): string {
4342
return path.join(os.homedir(), ".codex", "config.toml");
4443
}
4544

46-
private async loadSettings(): Promise<void> {
45+
private loadSettings(): void {
4746
const configPath = this.getConfigPath();
4847
try {
49-
const content = await fs.promises.readFile(configPath, "utf-8");
48+
const content = fs.readFileSync(configPath, "utf-8");
5049
this.settings = parseCodexToml(content, this.cwd);
5150
} catch {
52-
this.settings = {};
51+
this.settings = { mcpServerNames: [] };
5352
}
5453
}
5554

@@ -62,17 +61,13 @@ export class CodexSettingsManager {
6261
}
6362

6463
async setCwd(cwd: string): Promise<void> {
65-
if (this.cwd === cwd) {
66-
return;
67-
}
68-
this.dispose();
64+
if (this.cwd === cwd) return;
6965
this.cwd = cwd;
70-
this.initialized = false;
71-
await this.initialize();
66+
this.loadSettings();
7267
}
7368

7469
dispose(): void {
75-
this.initialized = false;
70+
// No-op: no resources to release. Kept to satisfy the BaseSettingsManager interface.
7671
}
7772
}
7873

@@ -82,7 +77,8 @@ export class CodexSettingsManager {
8277
* Does NOT handle full TOML spec — only what codex config uses.
8378
*/
8479
function parseCodexToml(content: string, cwd: string): CodexSettings {
85-
const settings: CodexSettings = {};
80+
const settings: CodexSettings = { mcpServerNames: [] };
81+
const mcpServerNames = new Set<string>();
8682
let currentSection = "";
8783

8884
for (const line of content.split("\n")) {
@@ -93,6 +89,9 @@ function parseCodexToml(content: string, cwd: string): CodexSettings {
9389
const sectionMatch = trimmed.match(/^\[(.+)\]$/);
9490
if (sectionMatch) {
9591
currentSection = sectionMatch[1] ?? "";
92+
if (currentSection.startsWith("mcp_servers.")) {
93+
mcpServerNames.add(currentSection.slice("mcp_servers.".length));
94+
}
9695
continue;
9796
}
9897

@@ -123,5 +122,6 @@ function parseCodexToml(content: string, cwd: string): CodexSettings {
123122
}
124123
}
125124

125+
settings.mcpServerNames = Array.from(mcpServerNames);
126126
return settings;
127127
}

packages/agent/src/adapters/codex/spawn.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { delimiter, dirname } from "node:path";
44
import type { Readable, Writable } from "node:stream";
55
import type { ProcessSpawnedCallback } from "../../types";
66
import { Logger } from "../../utils/logger";
7+
import type { CodexSettings } from "./settings";
78

89
export interface CodexProcessOptions {
910
cwd?: string;
@@ -14,6 +15,7 @@ export interface CodexProcessOptions {
1415
binaryPath?: string;
1516
logger?: Logger;
1617
processCallbacks?: ProcessSpawnedCallback;
18+
settings?: CodexSettings;
1719
}
1820

1921
export interface CodexProcess {
@@ -28,6 +30,13 @@ function buildConfigArgs(options: CodexProcessOptions): string[] {
2830

2931
args.push("-c", `features.remote_models=false`);
3032

33+
// Disable the user's local MCPs one-by-one so Codex only uses the MCPs we
34+
// provide via ACP. We can't use `-c mcp_servers={}` because that makes Codex
35+
// ignore MCPs entirely, including the ones we inject later.
36+
for (const name of options.settings?.mcpServerNames ?? []) {
37+
args.push("-c", `mcp_servers.${name}.enabled=false`);
38+
}
39+
3140
if (options.apiBaseUrl) {
3241
args.push("-c", `model_provider="posthog"`);
3342
args.push("-c", `model_providers.posthog.name="PostHog Gateway"`);

0 commit comments

Comments
 (0)