This is a very large PR with some non-backwards-compatible changes. Historically, `codex mcp` (or `codex mcp serve`) started a JSON-RPC-ish server that had two overlapping responsibilities: - Running an MCP server, providing some basic tool calls. - Running the app server used to power experiences such as the VS Code extension. This PR aims to separate these into distinct concepts: - `codex mcp-server` for the MCP server - `codex app-server` for the "application server" Note `codex mcp` still exists because it already has its own subcommands for MCP management (`list`, `add`, etc.) The MCP logic continues to live in `codex-rs/mcp-server` whereas the refactored app server logic is in the new `codex-rs/app-server` folder. Note that most of the existing integration tests in `codex-rs/mcp-server/tests/suite` were actually for the app server, so all the tests have been moved with the exception of `codex-rs/mcp-server/tests/suite/mod.rs`. Because this is already a large diff, I tried not to change more than I had to, so `codex-rs/app-server/tests/common/mcp_process.rs` still uses the name `McpProcess` for now, but I will do some mechanical renamings to things like `AppServer` in subsequent PRs. While `mcp-server` and `app-server` share some overlapping functionality (like reading streams of JSONL and dispatching based on message types) and some differences (completely different message types), I ended up doing a bit of copypasta between the two crates, as both have somewhat similar `message_processor.rs` and `outgoing_message.rs` files for now, though I expect them to diverge more in the near future. One material change is that of the initialize handshake for `codex app-server`, as we no longer use the MCP types for that handshake. Instead, we update `codex-rs/protocol/src/mcp_protocol.rs` to add an `Initialize` variant to `ClientRequest`, which takes the `ClientInfo` object we need to update the `USER_AGENT_SUFFIX` in `codex-rs/app-server/src/message_processor.rs`. One other material change is in `codex-rs/app-server/src/codex_message_processor.rs` where I eliminated a use of the `send_event_as_notification()` method I am generally trying to deprecate (because it blindly maps an `EventMsg` into a `JSONNotification`) in favor of `send_server_notification()`, which takes a `ServerNotification`, as that is intended to be a custom enum of all notification types supported by the app server. So to make this update, I had to introduce a new variant of `ServerNotification`, `SessionConfigured`, which is a non-backwards compatible change with the old `codex mcp`, and clients will have to be updated after the next release that contains this PR. Note that `codex-rs/app-server/tests/suite/list_resume.rs` also had to be update to reflect this change. I introduced `codex-rs/utils/json-to-toml/src/lib.rs` as a small utility crate to avoid some of the copying between `mcp-server` and `app-server`.
125 lines
4.8 KiB
Markdown
125 lines
4.8 KiB
Markdown
# Codex MCP Interface [experimental]
|
||
|
||
This document describes Codex’s experimental MCP interface: a JSON‑RPC API that runs over the Model Context Protocol (MCP) transport to control a local Codex engine.
|
||
|
||
- Status: experimental and subject to change without notice
|
||
- Server binary: `codex mcp-server` (or `codex-mcp-server`)
|
||
- Transport: standard MCP over stdio (JSON‑RPC 2.0, line‑delimited)
|
||
|
||
## Overview
|
||
|
||
Codex exposes a small set of MCP‑compatible methods to create and manage conversations, send user input, receive live events, and handle approval prompts. The types are defined in `protocol/src/mcp_protocol.rs` and re‑used by the MCP server implementation in `mcp-server/`.
|
||
|
||
At a glance:
|
||
|
||
- Conversations
|
||
- `newConversation` → start a Codex session
|
||
- `sendUserMessage` / `sendUserTurn` → send user input into a conversation
|
||
- `interruptConversation` → stop the current turn
|
||
- `listConversations`, `resumeConversation`, `archiveConversation`
|
||
- Configuration and info
|
||
- `getUserSavedConfig`, `setDefaultModel`, `getUserAgent`, `userInfo`
|
||
- Auth
|
||
- `loginApiKey`, `loginChatGpt`, `cancelLoginChatGpt`, `logoutChatGpt`, `getAuthStatus`
|
||
- Utilities
|
||
- `gitDiffToRemote`, `execOneOffCommand`
|
||
- Approvals (server → client requests)
|
||
- `applyPatchApproval`, `execCommandApproval`
|
||
- Notifications (server → client)
|
||
- `loginChatGptComplete`, `authStatusChange`
|
||
- `codex/event` stream with agent events
|
||
|
||
See code for full type definitions and exact shapes: `protocol/src/mcp_protocol.rs`.
|
||
|
||
## Starting the server
|
||
|
||
Run Codex as an MCP server and connect an MCP client:
|
||
|
||
```bash
|
||
codex mcp-server | your_mcp_client
|
||
```
|
||
|
||
For a simple inspection UI, you can also try:
|
||
|
||
```bash
|
||
npx @modelcontextprotocol/inspector codex mcp-server
|
||
```
|
||
|
||
Use the separate `codex mcp` subcommand to manage configured MCP server launchers in `config.toml`.
|
||
|
||
## Conversations
|
||
|
||
Start a new session with optional overrides:
|
||
|
||
Request `newConversation` params (subset):
|
||
|
||
- `model`: string model id (e.g. "o3", "gpt-5", "gpt-5-codex")
|
||
- `profile`: optional named profile
|
||
- `cwd`: optional working directory
|
||
- `approvalPolicy`: `untrusted` | `on-request` | `on-failure` | `never`
|
||
- `sandbox`: `read-only` | `workspace-write` | `danger-full-access`
|
||
- `config`: map of additional config overrides
|
||
- `baseInstructions`: optional instruction override
|
||
- `includePlanTool` / `includeApplyPatchTool`: booleans
|
||
|
||
Response: `{ conversationId, model, reasoningEffort?, rolloutPath }`
|
||
|
||
Send input to the active turn:
|
||
|
||
- `sendUserMessage` → enqueue items to the conversation
|
||
- `sendUserTurn` → structured turn with explicit `cwd`, `approvalPolicy`, `sandboxPolicy`, `model`, optional `effort`, and `summary`
|
||
|
||
Interrupt a running turn: `interruptConversation`.
|
||
|
||
List/resume/archive: `listConversations`, `resumeConversation`, `archiveConversation`.
|
||
|
||
## Event stream
|
||
|
||
While a conversation runs, the server sends notifications:
|
||
|
||
- `codex/event` with the serialized Codex event payload. The shape matches `core/src/protocol.rs`’s `Event` and `EventMsg` types. Some notifications include a `_meta.requestId` to correlate with the originating request.
|
||
- Auth notifications via method names `loginChatGptComplete` and `authStatusChange`.
|
||
|
||
Clients should render events and, when present, surface approval requests (see next section).
|
||
|
||
## Approvals (server → client)
|
||
|
||
When Codex needs approval to apply changes or run commands, the server issues JSON‑RPC requests to the client:
|
||
|
||
- `applyPatchApproval { conversationId, callId, fileChanges, reason?, grantRoot? }`
|
||
- `execCommandApproval { conversationId, callId, command, cwd, reason? }`
|
||
|
||
The client must reply with `{ decision: "allow" | "deny" }` for each request.
|
||
|
||
## Auth helpers
|
||
|
||
For ChatGPT or API‑key based auth flows, the server exposes helpers:
|
||
|
||
- `loginApiKey { apiKey }`
|
||
- `loginChatGpt` → returns `{ loginId, authUrl }`; browser completes flow; then `loginChatGptComplete` notification follows
|
||
- `cancelLoginChatGpt { loginId }`, `logoutChatGpt`, `getAuthStatus { includeToken?, refreshToken? }`
|
||
|
||
## Example: start and send a message
|
||
|
||
```json
|
||
{ "jsonrpc": "2.0", "id": 1, "method": "newConversation", "params": { "model": "gpt-5", "approvalPolicy": "on-request" } }
|
||
```
|
||
|
||
Server responds:
|
||
|
||
```json
|
||
{ "jsonrpc": "2.0", "id": 1, "result": { "conversationId": "c7b0…", "model": "gpt-5", "rolloutPath": "/path/to/rollout.jsonl" } }
|
||
```
|
||
|
||
Then send input:
|
||
|
||
```json
|
||
{ "jsonrpc": "2.0", "id": 2, "method": "sendUserMessage", "params": { "conversationId": "c7b0…", "items": [{ "type": "text", "text": "Hello Codex" }] } }
|
||
```
|
||
|
||
While processing, the server emits `codex/event` notifications containing agent output, approvals, and status updates.
|
||
|
||
## Compatibility and stability
|
||
|
||
This interface is experimental. Method names, fields, and event shapes may evolve. For the authoritative schema, consult `protocol/src/mcp_protocol.rs` and the corresponding server wiring in `mcp-server/`.
|