[Feature]: Defer runtime discovery until needed: Windows where probes consume 30s before MCP initialize
Platform
Codex CLI
Feature description
Please move execution-runtime discovery off the MCP initialization critical path and cache runtime resolution on first use. Related: #670 (avoiding repeated PATH probes), but this report concerns the initial scan before the server can answer initialize.
Environment: Windows / PowerShell, Node 24.18.0, context-mode 1.0.169 (npm latest checked September 14, 2026), Codex Desktop with bundled codex 0.154.0-alpha.6.2. Installed as a standalone npm MCP server, launched directly with Node and server.bundle.mjs. No routing/session-capture hooks from context-mode.
Measured evidence
An isolated stdio MCP client took 31,271 ms to complete initialize. A diagnostic preload timed child_process.execSync/execFileSync/spawnSync, using syncBuiltinESMExports before importing the unchanged installed bundle. The 16 serial where invocations totalled 30,229 ms (96.7%). Python --version added 389 ms; a Git probe added 4 ms.
| Command | ms |
|---|---|
where bun |
2060 |
where bash |
1880 |
where tsx |
2030 |
where ts-node |
1622 |
where python3 |
1944 |
where python |
1734 |
where ruby |
1988 |
where go |
1456 |
where rustc |
2322 |
where php |
1562 |
where perl |
2111 |
where Rscript |
1673 |
where r |
1779 |
where elixir |
2036 |
where dotnet-script |
1901 |
where bun |
2131 |
Earlier uninstrumented isolated handshakes were approximately 32.2s and 34.9s. Direct where.exe also took about 1.93s on this machine, versus 1.86s via a shell; replacing execSync with execFileSync alone is not demonstrated to fix this. Why each Windows lookup is unusually expensive remains unproven. These are local observations, not a claim that every Windows host has this latency.
Reproduction / profiling
- Install [email protected] in an isolated directory on Windows with Node 24.18.0.
- Launch
node node_modules/context-mode/server.bundle.mjsthrough a stdio MCP client, with CONTEXT_MODE_PLATFORM=codex, a dedicated CONTEXT_MODE_DIR, and PATH containing only the Node directory, Python directory, Windows System32, and Windows PowerShell directory. Set SHELL to the existing powershell.exe path. No model prompt or tool execution is necessary. - Time spawn/connect through the initialize response. Then call tools/list to confirm successful initialization (11 tools in this direct client).
- To attribute synchronous probes, save this as profile.mjs and launch Node with
--import file:///absolute/path/to/profile.mjsbefore the server entrypoint:
import cp from 'node:child_process';
import { syncBuiltinESMExports } from 'node:module';
for (const name of ['execSync', 'execFileSync', 'spawnSync']) {
const original = cp[name];
cp[name] = function (...args) {
const start = performance.now();
try { return original.apply(this, args); }
finally {
console.error(JSON.stringify({
name, command: args[0], ms: performance.now() - start
}));
}
};
}
syncBuiltinESMExports();Inspect/redact diagnostic output before sharing: generic command arguments may contain private paths. The timings above are a targeted profiler, not output from ctx-debug.sh.
Use case
Our Codex configuration exposes only ctx_index, ctx_search and ctx_stats through the host-side enabled_tools filter. This filter does not tell the server to skip runtime discovery: the direct server still registers all tools, and the installed bundle eagerly calls its runtime-detection function before the MCP server is ready.
With context-mode.required=true, desktop task creation took 36.48-53.15s; one frontend request timed out at 30s and the backend replied later. Removing only required allowed an isolated ephemeral Codex thread/start to return in 935ms. That mitigates task-start blocking but does not speed up the context-mode server; desktop UI after this change has not yet been independently retested.
Searching/indexing users pay to locate Ruby, Go, Rust, PHP, Perl, R, Elixir, dotnet-script, etc., before performing any execution. No agents or network prewarm are involved in the direct 31.27s MCP handshake measurement. This differs from #634's synchronous install / Codex prewarm case.
Proposed solution
Preferred: lazily resolve and cache the specific runtime when an execution request needs it. Allow initialize and non-execution tools to respond without first locating every supported language. Keep explicit diagnostics free to request a full scan.
If tool schemas require an available-language list at registration time, consider separating the declared supported-language enum from actual runtime availability validation at execution time, or an explicit restricted/index-only startup mode. Please advise which contract fits the project best.
For Windows, consider direct filesystem-based PATH/PATHEXT resolution with process-local caching, preserving command precedence, quoted paths, supported executable extensions and Microsoft Store alias filtering. Do not simply assume missing runtimes or drop validation.
Suggested regression coverage: a deliberately slow/missing optional runtime must not delay initialize or ctx_index/ctx_search/ctx_stats; first execution resolves the selected runtime, repeated execution uses its cache, and missing-runtime errors remain actionable. Measure cold and warm startup on Windows as well as Linux/macOS. No production patch or claimed post-optimization speedup is included here.
Source: mksglu/context-mode