Preserve app invocation context across MCP tool refreshes (#59991)

## What changed

Keep the advertised `_codex_apps.invocation_context` when an app's tool metadata refreshes on the same server connection, while using refreshed values for other metadata. If the invocation context changes on a different connection, skip the call as unavailable.

## Testing

Extend the code-mode compaction test to refresh app tools before resuming a cell and verify that calls retain the original invocation context while picking up the refreshed `resource_uri`.

GitOrigin-RevId: 1b6072faed74623994ea82035a6ed977451984a4
This commit is contained in:
fahad-OAI
2026-11-06 21:53:04 +00:00
committed by copyberry
parent 1a2f5babe8
commit 8fcabd75a0
5 changed files with 65 additions and 16 deletions
+21 -4
View File
@@ -2031,10 +2031,17 @@ fn result_metadata_apps_builder(base_url: String, account_email: &str) -> TestCo
async fn code_mode_mcp_metadata_keeps_originating_window_after_compaction() -> Result<()> {
skip_if_no_network!(Ok(()));
let server = responses::start_mock_server().await;
let apps_server = mount_result_metadata_app(
&server, /*result_metadata*/ None, /*is_error*/ false,
)
.await?;
let tools = Arc::new(Mutex::new(vec![serde_json::json!({
"name": RESULT_METADATA_TOOL,
"inputSchema": { "type": "object" },
"annotations": { "readOnlyHint": true },
"_meta": {
"connector_id": "test_connector",
"connector_name": "MessageSearch",
"_codex_apps": { "invocation_context": "original" },
},
})]));
let apps_server = AppsTestServer::mount_with_tools(&server, Arc::clone(&tools)).await?;
let (reached_tx, reached_rx) = oneshot::channel();
let (release_tx, release_rx) = oneshot::channel();
let control = Arc::new(ResultMetadataTestControl {
@@ -2118,6 +2125,11 @@ text("done");"#,
"wait",
)
.await;
tools.lock().unwrap()[0]["_meta"]["_codex_apps"] = serde_json::json!({
"invocation_context": "refreshed",
"resource_uri": "connector://messages/search",
});
test.codex.refresh_codex_apps_tools().await?;
release_tx.send(()).unwrap();
test.submit_turn("Finish the code-mode cell").await?;
let resumed_request = resumed.function_call.single_request();
@@ -2138,8 +2150,13 @@ text("done");"#,
);
let calls = recorded_apps_tool_calls(&server).await;
assert_eq!(calls.len(), 2);
assert_eq!(
calls[1]["params"]["_meta"]["_codex_apps"]["resource_uri"],
"connector://messages/search"
);
for call in calls {
let meta = &call["params"]["_meta"];
assert_eq!(meta["_codex_apps"]["invocation_context"], "original");
assert_eq!(
serde_json::json!({
"sessionId": meta["sessionId"],