turbomcp_protocol/context/
capabilities.rs

1//! Server-to-client communication capabilities for bidirectional MCP communication.
2//!
3//! This module defines the trait that enables servers to make requests to clients,
4//! supporting sampling, elicitation, and roots listing operations.
5
6use futures::future::BoxFuture;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10use crate::context::RequestContext;
11use crate::error::Error;
12use crate::types::{
13    CreateMessageRequest, CreateMessageResult, ElicitRequest, ElicitResult, ListRootsResult,
14};
15
16/// Trait for server-to-client requests (sampling, elicitation, roots)
17///
18/// This trait provides a type-safe interface for servers to make requests to clients,
19/// enabling bidirectional MCP communication patterns. All methods accept a `RequestContext`
20/// parameter to enable proper context propagation for tracing, attribution, and auditing.
21///
22/// ## Design Rationale
23///
24/// This trait uses typed request/response structures instead of `serde_json::Value` to provide:
25/// - **Type safety**: Compile-time validation of request/response structures
26/// - **Performance**: Zero-cost abstraction with no intermediate serialization
27/// - **Context propagation**: Full support for distributed tracing and user attribution
28/// - **Better errors**: Structured error types instead of generic `Box<dyn Error>`
29///
30/// ## Breaking Change (v2.0.0)
31///
32/// This trait was renamed from `ServerCapabilities` to `ServerToClientRequests` and redesigned
33/// to fix fundamental architecture issues:
34/// - Old: `fn create_message(&self, request: serde_json::Value) -> Result<serde_json::Value, Box<dyn Error>>`
35/// - New: `fn create_message(&self, request: CreateMessageRequest, ctx: RequestContext) -> Result<CreateMessageResult, ServerError>`
36pub trait ServerToClientRequests: Send + Sync + fmt::Debug {
37    /// Send a sampling/createMessage request to the client
38    ///
39    /// This method allows server tools to request LLM sampling from the client.
40    /// The client is responsible for:
41    /// - Selecting an appropriate model based on preferences
42    /// - Making the LLM API call
43    /// - Returning the generated response
44    ///
45    /// # Arguments
46    ///
47    /// * `request` - The sampling request with messages, model preferences, and parameters
48    /// * `ctx` - Request context for tracing, user attribution, and metadata propagation
49    ///
50    /// # Errors
51    ///
52    /// Returns an error if:
53    /// - The client does not support sampling
54    /// - The transport layer fails
55    /// - The client returns an error response
56    /// - The LLM request fails
57    ///
58    /// # Example
59    ///
60    /// ```no_run
61    /// use turbomcp_protocol::context::capabilities::ServerToClientRequests;
62    /// use turbomcp_protocol::RequestContext;
63    /// # use turbomcp_protocol::types::{CreateMessageRequest, SamplingMessage, Role, Content, TextContent};
64    ///
65    /// async fn example(capabilities: &dyn ServerToClientRequests) {
66    ///     let request = CreateMessageRequest {
67    ///         messages: vec![SamplingMessage {
68    ///             role: Role::User,
69    ///             content: Content::Text(TextContent {
70    ///                 text: "What is 2+2?".to_string(),
71    ///                 annotations: None,
72    ///                 meta: None,
73    ///             }),
74    ///             metadata: None,
75    ///         }],
76    ///         model_preferences: None,
77    ///         system_prompt: None,
78    ///         include_context: None,
79    ///         temperature: None,
80    ///         max_tokens: 100,
81    ///         stop_sequences: None,
82    ///         task: None,
83    ///         _meta: None,
84    ///     };
85    ///
86    ///     let ctx = RequestContext::new();
87    ///     # #[allow(unused)]
88    ///     let result = capabilities.create_message(request, ctx).await;
89    /// }
90    /// ```
91    fn create_message(
92        &self,
93        request: CreateMessageRequest,
94        ctx: RequestContext,
95    ) -> BoxFuture<'_, Result<CreateMessageResult, Error>>;
96
97    /// Send an elicitation request to the client for user input
98    ///
99    /// This method allows server tools to request structured input from users through
100    /// the client's UI. The client is responsible for presenting the elicitation prompt
101    /// and collecting the user's response according to the requested schema.
102    ///
103    /// # Arguments
104    ///
105    /// * `request` - The elicitation request with prompt and optional schema
106    /// * `ctx` - Request context for tracing, user attribution, and metadata propagation
107    ///
108    /// # Errors
109    ///
110    /// Returns an error if:
111    /// - The client does not support elicitation
112    /// - The transport layer fails
113    /// - The user declines or cancels the request
114    /// - The client returns an error response
115    fn elicit(
116        &self,
117        request: ElicitRequest,
118        ctx: RequestContext,
119    ) -> BoxFuture<'_, Result<ElicitResult, Error>>;
120
121    /// List client's root capabilities
122    ///
123    /// This method allows servers to discover which directories or files the client
124    /// has granted access to. Roots define the filesystem boundaries for resource access.
125    ///
126    /// # Arguments
127    ///
128    /// * `ctx` - Request context for tracing, user attribution, and metadata propagation
129    ///
130    /// # Errors
131    ///
132    /// Returns an error if:
133    /// - The client does not support roots
134    /// - The transport layer fails
135    /// - The client returns an error response
136    fn list_roots(&self, ctx: RequestContext) -> BoxFuture<'_, Result<ListRootsResult, Error>>;
137}
138
139/// Communication direction for bidirectional requests
140#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
141pub enum CommunicationDirection {
142    /// Client to server
143    ClientToServer,
144    /// Server to client
145    ServerToClient,
146}
147
148/// Communication initiator for tracking request origins
149#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
150pub enum CommunicationInitiator {
151    /// Client initiated the request
152    Client,
153    /// Server initiated the request
154    Server,
155}
156
157/// Types of server-initiated requests
158#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
159pub enum ServerInitiatedType {
160    /// Sampling/message creation request
161    Sampling,
162    /// Elicitation request for user input
163    Elicitation,
164    /// Roots listing request
165    Roots,
166    /// Ping/health check request
167    Ping,
168}
169
170/// Origin of a ping request
171#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
172pub enum PingOrigin {
173    /// Client initiated ping
174    Client,
175    /// Server initiated ping
176    Server,
177}