rust_mcp_actix/
options.rs1use rust_mcp_sdk::auth::AuthProvider;
2use rust_mcp_sdk::event_store::EventStore;
3use rust_mcp_sdk::id_generator::IdGenerator;
4use rust_mcp_sdk::mcp_http::DnsRebindingOptions;
5use rust_mcp_sdk::mcp_http::HealthHandler;
6use rust_mcp_sdk::mcp_http::McpMountOptions;
7use rust_mcp_sdk::mcp_http::{
8 DEFAULT_MAX_REQUEST_BODY_SIZE, DEFAULT_MESSAGES_ENDPOINT, DEFAULT_SSE_ENDPOINT,
9 DEFAULT_STREAMABLE_HTTP_ENDPOINT,
10};
11use rust_mcp_sdk::schema::schema_utils::{ClientMessage, ServerMessage};
12use rust_mcp_sdk::session_store::SessionStore;
13use rust_mcp_sdk::task_store::{ClientTaskStore, ServerTaskStore};
14use rust_mcp_sdk::McpObserver;
15use rust_mcp_sdk::SessionId;
16use rust_mcp_sdk::TransportOptions;
17use std::net::{SocketAddr, ToSocketAddrs};
18use std::sync::Arc;
19use std::time::Duration;
20
21const DEFAULT_CLIENT_PING_INTERVAL: Duration = Duration::from_secs(12);
22
23pub struct ActixServerOptions {
28 pub host: String,
30 pub port: u16,
32 pub session_id_generator: Option<Arc<dyn IdGenerator<SessionId>>>,
34 pub custom_streamable_http_endpoint: Option<String>,
36 pub transport_options: Arc<TransportOptions>,
38 pub event_store: Option<Arc<dyn EventStore>>,
40 pub task_store: Option<Arc<ServerTaskStore>>,
42 pub client_task_store: Option<Arc<ClientTaskStore>>,
44 pub enable_json_response: Option<bool>,
46 pub ping_interval: Duration,
48 pub sse_support: bool,
50 pub custom_sse_endpoint: Option<String>,
52 pub custom_messages_endpoint: Option<String>,
54 pub auth: Option<Arc<dyn AuthProvider>>,
56 pub health_endpoint: Option<String>,
58 pub health_handler: Option<Arc<dyn HealthHandler>>,
60 pub message_observer: Option<Arc<dyn McpObserver<ClientMessage, ServerMessage>>>,
62 pub max_request_body_size: Option<usize>,
64 pub dns_rebinding: DnsRebindingOptions,
70 pub session_store: Option<Arc<dyn SessionStore>>,
75 pub enable_ssl: bool,
77 pub ssl_cert_path: Option<String>,
79 pub ssl_key_path: Option<String>,
81}
82
83impl ActixServerOptions {
84 pub fn validate(&self) -> Result<(), String> {
86 if self.host.is_empty() {
87 return Err("host must not be empty".into());
88 }
89 if self.enable_ssl && (self.ssl_cert_path.is_none() || self.ssl_key_path.is_none()) {
90 return Err(
91 "Both 'ssl_cert_path' and 'ssl_key_path' must be provided when SSL is enabled."
92 .into(),
93 );
94 }
95 Ok(())
96 }
97
98 pub fn resolve_server_address(&self) -> Result<SocketAddr, String> {
100 self.validate()?;
101
102 let host = self
103 .host
104 .strip_prefix("http://")
105 .or_else(|| self.host.strip_prefix("https://"))
106 .unwrap_or(&self.host)
107 .to_string();
108
109 let mut iter = (host.as_str(), self.port)
110 .to_socket_addrs()
111 .map_err(|e| format!("Failed to resolve address: {}", e))?;
112
113 iter.next()
114 .ok_or_else(|| format!("Could not resolve: {}:{}", self.host, self.port))
115 }
116
117 pub fn base_url(&self) -> String {
118 format!(
119 "{}://{}:{}",
120 if self.enable_ssl { "https" } else { "http" },
121 self.host,
122 self.port
123 )
124 }
125
126 pub fn streamable_http_url(&self) -> String {
127 format!("{}{}", self.base_url(), self.streamable_http_endpoint())
128 }
129
130 pub fn sse_url(&self) -> String {
131 format!("{}{}", self.base_url(), self.sse_endpoint())
132 }
133
134 pub fn sse_message_url(&self) -> String {
135 format!("{}{}", self.base_url(), self.sse_messages_endpoint())
136 }
137
138 pub fn sse_endpoint(&self) -> &str {
139 self.custom_sse_endpoint
140 .as_deref()
141 .unwrap_or(DEFAULT_SSE_ENDPOINT)
142 }
143
144 pub fn sse_messages_endpoint(&self) -> &str {
145 self.custom_messages_endpoint
146 .as_deref()
147 .unwrap_or(DEFAULT_MESSAGES_ENDPOINT)
148 }
149
150 pub fn streamable_http_endpoint(&self) -> &str {
151 self.custom_streamable_http_endpoint
152 .as_deref()
153 .unwrap_or(DEFAULT_STREAMABLE_HTTP_ENDPOINT)
154 }
155
156 pub fn max_request_body_size(&self) -> usize {
159 self.max_request_body_size
160 .unwrap_or(DEFAULT_MAX_REQUEST_BODY_SIZE)
161 }
162
163 pub fn resolve_mount_options(&self) -> McpMountOptions {
165 McpMountOptions {
166 streamable_http_endpoint: self.streamable_http_endpoint().to_string(),
167 sse_endpoint: self.sse_endpoint().to_string(),
168 sse_messages_endpoint: self.sse_messages_endpoint().to_string(),
169 health_endpoint: self.health_endpoint.clone(),
170 max_request_body_size: self.max_request_body_size(),
171 }
172 }
173}
174
175impl Default for ActixServerOptions {
176 fn default() -> Self {
177 Self {
178 host: "127.0.0.1".into(),
179 port: 8080,
180 session_id_generator: None,
181 custom_streamable_http_endpoint: None,
182 transport_options: Default::default(),
183 event_store: None,
184 task_store: None,
185 client_task_store: None,
186 enable_json_response: None,
187 ping_interval: DEFAULT_CLIENT_PING_INTERVAL,
188 sse_support: true,
189 custom_sse_endpoint: None,
190 custom_messages_endpoint: None,
191 auth: None,
192 health_endpoint: None,
193 health_handler: None,
194 message_observer: None,
195 max_request_body_size: None,
196 dns_rebinding: DnsRebindingOptions::default(),
197 session_store: None,
198 enable_ssl: false,
199 ssl_cert_path: None,
200 ssl_key_path: None,
201 }
202 }
203}