Skip to content

Commit ff7e2b0

Browse files
fix(#245): codex-sdk MCP injection — commhub_send_task + per-node alias
Closes the codex-sdk side of #245 ("新成员都用不了 send_task"). Root cause locked + verified by 通信龙 + TMCode 负责人 diagnostic (msg 459d1b6c) + my own audit (cli.ts:1337-1340 had ZERO mcp_servers in CODEX_CONFIG; createCommhubSdkMcpServer at agent-node/src/cli.ts:1126 is wired ONLY into the claude-agent-sdk processWithSdk path). Background ========== Vincent's "new agents can't use send_task" was: new nodes default to codex-sdk runtime (per [[feedback_new_node_codex_default]]); codex inherits MCP servers from `~/.codex/config.toml [mcp_servers.*]` (TOML — codex does NOT read cwd `.mcp.json`); for months the only [mcp_servers.commhub-proxy] block was a global stale proxy with a hardcoded `COMMHUB_ALIAS = "codex-硅谷"` pointing at a separate proxy script (`proxy/commhub-proxy.ts`) that exposed only 4 tools (get_task / report_result / get_status / send_message — NO send_task, NO get_all_status), and that script got rm-rf'd in the 06-16 incident so codex-sdk nodes started crashing "No such file or directory" on top of being functionally limited. 通信龙 removed the broken block this morning (~/.codex/config.toml.bak-20260617-245), exposing the real underlying gap: agent-node never injected commhub MCP for codex-sdk in the first place. Fix (two-package commit) ======================== agent-node/src/cli.ts: - Replace the bare CODEX_CONFIG constant with `buildCodexConfig(workdir)` that adds `mcp_servers.commhub = { command: "bun", args: [<cwd>/.anet/node-server.js] }`. - env intentionally OMITTED from the mcp_servers.commhub block — codex CLI subprocess inherits this agent-node process's env, which anet's launchAgent already sets per-node (COMMHUB_ALIAS = displayName, COMMHUB_TOKEN, COMMHUB_URL). Hard-coding env here would re-introduce the global-alias bug the 06-17 incident exposed. - The MCP server points at agent-network's `.anet/node-server.js` (a bun stdio MCP server bundled in agent-network's dist/), which exposes the full commhub_send_task / commhub_get_all_status / commhub_get_task / commhub_send_message / commhub_send_reply / commhub_report_status / commhub_get_session_status / commhub_list_tasks set. agent-network/bin/cli.ts: - ensureMcpJson runtime gate widened from `claude-code-cli only` to `claude-code-cli OR codex-sdk`. For codex-sdk the function still refreshes `.anet/node-server.js` from the npm package + self-heals `@modelcontextprotocol/sdk` in `.anet/node_modules` + writes `.anet/.env` (hub URL + token), but SKIPS the `.mcp.json` write (codex does not read cwd `.mcp.json`; that file would be a silent no-op + a debugging-trap). Why this fix is per-node-safe ============================= `Codex({ config })` (the SDK constructor) accepts the JSON object and flattens it into `--config key=value` TOML literal overrides on the codex CLI command line. The override is per-Codex-instance, in-memory, and does NOT mutate `~/.codex/config.toml`. Two codex-sdk nodes running simultaneously each get their own codex CLI subprocess with its own inherited env from its own agent-node parent — so their commhub MCP servers register against their own per-node alias. Verified ======== Docker node:24-alpine, fresh `npm i -g @preview` of both packages: - agent-node v2.4.11-preview.2 installed cleanly ✓ - agent-node bundle markers: `mcp_servers` ×1, `node-server.js` path ×1, `commhub` ×36 ✓ - agent-network 2.2.14-preview.0 installed cleanly ✓ - agent-network bundle marker: `codex-sdk` ×14 (the new gate addition + cross-references in existing #237 + #133 code) ✓ - `anet doctor` clean output ✓ Live verification (TMCode 副责人 codex-sdk node restart, agent self- report) is the next gate before promote latest — fast-follow patch flow per 通信龙 dispatch 478de9fe. Co-changes: - agent-network 2.2.13 → 2.2.14-preview.0 - agent-node 2.4.10 → 2.4.11-preview.2 (.0 and .1 occupied by prior #211 / #168 shipping cycles) Branch: fix/245-codex-mcp (forked from fix/245-connectivity-reliability which carries the just-released 2.2.13 telegram series + bump commit e409aff) Refs: #245 (umbrella), 通信龙 dispatches d2814e67 + 7c7c7e1f + 478de9fe + 7507d1fb + 71675e69, TMCode 负责人 diagnostic 459d1b6c, agent-node in-process commhub for claude-agent-sdk at cli.ts:1126 (createCommhubSdkMcpServer), agent-network ensureMcpJson at cli.ts:2233. Author-Agent: 通信工程马
1 parent e409aff commit ff7e2b0

4 files changed

Lines changed: 74 additions & 23 deletions

File tree

agent-network/bin/cli.ts

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2231,7 +2231,24 @@ async function interactiveCreateProfile(id: string): Promise<Profile> {
22312231
// ── ensure .mcp.json has commhub server ──
22322232

22332233
function ensureMcpJson(profile: Profile) {
2234-
if (normalizeRuntime(profile) !== "claude-code-cli") return;
2234+
// #245 codex-sdk fix — widened gate (was claude-code-cli only).
2235+
//
2236+
// Both claude-code-cli and codex-sdk runtimes need `.anet/node-server.js`
2237+
// (the in-process commhub MCP stdio server) refreshed + the @modelcontextprotocol/sdk
2238+
// dependency self-healed. The difference is the discovery mechanism:
2239+
// * claude-code-cli reads cwd `.mcp.json` and finds commhub there
2240+
// * codex-sdk reads `~/.codex/config.toml [mcp_servers.*]` and CANNOT use
2241+
// `.mcp.json` (TMCode负责人 459d1b6c diagnostic confirmed). For codex-sdk
2242+
// anet-node passes a `mcp_servers.commhub` override via the Codex SDK's
2243+
// `CodexOptions.config` (per-instance, in-memory) — see agent-node/src/cli.ts
2244+
// `CODEX_CONFIG.mcp_servers` block. That override points at the same
2245+
// `.anet/node-server.js`, so we still need to keep it fresh on this side.
2246+
//
2247+
// claude-agent-sdk and grok-build-acp do NOT use cwd .anet/node-server.js
2248+
// (they inject in-process via createCommhubSdkMcpServer at agent-node), so
2249+
// they keep the early-return.
2250+
const runtime = normalizeRuntime(profile);
2251+
if (runtime !== "claude-code-cli" && runtime !== "codex-sdk") return;
22352252
if (!profile.channels?.some(ch => ch.includes("commhub"))) return;
22362253

22372254
const mcpJsonPath = join(process.cwd(), ".mcp.json");
@@ -2322,28 +2339,25 @@ function ensureMcpJson(profile: Profile) {
23222339
}
23232340
}
23242341

2325-
// 只在没有 commhub 配置时才写 .mcp.json
2326-
// 用户可能手动配了指向开发源码(commhub-channel.ts),不能覆盖
2327-
mcpConfig.mcpServers = mcpConfig.mcpServers || {};
2328-
const hasCommhub = Object.keys(mcpConfig.mcpServers).some(k => k.includes("commhub"));
2329-
if (!hasCommhub) {
2330-
mcpConfig.mcpServers.commhub = { type: "stdio", command: "bun", args: [".anet/node-server.js"] };
2331-
writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2) + "\n");
2332-
console.log(`[anet] .mcp.json: added commhub`);
2333-
}
2334-
2335-
// Write .anet/.env (hub URL + token)
2342+
// Write .anet/.env (hub URL + token) — both runtimes need this; node-server.js
2343+
// reads COMMHUB_URL / COMMHUB_TOKEN from this file when spawned as a stdio MCP.
23362344
const anetEnvPath = join(anetDir, ".env");
23372345
const token = profile.token || "";
23382346
let envContent = `COMMHUB_URL=${profile.hub || "http://127.0.0.1:9200"}\n`;
23392347
if (token) envContent += `COMMHUB_TOKEN=${token}\n`;
23402348
writeFileSync(anetEnvPath, envContent);
23412349

