Skip to content

Commit 7561a6a

Browse files
support MCP elicitations (#6947)
No support for request schema yet, but we'll at least show the message and allow accept/decline. <img width="823" height="551" alt="Screenshot 2025-11-21 at 2 44 05 PM" src="https://github.com/user-attachments/assets/6fbb892d-ca12-4765-921e-9ac4b217534d" />
1 parent 3ea33a0 commit 7561a6a

File tree

16 files changed

+487
-128
lines changed

16 files changed

+487
-128
lines changed

codex-rs/core/src/codex.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use codex_protocol::protocol::SessionSource;
3434
use codex_protocol::protocol::TaskStartedEvent;
3535
use codex_protocol::protocol::TurnAbortReason;
3636
use codex_protocol::protocol::TurnContextItem;
37+
use codex_rmcp_client::ElicitationResponse;
3738
use futures::future::BoxFuture;
3839
use futures::prelude::*;
3940
use futures::stream::FuturesOrdered;
@@ -44,6 +45,7 @@ use mcp_types::ListResourcesRequestParams;
4445
use mcp_types::ListResourcesResult;
4546
use mcp_types::ReadResourceRequestParams;
4647
use mcp_types::ReadResourceResult;
48+
use mcp_types::RequestId;
4749
use serde_json;
4850
use serde_json::Value;
4951
use tokio::sync::Mutex;
@@ -940,6 +942,19 @@ impl Session {
940942
}
941943
}
942944

945+
pub async fn resolve_elicitation(
946+
&self,
947+
server_name: String,
948+
id: RequestId,
949+
response: ElicitationResponse,
950+
) -> anyhow::Result<()> {
951+
self.services
952+
.mcp_connection_manager
953+
.read()
954+
.await
955+
.resolve_elicitation(server_name, id, response)
956+
}
957+
943958
/// Records input items: always append to conversation history and
944959
/// persist these response items to rollout.
945960
pub(crate) async fn record_conversation_items(
@@ -1413,6 +1428,13 @@ async fn submission_loop(sess: Arc<Session>, config: Arc<Config>, rx_sub: Receiv
14131428
)
14141429
.await;
14151430
}
1431+
Op::ResolveElicitation {
1432+
server_name,
1433+
request_id,
1434+
decision,
1435+
} => {
1436+
handlers::resolve_elicitation(&sess, server_name, request_id, decision).await;
1437+
}
14161438
Op::Shutdown => {
14171439
if handlers::shutdown(&sess, sub.id.clone()).await {
14181440
break;
@@ -1452,6 +1474,9 @@ mod handlers {
14521474
use codex_protocol::protocol::TurnAbortReason;
14531475

14541476
use codex_protocol::user_input::UserInput;
1477+
use codex_rmcp_client::ElicitationAction;
1478+
use codex_rmcp_client::ElicitationResponse;
1479+
use mcp_types::RequestId;
14551480
use std::sync::Arc;
14561481
use tracing::info;
14571482
use tracing::warn;
@@ -1535,6 +1560,32 @@ mod handlers {
15351560
*previous_context = Some(turn_context);
15361561
}
15371562

1563+
pub async fn resolve_elicitation(
1564+
sess: &Arc<Session>,
1565+
server_name: String,
1566+
request_id: RequestId,
1567+
decision: codex_protocol::approvals::ElicitationAction,
1568+
) {
1569+
let action = match decision {
1570+
codex_protocol::approvals::ElicitationAction::Accept => ElicitationAction::Accept,
1571+
codex_protocol::approvals::ElicitationAction::Decline => ElicitationAction::Decline,
1572+
codex_protocol::approvals::ElicitationAction::Cancel => ElicitationAction::Cancel,
1573+
};
1574+
let response = ElicitationResponse {
1575+
action,
1576+
content: None,
1577+
};
1578+
if let Err(err) = sess
1579+
.resolve_elicitation(server_name, request_id, response)
1580+
.await
1581+
{
1582+
warn!(
1583+
error = %err,
1584+
"failed to resolve elicitation request in session"
1585+
);
1586+
}
1587+
}
1588+
15381589
pub async fn exec_approval(sess: &Arc<Session>, id: String, decision: ReviewDecision) {
15391590
match decision {
15401591
ReviewDecision::Abort => {

0 commit comments

Comments
 (0)