use super::shared::v2_enum_from_core; use crate::JsonSchema; use crate::TS; use codex_experimental_api_macros::ExperimentalApi; 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 serde::Deserialize; use serde::Serialize; use serde_json::Value as JsonValue; use std::collections::BTreeMap; v2_enum_from_core!( pub enum McpAuthStatus from codex_protocol::protocol::McpAuthStatus { Unknown, Unsupported, NotLoggedIn, BearerToken, OAuth } ); v2_enum_from_core!( pub enum McpServerStartupFailureReason from codex_protocol::protocol::McpStartupFailureReason { ReauthenticationRequired } ); v2_enum_from_core!( #[ts(rename_all = "camelCase")] pub enum McpServerConnectionStatus from codex_protocol::mcp::McpServerConnectionStatus { NotStarted, Starting, Connected, AuthenticationRequired, Failed, Cancelled, Disabled } ); #[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, /// Optional page size; defaults to a server-defined value. #[ts(optional = nullable)] pub limit: Option, /// Controls how much MCP inventory data to fetch for each server. /// Defaults to `Full` when omitted. #[ts(optional = nullable)] pub detail: Option, #[ts(optional = nullable)] pub thread_id: Option, } #[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, /// Current thread-runtime connection state; null when unavailable or the configuration changed. pub runtime_status: Option, pub plugin_id: Option, pub server_info: Option, /// Capabilities advertised by the initialized MCP server; null when unavailable. pub server_capabilities: Option, pub tools: std::collections::HashMap, /// Tool discovery failed and no catalog was returned. /// Null when a catalog is returned, including cached or empty catalogs. pub tools_error: Option, pub resources: Vec, pub resource_templates: Vec, 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, /// 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, } #[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, /// Originating MCP tool call used to select the resource's app. #[ts(optional = nullable)] pub origin_call_id: Option, pub server: String, pub uri: String, #[ts(optional = nullable)] pub connector_id: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct McpResourceReadResponse { pub contents: Vec, /// Originating call when the server applied app-specific resource scoping. pub origin_call_id: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct McpServerEventStreamStartParams { pub thread_id: String, pub server: String, pub subscription_id: String, pub name: String, pub arguments: JsonValue, #[serde(rename = "_meta")] #[ts(rename = "_meta", optional = nullable)] pub meta: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct McpServerEventStreamStartResponse {} #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct McpServerEventStreamStopParams { pub subscription_id: String, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct McpServerEventStreamStopResponse {} #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct McpServerEventNotification { pub method: String, pub params: JsonValue, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct McpServerEventStreamNotification { pub subscription_id: String, pub notification: McpServerEventNotification, } #[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, #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub meta: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct McpServerToolCallResponse { pub content: Vec, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub structured_content: Option, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub is_error: Option, #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub meta: Option, } #[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, pub structured_content: Option, #[serde(rename = "_meta")] #[ts(rename = "_meta")] pub meta: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct McpToolCallError { pub message: String, } impl From 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 for McpToolCallResult { fn from(result: CoreMcpCallToolResult) -> Self { Self { content: result.content, structured_content: result.structured_content, meta: result.meta, } } } impl From 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, #[ts(optional = nullable)] pub thread_id: Option, /// Registration strategy for this login only; omission selects automatic discovery. #[ts(optional = nullable)] pub client_registration: Option, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional = nullable)] pub scopes: Option>, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional = nullable)] pub timeout_secs: Option, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase", export_to = "v2/")] pub enum McpServerOauthClientRegistration { #[default] Auto, Cimd, Dcr, } #[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 thread_id: Option, pub success: bool, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub error: Option, } #[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, pub name: String, pub status: McpServerStartupState, pub error: Option, pub failure_reason: Option, } #[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 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 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, _ => Self::Cancel, } } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)] #[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, pub server_name: String, #[serde(flatten)] #[experimental(nested)] 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, #[serde(rename = "type")] #[ts(rename = "type")] pub type_: McpElicitationObjectType, pub properties: BTreeMap, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub required: Option>, } #[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), #[serde(serialize_with = "serialize_mcp_elicitation_number_schema")] Number(McpElicitationNumberSchema), Boolean(McpElicitationBooleanSchema), } fn serialize_mcp_elicitation_number_schema( schema: &McpElicitationNumberSchema, serializer: S, ) -> Result where S: serde::Serializer, { if schema.type_ != McpElicitationNumberType::Integer { return schema.serialize(serializer); } let mut value = serde_json::to_value(schema).map_err(serde::ser::Error::custom)?; if let Some(object) = value.as_object_mut() { for key in ["minimum", "maximum", "default"] { if let Some(value) = object.get_mut(key) && let Some(number) = value.as_f64() && number.fract() == 0.0 && number >= i64::MIN as f64 && number < -(i64::MIN as f64) { *value = serde_json::Value::from(number as i64); } } } value.serialize(serializer) } #[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, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub min_length: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub max_length: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub format: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option, } #[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, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub minimum: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub maximum: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option, } #[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, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option, } #[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, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option, #[serde(rename = "enum")] #[ts(rename = "enum")] pub enum_: Vec, #[serde(rename = "enumNames", skip_serializing_if = "Option::is_none")] #[ts(optional, rename = "enumNames")] pub enum_names: Option>, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option, } #[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, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option, #[serde(rename = "enum")] #[ts(rename = "enum")] pub enum_: Vec, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option, } #[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, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option, #[serde(rename = "oneOf")] #[ts(rename = "oneOf")] pub one_of: Vec, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option, } #[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, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub min_items: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub max_items: Option, pub items: McpElicitationUntitledEnumItems, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option>, } #[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, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub description: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub min_items: Option, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub max_items: Option, pub items: McpElicitationTitledEnumItems, #[serde(skip_serializing_if = "Option::is_none")] #[ts(optional)] pub default: Option>, } #[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, } #[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, } #[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, ExperimentalApi)] #[serde(tag = "mode", rename_all = "camelCase")] #[ts(tag = "mode")] #[ts(export_to = "v2/")] pub enum McpServerElicitationRequest { /// A device-authenticated approval; accepted responses contain the proof in `content`. #[experimental("mcpServer/elicitation/request.userVerification")] #[serde(rename = "openai/userVerification", rename_all = "camelCase")] #[ts(rename = "openai/userVerification", rename_all = "camelCase")] UserVerification { title: String, description: String, challenge: String, }, #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] Form { #[serde(rename = "_meta")] #[ts(rename = "_meta")] meta: Option, message: String, requested_schema: McpElicitationSchema, }, // TODO(victor): Deprecate once migrated to `openai/elicitation/create`. #[serde(rename = "openai/form", rename_all = "camelCase")] #[ts(rename = "openai/form", rename_all = "camelCase")] OpenAiForm { #[serde(rename = "_meta")] #[ts(rename = "_meta")] meta: Option, message: String, requested_schema: JsonValue, }, #[serde(rename = "openaiForm", rename_all = "camelCase")] #[ts(rename = "openaiForm", rename_all = "camelCase")] OpenAiElicitationForm { #[serde(rename = "_meta")] #[ts(rename = "_meta")] meta: Option, message: String, requested_schema: JsonValue, }, #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] Url { #[serde(rename = "_meta")] #[ts(rename = "_meta")] meta: Option, message: String, url: String, elicitation_id: String, }, } impl TryFrom for McpServerElicitationRequest { type Error = serde_json::Error; fn try_from(value: CoreElicitationRequest) -> Result { match value { CoreElicitationRequest::UserVerification { title, description, challenge, } => Ok(Self::UserVerification { title, description, challenge, }), CoreElicitationRequest::Form { meta, message, requested_schema, } => Ok(Self::Form { meta, message, requested_schema: serde_json::from_value(requested_schema)?, }), CoreElicitationRequest::OpenAiForm { meta, message, requested_schema, } => Ok(Self::OpenAiForm { meta, message, requested_schema, }), CoreElicitationRequest::OpenAiElicitationForm { meta, message, requested_schema, } => Ok(Self::OpenAiElicitationForm { meta, message, 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, /// Optional client metadata for form-mode action handling. #[serde(rename = "_meta")] #[ts(rename = "_meta")] pub meta: Option, } impl From for rmcp::model::ElicitResult { fn from(value: McpServerElicitationRequestResponse) -> Self { let mut result = Self::new(value.action.into()); result.content = value.content; result } } impl From for McpServerElicitationRequestResponse { fn from(value: rmcp::model::ElicitResult) -> Self { Self { action: value.action.into(), content: value.content, meta: None, } } }