Skip to main content

dcp/compat/
mcp2025.rs

1//! MCP 2025 Compatibility Layer
2//!
3//! Implements support for MCP specification features from 2025-03-26 and 2025-06-18:
4//! - Protocol version negotiation
5//! - Roots support
6//! - Elicitation
7//! - Resource templates
8//! - Enhanced structured output
9//! - List changed notifications
10//! - Cancellation support
11//! - Progress notifications
12//! - Ping/pong keep-alive
13
14use std::collections::HashMap;
15use std::sync::atomic::{AtomicU64, Ordering};
16use std::sync::Arc;
17
18use serde::{Deserialize, Serialize};
19use serde_json::Value;
20use tokio::sync::{broadcast, oneshot, RwLock};
21
22use super::json_rpc::RequestId;
23
24/// Simple ID generator for elicitation requests
25static ELICITATION_ID_COUNTER: AtomicU64 = AtomicU64::new(0);
26
27fn generate_elicitation_id() -> String {
28    let id = ELICITATION_ID_COUNTER.fetch_add(1, Ordering::SeqCst);
29    format!("elicit-{}", id)
30}
31
32// ============================================================================
33// Protocol Version Negotiation
34// ============================================================================
35
36/// Supported MCP protocol versions
37#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
38pub enum ProtocolVersion {
39    /// Original MCP specification (2024-11-05)
40    #[default]
41    V2024_11_05,
42    /// Added roots support (2025-03-26)
43    V2025_03_26,
44    /// Added elicitation, structured output (2025-06-18)
45    V2025_06_18,
46}
47
48impl ProtocolVersion {
49    /// Parse from version string
50    pub fn from_str(s: &str) -> Option<Self> {
51        match s {
52            "2024-11-05" => Some(Self::V2024_11_05),
53            "2025-03-26" => Some(Self::V2025_03_26),
54            "2025-06-18" => Some(Self::V2025_06_18),
55            _ => None,
56        }
57    }
58
59    /// Get version string
60    pub fn as_str(&self) -> &'static str {
61        match self {
62            Self::V2024_11_05 => "2024-11-05",
63            Self::V2025_03_26 => "2025-03-26",
64            Self::V2025_06_18 => "2025-06-18",
65        }
66    }
67
68    /// Check if roots feature is available
69    pub fn supports_roots(&self) -> bool {
70        *self >= Self::V2025_03_26
71    }
72
73    /// Check if elicitation feature is available
74    pub fn supports_elicitation(&self) -> bool {
75        *self >= Self::V2025_06_18
76    }
77
78    /// Check if progress notifications are available
79    pub fn supports_progress(&self) -> bool {
80        *self >= Self::V2025_03_26
81    }
82
83    /// Check if enhanced structured output is available
84    pub fn supports_structured_output(&self) -> bool {
85        *self >= Self::V2025_06_18
86    }
87
88    /// Get all supported versions
89    pub fn all_versions() -> &'static [ProtocolVersion] {
90        &[Self::V2024_11_05, Self::V2025_03_26, Self::V2025_06_18]
91    }
92
93    /// Get the latest supported version
94    pub fn latest() -> Self {
95        Self::V2025_06_18
96    }
97}
98
99impl std::fmt::Display for ProtocolVersion {
100    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101        write!(f, "{}", self.as_str())
102    }
103}
104
105/// Protocol version negotiator
106#[derive(Debug, Clone)]
107pub struct VersionNegotiator {
108    /// Latest supported version
109    latest: ProtocolVersion,
110}
111
112impl VersionNegotiator {
113    /// Create a new version negotiator
114    pub fn new() -> Self {
115        Self {
116            latest: ProtocolVersion::latest(),
117        }
118    }
119
120    /// Create with a specific latest version (for testing)
121    pub fn with_latest(latest: ProtocolVersion) -> Self {
122        Self { latest }
123    }
124
125    /// Strictly negotiate version with client.
126    ///
127    /// If the requested version is supported, returns it.
128    /// Otherwise, returns `None` so inbound request paths can fail closed.
129    pub fn try_negotiate(&self, requested: &str) -> Option<ProtocolVersion> {
130        ProtocolVersion::from_str(requested).filter(|version| *version <= self.latest)
131    }
132
133    /// Compatibility negotiation with client.
134    ///
135    /// If the requested version is supported, returns it.
136    /// Otherwise, falls back to the least-capable version.
137    pub fn negotiate(&self, requested: &str) -> ProtocolVersion {
138        self.try_negotiate(requested).unwrap_or_default()
139    }
140
141    /// Get the latest supported version
142    pub fn latest(&self) -> ProtocolVersion {
143        self.latest
144    }
145}
146
147impl Default for VersionNegotiator {
148    fn default() -> Self {
149        Self::new()
150    }
151}
152
153// ============================================================================
154// Roots Support
155// ============================================================================
156
157/// Root definition - filesystem boundary for server operations
158#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
159pub struct Root {
160    /// File URI (e.g., "file:///home/user/project")
161    pub uri: String,
162    /// Optional display name
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub name: Option<String>,
165}
166
167impl Root {
168    /// Create a new root with just a URI
169    pub fn new(uri: impl Into<String>) -> Self {
170        Self {
171            uri: uri.into(),
172            name: None,
173        }
174    }
175
176    /// Create a new root with URI and name
177    pub fn with_name(uri: impl Into<String>, name: impl Into<String>) -> Self {
178        Self {
179            uri: uri.into(),
180            name: Some(name.into()),
181        }
182    }
183}
184
185/// Roots registry - manages filesystem root boundaries
186pub struct RootsRegistry {
187    /// Configured roots
188    roots: RwLock<Vec<Root>>,
189    /// Change notification sender
190    change_tx: broadcast::Sender<()>,
191}
192
193impl RootsRegistry {
194    /// Create a new roots registry
195    pub fn new() -> Self {
196        let (change_tx, _) = broadcast::channel(16);
197        Self {
198            roots: RwLock::new(Vec::new()),
199            change_tx,
200        }
201    }
202
203    /// Add a root
204    pub async fn add_root(&self, root: Root) {
205        self.roots.write().await.push(root);
206        let _ = self.change_tx.send(());
207    }
208
209    /// Remove a root by URI
210    pub async fn remove_root(&self, uri: &str) -> bool {
211        let mut roots = self.roots.write().await;
212        let len_before = roots.len();
213        roots.retain(|r| r.uri != uri);
214        let removed = roots.len() < len_before;
215        if removed {
216            let _ = self.change_tx.send(());
217        }
218        removed
219    }
220
221    /// List all roots
222    pub async fn list(&self) -> Vec<Root> {
223        self.roots.read().await.clone()
224    }
225
226    /// Check whether a URI is within a configured root boundary.
227    pub async fn allows_uri(&self, uri: &str) -> bool {
228        if !uri.starts_with("file://") {
229            return true;
230        }
231
232        let roots = self.roots.read().await;
233        if roots.is_empty() {
234            return false;
235        }
236
237        let Some(uri_path) = normalize_file_uri_path(uri) else {
238            return false;
239        };
240
241        roots.iter().any(|root| {
242            let Some(root_path) = normalize_file_uri_path(&root.uri) else {
243                return false;
244            };
245            is_path_within_root(&uri_path, &root_path)
246        })
247    }
248
249    /// Clear all roots
250    pub async fn clear(&self) {
251        let mut roots = self.roots.write().await;
252        if !roots.is_empty() {
253            roots.clear();
254            let _ = self.change_tx.send(());
255        }
256    }
257
258    /// Get the number of roots
259    pub async fn len(&self) -> usize {
260        self.roots.read().await.len()
261    }
262
263    /// Check if empty
264    pub async fn is_empty(&self) -> bool {
265        self.roots.read().await.is_empty()
266    }
267
268    /// Subscribe to change notifications
269    pub fn subscribe(&self) -> broadcast::Receiver<()> {
270        self.change_tx.subscribe()
271    }
272
273    /// Get the number of subscribers
274    pub fn subscriber_count(&self) -> usize {
275        self.change_tx.receiver_count()
276    }
277}
278
279fn normalize_file_uri_path(uri: &str) -> Option<String> {
280    let raw_path = uri.strip_prefix("file://")?;
281    if raw_path.is_empty() || raw_path.contains('%') || raw_path.contains('\\') {
282        return None;
283    }
284
285    let mut parts = Vec::new();
286    for part in raw_path.split('/') {
287        match part {
288            "" | "." => {}
289            ".." => {
290                parts.pop()?;
291            }
292            value => parts.push(value),
293        }
294    }
295
296    if parts.is_empty() {
297        Some("/".to_string())
298    } else {
299        Some(format!("/{}", parts.join("/")))
300    }
301}
302
303fn is_path_within_root(path: &str, root: &str) -> bool {
304    root == "/"
305        || path == root
306        || path
307            .strip_prefix(root)
308            .is_some_and(|suffix| suffix.starts_with('/'))
309}
310
311impl Default for RootsRegistry {
312    fn default() -> Self {
313        Self::new()
314    }
315}
316
317// ============================================================================
318// Elicitation Support
319// ============================================================================
320
321/// Elicitation request - server-initiated user input request
322#[derive(Debug, Clone, Serialize, Deserialize)]
323pub struct ElicitationRequest {
324    /// Message to display to user
325    pub message: String,
326    /// Optional JSON schema for structured input
327    #[serde(rename = "requestedSchema", skip_serializing_if = "Option::is_none")]
328    pub requested_schema: Option<ElicitationSchema>,
329}
330
331impl ElicitationRequest {
332    /// Create a simple elicitation request with just a message
333    pub fn new(message: impl Into<String>) -> Self {
334        Self {
335            message: message.into(),
336            requested_schema: None,
337        }
338    }
339
340    /// Create an elicitation request with a schema
341    pub fn with_schema(message: impl Into<String>, schema: ElicitationSchema) -> Self {
342        Self {
343            message: message.into(),
344            requested_schema: Some(schema),
345        }
346    }
347}
348
349/// Restricted JSON schema for elicitation (primitives only)
350#[derive(Debug, Clone, Serialize, Deserialize, Default)]
351pub struct ElicitationSchema {
352    /// Schema type (should be "object")
353    #[serde(rename = "type")]
354    pub schema_type: String,
355    /// Property definitions
356    #[serde(skip_serializing_if = "Option::is_none")]
357    pub properties: Option<HashMap<String, PropertySchema>>,
358    /// Required field names
359    #[serde(skip_serializing_if = "Option::is_none")]
360    pub required: Option<Vec<String>>,
361}
362
363impl ElicitationSchema {
364    /// Create a new object schema
365    pub fn object() -> Self {
366        Self {
367            schema_type: "object".to_string(),
368            properties: Some(HashMap::new()),
369            required: None,
370        }
371    }
372
373    /// Add a property to the schema
374    pub fn with_property(mut self, name: impl Into<String>, schema: PropertySchema) -> Self {
375        self.properties
376            .get_or_insert_with(HashMap::new)
377            .insert(name.into(), schema);
378        self
379    }
380
381    /// Add a required field
382    pub fn with_required(mut self, name: impl Into<String>) -> Self {
383        self.required.get_or_insert_with(Vec::new).push(name.into());
384        self
385    }
386}
387
388/// Property schema for elicitation (primitives only)
389#[derive(Debug, Clone, Serialize, Deserialize, Default)]
390pub struct PropertySchema {
391    /// Property type: string, number, boolean, or enum
392    #[serde(rename = "type")]
393    pub prop_type: String,
394    /// Description of the property
395    #[serde(skip_serializing_if = "Option::is_none")]
396    pub description: Option<String>,
397    /// Format hint (email, uri, date, date-time)
398    #[serde(skip_serializing_if = "Option::is_none")]
399    pub format: Option<String>,
400    /// Minimum value for numbers
401    #[serde(skip_serializing_if = "Option::is_none")]
402    pub minimum: Option<f64>,
403    /// Maximum value for numbers
404    #[serde(skip_serializing_if = "Option::is_none")]
405    pub maximum: Option<f64>,
406    /// Enum values for enum type
407    #[serde(rename = "enum", skip_serializing_if = "Option::is_none")]
408    pub enum_values: Option<Vec<String>>,
409}
410
411impl PropertySchema {
412    /// Create a string property
413    pub fn string() -> Self {
414        Self {
415            prop_type: "string".to_string(),
416            ..Default::default()
417        }
418    }
419
420    /// Create a number property
421    pub fn number() -> Self {
422        Self {
423            prop_type: "number".to_string(),
424            ..Default::default()
425        }
426    }
427
428    /// Create a boolean property
429    pub fn boolean() -> Self {
430        Self {
431            prop_type: "boolean".to_string(),
432            ..Default::default()
433        }
434    }
435
436    /// Create an enum property
437    pub fn enumeration(values: Vec<String>) -> Self {
438        Self {
439            prop_type: "string".to_string(),
440            enum_values: Some(values),
441            ..Default::default()
442        }
443    }
444
445    /// Add a description
446    pub fn with_description(mut self, desc: impl Into<String>) -> Self {
447        self.description = Some(desc.into());
448        self
449    }
450
451    /// Add a format hint
452    pub fn with_format(mut self, format: impl Into<String>) -> Self {
453        self.format = Some(format.into());
454        self
455    }
456
457    /// Add minimum value
458    pub fn with_minimum(mut self, min: f64) -> Self {
459        self.minimum = Some(min);
460        self
461    }
462
463    /// Add maximum value
464    pub fn with_maximum(mut self, max: f64) -> Self {
465        self.maximum = Some(max);
466        self
467    }
468}
469
470/// Elicitation response action
471#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
472#[serde(rename_all = "lowercase")]
473pub enum ElicitationAction {
474    /// User accepted and provided input
475    Accept,
476    /// User declined to provide input
477    Decline,
478    /// User cancelled the request
479    Cancel,
480}
481
482/// Elicitation response
483#[derive(Debug, Clone, Serialize, Deserialize)]
484pub struct ElicitationResponse {
485    /// The action taken by the user
486    pub action: ElicitationAction,
487    /// Content provided (only present when action is Accept)
488    #[serde(skip_serializing_if = "Option::is_none")]
489    pub content: Option<Value>,
490}
491
492impl ElicitationResponse {
493    /// Create an accept response with content
494    pub fn accept(content: Value) -> Self {
495        Self {
496            action: ElicitationAction::Accept,
497            content: Some(content),
498        }
499    }
500
501    /// Create a decline response
502    pub fn decline() -> Self {
503        Self {
504            action: ElicitationAction::Decline,
505            content: None,
506        }
507    }
508
509    /// Create a cancel response
510    pub fn cancel() -> Self {
511        Self {
512            action: ElicitationAction::Cancel,
513            content: None,
514        }
515    }
516}
517
518/// Elicitation errors
519#[derive(Debug, Clone, thiserror::Error)]
520pub enum ElicitationError {
521    #[error("elicitation cancelled")]
522    Cancelled,
523    #[error("elicitation timeout")]
524    Timeout,
525    #[error("validation failed: {0}")]
526    ValidationFailed(String),
527}
528
529/// Elicitation handler - manages server-initiated user input requests
530pub struct ElicitationHandler {
531    /// Pending elicitation requests
532    pending: RwLock<HashMap<String, oneshot::Sender<ElicitationResponse>>>,
533    /// Timeout duration in seconds
534    timeout_secs: u64,
535}
536
537impl ElicitationHandler {
538    /// Create a new elicitation handler with default timeout (300 seconds)
539    pub fn new() -> Self {
540        Self {
541            pending: RwLock::new(HashMap::new()),
542            timeout_secs: 300,
543        }
544    }
545
546    /// Create with custom timeout
547    pub fn with_timeout(timeout_secs: u64) -> Self {
548        Self {
549            pending: RwLock::new(HashMap::new()),
550            timeout_secs,
551        }
552    }
553
554    /// Create an elicitation request and wait for response
555    pub async fn create(
556        &self,
557        request: ElicitationRequest,
558    ) -> Result<ElicitationResponse, ElicitationError> {
559        let id = generate_elicitation_id();
560        let (tx, rx) = oneshot::channel();
561
562        self.pending.write().await.insert(id.clone(), tx);
563
564        // Wait for response with timeout
565        let result =
566            tokio::time::timeout(std::time::Duration::from_secs(self.timeout_secs), rx).await;
567
568        // Clean up pending request
569        self.pending.write().await.remove(&id);
570
571        match result {
572            Ok(Ok(response)) => {
573                // Validate response against schema if provided
574                if let (Some(schema), Some(content)) =
575                    (&request.requested_schema, &response.content)
576                {
577                    self.validate_response(schema, content)?;
578                }
579                Ok(response)
580            }
581            Ok(Err(_)) => Err(ElicitationError::Cancelled),
582            Err(_) => Err(ElicitationError::Timeout),
583        }
584    }
585
586    /// Respond to a pending elicitation request
587    pub async fn respond(&self, id: &str, response: ElicitationResponse) -> bool {
588        if let Some(tx) = self.pending.write().await.remove(id) {
589            tx.send(response).is_ok()
590        } else {
591            false
592        }
593    }
594
595    /// Validate response against schema
596    fn validate_response(
597        &self,
598        schema: &ElicitationSchema,
599        content: &Value,
600    ) -> Result<(), ElicitationError> {
601        // Validate required fields
602        if let Some(required) = &schema.required {
603            for field in required {
604                if content.get(field).is_none() {
605                    return Err(ElicitationError::ValidationFailed(format!(
606                        "missing required field: {}",
607                        field
608                    )));
609                }
610            }
611        }
612
613        // Validate property types
614        if let (Some(properties), Some(obj)) = (&schema.properties, content.as_object()) {
615            for (name, prop_schema) in properties {
616                if let Some(value) = obj.get(name) {
617                    self.validate_property_type(name, prop_schema, value)?;
618                }
619            }
620        }
621
622        Ok(())
623    }
624
625    /// Validate a single property value against its schema
626    fn validate_property_type(
627        &self,
628        name: &str,
629        schema: &PropertySchema,
630        value: &Value,
631    ) -> Result<(), ElicitationError> {
632        match schema.prop_type.as_str() {
633            "string" => {
634                if !value.is_string() {
635                    return Err(ElicitationError::ValidationFailed(format!(
636                        "field '{}' must be a string",
637                        name
638                    )));
639                }
640                // Check enum values if specified
641                if let (Some(enum_values), Some(s)) = (&schema.enum_values, value.as_str()) {
642                    if !enum_values.contains(&s.to_string()) {
643                        return Err(ElicitationError::ValidationFailed(format!(
644                            "field '{}' must be one of: {:?}",
645                            name, enum_values
646                        )));
647                    }
648                }
649            }
650            "number" => {
651                if let Some(n) = value.as_f64() {
652                    if let Some(min) = schema.minimum {
653                        if n < min {
654                            return Err(ElicitationError::ValidationFailed(format!(
655                                "field '{}' must be >= {}",
656                                name, min
657                            )));
658                        }
659                    }
660                    if let Some(max) = schema.maximum {
661                        if n > max {
662                            return Err(ElicitationError::ValidationFailed(format!(
663                                "field '{}' must be <= {}",
664                                name, max
665                            )));
666                        }
667                    }
668                } else {
669                    return Err(ElicitationError::ValidationFailed(format!(
670                        "field '{}' must be a number",
671                        name
672                    )));
673                }
674            }
675            "boolean" => {
676                if !value.is_boolean() {
677                    return Err(ElicitationError::ValidationFailed(format!(
678                        "field '{}' must be a boolean",
679                        name
680                    )));
681                }
682            }
683            _ => {}
684        }
685        Ok(())
686    }
687
688    /// Get the number of pending requests
689    pub async fn pending_count(&self) -> usize {
690        self.pending.read().await.len()
691    }
692}
693
694impl Default for ElicitationHandler {
695    fn default() -> Self {
696        Self::new()
697    }
698}
699
700// ============================================================================
701// Resource Templates
702// ============================================================================
703
704/// Resource template definition
705#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
706pub struct ResourceTemplate {
707    /// URI template with placeholders (e.g., "file:///{path}")
708    #[serde(rename = "uriTemplate")]
709    pub uri_template: String,
710    /// Display name
711    pub name: String,
712    /// Description
713    #[serde(skip_serializing_if = "Option::is_none")]
714    pub description: Option<String>,
715    /// MIME type
716    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
717    pub mime_type: Option<String>,
718}
719
720impl ResourceTemplate {
721    /// Create a new resource template
722    pub fn new(uri_template: impl Into<String>, name: impl Into<String>) -> Self {
723        Self {
724            uri_template: uri_template.into(),
725            name: name.into(),
726            description: None,
727            mime_type: None,
728        }
729    }
730
731    /// Add a description
732    pub fn with_description(mut self, desc: impl Into<String>) -> Self {
733        self.description = Some(desc.into());
734        self
735    }
736
737    /// Add a MIME type
738    pub fn with_mime_type(mut self, mime: impl Into<String>) -> Self {
739        self.mime_type = Some(mime.into());
740        self
741    }
742
743    /// Extract placeholder names from the template
744    pub fn placeholders(&self) -> Vec<String> {
745        let mut placeholders = Vec::new();
746        let mut chars = self.uri_template.chars().peekable();
747
748        while let Some(c) = chars.next() {
749            if c == '{' {
750                let mut name = String::new();
751                while let Some(&next) = chars.peek() {
752                    if next == '}' {
753                        chars.next();
754                        break;
755                    }
756                    name.push(chars.next().unwrap());
757                }
758                if !name.is_empty() {
759                    placeholders.push(name);
760                }
761            }
762        }
763
764        placeholders
765    }
766}
767
768/// Template parameter extracted from a URI
769#[derive(Debug, Clone, PartialEq, Eq)]
770pub struct TemplateParam {
771    /// Parameter name
772    pub name: String,
773    /// Parameter value
774    pub value: String,
775}
776
777/// Resource template registry
778pub struct ResourceTemplateRegistry {
779    /// Registered templates
780    templates: RwLock<Vec<ResourceTemplate>>,
781}
782
783impl ResourceTemplateRegistry {
784    /// Create a new template registry
785    pub fn new() -> Self {
786        Self {
787            templates: RwLock::new(Vec::new()),
788        }
789    }
790
791    /// Register a template
792    pub async fn register(&self, template: ResourceTemplate) {
793        self.templates.write().await.push(template);
794    }
795
796    /// Unregister a template by URI template
797    pub async fn unregister(&self, uri_template: &str) -> bool {
798        let mut templates = self.templates.write().await;
799        let len_before = templates.len();
800        templates.retain(|t| t.uri_template != uri_template);
801        templates.len() < len_before
802    }
803
804    /// List all templates
805    pub async fn list(&self) -> Vec<ResourceTemplate> {
806        self.templates.read().await.clone()
807    }
808
809    /// Match a URI to a template and extract parameters
810    pub async fn match_uri(&self, uri: &str) -> Option<(ResourceTemplate, Vec<TemplateParam>)> {
811        let templates = self.templates.read().await;
812        for template in templates.iter() {
813            if let Some(params) = Self::extract_params(uri, &template.uri_template) {
814                return Some((template.clone(), params));
815            }
816        }
817        None
818    }
819
820    /// Extract parameters from a URI using a template
821    fn extract_params(uri: &str, template: &str) -> Option<Vec<TemplateParam>> {
822        let mut params = Vec::new();
823        let mut uri_chars = uri.chars().peekable();
824        let mut template_chars = template.chars().peekable();
825
826        while let Some(tc) = template_chars.next() {
827            if tc == '{' {
828                // Extract placeholder name
829                let mut name = String::new();
830                while let Some(&next) = template_chars.peek() {
831                    if next == '}' {
832                        template_chars.next();
833                        break;
834                    }
835                    name.push(template_chars.next().unwrap());
836                }
837
838                // Find the next literal character in template (or end)
839                let next_literal = template_chars.peek().copied();
840
841                // Extract value from URI until we hit the next literal or end
842                let mut value = String::new();
843                while let Some(&uc) = uri_chars.peek() {
844                    if Some(uc) == next_literal {
845                        break;
846                    }
847                    value.push(uri_chars.next().unwrap());
848                }
849
850                if !name.is_empty() {
851                    params.push(TemplateParam { name, value });
852                }
853            } else {
854                // Literal character - must match
855                match uri_chars.next() {
856                    Some(uc) if uc == tc => continue,
857                    _ => return None,
858                }
859            }
860        }
861
862        // Both should be exhausted
863        if uri_chars.next().is_some() {
864            return None;
865        }
866
867        Some(params)
868    }
869
870    /// Get the number of registered templates
871    pub async fn len(&self) -> usize {
872        self.templates.read().await.len()
873    }
874
875    /// Check if empty
876    pub async fn is_empty(&self) -> bool {
877        self.templates.read().await.is_empty()
878    }
879}
880
881impl Default for ResourceTemplateRegistry {
882    fn default() -> Self {
883        Self::new()
884    }
885}
886
887// ============================================================================
888// Enhanced Structured Output
889// ============================================================================
890
891/// Content annotations for structured output
892#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
893pub struct Annotations {
894    /// Target audience roles
895    #[serde(skip_serializing_if = "Option::is_none")]
896    pub audience: Option<Vec<String>>,
897    /// Priority (0.0 to 1.0)
898    #[serde(skip_serializing_if = "Option::is_none")]
899    pub priority: Option<f64>,
900}
901
902impl Annotations {
903    /// Create empty annotations
904    pub fn new() -> Self {
905        Self::default()
906    }
907
908    /// Set audience
909    pub fn with_audience(mut self, audience: Vec<String>) -> Self {
910        self.audience = Some(audience);
911        self
912    }
913
914    /// Set priority
915    pub fn with_priority(mut self, priority: f64) -> Self {
916        self.priority = Some(priority.clamp(0.0, 1.0));
917        self
918    }
919}
920
921/// Content type for MCP messages
922#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
923#[serde(tag = "type")]
924pub enum Content {
925    /// Text content
926    #[serde(rename = "text")]
927    Text { text: String },
928    /// Image content (base64 encoded)
929    #[serde(rename = "image")]
930    Image {
931        data: String,
932        #[serde(rename = "mimeType")]
933        mime_type: String,
934    },
935    /// Resource reference
936    #[serde(rename = "resource")]
937    Resource { uri: String },
938}
939
940impl Content {
941    /// Create text content
942    pub fn text(text: impl Into<String>) -> Self {
943        Self::Text { text: text.into() }
944    }
945
946    /// Create image content
947    pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
948        Self::Image {
949            data: data.into(),
950            mime_type: mime_type.into(),
951        }
952    }
953
954    /// Create resource reference
955    pub fn resource(uri: impl Into<String>) -> Self {
956        Self::Resource { uri: uri.into() }
957    }
958}
959
960/// Content with optional annotations
961#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
962pub struct AnnotatedContent {
963    /// The content
964    #[serde(flatten)]
965    pub content: Content,
966    /// Optional annotations
967    #[serde(skip_serializing_if = "Option::is_none")]
968    pub annotations: Option<Annotations>,
969}
970
971impl AnnotatedContent {
972    /// Create annotated content
973    pub fn new(content: Content) -> Self {
974        Self {
975            content,
976            annotations: None,
977        }
978    }
979
980    /// Add annotations
981    pub fn with_annotations(mut self, annotations: Annotations) -> Self {
982        self.annotations = Some(annotations);
983        self
984    }
985}
986
987/// Enhanced tool result with isError support
988#[derive(Debug, Clone, Serialize, Deserialize)]
989pub struct EnhancedToolResult {
990    /// Content items
991    pub content: Vec<AnnotatedContent>,
992    /// Whether this is an error result
993    #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
994    pub is_error: Option<bool>,
995}
996
997impl EnhancedToolResult {
998    /// Create a success result
999    pub fn success(content: Vec<AnnotatedContent>) -> Self {
1000        Self {
1001            content,
1002            is_error: None,
1003        }
1004    }
1005
1006    /// Create an error result
1007    pub fn error(message: impl Into<String>) -> Self {
1008        Self {
1009            content: vec![AnnotatedContent {
1010                content: Content::text(message),
1011                annotations: Some(Annotations::new().with_priority(1.0)),
1012            }],
1013            is_error: Some(true),
1014        }
1015    }
1016
1017    /// Create from a single text content
1018    pub fn text(text: impl Into<String>) -> Self {
1019        Self::success(vec![AnnotatedContent::new(Content::text(text))])
1020    }
1021}
1022
1023// ============================================================================
1024// Notification Manager
1025// ============================================================================
1026
1027/// Progress notification
1028#[derive(Debug, Clone, Serialize, Deserialize)]
1029pub struct ProgressNotification {
1030    /// Progress token from request _meta
1031    #[serde(rename = "progressToken")]
1032    pub progress_token: String,
1033    /// Progress value (0.0 to 1.0)
1034    pub progress: f64,
1035    /// Optional total for absolute progress
1036    #[serde(skip_serializing_if = "Option::is_none")]
1037    pub total: Option<u64>,
1038}
1039
1040/// Cancellation notification
1041#[derive(Debug, Clone, Serialize, Deserialize)]
1042pub struct CancellationNotification {
1043    /// Request ID to cancel
1044    #[serde(rename = "requestId")]
1045    pub request_id: RequestId,
1046    /// Optional reason
1047    #[serde(skip_serializing_if = "Option::is_none")]
1048    pub reason: Option<String>,
1049}
1050
1051/// Notification types
1052#[derive(Debug, Clone, Serialize)]
1053#[serde(tag = "method", content = "params")]
1054pub enum Notification {
1055    /// Tools list changed
1056    #[serde(rename = "notifications/tools/list_changed")]
1057    ToolsListChanged,
1058    /// Resources list changed
1059    #[serde(rename = "notifications/resources/list_changed")]
1060    ResourcesListChanged,
1061    /// Prompts list changed
1062    #[serde(rename = "notifications/prompts/list_changed")]
1063    PromptsListChanged,
1064    /// Roots list changed
1065    #[serde(rename = "notifications/roots/list_changed")]
1066    RootsListChanged,
1067    /// Progress update
1068    #[serde(rename = "notifications/progress")]
1069    Progress(ProgressNotification),
1070    /// Request cancelled
1071    #[serde(rename = "notifications/cancelled")]
1072    Cancelled(CancellationNotification),
1073}
1074
1075impl Notification {
1076    /// Format notification as JSON-RPC message
1077    pub fn to_json_rpc(&self) -> String {
1078        let json = match self {
1079            Notification::ToolsListChanged => serde_json::json!({
1080                "jsonrpc": "2.0",
1081                "method": "notifications/tools/list_changed"
1082            }),
1083            Notification::ResourcesListChanged => serde_json::json!({
1084                "jsonrpc": "2.0",
1085                "method": "notifications/resources/list_changed"
1086            }),
1087            Notification::PromptsListChanged => serde_json::json!({
1088                "jsonrpc": "2.0",
1089                "method": "notifications/prompts/list_changed"
1090            }),
1091            Notification::RootsListChanged => serde_json::json!({
1092                "jsonrpc": "2.0",
1093                "method": "notifications/roots/list_changed"
1094            }),
1095            Notification::Progress(p) => serde_json::json!({
1096                "jsonrpc": "2.0",
1097                "method": "notifications/progress",
1098                "params": p
1099            }),
1100            Notification::Cancelled(c) => serde_json::json!({
1101                "jsonrpc": "2.0",
1102                "method": "notifications/cancelled",
1103                "params": c
1104            }),
1105        };
1106        serde_json::to_string(&json).unwrap_or_default()
1107    }
1108}
1109
1110/// Notification manager - centralized notification handling
1111pub struct NotificationManager {
1112    /// Broadcast channel for notifications
1113    tx: broadcast::Sender<Notification>,
1114}
1115
1116impl NotificationManager {
1117    /// Create a new notification manager
1118    pub fn new() -> Self {
1119        let (tx, _) = broadcast::channel(256);
1120        Self { tx }
1121    }
1122
1123    /// Send a notification
1124    pub fn notify(&self, notification: Notification) {
1125        let _ = self.tx.send(notification);
1126    }
1127
1128    /// Subscribe to notifications
1129    pub fn subscribe(&self) -> broadcast::Receiver<Notification> {
1130        self.tx.subscribe()
1131    }
1132
1133    /// Get the number of subscribers
1134    pub fn subscriber_count(&self) -> usize {
1135        self.tx.receiver_count()
1136    }
1137
1138    /// Notify tools list changed
1139    pub fn notify_tools_changed(&self) {
1140        self.notify(Notification::ToolsListChanged);
1141    }
1142
1143    /// Notify resources list changed
1144    pub fn notify_resources_changed(&self) {
1145        self.notify(Notification::ResourcesListChanged);
1146    }
1147
1148    /// Notify prompts list changed
1149    pub fn notify_prompts_changed(&self) {
1150        self.notify(Notification::PromptsListChanged);
1151    }
1152
1153    /// Notify roots list changed
1154    pub fn notify_roots_changed(&self) {
1155        self.notify(Notification::RootsListChanged);
1156    }
1157
1158    /// Send progress notification
1159    pub fn notify_progress(&self, token: impl Into<String>, progress: f64, total: Option<u64>) {
1160        self.notify(Notification::Progress(ProgressNotification {
1161            progress_token: token.into(),
1162            progress: progress.clamp(0.0, 1.0),
1163            total,
1164        }));
1165    }
1166
1167    /// Send cancellation notification
1168    pub fn notify_cancelled(&self, request_id: RequestId, reason: Option<String>) {
1169        self.notify(Notification::Cancelled(CancellationNotification {
1170            request_id,
1171            reason,
1172        }));
1173    }
1174}
1175
1176impl Default for NotificationManager {
1177    fn default() -> Self {
1178        Self::new()
1179    }
1180}
1181
1182// ============================================================================
1183// Resource Subscription Tracking
1184// ============================================================================
1185
1186/// Resource subscription tracker for unsubscribe support
1187pub struct SubscriptionTracker {
1188    /// Maximum subscribers retained for a single URI.
1189    max_subscribers_per_resource: usize,
1190    /// Active subscriptions: URI -> set of subscriber IDs
1191    subscriptions: RwLock<HashMap<String, Vec<String>>>,
1192}
1193
1194impl SubscriptionTracker {
1195    /// Default per-resource subscriber limit.
1196    pub const DEFAULT_MAX_SUBSCRIBERS_PER_RESOURCE: usize = 1024;
1197
1198    /// Create a new subscription tracker
1199    pub fn new() -> Self {
1200        Self::with_max_subscribers_per_resource(Self::DEFAULT_MAX_SUBSCRIBERS_PER_RESOURCE)
1201    }
1202
1203    /// Create a subscription tracker with an explicit per-resource subscriber limit.
1204    pub fn with_max_subscribers_per_resource(max_subscribers_per_resource: usize) -> Self {
1205        Self {
1206            max_subscribers_per_resource,
1207            subscriptions: RwLock::new(HashMap::new()),
1208        }
1209    }
1210
1211    /// Subscribe to a resource. Returns false when the per-resource limit is reached.
1212    pub async fn subscribe(&self, uri: &str, subscriber_id: &str) -> bool {
1213        let mut subs = self.subscriptions.write().await;
1214        let subscribers = subs.entry(uri.to_string()).or_insert_with(Vec::new);
1215
1216        if subscribers.iter().any(|id| id == subscriber_id) {
1217            return true;
1218        }
1219        if subscribers.len() >= self.max_subscribers_per_resource {
1220            return false;
1221        }
1222
1223        subscribers.push(subscriber_id.to_string());
1224        true
1225    }
1226
1227    /// Unsubscribe from a resource (idempotent)
1228    pub async fn unsubscribe(&self, uri: &str, subscriber_id: &str) -> bool {
1229        let mut subs = self.subscriptions.write().await;
1230        let should_remove;
1231        let removed;
1232
1233        if let Some(subscribers) = subs.get_mut(uri) {
1234            let len_before = subscribers.len();
1235            subscribers.retain(|id| id != subscriber_id);
1236            removed = subscribers.len() < len_before;
1237            should_remove = subscribers.is_empty();
1238        } else {
1239            // Return true even if not found (idempotent)
1240            return true;
1241        }
1242
1243        if should_remove {
1244            subs.remove(uri);
1245        }
1246        removed
1247    }
1248
1249    /// Check if a subscriber is subscribed to a resource
1250    pub async fn is_subscribed(&self, uri: &str, subscriber_id: &str) -> bool {
1251        let subs = self.subscriptions.read().await;
1252        subs.get(uri)
1253            .map(|subscribers| subscribers.iter().any(|id| id == subscriber_id))
1254            .unwrap_or(false)
1255    }
1256
1257    /// Get all subscribers for a resource
1258    pub async fn get_subscribers(&self, uri: &str) -> Vec<String> {
1259        let subs = self.subscriptions.read().await;
1260        subs.get(uri).cloned().unwrap_or_default()
1261    }
1262
1263    /// Get the number of subscriptions for a resource
1264    pub async fn subscription_count(&self, uri: &str) -> usize {
1265        let subs = self.subscriptions.read().await;
1266        subs.get(uri).map(|s| s.len()).unwrap_or(0)
1267    }
1268
1269    /// Clear all subscriptions
1270    pub async fn clear(&self) {
1271        self.subscriptions.write().await.clear();
1272    }
1273}
1274
1275impl Default for SubscriptionTracker {
1276    fn default() -> Self {
1277        Self::new()
1278    }
1279}
1280
1281// ============================================================================
1282// Cancellation Support
1283// ============================================================================
1284
1285/// Cancellation state for a request
1286#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1287pub enum CancellationState {
1288    /// Request is active
1289    Active,
1290    /// Request was cancelled
1291    Cancelled,
1292    /// Request completed before cancellation
1293    Completed,
1294}
1295
1296/// Cancellation token for tracking request cancellation
1297#[derive(Debug)]
1298pub struct CancellationToken {
1299    /// Request ID
1300    request_id: RequestId,
1301    /// Cancellation state
1302    state: std::sync::atomic::AtomicU8,
1303    /// Optional reason for cancellation
1304    reason: RwLock<Option<String>>,
1305}
1306
1307impl CancellationToken {
1308    /// Create a new cancellation token
1309    pub fn new(request_id: RequestId) -> Self {
1310        Self {
1311            request_id,
1312            state: std::sync::atomic::AtomicU8::new(0), // Active
1313            reason: RwLock::new(None),
1314        }
1315    }
1316
1317    /// Get the request ID
1318    pub fn request_id(&self) -> &RequestId {
1319        &self.request_id
1320    }
1321
1322    /// Check if cancelled
1323    pub fn is_cancelled(&self) -> bool {
1324        self.state.load(Ordering::SeqCst) == 1
1325    }
1326
1327    /// Check if completed
1328    pub fn is_completed(&self) -> bool {
1329        self.state.load(Ordering::SeqCst) == 2
1330    }
1331
1332    /// Get the current state
1333    pub fn state(&self) -> CancellationState {
1334        match self.state.load(Ordering::SeqCst) {
1335            1 => CancellationState::Cancelled,
1336            2 => CancellationState::Completed,
1337            _ => CancellationState::Active,
1338        }
1339    }
1340
1341    /// Cancel the request
1342    pub async fn cancel(&self, reason: Option<String>) -> bool {
1343        // Only cancel if still active
1344        let result = self.state.compare_exchange(
1345            0, // Active
1346            1, // Cancelled
1347            Ordering::SeqCst,
1348            Ordering::SeqCst,
1349        );
1350        if result.is_ok() {
1351            *self.reason.write().await = reason;
1352            true
1353        } else {
1354            false
1355        }
1356    }
1357
1358    /// Mark the request as completed
1359    pub fn complete(&self) -> bool {
1360        // Only complete if still active
1361        self.state
1362            .compare_exchange(
1363                0, // Active
1364                2, // Completed
1365                Ordering::SeqCst,
1366                Ordering::SeqCst,
1367            )
1368            .is_ok()
1369    }
1370
1371    /// Get the cancellation reason
1372    pub async fn reason(&self) -> Option<String> {
1373        self.reason.read().await.clone()
1374    }
1375}
1376
1377/// Cancellation manager - tracks cancellation state for requests
1378pub struct CancellationManager {
1379    /// Active tokens: request ID -> token
1380    tokens: RwLock<HashMap<String, Arc<CancellationToken>>>,
1381}
1382
1383impl CancellationManager {
1384    /// Create a new cancellation manager
1385    pub fn new() -> Self {
1386        Self {
1387            tokens: RwLock::new(HashMap::new()),
1388        }
1389    }
1390
1391    /// Create a cancellation token for a request
1392    pub async fn create_token(&self, request_id: RequestId) -> Arc<CancellationToken> {
1393        let token = Arc::new(CancellationToken::new(request_id.clone()));
1394        let key = Self::request_id_to_key(&request_id);
1395        self.tokens.write().await.insert(key, Arc::clone(&token));
1396        token
1397    }
1398
1399    /// Get a token by request ID
1400    pub async fn get_token(&self, request_id: &RequestId) -> Option<Arc<CancellationToken>> {
1401        let key = Self::request_id_to_key(request_id);
1402        self.tokens.read().await.get(&key).cloned()
1403    }
1404
1405    /// Cancel a request by ID
1406    pub async fn cancel(&self, request_id: &RequestId, reason: Option<String>) -> bool {
1407        if let Some(token) = self.get_token(request_id).await {
1408            token.cancel(reason).await
1409        } else {
1410            // Request not found - might have already completed
1411            false
1412        }
1413    }
1414
1415    /// Remove a token (called when request completes)
1416    pub async fn remove_token(&self, request_id: &RequestId) {
1417        let key = Self::request_id_to_key(request_id);
1418        self.tokens.write().await.remove(&key);
1419    }
1420
1421    /// Check if a request is cancelled
1422    pub async fn is_cancelled(&self, request_id: &RequestId) -> bool {
1423        if let Some(token) = self.get_token(request_id).await {
1424            token.is_cancelled()
1425        } else {
1426            false
1427        }
1428    }
1429
1430    /// Get the number of active tokens
1431    pub async fn active_count(&self) -> usize {
1432        self.tokens.read().await.len()
1433    }
1434
1435    fn request_id_to_key(request_id: &RequestId) -> String {
1436        match request_id {
1437            RequestId::Number(n) => format!("n:{}", n),
1438            RequestId::String(s) => format!("s:{}", s),
1439            RequestId::Null => "null".to_string(),
1440            RequestId::Missing => "missing".to_string(),
1441        }
1442    }
1443}
1444
1445impl Default for CancellationManager {
1446    fn default() -> Self {
1447        Self::new()
1448    }
1449}
1450
1451// ============================================================================
1452// Progress Tracking
1453// ============================================================================
1454
1455/// Progress state for a request
1456#[derive(Debug, Clone)]
1457pub struct ProgressState {
1458    /// Progress token
1459    pub token: String,
1460    /// Current progress (0.0 to 1.0)
1461    pub progress: f64,
1462    /// Optional total for absolute progress
1463    pub total: Option<u64>,
1464    /// Whether progress tracking is complete
1465    pub completed: bool,
1466}
1467
1468/// Progress tracker - tracks progress for requests with progressToken
1469pub struct ProgressTracker {
1470    /// Active progress states: token -> state
1471    states: RwLock<HashMap<String, ProgressState>>,
1472    /// Notification sender
1473    notification_tx: broadcast::Sender<ProgressNotification>,
1474}
1475
1476impl ProgressTracker {
1477    /// Create a new progress tracker
1478    pub fn new() -> Self {
1479        let (notification_tx, _) = broadcast::channel(256);
1480        Self {
1481            states: RwLock::new(HashMap::new()),
1482            notification_tx,
1483        }
1484    }
1485
1486    /// Start tracking progress for a token
1487    pub async fn start(&self, token: impl Into<String>, total: Option<u64>) {
1488        let token = token.into();
1489        self.states.write().await.insert(
1490            token.clone(),
1491            ProgressState {
1492                token,
1493                progress: 0.0,
1494                total,
1495                completed: false,
1496            },
1497        );
1498    }
1499
1500    /// Update progress for a token
1501    pub async fn update(&self, token: &str, progress: f64) -> bool {
1502        let mut states = self.states.write().await;
1503        if let Some(state) = states.get_mut(token) {
1504            if !state.completed {
1505                state.progress = progress.clamp(0.0, 1.0);
1506                let _ = self.notification_tx.send(ProgressNotification {
1507                    progress_token: token.to_string(),
1508                    progress: state.progress,
1509                    total: state.total,
1510                });
1511                return true;
1512            }
1513        }
1514        false
1515    }
1516
1517    /// Complete progress tracking for a token
1518    pub async fn complete(&self, token: &str) -> bool {
1519        let mut states = self.states.write().await;
1520        if let Some(state) = states.get_mut(token) {
1521            if !state.completed {
1522                state.progress = 1.0;
1523                state.completed = true;
1524                let _ = self.notification_tx.send(ProgressNotification {
1525                    progress_token: token.to_string(),
1526                    progress: 1.0,
1527                    total: state.total,
1528                });
1529                return true;
1530            }
1531        }
1532        false
1533    }
1534
1535    /// Get progress state for a token
1536    pub async fn get(&self, token: &str) -> Option<ProgressState> {
1537        self.states.read().await.get(token).cloned()
1538    }
1539
1540    /// Remove progress tracking for a token
1541    pub async fn remove(&self, token: &str) {
1542        self.states.write().await.remove(token);
1543    }
1544
1545    /// Subscribe to progress notifications
1546    pub fn subscribe(&self) -> broadcast::Receiver<ProgressNotification> {
1547        self.notification_tx.subscribe()
1548    }
1549
1550    /// Check if a token is being tracked
1551    pub async fn is_tracking(&self, token: &str) -> bool {
1552        self.states.read().await.contains_key(token)
1553    }
1554
1555    /// Get the number of active progress trackers
1556    pub async fn active_count(&self) -> usize {
1557        self.states.read().await.len()
1558    }
1559}
1560
1561impl Default for ProgressTracker {
1562    fn default() -> Self {
1563        Self::new()
1564    }
1565}
1566
1567// ============================================================================
1568// Extended MCP Adapter
1569// ============================================================================
1570
1571/// Configuration for ping timeout
1572#[derive(Debug, Clone)]
1573pub struct PingConfig {
1574    /// Timeout in seconds for ping response
1575    pub timeout_secs: u64,
1576}
1577
1578impl Default for PingConfig {
1579    fn default() -> Self {
1580        Self { timeout_secs: 30 }
1581    }
1582}
1583
1584/// Extended MCP adapter integrating all MCP 2025 features.
1585///
1586/// This adapter composes all the new feature handlers and routes methods
1587/// based on the negotiated protocol version.
1588pub struct ExtendedMcpAdapter {
1589    /// Protocol version negotiator
1590    version_negotiator: VersionNegotiator,
1591    /// Negotiated protocol version
1592    negotiated_version: RwLock<ProtocolVersion>,
1593    /// Roots registry
1594    roots: Arc<RootsRegistry>,
1595    /// Elicitation handler
1596    elicitation: Arc<ElicitationHandler>,
1597    /// Resource template registry
1598    resource_templates: Arc<ResourceTemplateRegistry>,
1599    /// Subscription tracker
1600    subscriptions: Arc<SubscriptionTracker>,
1601    /// Notification manager
1602    notifications: Arc<NotificationManager>,
1603    /// Cancellation manager
1604    cancellation: Arc<CancellationManager>,
1605    /// Progress tracker
1606    progress: Arc<ProgressTracker>,
1607    /// Ping configuration
1608    ping_config: PingConfig,
1609}
1610
1611impl ExtendedMcpAdapter {
1612    /// Create a new extended adapter with default configuration
1613    pub fn new() -> Self {
1614        Self {
1615            version_negotiator: VersionNegotiator::new(),
1616            negotiated_version: RwLock::new(ProtocolVersion::default()),
1617            roots: Arc::new(RootsRegistry::new()),
1618            elicitation: Arc::new(ElicitationHandler::new()),
1619            resource_templates: Arc::new(ResourceTemplateRegistry::new()),
1620            subscriptions: Arc::new(SubscriptionTracker::new()),
1621            notifications: Arc::new(NotificationManager::new()),
1622            cancellation: Arc::new(CancellationManager::new()),
1623            progress: Arc::new(ProgressTracker::new()),
1624            ping_config: PingConfig::default(),
1625        }
1626    }
1627
1628    /// Create with custom ping timeout
1629    pub fn with_ping_timeout(mut self, timeout_secs: u64) -> Self {
1630        self.ping_config.timeout_secs = timeout_secs;
1631        self
1632    }
1633
1634    /// Create with custom elicitation timeout
1635    pub fn with_elicitation_timeout(mut self, timeout_secs: u64) -> Self {
1636        self.elicitation = Arc::new(ElicitationHandler::with_timeout(timeout_secs));
1637        self
1638    }
1639
1640    // ========================================================================
1641    // Accessors
1642    // ========================================================================
1643
1644    /// Get the version negotiator
1645    pub fn version_negotiator(&self) -> &VersionNegotiator {
1646        &self.version_negotiator
1647    }
1648
1649    /// Get the negotiated protocol version
1650    pub async fn negotiated_version(&self) -> ProtocolVersion {
1651        *self.negotiated_version.read().await
1652    }
1653
1654    /// Set the negotiated protocol version
1655    pub async fn set_negotiated_version(&self, version: ProtocolVersion) {
1656        *self.negotiated_version.write().await = version;
1657    }
1658
1659    /// Get the roots registry
1660    pub fn roots(&self) -> Arc<RootsRegistry> {
1661        Arc::clone(&self.roots)
1662    }
1663
1664    /// Get the elicitation handler
1665    pub fn elicitation(&self) -> Arc<ElicitationHandler> {
1666        Arc::clone(&self.elicitation)
1667    }
1668
1669    /// Get the resource template registry
1670    pub fn resource_templates(&self) -> Arc<ResourceTemplateRegistry> {
1671        Arc::clone(&self.resource_templates)
1672    }
1673
1674    /// Get the subscription tracker
1675    pub fn subscriptions(&self) -> Arc<SubscriptionTracker> {
1676        Arc::clone(&self.subscriptions)
1677    }
1678
1679    /// Get the notification manager
1680    pub fn notifications(&self) -> Arc<NotificationManager> {
1681        Arc::clone(&self.notifications)
1682    }
1683
1684    /// Get the cancellation manager
1685    pub fn cancellation(&self) -> Arc<CancellationManager> {
1686        Arc::clone(&self.cancellation)
1687    }
1688
1689    /// Get the progress tracker
1690    pub fn progress(&self) -> Arc<ProgressTracker> {
1691        Arc::clone(&self.progress)
1692    }
1693
1694    /// Get the ping configuration
1695    pub fn ping_config(&self) -> &PingConfig {
1696        &self.ping_config
1697    }
1698
1699    // ========================================================================
1700    // Version Negotiation
1701    // ========================================================================
1702
1703    /// Negotiate protocol version from client request
1704    pub async fn negotiate_version(&self, requested: &str) -> ProtocolVersion {
1705        let version = self.version_negotiator.negotiate(requested);
1706        *self.negotiated_version.write().await = version;
1707        version
1708    }
1709
1710    /// Check if a feature is available in the negotiated version
1711    pub async fn supports_roots(&self) -> bool {
1712        self.negotiated_version.read().await.supports_roots()
1713    }
1714
1715    /// Check if elicitation is available
1716    pub async fn supports_elicitation(&self) -> bool {
1717        self.negotiated_version.read().await.supports_elicitation()
1718    }
1719
1720    /// Check if progress notifications are available
1721    pub async fn supports_progress(&self) -> bool {
1722        self.negotiated_version.read().await.supports_progress()
1723    }
1724
1725    /// Check if structured output is available
1726    pub async fn supports_structured_output(&self) -> bool {
1727        self.negotiated_version
1728            .read()
1729            .await
1730            .supports_structured_output()
1731    }
1732
1733    // ========================================================================
1734    // Capability Building
1735    // ========================================================================
1736
1737    /// Build capabilities object based on negotiated version
1738    pub async fn build_capabilities(&self) -> serde_json::Value {
1739        let version = *self.negotiated_version.read().await;
1740
1741        let mut capabilities = serde_json::json!({
1742            "tools": { "listChanged": true },
1743            "resources": { "subscribe": true, "listChanged": true },
1744            "prompts": { "listChanged": true },
1745            "logging": {}
1746        });
1747
1748        if version.supports_roots() {
1749            capabilities["roots"] = serde_json::json!({ "listChanged": true });
1750        }
1751
1752        if version.supports_elicitation() {
1753            capabilities["elicitation"] = serde_json::json!({});
1754        }
1755
1756        capabilities
1757    }
1758
1759    // ========================================================================
1760    // Request Handling Helpers
1761    // ========================================================================
1762
1763    /// Check if a method is available in the current version
1764    pub async fn is_method_available(&self, method: &str) -> bool {
1765        let version = *self.negotiated_version.read().await;
1766
1767        match method {
1768            "roots/list" => version.supports_roots(),
1769            "elicitation/create" => version.supports_elicitation(),
1770            // All other methods are available in all versions
1771            _ => true,
1772        }
1773    }
1774
1775    /// Create a cancellation token for a request
1776    pub async fn create_cancellation_token(&self, request_id: RequestId) -> Arc<CancellationToken> {
1777        self.cancellation.create_token(request_id).await
1778    }
1779
1780    /// Start progress tracking for a request
1781    pub async fn start_progress(&self, token: &str, total: Option<u64>) {
1782        self.progress.start(token, total).await;
1783    }
1784
1785    /// Update progress for a request
1786    pub async fn update_progress(&self, token: &str, progress: f64) -> bool {
1787        self.progress.update(token, progress).await
1788    }
1789
1790    /// Complete progress tracking for a request
1791    pub async fn complete_progress(&self, token: &str) -> bool {
1792        self.progress.complete(token).await
1793    }
1794
1795    // ========================================================================
1796    // Notification Helpers
1797    // ========================================================================
1798
1799    /// Notify that tools list has changed
1800    pub fn notify_tools_changed(&self) {
1801        self.notifications.notify_tools_changed();
1802    }
1803
1804    /// Notify that resources list has changed
1805    pub fn notify_resources_changed(&self) {
1806        self.notifications.notify_resources_changed();
1807    }
1808
1809    /// Notify that prompts list has changed
1810    pub fn notify_prompts_changed(&self) {
1811        self.notifications.notify_prompts_changed();
1812    }
1813
1814    /// Notify that roots list has changed
1815    pub fn notify_roots_changed(&self) {
1816        self.notifications.notify_roots_changed();
1817    }
1818
1819    /// Subscribe to all notifications
1820    pub fn subscribe_notifications(&self) -> broadcast::Receiver<Notification> {
1821        self.notifications.subscribe()
1822    }
1823}
1824
1825impl Default for ExtendedMcpAdapter {
1826    fn default() -> Self {
1827        Self::new()
1828    }
1829}
1830
1831// ============================================================================
1832// Tests
1833// ============================================================================
1834
1835#[cfg(test)]
1836mod tests {
1837    use super::*;
1838
1839    // Protocol Version Tests
1840
1841    #[test]
1842    fn test_protocol_version_parsing() {
1843        assert_eq!(
1844            ProtocolVersion::from_str("2024-11-05"),
1845            Some(ProtocolVersion::V2024_11_05)
1846        );
1847        assert_eq!(
1848            ProtocolVersion::from_str("2025-03-26"),
1849            Some(ProtocolVersion::V2025_03_26)
1850        );
1851        assert_eq!(
1852            ProtocolVersion::from_str("2025-06-18"),
1853            Some(ProtocolVersion::V2025_06_18)
1854        );
1855        assert_eq!(ProtocolVersion::from_str("invalid"), None);
1856    }
1857
1858    #[test]
1859    fn test_protocol_version_as_str() {
1860        assert_eq!(ProtocolVersion::V2024_11_05.as_str(), "2024-11-05");
1861        assert_eq!(ProtocolVersion::V2025_03_26.as_str(), "2025-03-26");
1862        assert_eq!(ProtocolVersion::V2025_06_18.as_str(), "2025-06-18");
1863    }
1864
1865    #[test]
1866    fn test_protocol_version_ordering() {
1867        assert!(ProtocolVersion::V2024_11_05 < ProtocolVersion::V2025_03_26);
1868        assert!(ProtocolVersion::V2025_03_26 < ProtocolVersion::V2025_06_18);
1869    }
1870
1871    #[test]
1872    fn test_protocol_version_features() {
1873        let v1 = ProtocolVersion::V2024_11_05;
1874        assert!(!v1.supports_roots());
1875        assert!(!v1.supports_elicitation());
1876        assert!(!v1.supports_progress());
1877
1878        let v2 = ProtocolVersion::V2025_03_26;
1879        assert!(v2.supports_roots());
1880        assert!(!v2.supports_elicitation());
1881        assert!(v2.supports_progress());
1882
1883        let v3 = ProtocolVersion::V2025_06_18;
1884        assert!(v3.supports_roots());
1885        assert!(v3.supports_elicitation());
1886        assert!(v3.supports_progress());
1887    }
1888
1889    #[test]
1890    fn test_version_negotiator() {
1891        let negotiator = VersionNegotiator::new();
1892
1893        // Supported versions return as-is
1894        assert_eq!(
1895            negotiator.negotiate("2024-11-05"),
1896            ProtocolVersion::V2024_11_05
1897        );
1898        assert_eq!(
1899            negotiator.negotiate("2025-03-26"),
1900            ProtocolVersion::V2025_03_26
1901        );
1902        assert_eq!(
1903            negotiator.negotiate("2025-06-18"),
1904            ProtocolVersion::V2025_06_18
1905        );
1906
1907        // Unsupported versions fall back to the least-capable version
1908        assert_eq!(
1909            negotiator.negotiate("invalid"),
1910            ProtocolVersion::V2024_11_05
1911        );
1912        assert_eq!(
1913            negotiator.negotiate("2099-01-01"),
1914            ProtocolVersion::V2024_11_05
1915        );
1916    }
1917
1918    // Roots Tests
1919
1920    #[tokio::test]
1921    async fn test_roots_registry() {
1922        let registry = RootsRegistry::new();
1923
1924        assert!(registry.is_empty().await);
1925
1926        registry.add_root(Root::new("file:///home/user")).await;
1927        assert_eq!(registry.len().await, 1);
1928
1929        registry
1930            .add_root(Root::with_name("file:///project", "Project"))
1931            .await;
1932        assert_eq!(registry.len().await, 2);
1933
1934        let roots = registry.list().await;
1935        assert_eq!(roots.len(), 2);
1936        assert_eq!(roots[0].uri, "file:///home/user");
1937        assert_eq!(roots[1].name, Some("Project".to_string()));
1938    }
1939
1940    #[tokio::test]
1941    async fn test_roots_remove() {
1942        let registry = RootsRegistry::new();
1943        registry.add_root(Root::new("file:///a")).await;
1944        registry.add_root(Root::new("file:///b")).await;
1945
1946        assert!(registry.remove_root("file:///a").await);
1947        assert_eq!(registry.len().await, 1);
1948
1949        // Removing non-existent returns false
1950        assert!(!registry.remove_root("file:///nonexistent").await);
1951    }
1952
1953    // Elicitation Tests
1954
1955    #[test]
1956    fn test_elicitation_schema() {
1957        let schema = ElicitationSchema::object()
1958            .with_property(
1959                "name",
1960                PropertySchema::string().with_description("User name"),
1961            )
1962            .with_property(
1963                "age",
1964                PropertySchema::number()
1965                    .with_minimum(0.0)
1966                    .with_maximum(150.0),
1967            )
1968            .with_required("name");
1969
1970        assert_eq!(schema.schema_type, "object");
1971        assert!(schema.properties.as_ref().unwrap().contains_key("name"));
1972        assert!(schema
1973            .required
1974            .as_ref()
1975            .unwrap()
1976            .contains(&"name".to_string()));
1977    }
1978
1979    #[test]
1980    fn test_elicitation_response() {
1981        let accept = ElicitationResponse::accept(serde_json::json!({"name": "test"}));
1982        assert_eq!(accept.action, ElicitationAction::Accept);
1983        assert!(accept.content.is_some());
1984
1985        let decline = ElicitationResponse::decline();
1986        assert_eq!(decline.action, ElicitationAction::Decline);
1987        assert!(decline.content.is_none());
1988
1989        let cancel = ElicitationResponse::cancel();
1990        assert_eq!(cancel.action, ElicitationAction::Cancel);
1991    }
1992
1993    // Resource Template Tests
1994
1995    #[test]
1996    fn test_resource_template_placeholders() {
1997        let template = ResourceTemplate::new("file:///{path}", "File");
1998        assert_eq!(template.placeholders(), vec!["path"]);
1999
2000        let template2 = ResourceTemplate::new("db:///{table}/{id}", "Database");
2001        assert_eq!(template2.placeholders(), vec!["table", "id"]);
2002    }
2003
2004    #[tokio::test]
2005    async fn test_resource_template_matching() {
2006        let registry = ResourceTemplateRegistry::new();
2007        registry
2008            .register(ResourceTemplate::new("file:///{path}", "File"))
2009            .await;
2010
2011        let result = registry.match_uri("file:///test.txt").await;
2012        assert!(result.is_some());
2013
2014        let (template, params) = result.unwrap();
2015        assert_eq!(template.name, "File");
2016        assert_eq!(params.len(), 1);
2017        assert_eq!(params[0].name, "path");
2018        assert_eq!(params[0].value, "test.txt");
2019    }
2020
2021    #[test]
2022    fn test_extract_params() {
2023        let params = ResourceTemplateRegistry::extract_params("file:///test.txt", "file:///{path}");
2024        assert!(params.is_some());
2025        let params = params.unwrap();
2026        assert_eq!(params.len(), 1);
2027        assert_eq!(params[0].value, "test.txt");
2028
2029        // Non-matching
2030        let params =
2031            ResourceTemplateRegistry::extract_params("http://example.com", "file:///{path}");
2032        assert!(params.is_none());
2033    }
2034
2035    // Annotation Tests
2036
2037    #[test]
2038    fn test_annotations() {
2039        let ann = Annotations::new()
2040            .with_audience(vec!["user".to_string(), "admin".to_string()])
2041            .with_priority(0.8);
2042
2043        assert_eq!(
2044            ann.audience,
2045            Some(vec!["user".to_string(), "admin".to_string()])
2046        );
2047        assert_eq!(ann.priority, Some(0.8));
2048    }
2049
2050    #[test]
2051    fn test_annotations_priority_clamping() {
2052        let ann = Annotations::new().with_priority(1.5);
2053        assert_eq!(ann.priority, Some(1.0));
2054
2055        let ann = Annotations::new().with_priority(-0.5);
2056        assert_eq!(ann.priority, Some(0.0));
2057    }
2058
2059    #[test]
2060    fn test_enhanced_tool_result() {
2061        let success = EnhancedToolResult::text("Hello");
2062        assert!(success.is_error.is_none());
2063
2064        let error = EnhancedToolResult::error("Something went wrong");
2065        assert_eq!(error.is_error, Some(true));
2066    }
2067
2068    // Notification Tests
2069
2070    #[test]
2071    fn test_notification_json_rpc() {
2072        let notif = Notification::ToolsListChanged;
2073        let json = notif.to_json_rpc();
2074        assert!(json.contains("notifications/tools/list_changed"));
2075
2076        let progress = Notification::Progress(ProgressNotification {
2077            progress_token: "token-1".to_string(),
2078            progress: 0.5,
2079            total: Some(100),
2080        });
2081        let json = progress.to_json_rpc();
2082        assert!(json.contains("notifications/progress"));
2083        assert!(json.contains("token-1"));
2084    }
2085
2086    // Subscription Tracker Tests
2087
2088    #[tokio::test]
2089    async fn test_subscription_tracker() {
2090        let tracker = SubscriptionTracker::new();
2091
2092        tracker.subscribe("file:///test.txt", "client-1").await;
2093        assert!(tracker.is_subscribed("file:///test.txt", "client-1").await);
2094        assert!(!tracker.is_subscribed("file:///test.txt", "client-2").await);
2095
2096        tracker.subscribe("file:///test.txt", "client-2").await;
2097        assert_eq!(tracker.subscription_count("file:///test.txt").await, 2);
2098
2099        // Unsubscribe
2100        assert!(tracker.unsubscribe("file:///test.txt", "client-1").await);
2101        assert!(!tracker.is_subscribed("file:///test.txt", "client-1").await);
2102        assert_eq!(tracker.subscription_count("file:///test.txt").await, 1);
2103    }
2104
2105    #[tokio::test]
2106    async fn test_subscription_tracker_idempotent() {
2107        let tracker = SubscriptionTracker::new();
2108
2109        // Unsubscribing from non-existent subscription returns true (idempotent)
2110        assert!(tracker.unsubscribe("file:///nonexistent", "client-1").await);
2111    }
2112}