use super::shared::v2_enum_from_core;use codex_protocol::approvals::ElicitationRequest as CoreElicitationRequest;use codex_protocol::items::McpToolCallError as CoreMcpToolCallError;use codex_protocol::mcp::CallToolResult as CoreMcpCallToolResult;use codex_protocol::mcp::McpServerInfo;use codex_protocol::mcp::Resource as McpResource;pub use codex_protocol::mcp::ResourceContent as McpResourceContent;use codex_protocol::mcp::ResourceTemplate as McpResourceTemplate;use codex_protocol::mcp::Tool as McpTool;use schemars::JsonSchema;use serde::Deserialize;use serde::Serialize;use serde_json::Value as JsonValue;use std::collections::BTreeMap;use ts_rs::TS;v2_enum_from_core!( pub enum McpAuthStatus from codex_protocol::protocol::McpAuthStatus { Unsupported, NotLoggedIn, BearerToken, OAuth });#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct ListMcpServerStatusParams { /// Opaque pagination cursor returned by a previous call. #[ts(optional = nullable)] pub cursor: Option<String>, /// Optional page size; defaults to a server-defined value. #[ts(optional = nullable)] pub limit: Option<u32>, /// Controls how much MCP inventory data to fetch for each server. /// Defaults to `Full` when omitted. #[ts(optional = nullable)] pub detail: Option<McpServerStatusDetail>, #[ts(optional = nullable)] pub thread_id: Option<String>,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(rename_all = "camelCase", export_to = "v2/")]pub enum McpServerStatusDetail { Full, ToolsAndAuthOnly,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpServerStatus { pub name: String, pub server_info: Option<McpServerInfo>, pub tools: std::collections::HashMap<String, McpTool>, pub resources: Vec<McpResource>, pub resource_templates: Vec<McpResourceTemplate>, pub auth_status: McpAuthStatus,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct ListMcpServerStatusResponse { pub data: Vec<McpServerStatus>, /// Opaque cursor to pass to the next call to continue after the last item. /// If None, there are no more items to return. pub next_cursor: Option<String>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpResourceReadParams { #[ts(optional = nullable)] pub thread_id: Option<String>, pub server: String, pub uri: String,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpResourceReadResponse { pub contents: Vec<McpResourceContent>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpServerToolCallParams { pub thread_id: String, pub server: String, pub tool: String, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub arguments: Option<JsonValue>, #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub meta: Option<JsonValue>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpServerToolCallResponse { pub content: Vec<JsonValue>, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub structured_content: Option<JsonValue>, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub is_error: Option<bool>, #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub meta: Option<JsonValue>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpToolCallResult { // NOTE: `rmcp::model::Content` (and its `RawContent` variants) would be a more precise Rust // representation of MCP content blocks. We intentionally use `serde_json::Value` here because // this crate exports JSON schema + TS types (`schemars`/`ts-rs`), and the rmcp model types // aren't set up to be schema/TS friendly (and would introduce heavier coupling to rmcp's Rust // representations). Using `JsonValue` keeps the payload wire-shaped and easy to export. pub content: Vec<JsonValue>, pub structured_content: Option<JsonValue>, #[serde(rename = "_meta")] #[ts(rename = "_meta")] pub meta: Option<JsonValue>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpToolCallError { pub message: String,}impl From<CoreMcpCallToolResult> for McpServerToolCallResponse { fn from(result: CoreMcpCallToolResult) -> Self { Self { content: result.content, structured_content: result.structured_content, is_error: result.is_error, meta: result.meta, } }}impl From<CoreMcpCallToolResult> for McpToolCallResult { fn from(result: CoreMcpCallToolResult) -> Self { Self { content: result.content, structured_content: result.structured_content, meta: result.meta, } }}impl From<CoreMcpToolCallError> for McpToolCallError { fn from(error: CoreMcpToolCallError) -> Self { Self { message: error.message, } }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpServerRefreshParams {}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpServerRefreshResponse {}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpServerOauthLoginParams { pub name: String, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional = nullable)] pub scopes: Option<Vec<String>>, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional = nullable)] pub timeout_secs: Option<i64>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpServerOauthLoginResponse { pub authorization_url: String,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpToolCallProgressNotification { pub thread_id: String, pub turn_id: String, pub item_id: String, pub message: String,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpServerOauthLoginCompletedNotification { pub name: String, pub success: bool, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub error: Option<String>,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum McpServerStartupState { Starting, Ready, Failed, Cancelled,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpServerStatusUpdatedNotification { pub thread_id: Option<String>, pub name: String, pub status: McpServerStartupState, pub error: Option<String>,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub enum McpServerElicitationAction { Accept, Decline, Cancel,}impl McpServerElicitationAction { pub fn to_core(self) -> codex_protocol::approvals::ElicitationAction { match self { Self::Accept => codex_protocol::approvals::ElicitationAction::Accept, Self::Decline => codex_protocol::approvals::ElicitationAction::Decline, Self::Cancel => codex_protocol::approvals::ElicitationAction::Cancel, } }}impl From<McpServerElicitationAction> for rmcp::model::ElicitationAction { fn from(value: McpServerElicitationAction) -> Self { match value { McpServerElicitationAction::Accept => Self::Accept, McpServerElicitationAction::Decline => Self::Decline, McpServerElicitationAction::Cancel => Self::Cancel, } }}impl From<rmcp::model::ElicitationAction> for McpServerElicitationAction { fn from(value: rmcp::model::ElicitationAction) -> Self { match value { rmcp::model::ElicitationAction::Accept => Self::Accept, rmcp::model::ElicitationAction::Decline => Self::Decline, rmcp::model::ElicitationAction::Cancel => Self::Cancel, } }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpServerElicitationRequestParams { pub thread_id: String, /// Active Codex turn when this elicitation was observed, if app-server could correlate one. /// /// This is nullable because MCP models elicitation as a standalone server-to-client request /// identified by the MCP server request id. It may be triggered during a turn, but turn /// context is app-server correlation rather than part of the protocol identity of the /// elicitation itself. pub turn_id: Option<String>, pub server_name: String, #[serde(flatten)] pub request: McpServerElicitationRequest, // TODO: When core can correlate an elicitation with an MCP tool call, expose the associated // McpToolCall item id here as an optional field. The current core event does not carry that // association.}/// Typed form schema for MCP `elicitation/create` requests.////// This matches the `requestedSchema` shape from the MCP 2025-11-25/// `ElicitRequestFormParams` schema.#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase", deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationSchema { #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")] #[ts(optional, rename = "$schema")] pub schema_uri: Option<String>, #[serde(rename = "type")] #[ts(rename = "type")] pub type_: McpElicitationObjectType, pub properties: BTreeMap<String, McpElicitationPrimitiveSchema>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub required: Option<Vec<String>>,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "lowercase")]#[ts(export_to = "v2/")]pub enum McpElicitationObjectType { Object,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(untagged)]#[ts(export_to = "v2/")]pub enum McpElicitationPrimitiveSchema { Enum(McpElicitationEnumSchema), String(McpElicitationStringSchema), Number(McpElicitationNumberSchema), Boolean(McpElicitationBooleanSchema),}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase", deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationStringSchema { #[serde(rename = "type")] #[ts(rename = "type")] pub type_: McpElicitationStringType, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub title: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub min_length: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub max_length: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub format: Option<McpElicitationStringFormat>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option<String>,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "lowercase")]#[ts(export_to = "v2/")]pub enum McpElicitationStringType { String,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "kebab-case")]#[ts(rename_all = "kebab-case", export_to = "v2/")]pub enum McpElicitationStringFormat { Email, Uri, Date, DateTime,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase", deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationNumberSchema { #[serde(rename = "type")] #[ts(rename = "type")] pub type_: McpElicitationNumberType, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub title: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub minimum: Option<f64>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub maximum: Option<f64>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option<f64>,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "lowercase")]#[ts(export_to = "v2/")]pub enum McpElicitationNumberType { Number, Integer,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase", deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationBooleanSchema { #[serde(rename = "type")] #[ts(rename = "type")] pub type_: McpElicitationBooleanType, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub title: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option<bool>,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "lowercase")]#[ts(export_to = "v2/")]pub enum McpElicitationBooleanType { Boolean,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(untagged)]#[ts(export_to = "v2/")]pub enum McpElicitationEnumSchema { SingleSelect(McpElicitationSingleSelectEnumSchema), MultiSelect(McpElicitationMultiSelectEnumSchema), Legacy(McpElicitationLegacyTitledEnumSchema),}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase", deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationLegacyTitledEnumSchema { #[serde(rename = "type")] #[ts(rename = "type")] pub type_: McpElicitationStringType, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub title: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option<String>, #[serde(rename = "enum")] #[ts(rename = "enum")] pub enum_: Vec<String>, #[serde(rename = "enumNames", skip_serializing_if = "Option::is_none")] #[ts(optional, rename = "enumNames")] pub enum_names: Option<Vec<String>>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option<String>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(untagged)]#[ts(export_to = "v2/")]pub enum McpElicitationSingleSelectEnumSchema { Untitled(McpElicitationUntitledSingleSelectEnumSchema), Titled(McpElicitationTitledSingleSelectEnumSchema),}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase", deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationUntitledSingleSelectEnumSchema { #[serde(rename = "type")] #[ts(rename = "type")] pub type_: McpElicitationStringType, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub title: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option<String>, #[serde(rename = "enum")] #[ts(rename = "enum")] pub enum_: Vec<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option<String>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase", deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationTitledSingleSelectEnumSchema { #[serde(rename = "type")] #[ts(rename = "type")] pub type_: McpElicitationStringType, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub title: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option<String>, #[serde(rename = "oneOf")] #[ts(rename = "oneOf")] pub one_of: Vec<McpElicitationConstOption>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option<String>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(untagged)]#[ts(export_to = "v2/")]pub enum McpElicitationMultiSelectEnumSchema { Untitled(McpElicitationUntitledMultiSelectEnumSchema), Titled(McpElicitationTitledMultiSelectEnumSchema),}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase", deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationUntitledMultiSelectEnumSchema { #[serde(rename = "type")] #[ts(rename = "type")] pub type_: McpElicitationArrayType, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub title: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub min_items: Option<u64>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub max_items: Option<u64>, pub items: McpElicitationUntitledEnumItems, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option<Vec<String>>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase", deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationTitledMultiSelectEnumSchema { #[serde(rename = "type")] #[ts(rename = "type")] pub type_: McpElicitationArrayType, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub title: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub min_items: Option<u64>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub max_items: Option<u64>, pub items: McpElicitationTitledEnumItems, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option<Vec<String>>,}#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]#[serde(rename_all = "lowercase")]#[ts(export_to = "v2/")]pub enum McpElicitationArrayType { Array,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationUntitledEnumItems { #[serde(rename = "type")] #[ts(rename = "type")] pub type_: McpElicitationStringType, #[serde(rename = "enum")] #[ts(rename = "enum")] pub enum_: Vec<String>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationTitledEnumItems { #[serde(rename = "anyOf", alias = "oneOf")] #[ts(rename = "anyOf")] pub any_of: Vec<McpElicitationConstOption>,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]#[serde(deny_unknown_fields)]#[ts(export_to = "v2/")]pub struct McpElicitationConstOption { #[serde(rename = "const")] #[ts(rename = "const")] pub const_: String, pub title: String,}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(tag = "mode", rename_all = "camelCase")]#[ts(tag = "mode")]#[ts(export_to = "v2/")]pub enum McpServerElicitationRequest { #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] Form { #[serde(rename = "_meta")] #[ts(rename = "_meta")] meta: Option<JsonValue>, message: String, requested_schema: McpElicitationSchema, }, #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] Url { #[serde(rename = "_meta")] #[ts(rename = "_meta")] meta: Option<JsonValue>, message: String, url: String, elicitation_id: String, },}impl TryFrom<CoreElicitationRequest> for McpServerElicitationRequest { type Error = serde_json::Error; fn try_from(value: CoreElicitationRequest) -> Result<Self, Self::Error> { match value { CoreElicitationRequest::Form { meta, message, requested_schema, } => Ok(Self::Form { meta, message, requested_schema: serde_json::from_value(requested_schema)?, }), CoreElicitationRequest::Url { meta, message, url, elicitation_id, } => Ok(Self::Url { meta, message, url, elicitation_id, }), } }}#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]#[serde(rename_all = "camelCase")]#[ts(export_to = "v2/")]pub struct McpServerElicitationRequestResponse { pub action: McpServerElicitationAction, /// Structured user input for accepted elicitations, mirroring RMCP `CreateElicitationResult`. /// /// This is nullable because decline/cancel responses have no content. pub content: Option<JsonValue>, /// Optional client metadata for form-mode action handling. #[serde(rename = "_meta")] #[ts(rename = "_meta")] pub meta: Option<JsonValue>,}impl From<McpServerElicitationRequestResponse> for rmcp::model::CreateElicitationResult { fn from(value: McpServerElicitationRequestResponse) -> Self { Self { action: value.action.into(), content: value.content, meta: None, } }}impl From<rmcp::model::CreateElicitationResult> for McpServerElicitationRequestResponse { fn from(value: rmcp::model::CreateElicitationResult) -> Self { Self { action: value.action.into(), content: value.content, meta: None, } }}