mcp: keep elicitation requests below app wire types (#29724)

## Why

Core and tools need to request MCP elicitation without constructing
app-server wire payloads. The request should remain a neutral protocol
concept until app-server serializes it for a client.

## What changed

- Switched core and tools to
`codex_protocol::approvals::ElicitationRequest`.
- Derived turn and server context inside core instead of carrying
app-server request types through lower layers.
- Kept the app-server payload unchanged through an explicit boundary
conversion.
- Removed the remaining production app-server-protocol dependency from
tools.

## Stack

This is PR 5 of 6, stacked on [PR
#29723](https://github.com/openai/codex/pull/29723). Review only the
delta from `codex/split-connector-metadata-types`. Next: [PR
#29725](https://github.com/openai/codex/pull/29725).

## Validation

- `codex-core` MCP coverage passed: 87 tests.
- Tools elicitation and app-server round-trip coverage passed.
This commit is contained in:
Adam Perry @ OpenAI
2026-06-24 13:53:27 -07:00
committed by GitHub
Unverified
parent a33ad93996
commit df1ee09ec5
10 changed files with 173 additions and 288 deletions
+12 -27
View File
@@ -1,10 +1,5 @@
use std::collections::BTreeMap;
use codex_app_server_protocol::McpElicitationObjectType;
use codex_app_server_protocol::McpElicitationSchema;
use codex_app_server_protocol::McpServerElicitationRequest;
use codex_app_server_protocol::McpServerElicitationRequestParams;
use codex_connectors::AppInfo;
use codex_protocol::approvals::ElicitationRequest;
use serde::Deserialize;
use serde::Serialize;
use serde_json::json;
@@ -54,31 +49,21 @@ pub struct RequestPluginInstallMeta<'a> {
}
pub fn build_request_plugin_install_elicitation_request(
server_name: &str,
thread_id: String,
turn_id: String,
suggest_reason: &str,
tool: &DiscoverableTool,
) -> McpServerElicitationRequestParams {
) -> ElicitationRequest {
let message = suggest_reason.to_string();
McpServerElicitationRequestParams {
thread_id,
turn_id: Some(turn_id),
server_name: server_name.to_string(),
request: McpServerElicitationRequest::Form {
meta: Some(json!(build_request_plugin_install_meta(
suggest_reason,
tool,
))),
message,
requested_schema: McpElicitationSchema {
schema_uri: None,
type_: McpElicitationObjectType::Object,
properties: BTreeMap::new(),
required: None,
},
},
ElicitationRequest::Form {
meta: Some(json!(build_request_plugin_install_meta(
suggest_reason,
tool,
))),
message,
requested_schema: json!({
"type": "object",
"properties": {},
}),
}
}
@@ -27,42 +27,32 @@ fn build_request_plugin_install_elicitation_request_uses_expected_shape() {
}));
let request = build_request_plugin_install_elicitation_request(
"codex-apps",
"thread-1".to_string(),
"turn-1".to_string(),
"Plan and reference events from your calendar",
&connector,
);
assert_eq!(
request,
McpServerElicitationRequestParams {
thread_id: "thread-1".to_string(),
turn_id: Some("turn-1".to_string()),
server_name: "codex-apps".to_string(),
request: McpServerElicitationRequest::Form {
meta: Some(json!(RequestPluginInstallMeta {
codex_approval_kind: REQUEST_PLUGIN_INSTALL_APPROVAL_KIND_VALUE,
persist: REQUEST_PLUGIN_INSTALL_PERSIST_ALWAYS_VALUE,
tool_type: DiscoverableToolType::Connector,
suggest_type: DiscoverableToolAction::Install,
suggest_reason: "Plan and reference events from your calendar",
tool_id: "connector_2128aebfecb84f64a069897515042a44",
tool_name: "Google Calendar",
install_url: Some(
"https://chatgpt.com/apps/google-calendar/connector_2128aebfecb84f64a069897515042a44"
),
remote_plugin_id: None,
app_connector_ids: None,
})),
message: "Plan and reference events from your calendar".to_string(),
requested_schema: McpElicitationSchema {
schema_uri: None,
type_: McpElicitationObjectType::Object,
properties: BTreeMap::new(),
required: None,
},
},
ElicitationRequest::Form {
meta: Some(json!(RequestPluginInstallMeta {
codex_approval_kind: REQUEST_PLUGIN_INSTALL_APPROVAL_KIND_VALUE,
persist: REQUEST_PLUGIN_INSTALL_PERSIST_ALWAYS_VALUE,
tool_type: DiscoverableToolType::Connector,
suggest_type: DiscoverableToolAction::Install,
suggest_reason: "Plan and reference events from your calendar",
tool_id: "connector_2128aebfecb84f64a069897515042a44",
tool_name: "Google Calendar",
install_url: Some(
"https://chatgpt.com/apps/google-calendar/connector_2128aebfecb84f64a069897515042a44"
),
remote_plugin_id: None,
app_connector_ids: None,
})),
message: "Plan and reference events from your calendar".to_string(),
requested_schema: json!({
"type": "object",
"properties": {},
}),
},
);
}
@@ -80,40 +70,30 @@ fn build_request_plugin_install_elicitation_request_injects_plugin_metadata() {
}));
let request = build_request_plugin_install_elicitation_request(
"codex-apps",
"thread-1".to_string(),
"turn-1".to_string(),
"Use the sample plugin's skills and MCP server",
&plugin,
);
assert_eq!(
request,
McpServerElicitationRequestParams {
thread_id: "thread-1".to_string(),
turn_id: Some("turn-1".to_string()),
server_name: "codex-apps".to_string(),
request: McpServerElicitationRequest::Form {
meta: Some(json!(RequestPluginInstallMeta {
codex_approval_kind: REQUEST_PLUGIN_INSTALL_APPROVAL_KIND_VALUE,
persist: REQUEST_PLUGIN_INSTALL_PERSIST_ALWAYS_VALUE,
tool_type: DiscoverableToolType::Plugin,
suggest_type: DiscoverableToolAction::Install,
suggest_reason: "Use the sample plugin's skills and MCP server",
tool_id: "sample@openai-curated-remote",
tool_name: "Sample Plugin",
install_url: None,
remote_plugin_id: Some("plugins~Plugin_sample"),
app_connector_ids: Some(&["connector_calendar".to_string()]),
})),
message: "Use the sample plugin's skills and MCP server".to_string(),
requested_schema: McpElicitationSchema {
schema_uri: None,
type_: McpElicitationObjectType::Object,
properties: BTreeMap::new(),
required: None,
},
},
ElicitationRequest::Form {
meta: Some(json!(RequestPluginInstallMeta {
codex_approval_kind: REQUEST_PLUGIN_INSTALL_APPROVAL_KIND_VALUE,
persist: REQUEST_PLUGIN_INSTALL_PERSIST_ALWAYS_VALUE,
tool_type: DiscoverableToolType::Plugin,
suggest_type: DiscoverableToolAction::Install,
suggest_reason: "Use the sample plugin's skills and MCP server",
tool_id: "sample@openai-curated-remote",
tool_name: "Sample Plugin",
install_url: None,
remote_plugin_id: Some("plugins~Plugin_sample"),
app_connector_ids: Some(&["connector_calendar".to_string()]),
})),
message: "Use the sample plugin's skills and MCP server".to_string(),
requested_schema: json!({
"type": "object",
"properties": {},
}),
},
);
}