mcp_tool Stop hook fails open when MCP server is missing or cannot start
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of Codex CLI is running?
codex-cli 0.149.0
What subscription do you have?
ChatGPT Pro
Which model were you using?
Default OpenAI model selected by Codex CLI.
What platform is your computer?
Linux 7.0.0-29-generic x86_64 x86_64 (Linux Mint 22.3)
What terminal emulator and version are you using?
Kitty on Linux; reproduced with non-interactive codex exec --ephemeral.
Codex doctor report
Redacted summary: overallStatus ok; Codex 0.149.0; installation and update target consistent; config loaded; MCP configuration locally consistent; provider HTTP and WebSocket checks pass; state databases healthy. The full report contains only local-path details and does not show a failing prerequisite.
What issue are you seeing?
An mcp_tool Stop hook works when its configured stdio MCP server is available, but fails open when that MCP server is unavailable.
Positive control on 0.149.0: the Stop hook successfully invoked two MCP tools in sequence and the second tool wrote a valid terminal-seal fixture. This confirms that the MCP hook executor is wired in this release.
Negative controls:
- The Stop hook references an MCP server name that is not registered.
- The referenced MCP server is registered, but its command points to a nonexistent executable and cannot start.
In both cases Codex emitted the requested agent message followed by turn.completed. There was no hook failure event in JSONL output and the Stop hook did not block completion.
This makes an MCP-backed validation, compliance, or release gate fail open precisely when its validator is unavailable.
What steps can reproduce the bug?
- Enable the stable hooks feature.
- Configure a Stop hook similar to:
{
"hooks": {
"Stop": [
{
"matcher": ".*",
"hooks": [
{
"type": "mcp_tool",
"server": "repro_validator",
"tool": "validate",
"input": {},
"timeout": 20
}
]
}
]
}
}
- First register a working stdio server named
repro_validatorwhosevalidatetool returns a successful Stop-hook response. Run:
codex exec --ephemeral --skip-git-repo-check --dangerously-bypass-hook-trust --json "Reply exactly POSITIVE_CONTROL"
Confirm the MCP tool is invoked. This positive control passes on 0.149.0.
-
Remove
repro_validatorfrom the MCP configuration while leaving the hook enabled. Run the same command. The output still ends withturn.completed. -
Register
repro_validatoragain with a nonexistent command, for example/__missing_mcp_server__, and run the same command. The output again ends withturn.completed.
Observed negative-control shape:
{"type":"item.completed","item":{"type":"agent_message","text":"..."}}
{"type":"turn.completed","usage":{}}
No successful MCP validation occurred in either negative control.
What is the expected behavior?
If an enabled mcp_tool Stop hook cannot resolve, start, or call its MCP server, Stop should fail closed. Codex should block completion or return a non-success terminal result that callers cannot mistake for a completed turn. JSONL output should identify the failed hook and MCP failure.
Additional information
The same fixture was also exercised with ten validator fault-injection cases; all validator-side cases pass. The remaining issue is specifically runtime behavior when the MCP hook dependency is missing or cannot start.
This is reproducible after a clean Canary rollback: the test hook and MCP registration were removed, and no production configuration or data is involved.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the mcp_tool Stop-hook execution path and its handling of an unregistered or unstartable MCP server. Reproduce both negative controls with codex exec --ephemeral and inspect the JSONL events; done means completion is blocked or reported as unsuccessful and the failed hook identifies the MCP failure.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100