diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 7796d4854..8cc9ca818 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -4020,7 +4020,6 @@ dependencies = [ name = "codex-tools" version = "0.0.0" dependencies = [ - "codex-app-server-protocol", "codex-code-mode", "codex-connectors", "codex-features", diff --git a/codex-rs/core/src/mcp_tool_call.rs b/codex-rs/core/src/mcp_tool_call.rs index c95c49eb5..fea6e45e9 100644 --- a/codex-rs/core/src/mcp_tool_call.rs +++ b/codex-rs/core/src/mcp_tool_call.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::collections::HashMap; use std::time::Duration; use std::time::Instant; @@ -26,10 +25,6 @@ use crate::turn_metadata::McpTurnMetadataContext; use codex_analytics::AppInvocation; use codex_analytics::InvocationType; use codex_analytics::build_track_events_context; -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_config::ConfigLayerSource; use codex_config::types::AppToolApproval; use codex_config::types::ApprovalsReviewer; @@ -46,6 +41,7 @@ use codex_mcp::auth_elicitation_completed_result; use codex_mcp::build_auth_elicitation_plan; use codex_mcp::declared_openai_file_input_param_names; use codex_mcp::mcp_permission_prompt_is_auto_approved; +use codex_protocol::approvals::ElicitationRequest; use codex_protocol::items::McpToolCallError; use codex_protocol::items::McpToolCallItem; use codex_protocol::items::McpToolCallStatus; @@ -653,19 +649,19 @@ async fn maybe_request_codex_apps_auth_elicitation( }; let request_id = rmcp::model::RequestId::String(plan.elicitation.elicitation_id.clone().into()); - let params = McpServerElicitationRequestParams { - thread_id: sess.thread_id.to_string(), - turn_id: Some(turn_context.sub_id.clone()), - server_name: CODEX_APPS_MCP_SERVER_NAME.to_string(), - request: McpServerElicitationRequest::Url { - meta: Some(plan.elicitation.meta), - message: plan.elicitation.message, - url: plan.elicitation.url, - elicitation_id: plan.elicitation.elicitation_id, - }, + let request = ElicitationRequest::Url { + meta: Some(plan.elicitation.meta), + message: plan.elicitation.message, + url: plan.elicitation.url, + elicitation_id: plan.elicitation.elicitation_id, }; let response = sess - .request_mcp_server_elicitation(turn_context, request_id, params) + .request_mcp_server_elicitation( + turn_context, + CODEX_APPS_MCP_SERVER_NAME.to_string(), + request_id, + request, + ) .await .response; if !response @@ -1309,10 +1305,8 @@ async fn maybe_request_mcp_tool_approval( let request_id = rmcp::model::RequestId::String( format!("{MCP_TOOL_APPROVAL_QUESTION_ID_PREFIX}_{call_id}").into(), ); - let params = build_mcp_tool_approval_elicitation_request( - sess.as_ref(), - turn_context.as_ref(), - McpToolApprovalElicitationRequest { + let request = + build_mcp_tool_approval_elicitation_request(McpToolApprovalElicitationRequest { server: &invocation.server, metadata, tool_params: rendered_template @@ -1325,12 +1319,16 @@ async fn maybe_request_mcp_tool_approval( .as_ref() .map(|rendered_template| rendered_template.elicitation_message.as_str()), prompt_options, - }, - ); + }); let decision = parse_mcp_tool_approval_elicitation_response( - sess.request_mcp_server_elicitation(turn_context.as_ref(), request_id, params) - .await - .response, + sess.request_mcp_server_elicitation( + turn_context.as_ref(), + invocation.server.clone(), + request_id, + request, + ) + .await + .response, &question_id, ); let decision = normalize_approval_decision_for_mode(decision, approval_mode); @@ -1658,35 +1656,26 @@ fn build_mcp_tool_approval_fallback_message( } fn build_mcp_tool_approval_elicitation_request( - sess: &Session, - turn_context: &TurnContext, request: McpToolApprovalElicitationRequest<'_>, -) -> McpServerElicitationRequestParams { +) -> ElicitationRequest { let message = request .message_override .map(ToString::to_string) .unwrap_or_else(|| request.question.question.clone()); - McpServerElicitationRequestParams { - thread_id: sess.thread_id.to_string(), - turn_id: Some(turn_context.sub_id.clone()), - server_name: request.server.to_string(), - request: McpServerElicitationRequest::Form { - meta: build_mcp_tool_approval_elicitation_meta( - request.server, - request.metadata, - request.tool_params, - request.tool_params_display, - request.prompt_options, - ), - message, - requested_schema: McpElicitationSchema { - schema_uri: None, - type_: McpElicitationObjectType::Object, - properties: BTreeMap::new(), - required: None, - }, - }, + ElicitationRequest::Form { + meta: build_mcp_tool_approval_elicitation_meta( + request.server, + request.metadata, + request.tool_params, + request.tool_params_display, + request.prompt_options, + ), + message, + requested_schema: serde_json::json!({ + "type": "object", + "properties": {}, + }), } } diff --git a/codex-rs/core/src/mcp_tool_call_tests.rs b/codex-rs/core/src/mcp_tool_call_tests.rs index b03262440..1be7f53b6 100644 --- a/codex-rs/core/src/mcp_tool_call_tests.rs +++ b/codex-rs/core/src/mcp_tool_call_tests.rs @@ -653,9 +653,8 @@ fn truncates_strings_on_char_boundaries() { ); } -#[tokio::test] -async fn approval_elicitation_request_uses_message_override_and_preserves_tool_params_keys() { - let (session, turn_context) = make_session_and_context().await; +#[test] +fn approval_elicitation_request_uses_message_override_and_preserves_tool_params_keys() { let question = build_mcp_tool_approval_question( "q".to_string(), CODEX_APPS_MCP_SERVER_NAME, @@ -667,86 +666,75 @@ async fn approval_elicitation_request_uses_message_override_and_preserves_tool_p Some("Allow Calendar to create an event?"), ); - let request = build_mcp_tool_approval_elicitation_request( - &session, - &turn_context, - McpToolApprovalElicitationRequest { - server: CODEX_APPS_MCP_SERVER_NAME, - metadata: Some(&approval_metadata( - Some("calendar"), - Some("Calendar"), - Some("Manage events and schedules."), - Some("Create Event"), - Some("Create a calendar event."), - )), - tool_params: Some(&serde_json::json!({ - "calendar_id": "primary", - "title": "Roadmap review", - })), - tool_params_display: Some(&[ - RenderedMcpToolApprovalParam { - name: "calendar_id".to_string(), - value: serde_json::json!("primary"), - display_name: "Calendar".to_string(), - }, - RenderedMcpToolApprovalParam { - name: "title".to_string(), - value: serde_json::json!("Roadmap review"), - display_name: "Title".to_string(), - }, - ]), - question, - message_override: Some("Allow Calendar to create an event?"), - prompt_options: prompt_options( - /*allow_session_remember*/ true, /*allow_persistent_approval*/ true, - ), - }, - ); + let request = build_mcp_tool_approval_elicitation_request(McpToolApprovalElicitationRequest { + server: CODEX_APPS_MCP_SERVER_NAME, + metadata: Some(&approval_metadata( + Some("calendar"), + Some("Calendar"), + Some("Manage events and schedules."), + Some("Create Event"), + Some("Create a calendar event."), + )), + tool_params: Some(&serde_json::json!({ + "calendar_id": "primary", + "title": "Roadmap review", + })), + tool_params_display: Some(&[ + RenderedMcpToolApprovalParam { + name: "calendar_id".to_string(), + value: serde_json::json!("primary"), + display_name: "Calendar".to_string(), + }, + RenderedMcpToolApprovalParam { + name: "title".to_string(), + value: serde_json::json!("Roadmap review"), + display_name: "Title".to_string(), + }, + ]), + question, + message_override: Some("Allow Calendar to create an event?"), + prompt_options: prompt_options( + /*allow_session_remember*/ true, /*allow_persistent_approval*/ true, + ), + }); assert_eq!( request, - McpServerElicitationRequestParams { - thread_id: session.thread_id.to_string(), - turn_id: Some(turn_context.sub_id), - server_name: CODEX_APPS_MCP_SERVER_NAME.to_string(), - request: McpServerElicitationRequest::Form { - meta: Some(serde_json::json!({ - MCP_TOOL_APPROVAL_KIND_KEY: MCP_TOOL_APPROVAL_KIND_MCP_TOOL_CALL, - MCP_TOOL_APPROVAL_PERSIST_KEY: [ - MCP_TOOL_APPROVAL_PERSIST_SESSION, - MCP_TOOL_APPROVAL_PERSIST_ALWAYS, - ], - MCP_TOOL_APPROVAL_SOURCE_KEY: MCP_TOOL_APPROVAL_SOURCE_CONNECTOR, - MCP_TOOL_APPROVAL_CONNECTOR_ID_KEY: "calendar", - MCP_TOOL_APPROVAL_CONNECTOR_NAME_KEY: "Calendar", - MCP_TOOL_APPROVAL_CONNECTOR_DESCRIPTION_KEY: "Manage events and schedules.", - MCP_TOOL_APPROVAL_TOOL_TITLE_KEY: "Create Event", - MCP_TOOL_APPROVAL_TOOL_DESCRIPTION_KEY: "Create a calendar event.", - MCP_TOOL_APPROVAL_TOOL_PARAMS_KEY: { - "calendar_id": "primary", - "title": "Roadmap review", - }, - MCP_TOOL_APPROVAL_TOOL_PARAMS_DISPLAY_KEY: [ - { - "name": "calendar_id", - "value": "primary", - "display_name": "Calendar", - }, - { - "name": "title", - "value": "Roadmap review", - "display_name": "Title", - }, - ], - })), - message: "Allow Calendar to create an event?".to_string(), - requested_schema: McpElicitationSchema { - schema_uri: None, - type_: McpElicitationObjectType::Object, - properties: BTreeMap::new(), - required: None, + ElicitationRequest::Form { + meta: Some(serde_json::json!({ + MCP_TOOL_APPROVAL_KIND_KEY: MCP_TOOL_APPROVAL_KIND_MCP_TOOL_CALL, + MCP_TOOL_APPROVAL_PERSIST_KEY: [ + MCP_TOOL_APPROVAL_PERSIST_SESSION, + MCP_TOOL_APPROVAL_PERSIST_ALWAYS, + ], + MCP_TOOL_APPROVAL_SOURCE_KEY: MCP_TOOL_APPROVAL_SOURCE_CONNECTOR, + MCP_TOOL_APPROVAL_CONNECTOR_ID_KEY: "calendar", + MCP_TOOL_APPROVAL_CONNECTOR_NAME_KEY: "Calendar", + MCP_TOOL_APPROVAL_CONNECTOR_DESCRIPTION_KEY: "Manage events and schedules.", + MCP_TOOL_APPROVAL_TOOL_TITLE_KEY: "Create Event", + MCP_TOOL_APPROVAL_TOOL_DESCRIPTION_KEY: "Create a calendar event.", + MCP_TOOL_APPROVAL_TOOL_PARAMS_KEY: { + "calendar_id": "primary", + "title": "Roadmap review", }, - }, + MCP_TOOL_APPROVAL_TOOL_PARAMS_DISPLAY_KEY: [ + { + "name": "calendar_id", + "value": "primary", + "display_name": "Calendar", + }, + { + "name": "title", + "value": "Roadmap review", + "display_name": "Title", + }, + ], + })), + message: "Allow Calendar to create an event?".to_string(), + requested_schema: serde_json::json!({ + "type": "object", + "properties": {}, + }), } ); } diff --git a/codex-rs/core/src/session/mcp.rs b/codex-rs/core/src/session/mcp.rs index 9b36be536..5a115b917 100644 --- a/codex-rs/core/src/session/mcp.rs +++ b/codex-rs/core/src/session/mcp.rs @@ -99,8 +99,9 @@ impl Session { pub async fn request_mcp_server_elicitation( &self, turn_context: &TurnContext, + server_name: String, request_id: RequestId, - params: McpServerElicitationRequestParams, + request: ElicitationRequest, ) -> McpServerElicitationOutcome { if self .services @@ -118,53 +119,6 @@ impl Session { }; } - let server_name = params.server_name.clone(); - let request = match params.request { - McpServerElicitationRequest::Form { - meta, - message, - requested_schema, - } => { - let requested_schema = match serde_json::to_value(requested_schema) { - Ok(requested_schema) => requested_schema, - Err(err) => { - warn!( - "failed to serialize MCP elicitation schema for server_name: {server_name}, request_id: {request_id}: {err:#}" - ); - return McpServerElicitationOutcome { - response: None, - sent: false, - }; - } - }; - codex_protocol::approvals::ElicitationRequest::Form { - meta, - message, - requested_schema, - } - } - McpServerElicitationRequest::OpenAiForm { - meta, - message, - requested_schema, - } => codex_protocol::approvals::ElicitationRequest::OpenAiForm { - meta, - message, - requested_schema, - }, - McpServerElicitationRequest::Url { - meta, - message, - url, - elicitation_id, - } => codex_protocol::approvals::ElicitationRequest::Url { - meta, - message, - url, - elicitation_id, - }, - }; - let (tx_response, rx_response) = oneshot::channel(); let prev_entry = { let mut active = self.active_turn.lock().await; @@ -194,7 +148,7 @@ impl Session { } }; let event = EventMsg::ElicitationRequest(ElicitationRequestEvent { - turn_id: params.turn_id, + turn_id: Some(turn_context.sub_id.clone()), server_name, id, request, diff --git a/codex-rs/core/src/session/mod.rs b/codex-rs/core/src/session/mod.rs index 00d2fdca3..daf981258 100644 --- a/codex-rs/core/src/session/mod.rs +++ b/codex-rs/core/src/session/mod.rs @@ -54,8 +54,6 @@ use chrono::Utc; use codex_analytics::AnalyticsEventsClient; use codex_analytics::SubAgentThreadStartedInput; use codex_analytics::TurnCodexErrorFact; -use codex_app_server_protocol::McpServerElicitationRequest; -use codex_app_server_protocol::McpServerElicitationRequestParams; use codex_config::types::AuthKeyringBackendKind; use codex_config::types::OAuthCredentialsStoreMode; use codex_exec_server::Environment; @@ -87,6 +85,7 @@ use codex_otel::current_span_w3c_trace_context; use codex_otel::set_parent_from_w3c_trace_context; use codex_protocol::SessionId; use codex_protocol::ThreadId; +use codex_protocol::approvals::ElicitationRequest; use codex_protocol::approvals::ElicitationRequestEvent; use codex_protocol::approvals::ExecPolicyAmendment; use codex_protocol::approvals::NetworkPolicyAmendment; diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index 3d95bc208..983ed2009 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -84,7 +84,6 @@ use crate::tools::handlers::ShellCommandHandler; use crate::tools::registry::ToolExecutor; use crate::tools::router::ToolCallSource; use crate::turn_diff_tracker::TurnDiffTracker; -use codex_app_server_protocol::McpElicitationSchema; use codex_config::config_toml::ConfigToml; use codex_config::config_toml::ProjectConfig; use codex_config::permissions_toml::FilesystemPermissionToml; @@ -377,24 +376,18 @@ async fn request_mcp_server_elicitation_auto_accepts_when_auto_deny_is_enabled() .load_full() .set_elicitations_auto_deny(/*auto_deny*/ true); - let requested_schema: McpElicitationSchema = serde_json::from_value(json!({ - "type": "object", - "properties": {}, - })) - .expect("schema should deserialize"); let response = session .request_mcp_server_elicitation( turn_context.as_ref(), + "codex_apps".to_string(), RequestId::String("request-1".into()), - McpServerElicitationRequestParams { - thread_id: session.thread_id.to_string(), - turn_id: Some(turn_context.sub_id.clone()), - server_name: "codex_apps".to_string(), - request: McpServerElicitationRequest::Form { - meta: None, - message: "Allow this request?".to_string(), - requested_schema, - }, + ElicitationRequest::Form { + meta: None, + message: "Allow this request?".to_string(), + requested_schema: json!({ + "type": "object", + "properties": {}, + }), }, ) .await; diff --git a/codex-rs/core/src/tools/handlers/request_plugin_install.rs b/codex-rs/core/src/tools/handlers/request_plugin_install.rs index b51345050..b9656f948 100644 --- a/codex-rs/core/src/tools/handlers/request_plugin_install.rs +++ b/codex-rs/core/src/tools/handlers/request_plugin_install.rs @@ -173,15 +173,14 @@ impl RequestPluginInstallHandler { let tool_type = tool.tool_type(); let request_id = RequestId::String(format!("request_plugin_install_{call_id}").into()); - let params = build_request_plugin_install_elicitation_request( - CODEX_APPS_MCP_SERVER_NAME, - session.thread_id.to_string(), - turn.sub_id.clone(), - suggest_reason, - &tool, - ); + let request = build_request_plugin_install_elicitation_request(suggest_reason, &tool); let elicitation = session - .request_mcp_server_elicitation(turn.as_ref(), request_id, params) + .request_mcp_server_elicitation( + turn.as_ref(), + CODEX_APPS_MCP_SERVER_NAME.to_string(), + request_id, + request, + ) .await; let response = elicitation.response; if let Some(response) = response.as_ref() { diff --git a/codex-rs/tools/Cargo.toml b/codex-rs/tools/Cargo.toml index f06e5f073..b5f838ca3 100644 --- a/codex-rs/tools/Cargo.toml +++ b/codex-rs/tools/Cargo.toml @@ -8,7 +8,6 @@ version.workspace = true workspace = true [dependencies] -codex-app-server-protocol = { workspace = true } codex-code-mode = { workspace = true } codex-connectors = { workspace = true } codex-features = { workspace = true } diff --git a/codex-rs/tools/src/request_plugin_install.rs b/codex-rs/tools/src/request_plugin_install.rs index c8c640606..207a9d724 100644 --- a/codex-rs/tools/src/request_plugin_install.rs +++ b/codex-rs/tools/src/request_plugin_install.rs @@ -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": {}, + }), } } diff --git a/codex-rs/tools/src/request_plugin_install_tests.rs b/codex-rs/tools/src/request_plugin_install_tests.rs index 08bec060f..666d0f246 100644 --- a/codex-rs/tools/src/request_plugin_install_tests.rs +++ b/codex-rs/tools/src/request_plugin_install_tests.rs @@ -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": {}, + }), }, ); }