turbomcp_protocol/context/
server_initiated.rs

1//! Server-initiated communication context types.
2//!
3//! This module contains types for handling bidirectional communication where
4//! the server initiates requests to clients, including sampling, elicitation,
5//! and other server-to-client operations.
6
7use std::collections::HashMap;
8
9use serde::{Deserialize, Serialize};
10use uuid::Uuid;
11
12use super::capabilities::{CommunicationDirection, CommunicationInitiator, ServerInitiatedType};
13use super::client::ClientCapabilities;
14use crate::types::Timestamp;
15
16/// Enhanced context for bidirectional MCP communication
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct BidirectionalContext {
19    /// Communication direction
20    pub direction: CommunicationDirection,
21    /// Initiator of the request
22    pub initiator: CommunicationInitiator,
23    /// Whether response is expected
24    pub expects_response: bool,
25    /// Parent request ID (for server-initiated requests in response to client requests)
26    pub parent_request_id: Option<String>,
27    /// Request type for validation
28    pub request_type: Option<String>,
29    /// Server ID for server-initiated requests
30    pub server_id: Option<String>,
31    /// Correlation ID for request tracking
32    pub correlation_id: String,
33    /// Bidirectional communication metadata
34    pub metadata: HashMap<String, serde_json::Value>,
35}
36
37/// Context for server-initiated requests (sampling, roots listing)
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct ServerInitiatedContext {
40    /// Type of server-initiated request
41    pub request_type: ServerInitiatedType,
42    /// Originating server ID
43    pub server_id: String,
44    /// Request correlation ID
45    pub correlation_id: String,
46    /// Client capabilities
47    pub client_capabilities: Option<ClientCapabilities>,
48    /// Request timestamp
49    pub initiated_at: Timestamp,
50    /// Request metadata
51    pub metadata: HashMap<String, serde_json::Value>,
52}
53
54impl BidirectionalContext {
55    /// Create a new bidirectional context
56    pub fn new(direction: CommunicationDirection, initiator: CommunicationInitiator) -> Self {
57        Self {
58            direction,
59            initiator,
60            expects_response: true,
61            parent_request_id: None,
62            request_type: None,
63            server_id: None,
64            correlation_id: Uuid::new_v4().to_string(),
65            metadata: HashMap::new(),
66        }
67    }
68
69    /// Track request direction for proper routing
70    pub fn with_direction(mut self, direction: CommunicationDirection) -> Self {
71        self.direction = direction;
72        self
73    }
74
75    /// Set the request type
76    pub fn with_request_type(mut self, request_type: String) -> Self {
77        self.request_type = Some(request_type);
78        self
79    }
80
81    /// Validate request direction against protocol rules
82    pub fn validate_direction(&self) -> Result<(), String> {
83        match (&self.direction, &self.initiator) {
84            (CommunicationDirection::ClientToServer, CommunicationInitiator::Client) => Ok(()),
85            (CommunicationDirection::ServerToClient, CommunicationInitiator::Server) => Ok(()),
86            _ => Err("Invalid direction/initiator combination".to_string()),
87        }
88    }
89}
90
91impl ServerInitiatedContext {
92    /// Create a new server-initiated context
93    pub fn new(request_type: ServerInitiatedType, server_id: String) -> Self {
94        Self {
95            request_type,
96            server_id,
97            correlation_id: Uuid::new_v4().to_string(),
98            client_capabilities: None,
99            initiated_at: Timestamp::now(),
100            metadata: HashMap::new(),
101        }
102    }
103
104    /// Set client capabilities
105    pub fn with_capabilities(mut self, capabilities: ClientCapabilities) -> Self {
106        self.client_capabilities = Some(capabilities);
107        self
108    }
109
110    /// Add metadata
111    pub fn with_metadata(mut self, key: String, value: serde_json::Value) -> Self {
112        self.metadata.insert(key, value);
113        self
114    }
115}