Codex to OpenCode MCP Server
# Codex to OpenCode MCP Server
A small local MCP (Model Context Protocol) server that lets Codex delegate coding work to
OpenCode. It uses the official MCP Python SDK, the `stdio` transport, and an asynchronous
OpenCode subprocess.
## Tools
### `opencode_execute`
```text
opencode_execute(
task: str,
working_directory: str,
model: str | None = None,
reasoning_effort: str | None = None,
timeout: int = 1800,
)
```
Runs this command without a shell:
```text
opencode run --format json --dir <working_directory> --auto [--model <model>] [--variant <reasoning_effort>] <task>
```
`reasoning_effort` maps to OpenCode's provider-specific `--variant` option. Common values
include `minimal`, `low`, `medium`, `high`, and `max`, but the available variants are defined
by the selected provider and model. The MCP server intentionally accepts any non-empty value
instead of enforcing a provider-specific enum.
Example:
```text
opencode_execute(
task="Implement uncertainty propagation and run the unit tests.",
working_directory="C:\\path\\to\\NuSR",
model="pinche_10/gpt-5.6-sol",
reasoning_effort="high",
timeout=1800,
)
```
It returns structured output containing:
- success, timeout, exit code, and elapsed time;
- OpenCode session ID and final assistant summary;
- completed OpenCode tool calls and errors;
- bounded stdout/stderr captures;
- final `git status --short`, `git diff --stat`, and a bounded unified diff.
The Git fields are post-run snapshots. They can include changes that were already present
before the call. Text contents of untracked files are represented as new-file patches; binary
untracked files are reported by path and size.
### `opencode_check`
Resolves the configured OpenCode executable and runs `opencode --version` without modifying
the environment.
## Install
Requirements: Python 3.11+, Git (optional for diff reporting), and OpenCode.
```powershell
git clone https://github.com/TAO-MINGYU/codex_to_opencode.git
cd codex_to_opencode
uv venv --python 3.11 .venv
uv pip install --python .venv\Scripts\python.exe -e ".[dev]"
```
OpenCode must be installed and authenticated independently. Verify it first:
```powershell
opencode --version
opencode auth list
```
The OpenCode desktop application and the OpenCode CLI are separate entry points on Windows.
An `OpenCode.exe --version` invocation that opens the GUI and prints nothing is not a usable
CLI. Install the official CLI when needed:
```powershell
npm install -g opencode-ai
```
If `opencode` is not in `PATH`, set `OPENCODE_MCP_COMMAND` to its absolute executable path.
On Windows npm installations, prefer the native binary under
`node_modules\opencode-ai\bin\opencode.exe`; the server also detects and bypasses the
`opencode.cmd` wrapper automatically.
## Connect Codex
Add the server through the Codex CLI, which avoids hand-editing configuration:
```powershell
codex mcp add opencode --env OPENCODE_MCP_COMMAND=C:\path\to\opencode.exe -- C:\path\to\opencode-mcp\.venv\Scripts\python.exe -m opencode_mcp.server
```
When OpenCode is already in `PATH`, omit the `--env` option:
```powershell
codex mcp add opencode -- C:\path\to\opencode-mcp\.venv\Scripts\python.exe -m opencode_mcp.server
```
Then verify registration:
```powershell
codex mcp list
```
Restart Codex after changing MCP configuration. The server writes protocol messages only to
stdout and sends logs to stderr, as required for `stdio` MCP servers.
## Configuration
Environment variable | Default | Meaning
--- | --- | ---
`OPENCODE_MCP_COMMAND` | `opencode` | Executable name or absolute path
`OPENCODE_MCP_ARGS` | `[]` | JSON array inserted after the executable (useful for wrappers/tests)
`OPENCODE_MCP_AUTO_APPROVE` | `true` | Add OpenCode's `--auto` permission flag
`OPENCODE_MCP_MAX_OUTPUT_BYTES` | `2097152` | Tail bytes retained independently for stdout/stderr
`OPENCODE_MCP_LOG_LEVEL` | `INFO` | Server log level written to stderr
Setting auto-approval to false makes OpenCode reject permissions it cannot ask interactively:
```powershell
$env:OPENCODE_MCP_AUTO_APPROVE = "false"
```
## Debug
Run the automated tests:
```powershell
.venv\Scripts\python.exe -m pytest --cov=opencode_mcp --cov-fail-under=80
.venv\Scripts\python.exe -m ruff check .
.venv\Scripts\python.exe -m ruff format --check .
```
Run the server under MCP Inspector:
```powershell
uv run --python 3.11 --with-editable ".[dev]" mcp dev src\opencode_mcp\server.py
```
The MCP tool timeout should be slightly longer than the `timeout` passed to
`opencode_execute`; otherwise Codex may cancel the MCP request before the server can terminate
OpenCode and return diagnostics.
## Security model
`opencode_execute` is intentionally a write-capable, potentially destructive tool. It grants
OpenCode the same filesystem and process permissions as this MCP server. The implementation:
- never invokes a shell for OpenCode tasks;
- requires an existing absolute working-directory path;
- bounds captured output to protect Codex context;
- terminates the OpenCode process tree on timeout or MCP cancellation;
- disables OpenCode auto-update during delegated runs;
- marks the MCP tool as non-idempotent and potentially destructive.
Use a restricted OS account or sandbox when delegating untrusted tasks or repositories.
TDQS
Scored across 2 tools
The two tools have clearly distinct roles: opencode_execute delegates a coding task, while opencode_check resolves the executable and reports its version. There is no realistic confusion between performing an action and checking the installation.
Both tools use the same opencode_ prefix followed by a concise imperative verb, maintaining a consistent snake_case pattern. Though the prefix is a product name, the convention is uniform and predictable.
Two tools is at the low end of typical server scope and feels thin for a coding integration. However, the narrow focus on delegating a single task plus a health check is reasonable enough to be borderline appropriate.
The server covers its core purpose: opencode_execute handles task delegation, and opencode_check verifies the underlying executable. Obvious lifecycle tools such as cancellation or querying current task status are absent, but they fall outside the stated minimal purpose.