1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10pub struct ServerCapabilities {
11 #[serde(skip_serializing_if = "Option::is_none")]
13 pub tools: Option<ToolCapability>,
14 #[serde(skip_serializing_if = "Option::is_none")]
16 pub resources: Option<ResourceCapability>,
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub prompts: Option<PromptCapability>,
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub tasks: Option<TaskCapability>,
23 #[serde(skip_serializing_if = "Option::is_none")]
25 pub logging: Option<LoggingCapability>,
26 #[serde(skip_serializing_if = "Option::is_none")]
28 pub completions: Option<CompletionCapability>,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub experimental: Option<serde_json::Value>,
32}
33
34impl ServerCapabilities {
35 #[must_use]
37 pub fn new() -> Self {
38 Self::default()
39 }
40
41 #[must_use]
43 pub fn with_tools(mut self) -> Self {
44 self.tools = Some(ToolCapability::default());
45 self
46 }
47
48 #[must_use]
50 pub const fn with_tools_and_changes(mut self) -> Self {
51 self.tools = Some(ToolCapability {
52 list_changed: Some(true),
53 });
54 self
55 }
56
57 #[must_use]
59 pub fn with_resources(mut self) -> Self {
60 self.resources = Some(ResourceCapability::default());
61 self
62 }
63
64 #[must_use]
66 pub const fn with_resources_and_subscriptions(mut self) -> Self {
67 self.resources = Some(ResourceCapability {
68 subscribe: Some(true),
69 list_changed: Some(true),
70 });
71 self
72 }
73
74 #[must_use]
76 pub fn with_prompts(mut self) -> Self {
77 self.prompts = Some(PromptCapability::default());
78 self
79 }
80
81 #[must_use]
83 pub fn with_tasks(mut self) -> Self {
84 self.tasks = Some(TaskCapability::default());
85 self
86 }
87
88 #[must_use]
90 pub const fn with_logging(mut self) -> Self {
91 self.logging = Some(LoggingCapability {});
92 self
93 }
94
95 #[must_use]
97 pub const fn with_completions(mut self) -> Self {
98 self.completions = Some(CompletionCapability {});
99 self
100 }
101
102 #[must_use]
104 pub const fn has_tools(&self) -> bool {
105 self.tools.is_some()
106 }
107
108 #[must_use]
110 pub const fn has_resources(&self) -> bool {
111 self.resources.is_some()
112 }
113
114 #[must_use]
116 pub const fn has_prompts(&self) -> bool {
117 self.prompts.is_some()
118 }
119
120 #[must_use]
122 pub const fn has_tasks(&self) -> bool {
123 self.tasks.is_some()
124 }
125
126 #[must_use]
128 pub const fn has_completions(&self) -> bool {
129 self.completions.is_some()
130 }
131
132 #[must_use]
134 pub fn has_resource_subscribe(&self) -> bool {
135 self.resources
136 .as_ref()
137 .and_then(|r| r.subscribe)
138 .unwrap_or(false)
139 }
140}
141
142#[derive(Debug, Clone, Default, Serialize, Deserialize)]
144pub struct ClientCapabilities {
145 #[serde(skip_serializing_if = "Option::is_none")]
147 pub roots: Option<RootsCapability>,
148 #[serde(skip_serializing_if = "Option::is_none")]
150 pub sampling: Option<SamplingCapability>,
151 #[serde(skip_serializing_if = "Option::is_none")]
153 pub elicitation: Option<ElicitationCapability>,
154 #[serde(skip_serializing_if = "Option::is_none")]
156 pub experimental: Option<serde_json::Value>,
157}
158
159impl ClientCapabilities {
160 #[must_use]
162 pub fn new() -> Self {
163 Self::default()
164 }
165
166 #[must_use]
168 pub fn with_roots(mut self) -> Self {
169 self.roots = Some(RootsCapability::default());
170 self
171 }
172
173 #[must_use]
175 pub const fn with_roots_and_changes(mut self) -> Self {
176 self.roots = Some(RootsCapability {
177 list_changed: Some(true),
178 });
179 self
180 }
181
182 #[must_use]
184 pub const fn with_sampling(mut self) -> Self {
185 self.sampling = Some(SamplingCapability {});
186 self
187 }
188
189 #[must_use]
191 pub const fn with_elicitation(mut self) -> Self {
192 self.elicitation = Some(ElicitationCapability {});
193 self
194 }
195
196 #[must_use]
198 pub const fn has_roots(&self) -> bool {
199 self.roots.is_some()
200 }
201
202 #[must_use]
204 pub const fn has_sampling(&self) -> bool {
205 self.sampling.is_some()
206 }
207
208 #[must_use]
210 pub const fn has_elicitation(&self) -> bool {
211 self.elicitation.is_some()
212 }
213}
214
215#[derive(Debug, Clone, Default, Serialize, Deserialize)]
217pub struct ToolCapability {
218 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
220 pub list_changed: Option<bool>,
221}
222
223#[derive(Debug, Clone, Default, Serialize, Deserialize)]
225pub struct ResourceCapability {
226 #[serde(skip_serializing_if = "Option::is_none")]
228 pub subscribe: Option<bool>,
229 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
231 pub list_changed: Option<bool>,
232}
233
234#[derive(Debug, Clone, Default, Serialize, Deserialize)]
236pub struct PromptCapability {
237 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
239 pub list_changed: Option<bool>,
240}
241
242#[derive(Debug, Clone, Default, Serialize, Deserialize)]
244pub struct TaskCapability {
245 #[serde(skip_serializing_if = "Option::is_none")]
247 pub cancellable: Option<bool>,
248}
249
250#[derive(Debug, Clone, Default, Serialize, Deserialize)]
252pub struct LoggingCapability {}
253
254#[derive(Debug, Clone, Default, Serialize, Deserialize)]
256pub struct CompletionCapability {}
257
258#[derive(Debug, Clone, Default, Serialize, Deserialize)]
260pub struct RootsCapability {
261 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
263 pub list_changed: Option<bool>,
264}
265
266#[derive(Debug, Clone, Default, Serialize, Deserialize)]
268pub struct SamplingCapability {}
269
270#[derive(Debug, Clone, Default, Serialize, Deserialize)]
272pub struct ElicitationCapability {}
273
274#[derive(Debug, Clone, Serialize, Deserialize)]
276pub struct ServerInfo {
277 pub name: String,
279 pub version: String,
281 #[serde(rename = "protocolVersion", skip_serializing_if = "Option::is_none")]
283 pub protocol_version: Option<String>,
284}
285
286impl ServerInfo {
287 #[must_use]
289 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
290 Self {
291 name: name.into(),
292 version: version.into(),
293 protocol_version: Some(PROTOCOL_VERSION.to_string()),
294 }
295 }
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize)]
300pub struct ClientInfo {
301 pub name: String,
303 pub version: String,
305}
306
307impl ClientInfo {
308 #[must_use]
310 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
311 Self {
312 name: name.into(),
313 version: version.into(),
314 }
315 }
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
320pub struct InitializeRequest {
321 #[serde(rename = "protocolVersion")]
323 pub protocol_version: String,
324 pub capabilities: ClientCapabilities,
326 #[serde(rename = "clientInfo")]
328 pub client_info: ClientInfo,
329}
330
331impl InitializeRequest {
332 #[must_use]
334 pub fn new(client_info: ClientInfo, capabilities: ClientCapabilities) -> Self {
335 Self {
336 protocol_version: PROTOCOL_VERSION.to_string(),
337 capabilities,
338 client_info,
339 }
340 }
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct InitializeResult {
346 #[serde(rename = "protocolVersion")]
348 pub protocol_version: String,
349 pub capabilities: ServerCapabilities,
351 #[serde(rename = "serverInfo")]
353 pub server_info: ServerInfo,
354 #[serde(skip_serializing_if = "Option::is_none")]
356 pub instructions: Option<String>,
357}
358
359impl InitializeResult {
360 #[must_use]
362 pub fn new(server_info: ServerInfo, capabilities: ServerCapabilities) -> Self {
363 Self {
364 protocol_version: PROTOCOL_VERSION.to_string(),
365 capabilities,
366 server_info,
367 instructions: None,
368 }
369 }
370
371 #[must_use]
373 pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
374 self.instructions = Some(instructions.into());
375 self
376 }
377}
378
379pub const PROTOCOL_VERSION: &str = "2025-11-25";
383
384pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &[
411 "2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05", ];
416
417#[must_use]
436pub fn is_version_supported(version: &str) -> bool {
437 SUPPORTED_PROTOCOL_VERSIONS.contains(&version)
438}
439
440#[must_use]
472pub fn negotiate_version(requested_version: &str) -> &'static str {
473 if is_version_supported(requested_version) {
474 SUPPORTED_PROTOCOL_VERSIONS
476 .iter()
477 .find(|&&v| v == requested_version)
478 .copied()
479 .unwrap_or(PROTOCOL_VERSION)
480 } else {
481 PROTOCOL_VERSION
483 }
484}
485
486#[derive(Debug, Clone, PartialEq, Eq)]
490pub enum VersionNegotiationResult {
491 Accepted(String),
493 CounterOffer {
496 requested: String,
498 offered: String,
500 },
501}
502
503impl VersionNegotiationResult {
504 #[must_use]
506 pub fn version(&self) -> &str {
507 match self {
508 Self::Accepted(v) => v,
509 Self::CounterOffer { offered, .. } => offered,
510 }
511 }
512
513 #[must_use]
515 pub const fn is_exact_match(&self) -> bool {
516 matches!(self, Self::Accepted(_))
517 }
518}
519
520#[must_use]
546pub fn negotiate_version_detailed(requested_version: &str) -> VersionNegotiationResult {
547 if is_version_supported(requested_version) {
548 VersionNegotiationResult::Accepted(requested_version.to_string())
549 } else {
550 VersionNegotiationResult::CounterOffer {
551 requested: requested_version.to_string(),
552 offered: PROTOCOL_VERSION.to_string(),
553 }
554 }
555}
556
557#[derive(Debug, Clone, Default, Serialize, Deserialize)]
559pub struct InitializedNotification {}
560
561#[derive(Debug, Clone, Default, Serialize, Deserialize)]
563pub struct PingRequest {}
564
565#[derive(Debug, Clone, Default, Serialize, Deserialize)]
567pub struct PingResult {}
568
569#[cfg(test)]
570mod tests {
571 use super::*;
572
573 #[test]
574 fn test_server_capabilities_builder() {
575 let caps = ServerCapabilities::new()
576 .with_tools()
577 .with_resources_and_subscriptions()
578 .with_prompts()
579 .with_tasks();
580
581 assert!(caps.has_tools());
582 assert!(caps.has_resources());
583 assert!(caps.has_prompts());
584 assert!(caps.has_tasks());
585 assert!(caps.resources.unwrap().subscribe.unwrap());
586 }
587
588 #[test]
589 fn test_client_capabilities_builder() {
590 let caps = ClientCapabilities::new()
591 .with_roots_and_changes()
592 .with_sampling()
593 .with_elicitation();
594
595 assert!(caps.has_roots());
596 assert!(caps.has_sampling());
597 assert!(caps.has_elicitation());
598 assert!(caps.roots.unwrap().list_changed.unwrap());
599 }
600
601 #[test]
602 fn test_initialize_request() {
603 let client = ClientInfo::new("test-client", "1.0.0");
604 let caps = ClientCapabilities::new().with_sampling();
605 let request = InitializeRequest::new(client, caps);
606
607 assert_eq!(request.protocol_version, PROTOCOL_VERSION);
608 assert_eq!(request.client_info.name, "test-client");
609 }
610
611 #[test]
612 fn test_initialize_result() {
613 let server = ServerInfo::new("test-server", "1.0.0");
614 let caps = ServerCapabilities::new().with_tools();
615 let result =
616 InitializeResult::new(server, caps).instructions("Use this server to do things");
617
618 assert_eq!(result.protocol_version, PROTOCOL_VERSION);
619 assert!(result.instructions.is_some());
620 }
621
622 #[test]
623 fn test_serialization() {
624 let caps = ServerCapabilities::new()
625 .with_tools_and_changes()
626 .with_resources();
627
628 let json = serde_json::to_string(&caps).unwrap();
629 assert!(json.contains("\"tools\""));
630 assert!(json.contains("\"listChanged\":true"));
631 }
632}