1#![expect(deprecated)]
3use std::borrow::Cow;
4#[cfg(feature = "elicitation")]
5use std::collections::HashSet;
6
7use thiserror::Error;
8#[cfg(feature = "elicitation")]
9use url::Url;
10
11use super::*;
12#[cfg(feature = "elicitation")]
13use crate::model::{ElicitRequest, ElicitRequestParams, ElicitResult, ElicitationAction};
14use crate::{
15 model::{
16 CancelledNotification, CancelledNotificationParam, ClientInfo, ClientJsonRpcMessage,
17 ClientNotification, ClientRequest, ClientResult, CreateMessageRequest,
18 CreateMessageRequestParams, CreateMessageResult, EmptyResult, ErrorData, ListRootsRequest,
19 ListRootsResult, LoggingMessageNotification, LoggingMessageNotificationParam,
20 ProgressNotification, ProgressNotificationParam, PromptListChangedNotification,
21 ProtocolVersion, ResourceListChangedNotification, ResourceUpdatedNotification,
22 ResourceUpdatedNotificationParam, ServerInfo, ServerNotification, ServerRequest,
23 ServerResult, ToolListChangedNotification,
24 },
25 transport::DynamicTransportError,
26};
27
28#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
29#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
30pub struct RoleServer;
31
32impl ServiceRole for RoleServer {
33 type Req = ServerRequest;
34 type Resp = ServerResult;
35 type Not = ServerNotification;
36 type PeerReq = ClientRequest;
37 type PeerResp = ClientResult;
38 type PeerNot = ClientNotification;
39 type Info = ServerInfo;
40 type PeerInfo = ClientInfo;
41
42 type InitializeError = ServerInitializeError;
43 const IS_CLIENT: bool = false;
44}
45
46#[derive(Error, Debug)]
50#[non_exhaustive]
51pub enum ServerInitializeError {
52 #[error("expect initialized request, but received: {0:?}")]
53 ExpectedInitializeRequest(Option<ClientJsonRpcMessage>),
54
55 #[deprecated(
56 since = "1.4.0",
57 note = "The server no longer gates on the initialized notification. This variant is never constructed and will be removed in a future major release."
58 )]
59 #[error("expect initialized notification, but received: {0:?}")]
60 ExpectedInitializedNotification(Option<ClientJsonRpcMessage>),
61
62 #[error("connection closed: {0}")]
63 ConnectionClosed(String),
64
65 #[error("unexpected initialize result: {0:?}")]
66 UnexpectedInitializeResponse(ServerResult),
67
68 #[error("initialize failed: {0}")]
69 InitializeFailed(ErrorData),
70
71 #[deprecated(
72 since = "1.8.0",
73 note = "Negotiation now falls back to the server-configured version. This variant is never constructed and will be removed in a future major release."
74 )]
75 #[error("unsupported protocol version: {0}")]
76 UnsupportedProtocolVersion(ProtocolVersion),
77
78 #[error("Send message error {error}, when {context}")]
79 TransportError {
80 error: DynamicTransportError,
81 context: Cow<'static, str>,
82 },
83
84 #[error("Cancelled")]
85 Cancelled,
86}
87
88impl ServerInitializeError {
89 pub fn transport<T: Transport<RoleServer> + 'static>(
90 error: T::Error,
91 context: impl Into<Cow<'static, str>>,
92 ) -> Self {
93 Self::TransportError {
94 error: DynamicTransportError::new::<T, _>(error),
95 context: context.into(),
96 }
97 }
98}
99pub type ClientSink = Peer<RoleServer>;
100
101impl<S: Service<RoleServer>> ServiceExt<RoleServer> for S {
102 fn serve_with_ct<T, E, A>(
103 self,
104 transport: T,
105 ct: CancellationToken,
106 ) -> impl Future<Output = Result<RunningService<RoleServer, Self>, ServerInitializeError>>
107 + MaybeSendFuture
108 where
109 T: IntoTransport<RoleServer, E, A>,
110 E: std::error::Error + Send + Sync + 'static,
111 Self: Sized,
112 {
113 serve_server_with_ct(self, transport, ct)
114 }
115}
116
117pub async fn serve_server<S, T, E, A>(
118 service: S,
119 transport: T,
120) -> Result<RunningService<RoleServer, S>, ServerInitializeError>
121where
122 S: Service<RoleServer>,
123 T: IntoTransport<RoleServer, E, A>,
124 E: std::error::Error + Send + Sync + 'static,
125{
126 serve_server_with_ct(service, transport, CancellationToken::new()).await
127}
128
129async fn expect_next_message<T>(
131 transport: &mut T,
132 context: &str,
133) -> Result<ClientJsonRpcMessage, ServerInitializeError>
134where
135 T: Transport<RoleServer>,
136{
137 transport
138 .receive()
139 .await
140 .ok_or_else(|| ServerInitializeError::ConnectionClosed(context.to_string()))
141}
142
143pub async fn serve_server_with_ct<S, T, E, A>(
144 service: S,
145 transport: T,
146 ct: CancellationToken,
147) -> Result<RunningService<RoleServer, S>, ServerInitializeError>
148where
149 S: Service<RoleServer>,
150 T: IntoTransport<RoleServer, E, A>,
151 E: std::error::Error + Send + Sync + 'static,
152{
153 tokio::select! {
154 result = serve_server_with_ct_inner(service, transport.into_transport(), ct.clone()) => { result }
155 _ = ct.cancelled() => {
156 Err(ServerInitializeError::Cancelled)
157 }
158 }
159}
160
161pub(crate) fn negotiate_protocol_version(
163 client_requested: &ProtocolVersion,
164 server_fallback: ProtocolVersion,
165) -> ProtocolVersion {
166 if ProtocolVersion::KNOWN_VERSIONS.contains(client_requested) {
167 client_requested.clone()
168 } else {
169 tracing::warn!(
170 client_requested = %client_requested,
171 server_fallback = %server_fallback,
172 "client requested unsupported protocol version; falling back to server default"
173 );
174 server_fallback
175 }
176}
177
178async fn serve_server_with_ct_inner<S, T>(
179 service: S,
180 transport: T,
181 ct: CancellationToken,
182) -> Result<RunningService<RoleServer, S>, ServerInitializeError>
183where
184 S: Service<RoleServer>,
185 T: Transport<RoleServer> + 'static,
186{
187 let mut transport = transport.into_transport();
188 let id_provider = <Arc<AtomicU32RequestIdProvider>>::default();
189
190 let (request, id) = loop {
193 let msg = expect_next_message(&mut transport, "initialize request").await?;
194 match msg {
195 ClientJsonRpcMessage::Request(req)
196 if matches!(req.request, ClientRequest::PingRequest(_)) =>
197 {
198 transport
199 .send(ServerJsonRpcMessage::response(
200 ServerResult::EmptyResult(EmptyResult {}),
201 req.id,
202 ))
203 .await
204 .map_err(|error| {
205 ServerInitializeError::transport::<T>(
206 error,
207 "sending pre-init ping response",
208 )
209 })?;
210 }
211 ClientJsonRpcMessage::Request(req) => break (req.request, req.id),
212 other => {
213 return Err(ServerInitializeError::ExpectedInitializeRequest(Some(
214 other,
215 )));
216 }
217 }
218 };
219
220 let initialize_request = match request {
221 ClientRequest::InitializeRequest(request) => request,
222 mut request => {
223 if !request
224 .get_meta()
225 .missing_required_keys(&ProtocolVersion::V_2026_07_28)
226 .is_empty()
227 {
228 return Err(ServerInitializeError::ExpectedInitializeRequest(Some(
229 ClientJsonRpcMessage::request(request, id),
230 )));
231 }
232 let (peer, peer_rx) = Peer::new(id_provider, None);
233 peer.require_request_metadata();
234 let context = RequestContext {
235 ct: ct.child_token(),
236 id: id.clone(),
237 meta: std::mem::take(request.get_meta_mut()),
238 extensions: std::mem::take(request.extensions_mut()),
239 peer: peer.clone(),
240 };
241 let response = match service.handle_request(request, context).await {
242 Ok(result) => ServerJsonRpcMessage::response(result, id),
243 Err(error) => ServerJsonRpcMessage::error(error, Some(id)),
244 };
245 transport.send(response).await.map_err(|error| {
246 ServerInitializeError::transport::<T>(error, "sending negotiated request response")
247 })?;
248 return Ok(serve_inner(service, transport, peer, peer_rx, ct));
249 }
250 };
251 let requested_protocol_version = initialize_request.params.protocol_version.clone();
252 let mut negotiated_peer_info = initialize_request.params.clone();
253 let (peer, peer_rx) = Peer::new(id_provider, Some(negotiated_peer_info.clone()));
254 let request = ClientRequest::InitializeRequest(initialize_request);
255 let context = RequestContext {
256 ct: ct.child_token(),
257 id: id.clone(),
258 meta: request.get_meta().clone(),
259 extensions: request.extensions().clone(),
260 peer: peer.clone(),
261 };
262 let init_response = service.handle_request(request, context).await;
264 let mut init_response = match init_response {
265 Ok(ServerResult::InitializeResult(init_response)) => init_response,
266 Ok(result) => {
267 return Err(ServerInitializeError::UnexpectedInitializeResponse(result));
268 }
269 Err(e) => {
270 transport
271 .send(ServerJsonRpcMessage::error(e.clone(), Some(id)))
272 .await
273 .map_err(|error| {
274 ServerInitializeError::transport::<T>(error, "sending error response")
275 })?;
276 return Err(ServerInitializeError::InitializeFailed(e));
277 }
278 };
279 init_response.protocol_version =
280 negotiate_protocol_version(&requested_protocol_version, init_response.protocol_version);
281 negotiated_peer_info.protocol_version = init_response.protocol_version.clone();
284 peer.set_peer_info(negotiated_peer_info);
285 transport
286 .send(ServerJsonRpcMessage::response(
287 ServerResult::InitializeResult(init_response),
288 id,
289 ))
290 .await
291 .map_err(|error| {
292 ServerInitializeError::transport::<T>(error, "sending initialize response")
293 })?;
294
295 Ok(serve_inner(service, transport, peer, peer_rx, ct))
302}
303
304macro_rules! method {
305 ($(#[$meta:meta])* peer_req $method:ident $Req:ident() => $Resp: ident ) => {
306 $(#[$meta])*
307 pub async fn $method(&self) -> Result<$Resp, ServiceError> {
308 let result = self
309 .send_request(ServerRequest::$Req($Req {
310 method: Default::default(),
311 extensions: Default::default(),
312 }))
313 .await?;
314 match result {
315 ClientResult::$Resp(result) => Ok(result),
316 _ => Err(ServiceError::UnexpectedResponse),
317 }
318 }
319 };
320 ($(#[$meta:meta])* peer_req $method:ident $Req:ident($Param: ident) => $Resp: ident ) => {
321 $(#[$meta])*
322 pub async fn $method(&self, params: $Param) -> Result<$Resp, ServiceError> {
323 let result = self
324 .send_request(ServerRequest::$Req($Req {
325 method: Default::default(),
326 params,
327 extensions: Default::default(),
328 }))
329 .await?;
330 match result {
331 ClientResult::$Resp(result) => Ok(result),
332 _ => Err(ServiceError::UnexpectedResponse),
333 }
334 }
335 };
336 ($(#[$meta:meta])* peer_req $method:ident $Req:ident($Param: ident)) => {
337 $(#[$meta])*
338 pub fn $method(
339 &self,
340 params: $Param,
341 ) -> impl Future<Output = Result<(), ServiceError>> + Send + '_ {
342 async move {
343 let result = self
344 .send_request(ServerRequest::$Req($Req {
345 method: Default::default(),
346 params,
347 }))
348 .await?;
349 match result {
350 ClientResult::EmptyResult(_) => Ok(()),
351 _ => Err(ServiceError::UnexpectedResponse),
352 }
353 }
354 }
355 };
356
357 ($(#[$meta:meta])* peer_not $method:ident $Not:ident($Param: ident)) => {
358 $(#[$meta])*
359 pub async fn $method(&self, params: $Param) -> Result<(), ServiceError> {
360 self.send_notification(ServerNotification::$Not($Not {
361 method: Default::default(),
362 params,
363 extensions: Default::default(),
364 }))
365 .await?;
366 Ok(())
367 }
368 };
369 ($(#[$meta:meta])* peer_not $method:ident $Not:ident) => {
370 $(#[$meta])*
371 pub async fn $method(&self) -> Result<(), ServiceError> {
372 self.send_notification(ServerNotification::$Not($Not {
373 method: Default::default(),
374 extensions: Default::default(),
375 }))
376 .await?;
377 Ok(())
378 }
379 };
380
381 ($(#[$meta:meta])* peer_req_with_timeout $method_with_timeout:ident $Req:ident() => $Resp: ident) => {
383 $(#[$meta])*
384 pub async fn $method_with_timeout(
385 &self,
386 timeout: Option<std::time::Duration>,
387 ) -> Result<$Resp, ServiceError> {
388 let request = ServerRequest::$Req($Req {
389 method: Default::default(),
390 extensions: Default::default(),
391 });
392 let options = crate::service::PeerRequestOptions {
393 timeout,
394 meta: None,
395 reset_timeout_on_progress: false,
396 max_total_timeout: None,
397 };
398 let result = self
399 .send_request_with_option(request, options)
400 .await?
401 .await_response()
402 .await?;
403 match result {
404 ClientResult::$Resp(result) => Ok(result),
405 _ => Err(ServiceError::UnexpectedResponse),
406 }
407 }
408 };
409
410 ($(#[$meta:meta])* peer_req_with_timeout $method_with_timeout:ident $Req:ident($Param: ident) => $Resp: ident) => {
411 $(#[$meta])*
412 pub async fn $method_with_timeout(
413 &self,
414 params: $Param,
415 timeout: Option<std::time::Duration>,
416 ) -> Result<$Resp, ServiceError> {
417 let request = ServerRequest::$Req($Req {
418 method: Default::default(),
419 params,
420 extensions: Default::default(),
421 });
422 let options = crate::service::PeerRequestOptions {
423 timeout,
424 meta: None,
425 reset_timeout_on_progress: false,
426 max_total_timeout: None,
427 };
428 let result = self
429 .send_request_with_option(request, options)
430 .await?
431 .await_response()
432 .await?;
433 match result {
434 ClientResult::$Resp(result) => Ok(result),
435 _ => Err(ServiceError::UnexpectedResponse),
436 }
437 }
438 };
439}
440
441impl Peer<RoleServer> {
442 pub fn supports_sampling_tools(&self) -> bool {
444 if let Some(client_info) = self.peer_info() {
445 client_info
446 .capabilities
447 .sampling
448 .as_ref()
449 .and_then(|s| s.tools.as_ref())
450 .is_some()
451 } else {
452 false
453 }
454 }
455
456 #[deprecated(
457 since = "1.8.0",
458 note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
459 )]
460 pub async fn create_message(
461 &self,
462 params: CreateMessageRequestParams,
463 ) -> Result<CreateMessageResult, ServiceError> {
464 if (params.tools.is_some() || params.tool_choice.is_some())
466 && !self.supports_sampling_tools()
467 {
468 return Err(ServiceError::McpError(ErrorData::invalid_params(
469 "tools or toolChoice provided but client does not support sampling tools capability",
470 None,
471 )));
472 }
473 params
475 .validate()
476 .map_err(|e| ServiceError::McpError(ErrorData::invalid_params(e, None)))?;
477 let result = self
478 .send_request(ServerRequest::CreateMessageRequest(CreateMessageRequest {
479 method: Default::default(),
480 params,
481 extensions: Default::default(),
482 }))
483 .await?;
484 match result {
485 ClientResult::CreateMessageResult(result) => Ok(*result),
486 _ => Err(ServiceError::UnexpectedResponse),
487 }
488 }
489 method!(
490 #[deprecated(
491 since = "1.8.0",
492 note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
493 )]
494 peer_req list_roots ListRootsRequest() => ListRootsResult
495 );
496 #[cfg(feature = "elicitation")]
497 method!(peer_req create_elicitation ElicitRequest(ElicitRequestParams) => ElicitResult);
498 #[cfg(feature = "elicitation")]
499 method!(peer_req_with_timeout create_elicitation_with_timeout ElicitRequest(ElicitRequestParams) => ElicitResult);
500
501 method!(peer_not notify_cancelled CancelledNotification(CancelledNotificationParam));
502 method!(peer_not notify_progress ProgressNotification(ProgressNotificationParam));
503 method!(
504 #[deprecated(
505 since = "1.8.0",
506 note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
507 )]
508 peer_not notify_logging_message LoggingMessageNotification(LoggingMessageNotificationParam)
509 );
510 method!(peer_not notify_resource_updated ResourceUpdatedNotification(ResourceUpdatedNotificationParam));
511 method!(peer_not notify_resource_list_changed ResourceListChangedNotification);
512 method!(peer_not notify_tool_list_changed ToolListChangedNotification);
513 method!(peer_not notify_prompt_list_changed PromptListChangedNotification);
514}
515
516#[cfg(feature = "elicitation")]
523#[derive(Error, Debug)]
524#[non_exhaustive]
525pub enum ElicitationError {
526 #[error("Service error: {0}")]
528 Service(#[from] ServiceError),
529
530 #[error("User explicitly declined the request")]
534 UserDeclined,
535
536 #[error("User cancelled/dismissed the request")]
540 UserCancelled,
541
542 #[error("Failed to parse response data: {error}\nReceived data: {data}")]
544 ParseError {
545 error: serde_json::Error,
546 data: serde_json::Value,
547 },
548
549 #[error("No response content provided")]
551 NoContent,
552
553 #[error("Client does not support elicitation - capability not declared during initialization")]
555 CapabilityNotSupported,
556}
557
558#[cfg(feature = "elicitation")]
576pub trait ElicitationSafe: schemars::JsonSchema {}
577
578#[cfg(feature = "elicitation")]
602#[macro_export]
603macro_rules! elicit_safe {
604 ($($t:ty),* $(,)?) => {
605 $(
606 impl $crate::service::ElicitationSafe for $t {}
607 )*
608 };
609}
610
611#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
612#[non_exhaustive]
613pub enum ElicitationMode {
614 Form,
615 Url,
616}
617
618#[cfg(feature = "elicitation")]
619impl Peer<RoleServer> {
620 pub fn supported_elicitation_modes(&self) -> HashSet<ElicitationMode> {
626 if let Some(client_info) = self.peer_info() {
627 if let Some(elicit_capability) = &client_info.capabilities.elicitation {
628 let mut modes = HashSet::new();
629 if elicit_capability.form.is_none() && elicit_capability.url.is_none() {
631 modes.insert(ElicitationMode::Form);
632 } else {
633 if elicit_capability.form.is_some() {
634 modes.insert(ElicitationMode::Form);
635 }
636 if elicit_capability.url.is_some() {
637 modes.insert(ElicitationMode::Url);
638 }
639 }
640 modes
641 } else {
642 HashSet::new()
643 }
644 } else {
645 HashSet::new()
646 }
647 }
648
649 #[cfg(all(feature = "schemars", feature = "elicitation"))]
727 pub async fn elicit<T>(&self, message: impl Into<String>) -> Result<Option<T>, ElicitationError>
728 where
729 T: ElicitationSafe + for<'de> serde::Deserialize<'de>,
730 {
731 self.elicit_with_timeout(message, None).await
732 }
733
734 #[cfg(all(feature = "schemars", feature = "elicitation"))]
788 pub async fn elicit_with_timeout<T>(
789 &self,
790 message: impl Into<String>,
791 timeout: Option<std::time::Duration>,
792 ) -> Result<Option<T>, ElicitationError>
793 where
794 T: ElicitationSafe + for<'de> serde::Deserialize<'de>,
795 {
796 if !self
798 .supported_elicitation_modes()
799 .contains(&ElicitationMode::Form)
800 {
801 return Err(ElicitationError::CapabilityNotSupported);
802 }
803
804 let schema = crate::model::ElicitationSchema::from_type::<T>().map_err(|e| {
806 ElicitationError::Service(ServiceError::McpError(crate::ErrorData::invalid_params(
807 format!(
808 "Invalid schema for type {}: {}",
809 std::any::type_name::<T>(),
810 e
811 ),
812 None,
813 )))
814 })?;
815
816 let response = self
817 .create_elicitation_with_timeout(
818 ElicitRequestParams::FormElicitationParams {
819 meta: None,
820 message: message.into(),
821 requested_schema: schema,
822 },
823 timeout,
824 )
825 .await?;
826
827 match response.action {
828 crate::model::ElicitationAction::Accept => {
829 if let Some(value) = response.content {
830 match serde_json::from_value::<T>(value.clone()) {
831 Ok(parsed) => Ok(Some(parsed)),
832 Err(error) => Err(ElicitationError::ParseError { error, data: value }),
833 }
834 } else {
835 Err(ElicitationError::NoContent)
836 }
837 }
838 crate::model::ElicitationAction::Decline => Err(ElicitationError::UserDeclined),
839 crate::model::ElicitationAction::Cancel => Err(ElicitationError::UserCancelled),
840 }
841 }
842
843 #[cfg(feature = "elicitation")]
883 pub async fn elicit_url(
884 &self,
885 message: impl Into<String>,
886 url: impl Into<Url>,
887 elicitation_id: impl Into<String>,
888 ) -> Result<ElicitationAction, ElicitationError> {
889 self.elicit_url_with_timeout(message, url, elicitation_id, None)
890 .await
891 }
892
893 #[cfg(feature = "elicitation")]
934 pub async fn elicit_url_with_timeout(
935 &self,
936 message: impl Into<String>,
937 url: impl Into<Url>,
938 elicitation_id: impl Into<String>,
939 timeout: Option<std::time::Duration>,
940 ) -> Result<ElicitationAction, ElicitationError> {
941 if !self
943 .supported_elicitation_modes()
944 .contains(&ElicitationMode::Url)
945 {
946 return Err(ElicitationError::CapabilityNotSupported);
947 }
948
949 let action = self
950 .create_elicitation_with_timeout(
951 ElicitRequestParams::UrlElicitationParams {
952 meta: None,
953 message: message.into(),
954 url: url.into().to_string(),
955 elicitation_id: elicitation_id.into(),
956 },
957 timeout,
958 )
959 .await?
960 .action;
961 Ok(action)
962 }
963}