Skip to content

Commit 12f023d

Browse files
committed
feat: enable Streamable HTTP MCP servers & lazy loading of tools
1 parent d2b2a6d commit 12f023d

File tree

8 files changed

+573
-94
lines changed

8 files changed

+573
-94
lines changed

codex-rs/Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codex-rs/config.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ You can further customize how Codex runs at the command line using the `--ask-fo
312312

313313
## mcp_servers
314314

315-
Defines the list of MCP servers that Codex can consult for tool use. Currently, only servers that are launched by executing a program that communicate over stdio are supported. For servers that use the SSE transport, consider an adapter like [mcp-proxy](https://github.com/sparfenyuk/mcp-proxy).
315+
Defines the list of MCP servers that Codex can consult for tool use. Servers may either be launched as subprocesses that communicate over stdio or accessed via the Streamable HTTP transport.
316316

317317
**Note:** Codex may cache the list of tools and resources from an MCP server so that Codex can include this information in context at startup without spawning all the servers. This is designed to save resources by loading MCP servers lazily.
318318

@@ -340,8 +340,15 @@ Should be represented as follows in `~/.codex/config.toml`:
340340
command = "npx"
341341
args = ["-y", "mcp-server"]
342342
env = { "API_KEY" = "value" }
343+
344+
# Streamable HTTP remote servers
345+
[mcp_servers.my_mcp_sever]
346+
url = "https://{the-actual-domain-here}/mcp"
347+
# headers = { Authorization = "Bearer {token}" }
343348
```
344349

350+
When you start a new session, it automatically begins fetching the list of tools in the background. If some tools may take a little longer to load, you can run `/mcp` command to confirm everything is ready before sending your prompt.
351+
345352
## disable_response_storage
346353

347354
Currently, customers whose accounts are set to use Zero Data Retention (ZDR) must set `disable_response_storage` to `true` so that Codex uses an alternative to the Responses API that works with ZDR:

codex-rs/core/src/codex.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,9 @@ impl Session {
532532
}
533533
}
534534

535+
// Kick off background MCP tool initialization/loading without blocking the UI.
536+
sess.mcp_connection_manager.refresh_tools_in_background();
537+
535538
Ok((sess, turn_context))
536539
}
537540

@@ -1206,7 +1209,12 @@ async fn submission_loop(
12061209
let tx_event = sess.tx_event.clone();
12071210
let sub_id = sub.id.clone();
12081211

1209-
// This is a cheap lookup from the connection manager's cache.
1212+
// Refresh tools on-demand to give users an up-to-date list.
1213+
// This runs in the foreground for this operation only.
1214+
if let Err(e) = sess.mcp_connection_manager.refresh_tools().await {
1215+
warn!("failed to refresh MCP tools: {e:#}");
1216+
}
1217+
12101218
let tools = sess.mcp_connection_manager.list_all_tools();
12111219
let event = Event {
12121220
id: sub_id,
@@ -1486,6 +1494,12 @@ async fn run_turn(
14861494
sub_id: String,
14871495
input: Vec<ResponseItem>,
14881496
) -> CodexResult<Vec<ProcessedResponseItem>> {
1497+
// Give MCP tools a brief moment to arrive if background discovery is still running.
1498+
// This avoids an empty tool list in the first turn right after startup.
1499+
sess.mcp_connection_manager
1500+
.wait_for_tools_with_timeout(std::time::Duration::from_millis(800))
1501+
.await;
1502+
14891503
let tools = get_openai_tools(
14901504
&turn_context.tools_config,
14911505
Some(sess.mcp_connection_manager.list_all_tools()),

codex-rs/core/src/config_types.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,25 @@ use wildmatch::WildMatchPattern;
1010
use serde::Deserialize;
1111

1212
#[derive(Deserialize, Debug, Clone, PartialEq)]
13-
pub struct McpServerConfig {
14-
pub command: String,
15-
16-
#[serde(default)]
17-
pub args: Vec<String>,
18-
19-
#[serde(default)]
20-
pub env: Option<HashMap<String, String>>,
13+
#[serde(untagged)]
14+
pub enum McpServerConfig {
15+
/// MCP server launched as a subprocess that communicates over stdio.
16+
Stdio {
17+
command: String,
18+
19+
#[serde(default)]
20+
args: Vec<String>,
21+
22+
#[serde(default)]
23+
env: Option<HashMap<String, String>>,
24+
},
25+
/// MCP server reachable via the Streamable HTTP transport.
26+
StreamableHttp {
27+
url: String,
28+
29+
#[serde(default)]
30+
headers: Option<HashMap<String, String>>,
31+
},
2132
}
2233

2334
#[derive(Deserialize, Debug, Copy, Clone, PartialEq)]

0 commit comments

Comments
 (0)