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    ///         _meta: None,
83    ///     };
84    ///
85    ///     let ctx = RequestContext::new();
86    ///     # #[allow(unused)]
87    ///     let result = capabilities.create_message(request, ctx).await;
88    /// }
89    /// ```
90    fn create_message(
91        &self,
92        request: CreateMessageRequest,
93        ctx: RequestContext,
94    ) -> BoxFuture<'_, Result<CreateMessageResult, Error>>;
95
96    /// Send an elicitation request to the client for user input
97    ///
98    /// This method allows server tools to request structured input from users through
99    /// the client's UI. The client is responsible for presenting the elicitation prompt
100    /// and collecting the user's response according to the requested schema.
101    ///
102    /// # Arguments
103    ///
104    /// * `request` - The elicitation request with prompt and optional schema
105    /// * `ctx` - Request context for tracing, user attribution, and metadata propagation
106    ///
107    /// # Errors
108    ///
109    /// Returns an error if:
110    /// - The client does not support elicitation
111    /// - The transport layer fails
112    /// - The user declines or cancels the request
113    /// - The client returns an error response
114    fn elicit(
115        &self,
116        request: ElicitRequest,
117        ctx: RequestContext,
118    ) -> BoxFuture<'_, Result<ElicitResult, Error>>;
119
120    /// List client's root capabilities
121    ///
122    /// This method allows servers to discover which directories or files the client
123    /// has granted access to. Roots define the filesystem boundaries for resource access.
124    ///
125    /// # Arguments
126    ///
127    /// * `ctx` - Request context for tracing, user attribution, and metadata propagation
128    ///
129    /// # Errors
130    ///
131    /// Returns an error if:
132    /// - The client does not support roots
133    /// - The transport layer fails
134    /// - The client returns an error response
135    fn list_roots(&self, ctx: RequestContext) -> BoxFuture<'_, Result<ListRootsResult, Error>>;
136}
137
138/// Communication direction for bidirectional requests
139#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
140pub enum CommunicationDirection {
141    /// Client to server
142    ClientToServer,
143    /// Server to client
144    ServerToClient,
145}
146
147/// Communication initiator for tracking request origins
148#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
149pub enum CommunicationInitiator {
150    /// Client initiated the request
151    Client,
152    /// Server initiated the request
153    Server,
154}
155
156/// Types of server-initiated requests
157#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
158pub enum ServerInitiatedType {
159    /// Sampling/message creation request
160    Sampling,
161    /// Elicitation request for user input
162    Elicitation,
163    /// Roots listing request
164    Roots,
165    /// Ping/health check request
166    Ping,
167}
168
169/// Origin of a ping request
170#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
171pub enum PingOrigin {
172    /// Client initiated ping
173    Client,
174    /// Server initiated ping
175    Server,
176}