The Model Context Protocol (MCP) integration enables Codex to connect to external tool servers that implement the MCP specification. MCP servers expose tools, resources, and resource templates that extend Codex's capabilities beyond built-in tools. The integration supports two transport mechanisms: stdio (subprocess-based) and streamable HTTP (network-based with OAuth support).
This page covers MCP server configuration, connection management, CLI commands, and the codex-mcp-server implementation that exposes Codex as an MCP tool provider. For information about how MCP tools integrate with the broader tool execution system, see Tool System.
MCP servers are configured in config.toml under the mcp_servers table. Each server entry is keyed by server name and contains a McpServerConfig struct specifying connection details, enabled/disabled status, timeouts, and optional tool filters.
Title: MCP Server Configuration Data Model
Sources: codex-rs/core/src/mcp_connection_manager.rs72-76 codex-rs/cli/src/mcp_cmd.rs66-127 codex-rs/core/tests/suite/rmcp_client.rs86-108
McpServerTransportConfig::Stdio
Launches an MCP server as a subprocess with stdio-based communication.
| Field | Type | Description |
|---|---|---|
command | String | Executable path or name |
args | Vec<String> | Command-line arguments |
env | Option<HashMap<String, String>> | Hardcoded environment variables (key=value pairs) |
env_vars | Vec<String> | Environment variable names to propagate from parent process |
cwd | Option<PathBuf> | Working directory for the subprocess |
McpServerTransportConfig::StreamableHttp
Connects to an HTTP-based MCP server with optional OAuth support.
| Field | Type | Description |
|---|---|---|
url | String | Base URL of the MCP server endpoint |
bearer_token_env_var | Option<String> | Environment variable containing bearer token |
http_headers | Option<HashMap<String, String>> | Static HTTP headers to include in requests |
env_http_headers | Option<HashMap<String, String>> | HTTP headers sourced from environment variables |
Sources: codex-rs/core/src/mcp_connection_manager.rs950-975 codex-rs/cli/src/mcp_cmd.rs93-127 codex-rs/core/tests/suite/rmcp_client.rs88-99
MCP servers expose tool filtering through two optional fields:
enabled_tools: If present, only listed tools are made available (allowlist)disabled_tools: Explicitly blocks listed tools (denylist)A tool is allowed if:
enabled_tools is None OR the tool is in enabled_tools, ANDdisabled_toolsSources: codex-rs/core/src/mcp_connection_manager.rs802-835
The McpConnectionManager struct (codex-rs/core/src/mcp_connection_manager.rs349-353) owns one RmcpClient per configured server and provides unified access to tools, resources, and resource templates across all servers. It handles server lifecycle, tool discovery, and execution routing.
Title: McpConnectionManager Architecture
Sources: codex-rs/core/src/mcp_connection_manager.rs349-353 codex-rs/core/src/mcp_connection_manager.rs252-259 codex-rs/core/src/mcp_connection_manager.rs279-282 codex-rs/core/src/mcp_connection_manager.rs165-172
The McpConnectionManager::initialize() method (codex-rs/core/src/mcp_connection_manager.rs356-458) spawns asynchronous initialization tasks for each enabled server. The process uses a Shared<BoxFuture> pattern to enable multiple concurrent consumers to await the same initialization result.
Title: MCP Server Initialization Flow
Initialization Steps:
validate_mcp_server_name() ensures server name matches ^[a-zA-Z0-9_-]+$make_rmcp_client() creates stdio or HTTP-based RmcpClientinitialize request with ClientCapabilities including elicitation supportlist_tools to fetch available tools from servercodex/sandbox-state capability, send initial stateMcpStartupUpdateEvent (Starting → Ready/Failed) and final McpStartupCompleteEventSources: codex-rs/core/src/mcp_connection_manager.rs356-458 codex-rs/core/src/mcp_connection_manager.rs995-1046 codex-rs/core/src/mcp_connection_manager.rs285-330
Servers marked with required: true will block turn execution if they fail to initialize. The required_startup_failures() method checks for failures among required servers and returns a list of McpStartupFailure entries.
Sources: codex-rs/core/src/mcp_connection_manager.rs477-500
The McpConnectionManager::list_all_tools() method (codex-rs/core/src/mcp_connection_manager.rs519-546) aggregates tools from all initialized servers and returns a qualified map.
Title: Tool Discovery and Name Qualification Flow
Tool Name Format:
MCP tools are qualified as mcp__<server>__<tool> to prevent collisions. For example:
github, tool search → mcp__github__searchslack, tool send_message → mcp__slack__send_messageThe MCP_TOOL_NAME_DELIMITER constant is "__" (codex-rs/core/src/mcp_connection_manager.rs82).
Name Sanitization:
The sanitize_responses_api_tool_name() function (codex-rs/core/src/mcp_connection_manager.rs99-114) enforces OpenAI's Responses API constraint of ^[a-zA-Z0-9_-]+$ by replacing disallowed characters with _.
If the sanitized name exceeds MAX_TOOL_NAME_LENGTH (64 characters), it is truncated and a SHA-1 hash of the original unsanitized name is appended to ensure uniqueness (codex-rs/core/src/mcp_connection_manager.rs147-151).
Codex Apps Caching:
The CODEX_APPS_MCP_SERVER_NAME server has special caching with CODEX_APPS_TOOLS_CACHE_TTL of 3600 seconds (codex-rs/core/src/mcp_connection_manager.rs91). The cache (CODEX_APPS_TOOLS_CACHE static at codex-rs/core/src/mcp_connection_manager.rs180-181) stores CachedCodexAppsTools with an expiry timestamp. On cache miss or expiry, list_tools_for_client() refreshes the tools.
Sources: codex-rs/core/src/mcp_connection_manager.rs519-546 codex-rs/core/src/mcp_connection_manager.rs82 codex-rs/core/src/mcp_connection_manager.rs99-114 codex-rs/core/src/mcp_connection_manager.rs123-163 codex-rs/core/src/mcp_connection_manager.rs91 codex-rs/core/src/mcp_connection_manager.rs180-181
When the model requests an MCP tool, the execution flow routes through McpConnectionManager::call_tool() (codex-rs/core/src/mcp_connection_manager.rs712-746).
Title: MCP Tool Call Execution Flow
Sources: codex-rs/core/src/mcp_connection_manager.rs712-746 codex-rs/core/src/mcp_connection_manager.rs460-467 codex-rs/core/src/mcp_connection_manager.rs797-802 codex-rs/core/src/mcp_connection_manager.rs869-877
CallToolResult Structure:
The CallToolResult returned by call_tool() is converted from rmcp::model::CallToolResult to codex_protocol::mcp::CallToolResult (codex-rs/core/src/mcp_connection_manager.rs731-745).
| Field | Type | Description |
|---|---|---|
content | Vec<Value> | Array of content items (text, image, resource) from result.content |
structured_content | Option<Value> | Optional structured data from result.structured_content |
is_error | Option<bool> | Whether the tool execution resulted in an error |
meta | Option<Value> | Optional metadata from result.meta |
Timeout Configuration:
| Timeout | Default | Description |
|---|---|---|
startup_timeout_sec | DEFAULT_STARTUP_TIMEOUT (10s) | Timeout for server initialization and initial tool listing |
tool_timeout_sec | DEFAULT_TOOL_TIMEOUT (60s) | Timeout for individual tools/call RPC requests |
Sources: codex-rs/core/src/mcp_connection_manager.rs731-745 codex-rs/core/src/mcp_connection_manager.rs86-89
MCP servers can expose resources (data/content) and resource templates (parameterized resource patterns). The McpConnectionManager provides methods to list and read these from all servers.
Resource API Methods:
| Method | Returns | Pagination | Source |
|---|---|---|---|
list_all_resources() | HashMap<String, Vec<Resource>> | Automatic cursor-based | codex-rs/core/src/mcp_connection_manager.rs577-639 |
list_all_resource_templates() | HashMap<String, Vec<ResourceTemplate>> | Automatic cursor-based | codex-rs/core/src/mcp_connection_manager.rs643-709 |
list_resources(server, params) | ListResourcesResult | Manual cursor in params | codex-rs/core/src/mcp_connection_manager.rs749-762 |
list_resource_templates(server, params) | ListResourceTemplatesResult | Manual cursor in params | codex-rs/core/src/mcp_connection_manager.rs765-778 |
read_resource(server, params) | ReadResourceResult | N/A | codex-rs/core/src/mcp_connection_manager.rs781-795 |
Pagination:
The list_all_*() methods automatically follow next_cursor values (codex-rs/core/src/mcp_connection_manager.rs606-616 codex-rs/core/src/mcp_connection_manager.rs672-683) until exhausted, returning all resources/templates across all servers keyed by server name.
Sources: codex-rs/core/src/mcp_connection_manager.rs577-795
Servers configured with required: true must initialize successfully before turn execution begins. The McpConnectionManager::required_startup_failures() method (codex-rs/core/src/mcp_connection_manager.rs491-514) checks for failures among required servers and returns Vec<McpStartupFailure> with error details.
Sources: codex-rs/core/src/mcp_connection_manager.rs491-514
The codex mcp subcommand (codex-rs/cli/src/mcp_cmd.rs30-37) provides a complete interface for managing MCP server configurations. The CLI dispatches to six subcommands defined in McpSubcommand (codex-rs/cli/src/mcp_cmd.rs39-47).
Title: MCP CLI Command Structure
Sources: codex-rs/cli/src/mcp_cmd.rs30-47 codex-rs/cli/src/mcp_cmd.rs66-127
The codex mcp add command (codex-rs/cli/src/mcp_cmd.rs183-287) creates a new MCP server configuration in ~/.codex/config.toml using ConfigEditsBuilder.
Add Stdio Server:
Creates McpServerTransportConfig::Stdio with:
command: "docs-server"args: ["--port", "4000"]env: {"TOKEN": "secret"}Add StreamableHttp Server:
Creates McpServerTransportConfig::StreamableHttp with:
url: "https://api.github.com/mcp"bearer_token_env_var: Some("GITHUB_TOKEN")After adding an HTTP server, the command checks for OAuth support via oauth_login_support() (codex-rs/cli/src/mcp_cmd.rs265-284). If detected, it automatically initiates the OAuth flow.
Sources: codex-rs/cli/src/mcp_cmd.rs183-287 codex-rs/cli/tests/mcp_add_remove.rs16-69
The codex mcp list command (codex-rs/cli/src/mcp_cmd.rs395-643) displays configured servers in human-readable or JSON format.
Human-Readable Output:
Servers are split into two tables by transport type:
Stdio Servers:
Name Command Args Env Cwd Status Auth
docs docs-server --port 4000 TOKEN=***** - enabled Unsupported
StreamableHttp Servers:
Name Url Bearer Token Env Var Status Auth
github https://api.github.com/mcp GITHUB_TOKEN enabled Required
JSON Output:
Returns a JSON array of server configurations with full details including transport, startup_timeout_sec, tool_timeout_sec, and auth_status.
Sources: codex-rs/cli/src/mcp_cmd.rs395-643 codex-rs/cli/tests/mcp_list.rs20-139
The codex mcp get <name> command (codex-rs/cli/src/mcp_cmd.rs645-802) displays details for a single server. Output includes transport configuration, enabled tools, disabled tools, and timeout settings.
Example Output:
docs
enabled: true
transport: stdio
command: docs-server
args: --port 4000
env: TOKEN=*****
remove: codex mcp remove docs
Sources: codex-rs/cli/src/mcp_cmd.rs645-802 codex-rs/cli/tests/mcp_list.rs34-139
The codex mcp remove <name> command (codex-rs/cli/src/mcp_cmd.rs289-320) deletes the server configuration from ~/.codex/config.toml.
Sources: codex-rs/cli/src/mcp_cmd.rs289-320 codex-rs/cli/tests/mcp_add_remove.rs48-68
MCP servers using StreamableHttp transport can require OAuth authentication. Codex supports OAuth discovery, token storage, and automatic refresh.
Title: OAuth Authentication Flow for MCP Servers
Sources: codex-rs/cli/src/mcp_cmd.rs322-362
| Command | Purpose | Implementation |
|---|---|---|
codex mcp login <server> [--scopes s1,s2] | Initiate OAuth flow | codex-rs/cli/src/mcp_cmd.rs322-362 |
codex mcp logout <server> | Delete stored credentials | codex-rs/cli/src/mcp_cmd.rs365-393 |
The login command:
StreamableHttp transport/.well-known/oauth-authorization-serverauthorization_endpointlocalhost:<mcp_oauth_callback_port> for callbacktoken_endpointaccess_token, refresh_token, expires_at in keychain or ~/.codex/.credentials.jsonToken Storage:
The mcp_oauth_credentials_store_mode config setting (codex-rs/cli/src/mcp_cmd.rs271 codex-rs/cli/src/mcp_cmd.rs354) controls storage:
OAuthCredentialsStoreMode::Keychain: System keychain (macOS/Windows)OAuthCredentialsStoreMode::FallbackFile: ~/.codex/.credentials.jsonSources: codex-rs/cli/src/mcp_cmd.rs322-393 codex-rs/cli/src/mcp_cmd.rs265-284
The codex-mcp-server crate exposes Codex as an MCP tool provider, enabling other MCP clients to invoke Codex as a tool. This allows integration with other MCP-compatible systems.
Key Features:
run_codex tool that accepts user input and returns Codex's responseThe server implementation follows the MCP specification and uses the RmcpServer from the rmcp library to handle protocol details. When a client calls run_codex, the server creates a new Codex session, submits the user's request, and streams events back as notifications.
Sources: Based on the codex-mcp-server crate structure referenced in the repository.
MCP servers can request user input during tool execution via the elicitation mechanism. The McpConnectionManager supports this by declaring elicitation capability in the initialize request (codex-rs/core/src/mcp_connection_manager.rs1011-1018) and providing a SendElicitation callback.
Title: Elicitation Request Flow
The ElicitationRequestManager (codex-rs/core/src/mcp_connection_manager.rs185-250) maintains a map of pending elicitation requests keyed by (server_name, request_id) and resolves them via resolve_elicitation() (codex-rs/core/src/mcp_connection_manager.rs469-478).
Sources: codex-rs/core/src/mcp_connection_manager.rs185-250 codex-rs/core/src/mcp_connection_manager.rs469-478 codex-rs/core/src/mcp_connection_manager.rs1011-1018 codex-rs/core/src/mcp_connection_manager.rs1032
MCP servers can opt into receiving notifications when Codex's sandbox state changes via the codex/sandbox-state capability (codex-rs/core/src/mcp_connection_manager.rs332).
Capability Check:
During initialization, Codex checks if the server's InitializeResult includes experimental capabilities with "codex/sandbox-state" (codex-rs/core/src/mcp_connection_manager.rs1043-1048).
Notification Dispatch:
When sandbox state changes, McpConnectionManager::notify_sandbox_state_change() (codex-rs/core/src/mcp_connection_manager.rs804-830) sends a custom MCP request codex/sandbox-state/update (codex-rs/core/src/mcp_connection_manager.rs336) with SandboxState payload:
Sources: codex-rs/core/src/mcp_connection_manager.rs332-346 codex-rs/core/src/mcp_connection_manager.rs804-830 codex-rs/core/src/mcp_connection_manager.rs1043-1048 codex-rs/core/src/mcp_connection_manager.rs263-277
The initialization process emits status events to inform users of server readiness:
| Event Type | When Emitted | Fields |
|---|---|---|
McpStartupUpdateEvent | Per-server during init | server: String, status: McpStartupStatus |
McpStartupCompleteEvent | After all servers init | ready: Vec<String>, cancelled: Vec<String>, failed: Vec<McpStartupFailure> |
McpStartupStatus Values:
Starting: Server initialization beganReady: Server initialized successfullyFailed { error: String }: Initialization failed with error messageFailure Handling:
The StartupOutcomeError enum (codex-rs/core/src/mcp_connection_manager.rs977-993) represents initialization failures:
Cancelled: Initialization was cancelled (e.g., shutdown)Failed { error: String }: Server failed to initializeSources: codex-rs/core/src/mcp_connection_manager.rs360-457 codex-rs/core/src/mcp_connection_manager.rs977-993
MCP servers can request input from the user during tool execution via the elicitation mechanism. Codex supports this by:
elicitation capability in the initialize requestSendElicitation callback to RmcpClientElicitationRequestEvent to the user interfaceMcpConnectionManager::resolve_elicitation()Sources: codex-rs/core/src/mcp_connection_manager.rs178-236 codex-rs/core/src/mcp_connection_manager.rs455-464 codex-rs/core/src/mcp_connection_manager.rs923-933
The initialization process tracks status for each server and emits events to inform the user:
| Event | When Emitted | Purpose |
|---|---|---|
McpStartupUpdateEvent | During initialization | Reports Starting, Ready, or Failed status per server |
McpStartupCompleteEvent | After all servers initialized | Summary with ready, cancelled, and failed lists |
| Failure Type | Cause | Impact |
|---|---|---|
| Validation Error | Invalid server name format | Server not initialized |
| Connection Error | Cannot spawn process / connect to HTTP | Server marked failed |
| Timeout | Initialization exceeds startup_timeout_sec | Server marked failed |
| Tool Listing Error | list_tools fails after connection | Server marked failed but may retry on use |
Sources: codex-rs/core/src/mcp_connection_manager.rs360-416 codex-rs/core/src/mcp_connection_manager.rs424-443 codex-rs/core/src/mcp_connection_manager.rs897-913
AsyncManagedClient wraps a Shared<BoxFuture> to enable multiple tasks to await the same initialization future. This prevents redundant initialization work when multiple operations need the client.
Sources: codex-rs/core/src/mcp_connection_manager.rs265-316
The list_all_tools() method aggregates tools from all servers:
AsyncManagedClient instancescodex-apps server, fetches fresh tools and updates cacheToolFilterHashMap<String, ToolInfo>Sources: codex-rs/core/src/mcp_connection_manager.rs504-532
Server names must match the pattern ^[a-zA-Z0-9_-]+$ to ensure they can be safely used in qualified tool names and file paths.
Sources: codex-rs/cli/src/mcp_cmd.rs819-830
The test suite demonstrates key MCP functionality:
| Test | Validates |
|---|---|
stdio_server_round_trip | Stdio transport, tool call, environment variable propagation |
stdio_image_responses_round_trip | Image content handling in tool results |
stdio_server_propagates_whitelisted_env_vars | env_vars field propagates parent environment |
streamable_http_tool_call_round_trip | HTTP transport, tool execution |
streamable_http_with_oauth_round_trip | OAuth token storage and usage |
mcp_tool_call_output_exceeds_limit_truncated_for_model | Tool output truncation for large responses |
Sources: codex-rs/core/tests/suite/rmcp_client.rs41-833 codex-rs/core/tests/suite/truncation.rs382-469
Refresh this wiki