2342-
// Write .mcp.json
2343-
mcpConfig.mcpServers = mcpConfig.mcpServers || {};
2344-
mcpConfig.mcpServers.commhub = { type: "stdio", command: "bun", args: [".anet/node-server.js"] };
2345-
writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2) + "\n");
2346-
console.log(`[anet] .mcp.json: added commhub channel server`);
2350+
// #245 codex-sdk fix — only write `.mcp.json` for claude-code-cli. codex-sdk
2351+
// does not read cwd `.mcp.json`; it reads `~/.codex/config.toml [mcp_servers.*]`
2352+
// (or accepts a `CodexOptions.config` override from agent-node, which is the
2353+
// path this fix uses). Writing `.mcp.json` for codex-sdk would be a silent
2354+
// no-op + confuse anyone reading the file expecting it to work.
2355+
if (runtime === "claude-code-cli") {
2356+
mcpConfig.mcpServers = mcpConfig.mcpServers || {};
2357+
mcpConfig.mcpServers.commhub = { type: "stdio", command: "bun", args: [".anet/node-server.js"] };
2358+
writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2) + "\n");
2359+
console.log(`[anet] .mcp.json: added commhub channel server`);
2360+
}
23472361
}
23482362

23492363
// ── launch helper (shared by start + resume) ──

