1use std::sync::atomic::{AtomicI64, Ordering};
117use std::sync::{Arc, RwLock};
118
119use async_trait::async_trait;
120use tokio::sync::mpsc;
121
122use crate::error::{Error, Result};
123use crate::protocol::{
124 CallToolResult, CancelTaskParams, CreateMessageParams, CreateMessageResult, ElicitFormParams,
125 ElicitRequestParams, ElicitResult, ElicitUrlParams, GetTaskInfoParams, GetTaskResultParams,
126 ListTasksParams, ListTasksResult, LogLevel, LoggingMessageParams, ProgressParams,
127 ProgressToken, RequestId, TaskObject, TaskStatus,
128};
129
130#[derive(Debug, Clone)]
132#[non_exhaustive]
133pub enum ServerNotification {
134 Progress(ProgressParams),
136 LogMessage(LoggingMessageParams),
138 ResourceUpdated {
140 uri: String,
142 },
143 ResourcesListChanged,
145 ToolsListChanged,
147 PromptsListChanged,
149 TaskStatusChanged(crate::protocol::TaskStatusParams),
151 FinalTaskStatusChanged(crate::tasks::TaskStatusNotificationParams),
157}
158
159pub type NotificationSender = mpsc::Sender<ServerNotification>;
161
162pub type NotificationReceiver = mpsc::Receiver<ServerNotification>;
164
165pub fn notification_channel(buffer: usize) -> (NotificationSender, NotificationReceiver) {
167 mpsc::channel(buffer)
168}
169
170#[async_trait]
180pub trait ClientRequester: Send + Sync {
181 async fn sample(&self, params: CreateMessageParams) -> Result<CreateMessageResult>;
185
186 async fn elicit(&self, params: ElicitRequestParams) -> Result<ElicitResult>;
193
194 async fn request(
202 &self,
203 method: String,
204 params: serde_json::Value,
205 ) -> Result<serde_json::Value> {
206 let _ = (method, params);
207 Err(Error::Internal(
208 "ClientRequester does not support arbitrary requests".to_string(),
209 ))
210 }
211}
212
213pub type ClientRequesterHandle = Arc<dyn ClientRequester>;
215
216#[derive(Debug)]
218pub struct OutgoingRequest {
219 pub id: RequestId,
221 pub method: String,
223 pub params: serde_json::Value,
225 pub response_tx: tokio::sync::oneshot::Sender<Result<serde_json::Value>>,
227}
228
229pub type OutgoingRequestSender = mpsc::Sender<OutgoingRequest>;
231
232pub type OutgoingRequestReceiver = mpsc::Receiver<OutgoingRequest>;
234
235pub fn outgoing_request_channel(buffer: usize) -> (OutgoingRequestSender, OutgoingRequestReceiver) {
237 mpsc::channel(buffer)
238}
239
240#[derive(Clone)]
242pub struct ChannelClientRequester {
243 request_tx: OutgoingRequestSender,
244 next_id: Arc<AtomicI64>,
245}
246
247impl ChannelClientRequester {
248 pub fn new(request_tx: OutgoingRequestSender) -> Self {
250 Self {
251 request_tx,
252 next_id: Arc::new(AtomicI64::new(1)),
253 }
254 }
255
256 #[cfg(feature = "http")]
262 pub(crate) fn with_id_allocator(
263 request_tx: OutgoingRequestSender,
264 next_id: Arc<AtomicI64>,
265 ) -> Self {
266 Self {
267 request_tx,
268 next_id,
269 }
270 }
271
272 fn next_request_id(&self) -> RequestId {
273 let id = self.next_id.fetch_add(1, Ordering::Relaxed);
274 RequestId::Number(id)
275 }
276}
277
278impl ChannelClientRequester {
279 async fn dispatch(&self, method: &str, params: serde_json::Value) -> Result<serde_json::Value> {
280 let id = self.next_request_id();
281 let (response_tx, response_rx) = tokio::sync::oneshot::channel();
282
283 let request = OutgoingRequest {
284 id,
285 method: method.to_string(),
286 params,
287 response_tx,
288 };
289
290 self.request_tx
291 .send(request)
292 .await
293 .map_err(|_| Error::Internal("Failed to send request: channel closed".to_string()))?;
294
295 response_rx.await.map_err(|_| {
296 Error::Internal("Failed to receive response: channel closed".to_string())
297 })?
298 }
299}
300
301#[async_trait]
302impl ClientRequester for ChannelClientRequester {
303 async fn sample(&self, params: CreateMessageParams) -> Result<CreateMessageResult> {
304 let params_json = serde_json::to_value(¶ms)
305 .map_err(|e| Error::Internal(format!("Failed to serialize params: {}", e)))?;
306 let response = self.dispatch("sampling/createMessage", params_json).await?;
307 serde_json::from_value(response)
308 .map_err(|e| Error::Internal(format!("Failed to deserialize response: {}", e)))
309 }
310
311 async fn elicit(&self, params: ElicitRequestParams) -> Result<ElicitResult> {
312 let params_json = serde_json::to_value(¶ms)
313 .map_err(|e| Error::Internal(format!("Failed to serialize params: {}", e)))?;
314 let response = self.dispatch("elicitation/create", params_json).await?;
315 serde_json::from_value(response)
316 .map_err(|e| Error::Internal(format!("Failed to deserialize response: {}", e)))
317 }
318
319 async fn request(
320 &self,
321 method: String,
322 params: serde_json::Value,
323 ) -> Result<serde_json::Value> {
324 self.dispatch(&method, params).await
325 }
326}
327
328#[derive(Clone)]
330pub struct RequestContext {
331 request_id: RequestId,
333 progress_token: Option<ProgressToken>,
335 cancellation: tokio_util::sync::CancellationToken,
337 notification_tx: Option<NotificationSender>,
339 client_requester: Option<ClientRequesterHandle>,
341 extensions: Arc<Extensions>,
343 min_log_level: Option<Arc<RwLock<LogLevel>>>,
345}
346
347#[derive(Clone, Default)]
352pub struct Extensions {
353 map: std::collections::HashMap<std::any::TypeId, Arc<dyn std::any::Any + Send + Sync>>,
354}
355
356impl Extensions {
357 pub fn new() -> Self {
359 Self::default()
360 }
361
362 pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) {
366 self.map.insert(std::any::TypeId::of::<T>(), Arc::new(val));
367 }
368
369 pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
373 self.map
374 .get(&std::any::TypeId::of::<T>())
375 .and_then(|val| val.downcast_ref::<T>())
376 }
377
378 pub fn contains<T: Send + Sync + 'static>(&self) -> bool {
380 self.map.contains_key(&std::any::TypeId::of::<T>())
381 }
382
383 pub fn merge(&mut self, other: &Extensions) {
387 for (k, v) in &other.map {
388 self.map.insert(*k, v.clone());
389 }
390 }
391
392 pub fn len(&self) -> usize {
394 self.map.len()
395 }
396
397 pub fn is_empty(&self) -> bool {
399 self.map.is_empty()
400 }
401}
402
403impl std::fmt::Debug for Extensions {
404 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
405 f.debug_struct("Extensions")
406 .field("len", &self.map.len())
407 .finish()
408 }
409}
410
411impl std::fmt::Debug for RequestContext {
412 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
413 f.debug_struct("RequestContext")
414 .field("request_id", &self.request_id)
415 .field("progress_token", &self.progress_token)
416 .field("cancelled", &self.cancellation.is_cancelled())
417 .finish()
418 }
419}
420
421impl RequestContext {
422 pub fn new(request_id: RequestId) -> Self {
424 Self {
425 request_id,
426 progress_token: None,
427 cancellation: tokio_util::sync::CancellationToken::new(),
428 notification_tx: None,
429 client_requester: None,
430 extensions: Arc::new(Extensions::new()),
431 min_log_level: None,
432 }
433 }
434
435 pub fn with_progress_token(mut self, token: ProgressToken) -> Self {
437 self.progress_token = Some(token);
438 self
439 }
440
441 pub fn with_notification_sender(mut self, tx: NotificationSender) -> Self {
443 self.notification_tx = Some(tx);
444 self
445 }
446
447 pub fn with_min_log_level(mut self, level: Arc<RwLock<LogLevel>>) -> Self {
452 self.min_log_level = Some(level);
453 self
454 }
455
456 pub fn with_client_requester(mut self, requester: ClientRequesterHandle) -> Self {
458 self.client_requester = Some(requester);
459 self
460 }
461
462 pub fn with_extensions(mut self, extensions: Arc<Extensions>) -> Self {
466 self.extensions = extensions;
467 self
468 }
469
470 pub fn extension<T: Send + Sync + 'static>(&self) -> Option<&T> {
486 self.extensions.get::<T>()
487 }
488
489 pub fn negotiated_extensions(&self) -> Option<&crate::NegotiatedExtensions> {
494 self.extension()
495 }
496
497 pub fn extensions_mut(&mut self) -> &mut Extensions {
502 Arc::make_mut(&mut self.extensions)
503 }
504
505 pub fn extensions(&self) -> &Extensions {
507 &self.extensions
508 }
509
510 #[cfg(feature = "stateless")]
537 pub fn per_request_meta(&self) -> Option<&crate::stateless::StatelessRequestMeta> {
538 self.extension::<crate::stateless::StatelessRequestMeta>()
539 }
540
541 #[cfg(feature = "stateless")]
543 pub fn mrtr(&self) -> Option<&crate::mrtr::MrtrRequest> {
544 self.extension::<crate::mrtr::MrtrRequest>()
545 }
546
547 #[cfg(feature = "stateless")]
549 pub fn input_responses(&self) -> Option<&crate::protocol::InputResponses> {
550 self.mrtr()
551 .and_then(crate::mrtr::MrtrRequest::input_responses)
552 }
553
554 #[cfg(feature = "stateless")]
556 pub fn request_state(&self) -> Option<&str> {
557 self.mrtr()
558 .and_then(crate::mrtr::MrtrRequest::request_state)
559 }
560
561 #[cfg(feature = "stateless")]
563 pub fn request_state_codec(&self) -> Option<&crate::mrtr::RequestStateCodec> {
564 self.extension::<crate::mrtr::RequestStateCodec>()
565 }
566
567 pub fn request_id(&self) -> &RequestId {
569 &self.request_id
570 }
571
572 pub fn progress_token(&self) -> Option<&ProgressToken> {
574 self.progress_token.as_ref()
575 }
576
577 pub fn is_cancelled(&self) -> bool {
579 self.cancellation.is_cancelled()
580 }
581
582 pub fn cancel(&self) {
584 self.cancellation.cancel();
585 }
586
587 pub async fn cancelled(&self) {
601 self.cancellation.cancelled().await
602 }
603
604 pub fn cancellation_token(&self) -> CancellationToken {
606 CancellationToken {
607 inner: self.cancellation.clone(),
608 }
609 }
610
611 pub fn with_cancellation_token(mut self, token: CancellationToken) -> Self {
619 self.cancellation = token.inner;
620 self
621 }
622
623 pub async fn report_progress(&self, progress: f64, total: Option<f64>, message: Option<&str>) {
627 let Some(token) = &self.progress_token else {
628 return;
629 };
630 let Some(tx) = &self.notification_tx else {
631 return;
632 };
633
634 let params = ProgressParams {
635 progress_token: token.clone(),
636 progress,
637 total,
638 message: message.map(|s| s.to_string()),
639 meta: None,
640 };
641
642 let _ = tx.try_send(ServerNotification::Progress(params));
644 }
645
646 pub fn report_progress_sync(&self, progress: f64, total: Option<f64>, message: Option<&str>) {
650 let Some(token) = &self.progress_token else {
651 return;
652 };
653 let Some(tx) = &self.notification_tx else {
654 return;
655 };
656
657 let params = ProgressParams {
658 progress_token: token.clone(),
659 progress,
660 total,
661 message: message.map(|s| s.to_string()),
662 meta: None,
663 };
664
665 let _ = tx.try_send(ServerNotification::Progress(params));
666 }
667
668 pub fn notify_tools_list_changed(&self) -> bool {
670 self.notification_tx
671 .as_ref()
672 .is_some_and(|tx| tx.try_send(ServerNotification::ToolsListChanged).is_ok())
673 }
674
675 pub fn notify_prompts_list_changed(&self) -> bool {
677 self.notification_tx
678 .as_ref()
679 .is_some_and(|tx| tx.try_send(ServerNotification::PromptsListChanged).is_ok())
680 }
681
682 pub fn notify_resources_list_changed(&self) -> bool {
684 self.notification_tx.as_ref().is_some_and(|tx| {
685 tx.try_send(ServerNotification::ResourcesListChanged)
686 .is_ok()
687 })
688 }
689
690 pub fn notify_resource_updated(&self, uri: impl Into<String>) -> bool {
692 self.notification_tx.as_ref().is_some_and(|tx| {
693 tx.try_send(ServerNotification::ResourceUpdated { uri: uri.into() })
694 .is_ok()
695 })
696 }
697
698 pub fn notify_task_status_changed(
703 &self,
704 params: crate::tasks::TaskStatusNotificationParams,
705 ) -> bool {
706 self.notification_tx.as_ref().is_some_and(|tx| {
707 tx.try_send(ServerNotification::FinalTaskStatusChanged(params))
708 .is_ok()
709 })
710 }
711
712 pub fn send_log(&self, params: LoggingMessageParams) {
729 let Some(tx) = &self.notification_tx else {
730 return;
731 };
732
733 #[cfg(feature = "stateless")]
736 if let Some(meta) = self.per_request_meta()
737 && meta.protocol_version.as_deref()
738 == Some(crate::protocol::PROTOCOL_VERSION_2026_07_28)
739 {
740 let Some(request_level) = meta.log_level else {
741 return;
742 };
743 let request_level = match request_level {
744 crate::stateless::LogLevel::Debug => LogLevel::Debug,
745 crate::stateless::LogLevel::Info => LogLevel::Info,
746 crate::stateless::LogLevel::Notice => LogLevel::Notice,
747 crate::stateless::LogLevel::Warning => LogLevel::Warning,
748 crate::stateless::LogLevel::Error => LogLevel::Error,
749 crate::stateless::LogLevel::Critical => LogLevel::Critical,
750 crate::stateless::LogLevel::Alert => LogLevel::Alert,
751 crate::stateless::LogLevel::Emergency => LogLevel::Emergency,
752 };
753 if params.level > request_level {
754 return;
755 }
756 let _ = tx.try_send(ServerNotification::LogMessage(params));
757 return;
758 }
759
760 if let Some(min_level) = &self.min_log_level
765 && let Ok(min) = min_level.read()
766 && params.level > *min
767 {
768 return;
769 }
770
771 let _ = tx.try_send(ServerNotification::LogMessage(params));
772 }
773
774 pub fn can_sample(&self) -> bool {
779 self.client_requester.is_some()
780 }
781
782 pub async fn sample(&self, params: CreateMessageParams) -> Result<CreateMessageResult> {
806 let requester = self.client_requester.as_ref().ok_or_else(|| {
807 Error::Internal("Sampling not available: no client requester configured".to_string())
808 })?;
809
810 requester.sample(params).await
811 }
812
813 pub fn can_elicit(&self) -> bool {
819 self.client_requester.is_some()
820 }
821
822 pub async fn elicit_form(&self, params: ElicitFormParams) -> Result<ElicitResult> {
854 let requester = self.client_requester.as_ref().ok_or_else(|| {
855 Error::Internal("Elicitation not available: no client requester configured".to_string())
856 })?;
857
858 requester.elicit(ElicitRequestParams::Form(params)).await
859 }
860
861 pub async fn elicit_url(&self, params: ElicitUrlParams) -> Result<ElicitResult> {
898 let requester = self.client_requester.as_ref().ok_or_else(|| {
899 Error::Internal("Elicitation not available: no client requester configured".to_string())
900 })?;
901
902 requester.elicit(ElicitRequestParams::Url(params)).await
903 }
904
905 pub async fn confirm(&self, message: impl Into<String>) -> Result<bool> {
929 use crate::protocol::{ElicitAction, ElicitFormParams, ElicitFormSchema, ElicitMode};
930
931 let params = ElicitFormParams {
932 mode: Some(ElicitMode::Form),
933 message: message.into(),
934 requested_schema: ElicitFormSchema::new().boolean_field_with_default(
935 "confirm",
936 Some("Confirm this action"),
937 true,
938 false,
939 ),
940 meta: None,
941 };
942
943 let result = self.elicit_form(params).await?;
944 Ok(result.action == ElicitAction::Accept)
945 }
946
947 #[deprecated(
957 since = "0.13.0",
958 note = "final SEP-2663 removes tasks/list; a conforming peer answers \
959 MethodNotFound (-32601). Only useful against legacy SEP-1686 \
960 clients."
961 )]
962 pub async fn list_tasks(&self, status: Option<TaskStatus>) -> Result<ListTasksResult> {
963 let params = ListTasksParams {
964 status,
965 cursor: None,
966 meta: None,
967 };
968 let value = self
969 .request_raw("tasks/list", serde_json::to_value(¶ms)?)
970 .await?;
971 serde_json::from_value(value)
972 .map_err(|e| Error::Internal(format!("Failed to deserialize tasks/list: {e}")))
973 }
974
975 pub async fn get_task_info(&self, task_id: impl Into<String>) -> Result<TaskObject> {
980 let params = GetTaskInfoParams {
981 task_id: task_id.into(),
982 meta: None,
983 };
984 let value = self
985 .request_raw("tasks/get", serde_json::to_value(¶ms)?)
986 .await?;
987 serde_json::from_value(value)
988 .map_err(|e| Error::Internal(format!("Failed to deserialize tasks/get: {e}")))
989 }
990
991 #[deprecated(
1000 since = "0.13.0",
1001 note = "final SEP-2663 removes tasks/result (results are inlined in \
1002 the tasks/get DetailedTask); a conforming peer answers \
1003 MethodNotFound (-32601). Only useful against legacy SEP-1686 \
1004 clients."
1005 )]
1006 pub async fn get_task_result(&self, task_id: impl Into<String>) -> Result<CallToolResult> {
1007 let params = GetTaskResultParams {
1008 task_id: task_id.into(),
1009 meta: None,
1010 };
1011 let value = self
1012 .request_raw("tasks/result", serde_json::to_value(¶ms)?)
1013 .await?;
1014 serde_json::from_value(value)
1015 .map_err(|e| Error::Internal(format!("Failed to deserialize tasks/result: {e}")))
1016 }
1017
1018 pub async fn cancel_task(
1025 &self,
1026 task_id: impl Into<String>,
1027 reason: Option<String>,
1028 ) -> Result<()> {
1029 let params = CancelTaskParams {
1030 task_id: task_id.into(),
1031 reason,
1032 meta: None,
1033 };
1034 self.request_raw("tasks/cancel", serde_json::to_value(¶ms)?)
1035 .await?;
1036 Ok(())
1037 }
1038
1039 pub async fn request_raw(
1045 &self,
1046 method: &str,
1047 params: serde_json::Value,
1048 ) -> Result<serde_json::Value> {
1049 let requester = self.client_requester.as_ref().ok_or_else(|| {
1050 Error::Internal(
1051 "Client request not available: no client requester configured".to_string(),
1052 )
1053 })?;
1054 requester.request(method.to_string(), params).await
1055 }
1056}
1057
1058#[derive(Clone, Debug, Default)]
1064pub struct CancellationToken {
1065 inner: tokio_util::sync::CancellationToken,
1066}
1067
1068impl CancellationToken {
1069 pub fn new() -> Self {
1071 Self::default()
1072 }
1073
1074 pub fn is_cancelled(&self) -> bool {
1076 self.inner.is_cancelled()
1077 }
1078
1079 pub fn cancel(&self) {
1081 self.inner.cancel();
1082 }
1083
1084 pub async fn cancelled(&self) {
1088 self.inner.cancelled().await
1089 }
1090}
1091
1092#[derive(Default)]
1094pub struct RequestContextBuilder {
1095 request_id: Option<RequestId>,
1096 progress_token: Option<ProgressToken>,
1097 notification_tx: Option<NotificationSender>,
1098 client_requester: Option<ClientRequesterHandle>,
1099 min_log_level: Option<Arc<RwLock<LogLevel>>>,
1100}
1101
1102impl RequestContextBuilder {
1103 pub fn new() -> Self {
1105 Self::default()
1106 }
1107
1108 pub fn request_id(mut self, id: RequestId) -> Self {
1110 self.request_id = Some(id);
1111 self
1112 }
1113
1114 pub fn progress_token(mut self, token: ProgressToken) -> Self {
1116 self.progress_token = Some(token);
1117 self
1118 }
1119
1120 pub fn notification_sender(mut self, tx: NotificationSender) -> Self {
1122 self.notification_tx = Some(tx);
1123 self
1124 }
1125
1126 pub fn client_requester(mut self, requester: ClientRequesterHandle) -> Self {
1128 self.client_requester = Some(requester);
1129 self
1130 }
1131
1132 pub fn min_log_level(mut self, level: Arc<RwLock<LogLevel>>) -> Self {
1134 self.min_log_level = Some(level);
1135 self
1136 }
1137
1138 pub fn build(self) -> RequestContext {
1142 let mut ctx = RequestContext::new(self.request_id.expect("request_id is required"));
1143 if let Some(token) = self.progress_token {
1144 ctx = ctx.with_progress_token(token);
1145 }
1146 if let Some(tx) = self.notification_tx {
1147 ctx = ctx.with_notification_sender(tx);
1148 }
1149 if let Some(requester) = self.client_requester {
1150 ctx = ctx.with_client_requester(requester);
1151 }
1152 if let Some(level) = self.min_log_level {
1153 ctx = ctx.with_min_log_level(level);
1154 }
1155 ctx
1156 }
1157}
1158
1159#[cfg(test)]
1160mod tests {
1161 use super::*;
1162
1163 #[test]
1164 fn test_cancellation() {
1165 let ctx = RequestContext::new(RequestId::Number(1));
1166 assert!(!ctx.is_cancelled());
1167
1168 let token = ctx.cancellation_token();
1169 assert!(!token.is_cancelled());
1170
1171 ctx.cancel();
1172 assert!(ctx.is_cancelled());
1173 assert!(token.is_cancelled());
1174 }
1175
1176 #[tokio::test]
1177 async fn test_progress_reporting() {
1178 let (tx, mut rx) = notification_channel(10);
1179
1180 let ctx = RequestContext::new(RequestId::Number(1))
1181 .with_progress_token(ProgressToken::Number(42))
1182 .with_notification_sender(tx);
1183
1184 ctx.report_progress(50.0, Some(100.0), Some("Halfway"))
1185 .await;
1186
1187 let notification = rx.recv().await.unwrap();
1188 match notification {
1189 ServerNotification::Progress(params) => {
1190 assert_eq!(params.progress, 50.0);
1191 assert_eq!(params.total, Some(100.0));
1192 assert_eq!(params.message.as_deref(), Some("Halfway"));
1193 }
1194 _ => panic!("Expected Progress notification"),
1195 }
1196 }
1197
1198 #[tokio::test]
1199 async fn test_progress_no_token() {
1200 let (tx, mut rx) = notification_channel(10);
1201
1202 let ctx = RequestContext::new(RequestId::Number(1)).with_notification_sender(tx);
1204
1205 ctx.report_progress(50.0, Some(100.0), None).await;
1206
1207 assert!(rx.try_recv().is_err());
1209 }
1210
1211 #[test]
1212 fn test_builder() {
1213 let (tx, _rx) = notification_channel(10);
1214
1215 let ctx = RequestContextBuilder::new()
1216 .request_id(RequestId::String("req-1".to_string()))
1217 .progress_token(ProgressToken::String("prog-1".to_string()))
1218 .notification_sender(tx)
1219 .build();
1220
1221 assert_eq!(ctx.request_id(), &RequestId::String("req-1".to_string()));
1222 assert!(ctx.progress_token().is_some());
1223 }
1224
1225 #[test]
1226 fn test_can_sample_without_requester() {
1227 let ctx = RequestContext::new(RequestId::Number(1));
1228 assert!(!ctx.can_sample());
1229 }
1230
1231 #[test]
1232 fn test_can_sample_with_requester() {
1233 let (request_tx, _rx) = outgoing_request_channel(10);
1234 let requester: ClientRequesterHandle = Arc::new(ChannelClientRequester::new(request_tx));
1235
1236 let ctx = RequestContext::new(RequestId::Number(1)).with_client_requester(requester);
1237 assert!(ctx.can_sample());
1238 }
1239
1240 #[tokio::test]
1241 async fn test_sample_without_requester_fails() {
1242 use crate::protocol::{CreateMessageParams, SamplingMessage};
1243
1244 let ctx = RequestContext::new(RequestId::Number(1));
1245 let params = CreateMessageParams::new(vec![SamplingMessage::user("test")], 100);
1246
1247 let result = ctx.sample(params).await;
1248 assert!(result.is_err());
1249 assert!(
1250 result
1251 .unwrap_err()
1252 .to_string()
1253 .contains("Sampling not available")
1254 );
1255 }
1256
1257 #[test]
1258 fn test_builder_with_client_requester() {
1259 let (request_tx, _rx) = outgoing_request_channel(10);
1260 let requester: ClientRequesterHandle = Arc::new(ChannelClientRequester::new(request_tx));
1261
1262 let ctx = RequestContextBuilder::new()
1263 .request_id(RequestId::Number(1))
1264 .client_requester(requester)
1265 .build();
1266
1267 assert!(ctx.can_sample());
1268 }
1269
1270 #[test]
1271 fn test_can_elicit_without_requester() {
1272 let ctx = RequestContext::new(RequestId::Number(1));
1273 assert!(!ctx.can_elicit());
1274 }
1275
1276 #[test]
1277 fn test_can_elicit_with_requester() {
1278 let (request_tx, _rx) = outgoing_request_channel(10);
1279 let requester: ClientRequesterHandle = Arc::new(ChannelClientRequester::new(request_tx));
1280
1281 let ctx = RequestContext::new(RequestId::Number(1)).with_client_requester(requester);
1282 assert!(ctx.can_elicit());
1283 }
1284
1285 #[tokio::test]
1286 async fn test_elicit_form_without_requester_fails() {
1287 use crate::protocol::{ElicitFormSchema, ElicitMode};
1288
1289 let ctx = RequestContext::new(RequestId::Number(1));
1290 let params = ElicitFormParams {
1291 mode: Some(ElicitMode::Form),
1292 message: "Enter details".to_string(),
1293 requested_schema: ElicitFormSchema::new().string_field("name", None, true),
1294 meta: None,
1295 };
1296
1297 let result = ctx.elicit_form(params).await;
1298 assert!(result.is_err());
1299 assert!(
1300 result
1301 .unwrap_err()
1302 .to_string()
1303 .contains("Elicitation not available")
1304 );
1305 }
1306
1307 #[tokio::test]
1308 async fn test_elicit_url_without_requester_fails() {
1309 use crate::protocol::ElicitMode;
1310
1311 let ctx = RequestContext::new(RequestId::Number(1));
1312 let params = ElicitUrlParams {
1313 mode: Some(ElicitMode::Url),
1314 elicitation_id: "test-123".to_string(),
1315 message: "Please authorize".to_string(),
1316 url: "https://example.com/auth".to_string(),
1317 meta: None,
1318 };
1319
1320 let result = ctx.elicit_url(params).await;
1321 assert!(result.is_err());
1322 assert!(
1323 result
1324 .unwrap_err()
1325 .to_string()
1326 .contains("Elicitation not available")
1327 );
1328 }
1329
1330 #[tokio::test]
1331 async fn test_confirm_without_requester_fails() {
1332 let ctx = RequestContext::new(RequestId::Number(1));
1333
1334 let result = ctx.confirm("Are you sure?").await;
1335 assert!(result.is_err());
1336 assert!(
1337 result
1338 .unwrap_err()
1339 .to_string()
1340 .contains("Elicitation not available")
1341 );
1342 }
1343
1344 #[tokio::test]
1345 async fn test_send_log_filtered_by_level() {
1346 let (tx, mut rx) = notification_channel(10);
1347 let min_level = Arc::new(RwLock::new(LogLevel::Warning));
1348
1349 let ctx = RequestContext::new(RequestId::Number(1))
1350 .with_notification_sender(tx)
1351 .with_min_log_level(min_level.clone());
1352
1353 ctx.send_log(LoggingMessageParams::new(
1355 LogLevel::Error,
1356 serde_json::Value::Null,
1357 ));
1358 let msg = rx.try_recv();
1359 assert!(msg.is_ok(), "Error should pass through Warning filter");
1360
1361 ctx.send_log(LoggingMessageParams::new(
1363 LogLevel::Warning,
1364 serde_json::Value::Null,
1365 ));
1366 let msg = rx.try_recv();
1367 assert!(msg.is_ok(), "Warning should pass through Warning filter");
1368
1369 ctx.send_log(LoggingMessageParams::new(
1371 LogLevel::Info,
1372 serde_json::Value::Null,
1373 ));
1374 let msg = rx.try_recv();
1375 assert!(msg.is_err(), "Info should be filtered by Warning filter");
1376
1377 ctx.send_log(LoggingMessageParams::new(
1379 LogLevel::Debug,
1380 serde_json::Value::Null,
1381 ));
1382 let msg = rx.try_recv();
1383 assert!(msg.is_err(), "Debug should be filtered by Warning filter");
1384 }
1385
1386 #[tokio::test]
1387 async fn test_send_log_level_updates_dynamically() {
1388 let (tx, mut rx) = notification_channel(10);
1389 let min_level = Arc::new(RwLock::new(LogLevel::Error));
1390
1391 let ctx = RequestContext::new(RequestId::Number(1))
1392 .with_notification_sender(tx)
1393 .with_min_log_level(min_level.clone());
1394
1395 ctx.send_log(LoggingMessageParams::new(
1397 LogLevel::Info,
1398 serde_json::Value::Null,
1399 ));
1400 assert!(
1401 rx.try_recv().is_err(),
1402 "Info should be filtered at Error level"
1403 );
1404
1405 *min_level.write().unwrap() = LogLevel::Debug;
1407
1408 ctx.send_log(LoggingMessageParams::new(
1410 LogLevel::Info,
1411 serde_json::Value::Null,
1412 ));
1413 assert!(
1414 rx.try_recv().is_ok(),
1415 "Info should pass through after level changed to Debug"
1416 );
1417 }
1418
1419 #[tokio::test]
1420 async fn test_send_log_no_min_level_sends_all() {
1421 let (tx, mut rx) = notification_channel(10);
1422
1423 let ctx = RequestContext::new(RequestId::Number(1)).with_notification_sender(tx);
1425
1426 ctx.send_log(LoggingMessageParams::new(
1427 LogLevel::Debug,
1428 serde_json::Value::Null,
1429 ));
1430 assert!(
1431 rx.try_recv().is_ok(),
1432 "Debug should pass when no min level is set"
1433 );
1434 }
1435
1436 #[tokio::test]
1437 #[cfg(feature = "stateless")]
1438 async fn final_request_log_level_is_required_and_filters_per_request() {
1439 let (tx, mut rx) = notification_channel(10);
1440 let mut extensions = Extensions::new();
1441 extensions.insert(crate::stateless::StatelessRequestMeta {
1442 protocol_version: Some(crate::protocol::PROTOCOL_VERSION_2026_07_28.to_string()),
1443 client_capabilities: Some(Default::default()),
1444 ..Default::default()
1445 });
1446 let ctx = RequestContext::new(RequestId::Number(1))
1447 .with_notification_sender(tx.clone())
1448 .with_extensions(Arc::new(extensions));
1449 ctx.send_log(LoggingMessageParams::new(
1450 LogLevel::Emergency,
1451 serde_json::Value::Null,
1452 ));
1453 assert!(
1454 rx.try_recv().is_err(),
1455 "final requests without logLevel must receive no logs"
1456 );
1457
1458 let mut extensions = Extensions::new();
1459 extensions.insert(crate::stateless::StatelessRequestMeta {
1460 protocol_version: Some(crate::protocol::PROTOCOL_VERSION_2026_07_28.to_string()),
1461 client_capabilities: Some(Default::default()),
1462 log_level: Some(crate::stateless::LogLevel::Warning),
1463 ..Default::default()
1464 });
1465 let ctx = RequestContext::new(RequestId::Number(2))
1466 .with_notification_sender(tx)
1467 .with_extensions(Arc::new(extensions));
1468 ctx.send_log(LoggingMessageParams::new(
1469 LogLevel::Info,
1470 serde_json::Value::Null,
1471 ));
1472 assert!(rx.try_recv().is_err(), "Info must be filtered at Warning");
1473 ctx.send_log(LoggingMessageParams::new(
1474 LogLevel::Error,
1475 serde_json::Value::Null,
1476 ));
1477 assert!(rx.try_recv().is_ok(), "Error must pass at Warning");
1478 }
1479
1480 fn make_task_object(id: &str, status: TaskStatus) -> serde_json::Value {
1481 serde_json::json!({
1482 "taskId": id,
1483 "status": status,
1484 "createdAt": "2026-04-24T00:00:00Z",
1485 "lastUpdatedAt": "2026-04-24T00:00:00Z",
1486 "ttl": null
1487 })
1488 }
1489
1490 fn spawn_mock_client(
1491 mut rx: OutgoingRequestReceiver,
1492 responder: impl Fn(&str, serde_json::Value) -> serde_json::Value + Send + 'static,
1493 ) {
1494 tokio::spawn(async move {
1495 while let Some(req) = rx.recv().await {
1496 let response = responder(&req.method, req.params);
1497 let _ = req.response_tx.send(Ok(response));
1498 }
1499 });
1500 }
1501
1502 #[tokio::test]
1503 async fn test_get_task_info_round_trips() {
1504 let (tx, rx) = outgoing_request_channel(10);
1505 spawn_mock_client(rx, |method, params| {
1506 assert_eq!(method, "tasks/get");
1507 let task_id = params["taskId"].as_str().unwrap().to_string();
1508 make_task_object(&task_id, TaskStatus::Working)
1509 });
1510 let requester: ClientRequesterHandle = Arc::new(ChannelClientRequester::new(tx));
1511 let ctx = RequestContext::new(RequestId::Number(1)).with_client_requester(requester);
1512
1513 let info = ctx.get_task_info("task-123").await.unwrap();
1514 assert_eq!(info.task_id, "task-123");
1515 assert!(matches!(info.status, TaskStatus::Working));
1516 }
1517
1518 #[tokio::test]
1519 #[allow(deprecated)] async fn test_list_tasks_round_trips() {
1521 let (tx, rx) = outgoing_request_channel(10);
1522 spawn_mock_client(rx, |method, params| {
1523 assert_eq!(method, "tasks/list");
1524 assert_eq!(params["status"], serde_json::json!("working"));
1526 serde_json::json!({
1527 "tasks": [
1528 make_task_object("task-1", TaskStatus::Working),
1529 make_task_object("task-2", TaskStatus::Working),
1530 ]
1531 })
1532 });
1533 let requester: ClientRequesterHandle = Arc::new(ChannelClientRequester::new(tx));
1534 let ctx = RequestContext::new(RequestId::Number(1)).with_client_requester(requester);
1535
1536 let result = ctx.list_tasks(Some(TaskStatus::Working)).await.unwrap();
1537 assert_eq!(result.tasks.len(), 2);
1538 assert_eq!(result.tasks[0].task_id, "task-1");
1539 }
1540
1541 #[tokio::test]
1542 async fn test_cancel_task_forwards_reason() {
1543 let (tx, rx) = outgoing_request_channel(10);
1544 spawn_mock_client(rx, |method, params| {
1545 assert_eq!(method, "tasks/cancel");
1546 assert_eq!(params["reason"], serde_json::json!("user requested"));
1547 serde_json::json!({})
1549 });
1550 let requester: ClientRequesterHandle = Arc::new(ChannelClientRequester::new(tx));
1551 let ctx = RequestContext::new(RequestId::Number(1)).with_client_requester(requester);
1552
1553 ctx.cancel_task("task-99", Some("user requested".into()))
1554 .await
1555 .expect("empty ack should succeed");
1556 }
1557
1558 #[tokio::test]
1559 async fn test_cancel_task_tolerates_legacy_task_object_ack() {
1560 let (tx, rx) = outgoing_request_channel(10);
1563 spawn_mock_client(rx, |method, _params| {
1564 assert_eq!(method, "tasks/cancel");
1565 make_task_object("task-99", TaskStatus::Cancelled)
1566 });
1567 let requester: ClientRequesterHandle = Arc::new(ChannelClientRequester::new(tx));
1568 let ctx = RequestContext::new(RequestId::Number(1)).with_client_requester(requester);
1569
1570 ctx.cancel_task("task-99", None)
1571 .await
1572 .expect("legacy task-object ack should also succeed");
1573 }
1574
1575 #[tokio::test]
1576 async fn test_get_task_info_without_requester_fails() {
1577 let ctx = RequestContext::new(RequestId::Number(1));
1578 let result = ctx.get_task_info("task-1").await;
1579 assert!(result.is_err());
1580 assert!(
1581 result
1582 .unwrap_err()
1583 .to_string()
1584 .contains("Client request not available")
1585 );
1586 }
1587
1588 #[tokio::test]
1589 async fn test_default_request_impl_errors() {
1590 struct OnlySampleAndElicit;
1593
1594 #[async_trait]
1595 impl ClientRequester for OnlySampleAndElicit {
1596 async fn sample(&self, _: CreateMessageParams) -> Result<CreateMessageResult> {
1597 unreachable!()
1598 }
1599 async fn elicit(&self, _: ElicitRequestParams) -> Result<ElicitResult> {
1600 unreachable!()
1601 }
1602 }
1603
1604 let requester: ClientRequesterHandle = Arc::new(OnlySampleAndElicit);
1605 let ctx = RequestContext::new(RequestId::Number(1)).with_client_requester(requester);
1606
1607 let err = ctx.get_task_info("x").await.unwrap_err();
1608 assert!(err.to_string().contains("does not support arbitrary"));
1609 }
1610}