feat: add threadId to MCP server messages (#9192)

This favors `threadId` instead of `conversationId` so we use the same
terms as https://developers.openai.com/codex/sdk/.

To test the local build:

```
cd codex-rs
cargo build --bin codex
npx -y @modelcontextprotocol/inspector ./target/debug/codex mcp-server
```

I sent:

```json
{
  "method": "tools/call",
  "params": {
    "name": "codex",
    "arguments": {
      "prompt": "favorite ls option?"
    },
    "_meta": {
      "progressToken": 0
    }
  }
}
```

and got:

```json
{
  "content": [
    {
      "type": "text",
      "text": "`ls -lah` (or `ls -alh`) — long listing, includes dotfiles, human-readable sizes."
    }
  ],
  "structuredContent": {
    "threadId": "019bbb20-bff6-7130-83aa-bf45ab33250e"
  }
}
```

and successfully used the `threadId` in the follow-up with the
`codex-reply` tool call:

```json
{
  "method": "tools/call",
  "params": {
    "name": "codex-reply",
    "arguments": {
      "prompt": "what is the long versoin",
      "threadId": "019bbb20-bff6-7130-83aa-bf45ab33250e"
    },
    "_meta": {
      "progressToken": 1
    }
  }
}
```

whose response also has the `threadId`:

```json
{
  "content": [
    {
      "type": "text",
      "text": "Long listing is `ls -l` (adds permissions, owner/group, size, timestamp)."
    }
  ],
  "structuredContent": {
    "threadId": "019bbb20-bff6-7130-83aa-bf45ab33250e"
  }
}
```

Fixes https://github.com/openai/codex/issues/3712.
This commit is contained in:
Michael Bolin
2026-01-13 22:14:41 -08:00
committed by GitHub
parent 5675af5190
commit 0c09dc3c03
7 changed files with 270 additions and 90 deletions

View File

@@ -4,6 +4,7 @@ use std::sync::Arc;
use codex_core::CodexThread;
use codex_core::protocol::Op;
use codex_core::protocol::ReviewDecision;
use codex_protocol::ThreadId;
use codex_protocol::parse_command::ParsedCommand;
use mcp_types::ElicitRequest;
use mcp_types::ElicitRequestParamsRequestedSchema;
@@ -30,6 +31,8 @@ pub struct ExecApprovalElicitRequestParams {
// These are additional fields the client can use to
// correlate the request with the codex tool call.
#[serde(rename = "threadId")]
pub thread_id: ThreadId,
pub codex_elicitation: String,
pub codex_mcp_tool_call_id: String,
pub codex_event_id: String,
@@ -59,6 +62,7 @@ pub(crate) async fn handle_exec_approval_request(
event_id: String,
call_id: String,
codex_parsed_cmd: Vec<ParsedCommand>,
thread_id: ThreadId,
) {
let escaped_command =
shlex::try_join(command.iter().map(String::as_str)).unwrap_or_else(|_| command.join(" "));
@@ -74,6 +78,7 @@ pub(crate) async fn handle_exec_approval_request(
properties: json!({}),
required: None,
},
thread_id,
codex_elicitation: "exec-approval".to_string(),
codex_mcp_tool_call_id: tool_call_id.clone(),
codex_event_id: event_id.clone(),