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"
/>
This commit is contained in:
Jeremy Rose
2025-11-21 14:44:53 -08:00
committed by GitHub
parent 3ea33a0616
commit 7561a6aaf0
16 changed files with 504 additions and 145 deletions

View File

@@ -1,13 +1,15 @@
use std::sync::Arc;
use rmcp::ClientHandler;
use rmcp::RoleClient;
use rmcp::model::CancelledNotificationParam;
use rmcp::model::ClientInfo;
use rmcp::model::CreateElicitationRequestParam;
use rmcp::model::CreateElicitationResult;
use rmcp::model::ElicitationAction;
use rmcp::model::LoggingLevel;
use rmcp::model::LoggingMessageNotificationParam;
use rmcp::model::ProgressNotificationParam;
use rmcp::model::RequestId;
use rmcp::model::ResourceUpdatedNotificationParam;
use rmcp::service::NotificationContext;
use rmcp::service::RequestContext;
@@ -16,32 +18,36 @@ use tracing::error;
use tracing::info;
use tracing::warn;
#[derive(Debug, Clone)]
use crate::rmcp_client::SendElicitation;
#[derive(Clone)]
pub(crate) struct LoggingClientHandler {
client_info: ClientInfo,
send_elicitation: Arc<SendElicitation>,
}
impl LoggingClientHandler {
pub(crate) fn new(client_info: ClientInfo) -> Self {
Self { client_info }
pub(crate) fn new(client_info: ClientInfo, send_elicitation: SendElicitation) -> Self {
Self {
client_info,
send_elicitation: Arc::new(send_elicitation),
}
}
}
impl ClientHandler for LoggingClientHandler {
// TODO (CODEX-3571): support elicitations.
async fn create_elicitation(
&self,
request: CreateElicitationRequestParam,
_context: RequestContext<RoleClient>,
context: RequestContext<RoleClient>,
) -> Result<CreateElicitationResult, rmcp::ErrorData> {
info!(
"MCP server requested elicitation ({}). Elicitations are not supported yet. Declining.",
request.message
);
Ok(CreateElicitationResult {
action: ElicitationAction::Decline,
content: None,
})
let id = match context.id {
RequestId::String(id) => mcp_types::RequestId::String(id.to_string()),
RequestId::Number(id) => mcp_types::RequestId::Integer(id),
};
(self.send_elicitation)(id, request)
.await
.map_err(|err| rmcp::ErrorData::internal_error(err.to_string(), None))
}
async fn on_cancelled(