agent-network/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sleep2agi/agent-network",
3-
"version": "2.2.13",
3+
"version": "2.2.14-preview.0",
44
"description": "AI Agent Network CLI — Local-first multi-agent orchestration across 4 runtimes (Claude Code CLI / Claude Agent SDK / Codex SDK / Grok Build ACP) and 8+ LLM providers (Anthropic / OpenAI / xAI Grok / MiniMax / DeepSeek / GLM / Kimi / InternLM / Xiaomi MiMo / OpenRouter). Apache 2.0.",
55
"type": "module",
66
"main": "dist/src/client.js",

agent-node/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sleep2agi/agent-node",
3-
"version": "2.4.10",
3+
"version": "2.4.11-preview.2",
44
"description": "AI Agent runtime for CommHub networks. Supports 4 runtimes: Claude Code CLI, Claude Agent SDK, Codex SDK, and Grok Build ACP.",
55
"bin": {
66
"agent-node": "dist/cli.js"

agent-node/src/cli.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,10 +1334,47 @@ const CODEX_INSTRUCTIONS = SYSTEM_PROMPT || [
13341334
`你的最终回复会被系统自动 send_reply 给任务发起者。`,
13351335
].join("\n");
13361336

1337-
const CODEX_CONFIG = {
1338-
model_auto_compact_token_limit: 200000,
1339-
developer_instructions: CODEX_INSTRUCTIONS,
1340-
};
1337+
// #245 codex-sdk fix — inject commhub MCP server config so codex-sdk nodes
1338+
// get the full commhub_send_task / get_all_status / etc. tool set, with
1339+
// per-node identity (alias / token) inherited from this agent-node process.
1340+
//
1341+
// Vincent retro 2026-06-17: "新成员都用不了 send_task" — new nodes default to
1342+
// codex-sdk runtime (per [[feedback_new_node_codex_default]]); for claude-
1343+
// agent-sdk runtime agent-node injects commhub via an in-process McpServer
1344+
// (createCommhubSdkMcpServer at line 1126); for codex-sdk no equivalent
1345+
// in-process channel exists, and CODEX_CONFIG had ZERO mcp_servers field —
1346+
// so codex inherited only whatever was in `~/.codex/config.toml` (a stale,
1347+
// limited "commhub-proxy" pointing at a separate script that got rm-rf'd
1348+
// in the 06-16 incident).
1349+
//
1350+
// Fix: the Codex SDK's `CodexOptions.config` accepts a JSON object that gets
1351+
// flattened to `--config key=value` TOML literal overrides — per-Codex-
1352+
// instance, in-memory, no mutation of `~/.codex/config.toml`. We point
1353+
// `mcp_servers.commhub` at `.anet/node-server.js` (the bun stdio commhub
1354+
// MCP server that agent-network's ensureMcpJson refreshes on every start —
1355+
// also patched in this fix to widen its runtime gate to codex-sdk). codex
1356+
// CLI subprocess inherits parent agent-node's env (COMMHUB_ALIAS / TOKEN /
1357+
// URL set by anet launchAgent per-node), so node-server.js runs with the
1358+
// correct per-node identity.
1359+
function buildCodexConfig(workdir: string): Record<string, any> {
1360+
const nodeServerPath = join(workdir, ".anet", "node-server.js");
1361+
return {
1362+
model_auto_compact_token_limit: 200000,
1363+
developer_instructions: CODEX_INSTRUCTIONS,
1364+
mcp_servers: {
1365+
commhub: {
1366+
command: "bun",
1367+
args: [nodeServerPath],
1368+
// env intentionally omitted: codex CLI subprocess inherits this
1369+
// agent-node parent process's env, which includes the per-node
1370+
// COMMHUB_ALIAS / COMMHUB_TOKEN / COMMHUB_URL that anet's
1371+
// launchAgent already sets. Hard-coding env here would re-introduce
1372+
// the global-alias bug the 06-17 incident exposed.
1373+
},
1374+
},
1375+
};
1376+
}
1377+
const CODEX_CONFIG = buildCodexConfig(process.cwd());
13411378

13421379
async function processWithCodex(task: string, from: string, images?: string[]): Promise<string> {
13431380
// Ensure system-installed codex binary is found (npm global bin)

0 commit comments

Comments
 (0)