Download codex-rs/app-server-protocol/src/protocol/v2/mcp.rs from SaylorTwift/codex: direct link, hf CLI and curl.
- Browser
- Download file 30.4 kB
-
https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/app-server-protocol/src/protocol/v2/mcp.rs
- Command line
-
hf download hf://SaylorTwift/codex/codex-rs/app-server-protocol/src/protocol/v2/mcp.rs
-
curl -L -o mcp.rs https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/app-server-protocol/src/protocol/v2/mcp.rs
30.4 kB
| 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!( | |
| pub enum McpServerConnectionStatus from codex_protocol::mcp::McpServerConnectionStatus { | |
| NotStarted, | |
| Starting, | |
| Connected, | |
| AuthenticationRequired, | |
| Failed, | |
| Cancelled, | |
| Disabled | |
| } | |
| ); | |
| pub struct ListMcpServerStatusParams { | |
| /// Opaque pagination cursor returned by a previous call. | |
| pub cursor: Option<String>, | |
| /// Optional page size; defaults to a server-defined value. | |
| pub limit: Option<u32>, | |
| /// Controls how much MCP inventory data to fetch for each server. | |
| /// Defaults to `Full` when omitted. | |
| pub detail: Option<McpServerStatusDetail>, | |
| pub thread_id: Option<String>, | |
| } | |
| pub enum McpServerStatusDetail { | |
| Full, | |
| ToolsAndAuthOnly, | |
| } | |
| pub struct McpServerStatus { | |
| pub name: String, | |
| /// Current thread-runtime connection state; null when unavailable or the configuration changed. | |
| pub runtime_status: Option<McpServerConnectionStatus>, | |
| pub plugin_id: Option<String>, | |
| pub server_info: Option<McpServerInfo>, | |
| /// Capabilities advertised by the initialized MCP server; null when unavailable. | |
| pub server_capabilities: Option<serde_json::Value>, | |
| pub tools: std::collections::HashMap<String, McpTool>, | |
| /// Tool discovery failed and no catalog was returned. | |
| /// Null when a catalog is returned, including cached or empty catalogs. | |
| pub tools_error: Option<String>, | |
| pub resources: Vec<McpResource>, | |
| pub resource_templates: Vec<McpResourceTemplate>, | |
| pub auth_status: McpAuthStatus, | |
| } | |
| 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>, | |
| } | |
| pub struct McpResourceReadParams { | |
| pub thread_id: Option<String>, | |
| /// Originating MCP tool call used to select the resource's app. | |
| pub origin_call_id: Option<String>, | |
| pub server: String, | |
| pub uri: String, | |
| pub connector_id: Option<String>, | |
| } | |
| pub struct McpResourceReadResponse { | |
| pub contents: Vec<McpResourceContent>, | |
| /// Originating call when the server applied app-specific resource scoping. | |
| pub origin_call_id: Option<String>, | |
| } | |
| pub struct McpServerEventStreamStartParams { | |
| pub thread_id: String, | |
| pub server: String, | |
| pub subscription_id: String, | |
| pub name: String, | |
| pub arguments: JsonValue, | |
| pub meta: Option<JsonValue>, | |
| } | |
| pub struct McpServerEventStreamStartResponse {} | |
| pub struct McpServerEventStreamStopParams { | |
| pub subscription_id: String, | |
| } | |
| pub struct McpServerEventStreamStopResponse {} | |
| pub struct McpServerEventNotification { | |
| pub method: String, | |
| pub params: JsonValue, | |
| } | |
| pub struct McpServerEventStreamNotification { | |
| pub subscription_id: String, | |
| pub notification: McpServerEventNotification, | |
| } | |
| pub struct McpServerToolCallParams { | |
| pub thread_id: String, | |
| pub server: String, | |
| pub tool: String, | |
| pub arguments: Option<JsonValue>, | |
| pub meta: Option<JsonValue>, | |
| } | |
| pub struct McpServerToolCallResponse { | |
| pub content: Vec<JsonValue>, | |
| pub structured_content: Option<JsonValue>, | |
| pub is_error: Option<bool>, | |
| pub meta: Option<JsonValue>, | |
| } | |
| 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>, | |
| pub meta: Option<JsonValue>, | |
| } | |
| 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, | |
| } | |
| } | |
| } | |
| pub struct McpServerRefreshParams {} | |
| pub struct McpServerRefreshResponse {} | |
| pub struct McpServerOauthLoginParams { | |
| pub name: String, | |
| pub thread_id: Option<String>, | |
| /// Registration strategy for this login only; omission selects automatic discovery. | |
| pub client_registration: Option<McpServerOauthClientRegistration>, | |
| pub scopes: Option<Vec<String>>, | |
| pub timeout_secs: Option<i64>, | |
| } | |
| pub enum McpServerOauthClientRegistration { | |
| Auto, | |
| Cimd, | |
| Dcr, | |
| } | |
| pub struct McpServerOauthLoginResponse { | |
| pub authorization_url: String, | |
| } | |
| pub struct McpToolCallProgressNotification { | |
| pub thread_id: String, | |
| pub turn_id: String, | |
| pub item_id: String, | |
| pub message: String, | |
| } | |
| pub struct McpServerOauthLoginCompletedNotification { | |
| pub name: String, | |
| pub thread_id: Option<String>, | |
| pub success: bool, | |
| pub error: Option<String>, | |
| } | |
| pub enum McpServerStartupState { | |
| Starting, | |
| Ready, | |
| Failed, | |
| Cancelled, | |
| } | |
| pub struct McpServerStatusUpdatedNotification { | |
| pub thread_id: Option<String>, | |
| pub name: String, | |
| pub status: McpServerStartupState, | |
| pub error: Option<String>, | |
| pub failure_reason: Option<McpServerStartupFailureReason>, | |
| } | |
| 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, | |
| _ => Self::Cancel, | |
| } | |
| } | |
| } | |
| 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, | |
| 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. | |
| pub struct McpElicitationSchema { | |
| pub schema_uri: Option<String>, | |
| pub type_: McpElicitationObjectType, | |
| pub properties: BTreeMap<String, McpElicitationPrimitiveSchema>, | |
| pub required: Option<Vec<String>>, | |
| } | |
| pub enum McpElicitationObjectType { | |
| Object, | |
| } | |
| pub enum McpElicitationPrimitiveSchema { | |
| Enum(McpElicitationEnumSchema), | |
| String(McpElicitationStringSchema), | |
| Number(McpElicitationNumberSchema), | |
| Boolean(McpElicitationBooleanSchema), | |
| } | |
| fn serialize_mcp_elicitation_number_schema<S>( | |
| schema: &McpElicitationNumberSchema, | |
| serializer: S, | |
| ) -> Result<S::Ok, S::Error> | |
| 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) | |
| } | |
| pub struct McpElicitationStringSchema { | |
| pub type_: McpElicitationStringType, | |
| pub title: Option<String>, | |
| pub description: Option<String>, | |
| pub min_length: Option<u32>, | |
| pub max_length: Option<u32>, | |
| pub format: Option<McpElicitationStringFormat>, | |
| pub default: Option<String>, | |
| } | |
| pub enum McpElicitationStringType { | |
| String, | |
| } | |
| pub enum McpElicitationStringFormat { | |
| Email, | |
| Uri, | |
| Date, | |
| DateTime, | |
| } | |
| pub struct McpElicitationNumberSchema { | |
| pub type_: McpElicitationNumberType, | |
| pub title: Option<String>, | |
| pub description: Option<String>, | |
| pub minimum: Option<f64>, | |
| pub maximum: Option<f64>, | |
| pub default: Option<f64>, | |
| } | |
| pub enum McpElicitationNumberType { | |
| Number, | |
| Integer, | |
| } | |
| pub struct McpElicitationBooleanSchema { | |
| pub type_: McpElicitationBooleanType, | |
| pub title: Option<String>, | |
| pub description: Option<String>, | |
| pub default: Option<bool>, | |
| } | |
| pub enum McpElicitationBooleanType { | |
| Boolean, | |
| } | |
| pub enum McpElicitationEnumSchema { | |
| SingleSelect(McpElicitationSingleSelectEnumSchema), | |
| MultiSelect(McpElicitationMultiSelectEnumSchema), | |
| Legacy(McpElicitationLegacyTitledEnumSchema), | |
| } | |
| pub struct McpElicitationLegacyTitledEnumSchema { | |
| pub type_: McpElicitationStringType, | |
| pub title: Option<String>, | |
| pub description: Option<String>, | |
| pub enum_: Vec<String>, | |
| pub enum_names: Option<Vec<String>>, | |
| pub default: Option<String>, | |
| } | |
| pub enum McpElicitationSingleSelectEnumSchema { | |
| Untitled(McpElicitationUntitledSingleSelectEnumSchema), | |
| Titled(McpElicitationTitledSingleSelectEnumSchema), | |
| } | |
| pub struct McpElicitationUntitledSingleSelectEnumSchema { | |
| pub type_: McpElicitationStringType, | |
| pub title: Option<String>, | |
| pub description: Option<String>, | |
| pub enum_: Vec<String>, | |
| pub default: Option<String>, | |
| } | |
| pub struct McpElicitationTitledSingleSelectEnumSchema { | |
| pub type_: McpElicitationStringType, | |
| pub title: Option<String>, | |
| pub description: Option<String>, | |
| pub one_of: Vec<McpElicitationConstOption>, | |
| pub default: Option<String>, | |
| } | |
| pub enum McpElicitationMultiSelectEnumSchema { | |
| Untitled(McpElicitationUntitledMultiSelectEnumSchema), | |
| Titled(McpElicitationTitledMultiSelectEnumSchema), | |
| } | |
| pub struct McpElicitationUntitledMultiSelectEnumSchema { | |
| pub type_: McpElicitationArrayType, | |
| pub title: Option<String>, | |
| pub description: Option<String>, | |
| pub min_items: Option<u64>, | |
| pub max_items: Option<u64>, | |
| pub items: McpElicitationUntitledEnumItems, | |
| pub default: Option<Vec<String>>, | |
| } | |
| pub struct McpElicitationTitledMultiSelectEnumSchema { | |
| pub type_: McpElicitationArrayType, | |
| pub title: Option<String>, | |
| pub description: Option<String>, | |
| pub min_items: Option<u64>, | |
| pub max_items: Option<u64>, | |
| pub items: McpElicitationTitledEnumItems, | |
| pub default: Option<Vec<String>>, | |
| } | |
| pub enum McpElicitationArrayType { | |
| Array, | |
| } | |
| pub struct McpElicitationUntitledEnumItems { | |
| pub type_: McpElicitationStringType, | |
| pub enum_: Vec<String>, | |
| } | |
| pub struct McpElicitationTitledEnumItems { | |
| pub any_of: Vec<McpElicitationConstOption>, | |
| } | |
| pub struct McpElicitationConstOption { | |
| pub const_: String, | |
| pub title: String, | |
| } | |
| pub enum McpServerElicitationRequest { | |
| /// A device-authenticated approval; accepted responses contain the proof in `content`. | |
| UserVerification { | |
| title: String, | |
| description: String, | |
| challenge: String, | |
| }, | |
| Form { | |
| meta: Option<JsonValue>, | |
| message: String, | |
| requested_schema: McpElicitationSchema, | |
| }, | |
| // TODO(victor): Deprecate once migrated to `openai/elicitation/create`. | |
| OpenAiForm { | |
| meta: Option<JsonValue>, | |
| message: String, | |
| requested_schema: JsonValue, | |
| }, | |
| OpenAiElicitationForm { | |
| meta: Option<JsonValue>, | |
| message: String, | |
| requested_schema: JsonValue, | |
| }, | |
| Url { | |
| 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::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, | |
| }), | |
| } | |
| } | |
| } | |
| 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. | |
| pub meta: Option<JsonValue>, | |
| } | |
| impl From<McpServerElicitationRequestResponse> for rmcp::model::ElicitResult { | |
| fn from(value: McpServerElicitationRequestResponse) -> Self { | |
| let mut result = Self::new(value.action.into()); | |
| result.content = value.content; | |
| result | |
| } | |
| } | |
| impl From<rmcp::model::ElicitResult> for McpServerElicitationRequestResponse { | |
| fn from(value: rmcp::model::ElicitResult) -> Self { | |
| Self { | |
| action: value.action.into(), | |
| content: value.content, | |
| meta: None, | |
| } | |
| } | |
| } | |