Skip to main content

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