diff --git a/codex-rs/app-server-protocol/schema/json/ServerNotification.json b/codex-rs/app-server-protocol/schema/json/ServerNotification.json index 116844171..d7619354f 100644 --- a/codex-rs/app-server-protocol/schema/json/ServerNotification.json +++ b/codex-rs/app-server-protocol/schema/json/ServerNotification.json @@ -1736,6 +1736,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 80f2b226b..09f0daefd 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -9184,6 +9184,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index eb4e9d7b1..620495f8b 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -6007,6 +6007,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json index 396410786..2883670c8 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json @@ -294,6 +294,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json index abb8aee5d..c2e71ccba 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json @@ -294,6 +294,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json index 4bdeebf57..a7fe2e8d6 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json @@ -430,6 +430,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json index a79ac103c..9b1870198 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json @@ -518,6 +518,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json index e8211b252..426f34ce3 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json @@ -456,6 +456,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json index 08c4696bb..c869a7974 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json @@ -456,6 +456,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json index f6d67d5c0..9569860c3 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json @@ -456,6 +456,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json index 169743504..5143545ec 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json @@ -518,6 +518,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json index e664490df..502dd3961 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json @@ -456,6 +456,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json index 98e022c75..c07b4d825 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json @@ -518,6 +518,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json index f640c4096..ff87af206 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json @@ -456,6 +456,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json index 1c10ea3b8..daf821c37 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json @@ -456,6 +456,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json index fc1deb675..82c2b3c76 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json @@ -430,6 +430,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json index 5b79f4df1..ebb2065cb 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json @@ -430,6 +430,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json index ccbe93e9c..8b7c2bc41 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json @@ -430,6 +430,7 @@ }, "McpToolCallResult": { "properties": { + "_meta": true, "content": { "items": true, "type": "array" diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/McpToolCallResult.ts b/codex-rs/app-server-protocol/schema/typescript/v2/McpToolCallResult.ts index f493a8609..916a5f5bb 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/McpToolCallResult.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/McpToolCallResult.ts @@ -3,4 +3,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { JsonValue } from "../serde_json/JsonValue"; -export type McpToolCallResult = { content: Array, structuredContent: JsonValue | null, }; +export type McpToolCallResult = { content: Array, structuredContent: JsonValue | null, _meta: JsonValue | null, }; diff --git a/codex-rs/app-server-protocol/src/protocol/thread_history.rs b/codex-rs/app-server-protocol/src/protocol/thread_history.rs index 10d55bb23..27d393629 100644 --- a/codex-rs/app-server-protocol/src/protocol/thread_history.rs +++ b/codex-rs/app-server-protocol/src/protocol/thread_history.rs @@ -520,6 +520,7 @@ impl ThreadHistoryBuilder { Some(McpToolCallResult { content: value.content.clone(), structured_content: value.structured_content.clone(), + meta: value.meta.clone(), }), None, ), @@ -1167,6 +1168,7 @@ mod tests { use codex_protocol::items::TurnItem as CoreTurnItem; use codex_protocol::items::UserMessageItem as CoreUserMessageItem; use codex_protocol::items::build_hook_prompt_message; + use codex_protocol::mcp::CallToolResult; use codex_protocol::models::MessagePhase as CoreMessagePhase; use codex_protocol::models::WebSearchAction as CoreWebSearchAction; use codex_protocol::parse_command::ParsedCommand; @@ -1861,6 +1863,67 @@ mod tests { ); } + #[test] + fn reconstructs_mcp_tool_result_meta_from_persisted_completion_events() { + let events = vec![ + EventMsg::TurnStarted(TurnStartedEvent { + turn_id: "turn-1".into(), + started_at: None, + model_context_window: None, + collaboration_mode_kind: Default::default(), + }), + EventMsg::McpToolCallEnd(McpToolCallEndEvent { + call_id: "mcp-1".into(), + invocation: McpInvocation { + server: "docs".into(), + tool: "lookup".into(), + arguments: Some(serde_json::json!({"id":"123"})), + }, + duration: Duration::from_millis(8), + result: Ok(CallToolResult { + content: vec![serde_json::json!({ + "type": "text", + "text": "result" + })], + structured_content: Some(serde_json::json!({"id":"123"})), + is_error: Some(false), + meta: Some(serde_json::json!({ + "ui/resourceUri": "ui://widget/lookup.html" + })), + }), + }), + ]; + + let items = events + .into_iter() + .map(RolloutItem::EventMsg) + .collect::>(); + let turns = build_turns_from_rollout_items(&items); + assert_eq!(turns.len(), 1); + assert_eq!( + turns[0].items[0], + ThreadItem::McpToolCall { + id: "mcp-1".into(), + server: "docs".into(), + tool: "lookup".into(), + status: McpToolCallStatus::Completed, + arguments: serde_json::json!({"id":"123"}), + result: Some(McpToolCallResult { + content: vec![serde_json::json!({ + "type": "text", + "text": "result" + })], + structured_content: Some(serde_json::json!({"id":"123"})), + meta: Some(serde_json::json!({ + "ui/resourceUri": "ui://widget/lookup.html" + })), + }), + error: None, + duration_ms: Some(8), + } + ); + } + #[test] fn reconstructs_dynamic_tool_items_from_request_and_response_events() { let events = vec![ diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 3562d9cda..296baa1fe 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -5048,6 +5048,9 @@ pub struct McpToolCallResult { // representations). Using `JsonValue` keeps the payload wire-shaped and easy to export. pub content: Vec, pub structured_content: Option, + #[serde(rename = "_meta")] + #[ts(rename = "_meta")] + pub meta: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] diff --git a/codex-rs/app-server/src/bespoke_event_handling.rs b/codex-rs/app-server/src/bespoke_event_handling.rs index 141ee78bd..f5c60fe9d 100644 --- a/codex-rs/app-server/src/bespoke_event_handling.rs +++ b/codex-rs/app-server/src/bespoke_event_handling.rs @@ -2843,6 +2843,7 @@ async fn construct_mcp_tool_call_end_notification( Some(McpToolCallResult { content: value.content.clone(), structured_content: value.structured_content.clone(), + meta: value.meta.clone(), }), None, ), @@ -4233,7 +4234,9 @@ mod tests { content: content.clone(), is_error: Some(false), structured_content: None, - meta: None, + meta: Some(serde_json::json!({ + "ui/resourceUri": "ui://widget/list-resources.html" + })), }; let end_event = McpToolCallEndEvent { @@ -4268,6 +4271,9 @@ mod tests { result: Some(McpToolCallResult { content, structured_content: None, + meta: Some(serde_json::json!({ + "ui/resourceUri": "ui://widget/list-resources.html" + })), }), error: None, duration_ms: Some(0), diff --git a/codex-rs/exec/tests/event_processor_with_json_output.rs b/codex-rs/exec/tests/event_processor_with_json_output.rs index a6b25b66b..bb2936656 100644 --- a/codex-rs/exec/tests/event_processor_with_json_output.rs +++ b/codex-rs/exec/tests/event_processor_with_json_output.rs @@ -482,6 +482,7 @@ fn mcp_tool_call_begin_and_end_emit_item_events() { result: Some(McpToolCallResult { content: Vec::new(), structured_content: None, + meta: None, }), error: None, duration_ms: Some(1_000), @@ -613,6 +614,7 @@ fn mcp_tool_call_defaults_arguments_and_preserves_structured_content() { "text": "done", })], structured_content: Some(json!({ "status": "ok" })), + meta: None, }), error: None, duration_ms: Some(10),