Skip to main content

turul_mcp_builders/
protocol_impls.rs

1//! Framework trait implementations for protocol types
2//!
3//! This module provides framework trait implementations for concrete protocol types
4//! (Resource, Prompt, Tool, Root, etc.) from turul_mcp_protocol, enabling them to be used
5//! with framework features like ResourceDefinition, PromptDefinition, ToolDefinition, etc.
6//!
7//! **CRITICAL**: Every protocol type that has corresponding framework traits MUST have
8//! implementations here. Missing implementations break the trait hierarchy and cause
9//! compilation failures in user code.
10
11use crate::traits::*;
12use turul_mcp_protocol::completion::{
13    CompleteArgument, CompleteRequest, CompletionContext, CompletionReference,
14};
15use turul_mcp_protocol::notifications::{
16    CancelledNotification, Notification, ProgressNotification, PromptListChangedNotification,
17    ResourceListChangedNotification, ResourceUpdatedNotification, ToolListChangedNotification,
18};
19// `Root` is deprecated-but-present in 2026-07-28 (SEP-2577); roots remain a valid feature.
20#[allow(deprecated)]
21use turul_mcp_protocol::roots::Root;
22use turul_mcp_protocol::{Prompt, Resource, Tool, ToolSchema};
23
24#[cfg(feature = "protocol-2025-11-25")]
25use turul_mcp_protocol::elicitation::{ElicitCreateRequest, ElicitationSchema};
26#[cfg(feature = "protocol-2025-11-25")]
27use turul_mcp_protocol::logging::{LoggingLevel, LoggingMessageNotification};
28#[cfg(feature = "protocol-2025-11-25")]
29use turul_mcp_protocol::notifications::{InitializedNotification, RootsListChangedNotification};
30#[cfg(feature = "protocol-2025-11-25")]
31use turul_mcp_protocol::sampling::{CreateMessageParams, ModelPreferences, SamplingMessage};
32#[cfg(feature = "protocol-2025-11-25")]
33use turul_mcp_protocol::tools::ToolExecution;
34
35// ============================================================================
36// Resource trait implementations
37// ============================================================================
38
39impl HasResourceMetadata for Resource {
40    fn name(&self) -> &str {
41        &self.name
42    }
43
44    fn title(&self) -> Option<&str> {
45        self.title.as_deref()
46    }
47}
48
49impl HasResourceDescription for Resource {
50    fn description(&self) -> Option<&str> {
51        self.description.as_deref()
52    }
53}
54
55impl HasResourceUri for Resource {
56    fn uri(&self) -> &str {
57        &self.uri
58    }
59}
60
61impl HasResourceMimeType for Resource {
62    fn mime_type(&self) -> Option<&str> {
63        self.mime_type.as_deref()
64    }
65}
66
67impl HasResourceSize for Resource {
68    fn size(&self) -> Option<u64> {
69        self.size
70    }
71}
72
73impl HasResourceAnnotations for Resource {
74    fn annotations(&self) -> Option<&turul_mcp_protocol::meta::Annotations> {
75        self.annotations.as_ref()
76    }
77}
78
79impl HasResourceMeta for Resource {
80    fn resource_meta(&self) -> Option<&std::collections::HashMap<String, serde_json::Value>> {
81        self.meta.as_ref()
82    }
83}
84
85impl HasIcons for Resource {
86    fn icons(&self) -> Option<&Vec<turul_mcp_protocol::icons::Icon>> {
87        self.icons.as_ref()
88    }
89}
90
91// ResourceDefinition is automatically implemented via blanket impl
92
93// ============================================================================
94// Prompt trait implementations
95// ============================================================================
96
97impl HasPromptMetadata for Prompt {
98    fn name(&self) -> &str {
99        &self.name
100    }
101
102    fn title(&self) -> Option<&str> {
103        self.title.as_deref()
104    }
105}
106
107impl HasPromptDescription for Prompt {
108    fn description(&self) -> Option<&str> {
109        self.description.as_deref()
110    }
111}
112
113impl HasPromptArguments for Prompt {
114    fn arguments(&self) -> Option<&Vec<turul_mcp_protocol::prompts::PromptArgument>> {
115        self.arguments.as_ref()
116    }
117}
118
119impl HasPromptAnnotations for Prompt {
120    fn annotations(&self) -> Option<&crate::traits::prompt_traits::PromptAnnotations> {
121        // Prompt struct doesn't have annotations field in current protocol
122        None
123    }
124}
125
126impl HasPromptMeta for Prompt {
127    fn prompt_meta(&self) -> Option<&std::collections::HashMap<String, serde_json::Value>> {
128        self.meta.as_ref()
129    }
130}
131
132impl HasIcons for Prompt {
133    fn icons(&self) -> Option<&Vec<turul_mcp_protocol::icons::Icon>> {
134        self.icons.as_ref()
135    }
136}
137
138// PromptDefinition is automatically implemented via blanket impl
139
140// ============================================================================
141// Tool trait implementations
142// ============================================================================
143
144impl HasBaseMetadata for Tool {
145    fn name(&self) -> &str {
146        &self.name
147    }
148
149    fn title(&self) -> Option<&str> {
150        self.title.as_deref()
151    }
152}
153
154impl HasDescription for Tool {
155    fn description(&self) -> Option<&str> {
156        self.description.as_deref()
157    }
158}
159
160impl HasInputSchema for Tool {
161    fn input_schema(&self) -> &ToolSchema {
162        &self.input_schema
163    }
164}
165
166impl HasOutputSchema for Tool {
167    #[cfg(feature = "protocol-2025-11-25")]
168    fn output_schema(&self) -> Option<&ToolSchema> {
169        self.output_schema.as_ref()
170    }
171
172    #[cfg(feature = "protocol-2026-07-28")]
173    fn output_schema(&self) -> Option<&ToolSchema> {
174        None
175    }
176}
177
178impl HasAnnotations for Tool {
179    fn annotations(&self) -> Option<&turul_mcp_protocol::tools::ToolAnnotations> {
180        self.annotations.as_ref()
181    }
182}
183
184impl HasToolMeta for Tool {
185    fn tool_meta(&self) -> Option<&std::collections::HashMap<String, serde_json::Value>> {
186        self.meta.as_ref()
187    }
188}
189
190impl HasIcons for Tool {
191    fn icons(&self) -> Option<&Vec<turul_mcp_protocol::icons::Icon>> {
192        self.icons.as_ref()
193    }
194}
195
196#[cfg(feature = "protocol-2025-11-25")]
197impl HasExecution for Tool {
198    fn execution(&self) -> Option<ToolExecution> {
199        self.execution.clone()
200    }
201}
202
203// ToolDefinition is automatically implemented via blanket impl
204
205// ============================================================================
206// Root trait implementations
207// ============================================================================
208
209#[allow(deprecated)]
210impl HasRootMetadata for Root {
211    fn name(&self) -> Option<&str> {
212        self.name.as_deref()
213    }
214
215    fn uri(&self) -> &str {
216        &self.uri
217    }
218}
219
220#[allow(deprecated)]
221impl HasRootPermissions for Root {
222    // Root struct doesn't have permissions field - framework can add later if needed
223}
224
225#[allow(deprecated)]
226impl HasRootFiltering for Root {
227    // Root struct doesn't have filtering field - framework can add later if needed
228}
229
230#[allow(deprecated)]
231impl HasRootAnnotations for Root {
232    fn annotations(&self) -> Option<&std::collections::HashMap<String, serde_json::Value>> {
233        self.meta.as_ref()
234    }
235}
236
237// RootDefinition is automatically implemented via blanket impl
238
239// ============================================================================
240// Sampling trait implementations
241// ============================================================================
242
243#[cfg(feature = "protocol-2025-11-25")]
244impl HasSamplingConfig for CreateMessageParams {
245    fn max_tokens(&self) -> u32 {
246        self.max_tokens
247    }
248
249    fn temperature(&self) -> Option<f64> {
250        self.temperature
251    }
252
253    fn stop_sequences(&self) -> Option<&Vec<String>> {
254        self.stop_sequences.as_ref()
255    }
256}
257
258#[cfg(feature = "protocol-2025-11-25")]
259impl HasSamplingContext for CreateMessageParams {
260    fn messages(&self) -> &[SamplingMessage] {
261        &self.messages
262    }
263
264    fn system_prompt(&self) -> Option<&str> {
265        self.system_prompt.as_deref()
266    }
267
268    fn include_context(&self) -> Option<&str> {
269        self.include_context.as_deref()
270    }
271}
272
273#[cfg(feature = "protocol-2025-11-25")]
274impl HasModelPreferences for CreateMessageParams {
275    fn model_preferences(&self) -> Option<&ModelPreferences> {
276        self.model_preferences.as_ref()
277    }
278
279    fn metadata(&self) -> Option<&serde_json::Value> {
280        self.metadata.as_ref()
281    }
282}
283
284#[cfg(feature = "protocol-2025-11-25")]
285impl HasSamplingTools for CreateMessageParams {
286    fn tools(&self) -> Option<&Vec<turul_mcp_protocol::Tool>> {
287        self.tools.as_ref()
288    }
289}
290
291// SamplingDefinition is automatically implemented via blanket impl
292
293#[cfg(feature = "protocol-2025-11-25")]
294impl HasSamplingMessageMetadata for SamplingMessage {
295    fn role(&self) -> &turul_mcp_protocol::sampling::Role {
296        &self.role
297    }
298
299    fn content(&self) -> &turul_mcp_protocol::prompts::ContentBlock {
300        &self.content
301    }
302}
303
304// ============================================================================
305// Logging trait implementations
306// ============================================================================
307
308#[cfg(feature = "protocol-2025-11-25")]
309impl HasLoggingMetadata for LoggingMessageNotification {
310    fn method(&self) -> &str {
311        &self.method
312    }
313
314    fn logger_name(&self) -> Option<&str> {
315        self.params.logger.as_deref()
316    }
317}
318
319#[cfg(feature = "protocol-2025-11-25")]
320impl HasLogLevel for LoggingMessageNotification {
321    fn level(&self) -> LoggingLevel {
322        self.params.level
323    }
324}
325
326#[cfg(feature = "protocol-2025-11-25")]
327impl HasLogFormat for LoggingMessageNotification {
328    fn data(&self) -> &serde_json::Value {
329        &self.params.data
330    }
331}
332
333#[cfg(feature = "protocol-2025-11-25")]
334impl HasLogTransport for LoggingMessageNotification {
335    // Use default implementations
336}
337
338// LoggerDefinition is automatically implemented via blanket impl
339
340// ============================================================================
341// Completion trait implementations
342// ============================================================================
343
344impl HasCompletionMetadata for CompleteRequest {
345    fn method(&self) -> &str {
346        &self.method
347    }
348
349    fn reference(&self) -> &CompletionReference {
350        &self.params.reference
351    }
352}
353
354impl HasCompletionContext for CompleteRequest {
355    fn argument(&self) -> &CompleteArgument {
356        &self.params.argument
357    }
358
359    fn context(&self) -> Option<&CompletionContext> {
360        self.params.context.as_ref()
361    }
362}
363
364impl HasCompletionHandling for CompleteRequest {
365    // Use default implementations
366}
367
368// CompletionDefinition is automatically implemented via blanket impl
369
370// ============================================================================
371// Elicitation trait implementations
372// ============================================================================
373
374#[cfg(feature = "protocol-2025-11-25")]
375impl HasElicitationMetadata for ElicitCreateRequest {
376    fn message(&self) -> &str {
377        &self.params.message
378    }
379
380    // title() uses default implementation which returns None
381}
382
383#[cfg(feature = "protocol-2025-11-25")]
384impl HasElicitationSchema for ElicitCreateRequest {
385    fn requested_schema(&self) -> &ElicitationSchema {
386        &self.params.requested_schema
387    }
388}
389
390#[cfg(feature = "protocol-2025-11-25")]
391impl HasElicitationHandling for ElicitCreateRequest {
392    // Use default implementations
393}
394
395// ElicitationDefinition is automatically implemented via blanket impl
396
397// ============================================================================
398// Notification trait implementations
399// ============================================================================
400
401// Base Notification type
402impl HasNotificationMetadata for Notification {
403    fn method(&self) -> &str {
404        &self.method
405    }
406}
407
408impl HasNotificationPayload for Notification {
409    fn payload(&self) -> Option<serde_json::Value> {
410        self.params.as_ref().map(|params| {
411            let mut map = serde_json::Map::new();
412
413            // Add all params.other fields
414            for (key, value) in &params.other {
415                map.insert(key.clone(), value.clone());
416            }
417
418            // Add _meta if present
419            if let Some(meta) = &params.meta
420                && let Ok(meta_value) = serde_json::to_value(meta)
421            {
422                map.insert("_meta".to_string(), meta_value);
423            }
424
425            serde_json::Value::Object(map)
426        })
427    }
428}
429
430impl HasNotificationRules for Notification {}
431
432// ResourceListChangedNotification
433impl HasNotificationMetadata for ResourceListChangedNotification {
434    fn method(&self) -> &str {
435        &self.method
436    }
437}
438
439impl HasNotificationPayload for ResourceListChangedNotification {
440    fn payload(&self) -> Option<serde_json::Value> {
441        // Serialize params if present (includes _meta)
442        self.params
443            .as_ref()
444            .and_then(|p| serde_json::to_value(p).ok())
445    }
446}
447
448impl HasNotificationRules for ResourceListChangedNotification {}
449
450// ToolListChangedNotification
451impl HasNotificationMetadata for ToolListChangedNotification {
452    fn method(&self) -> &str {
453        &self.method
454    }
455}
456
457impl HasNotificationPayload for ToolListChangedNotification {
458    fn payload(&self) -> Option<serde_json::Value> {
459        // Serialize params if present (includes _meta)
460        self.params
461            .as_ref()
462            .and_then(|p| serde_json::to_value(p).ok())
463    }
464}
465
466impl HasNotificationRules for ToolListChangedNotification {}
467
468// PromptListChangedNotification
469impl HasNotificationMetadata for PromptListChangedNotification {
470    fn method(&self) -> &str {
471        &self.method
472    }
473}
474
475impl HasNotificationPayload for PromptListChangedNotification {
476    fn payload(&self) -> Option<serde_json::Value> {
477        // Serialize params if present (includes _meta)
478        self.params
479            .as_ref()
480            .and_then(|p| serde_json::to_value(p).ok())
481    }
482}
483
484impl HasNotificationRules for PromptListChangedNotification {}
485
486// RootsListChangedNotification
487#[cfg(feature = "protocol-2025-11-25")]
488impl HasNotificationMetadata for RootsListChangedNotification {
489    fn method(&self) -> &str {
490        &self.method
491    }
492}
493
494#[cfg(feature = "protocol-2025-11-25")]
495impl HasNotificationPayload for RootsListChangedNotification {
496    fn payload(&self) -> Option<serde_json::Value> {
497        // Serialize params if present (includes _meta)
498        self.params
499            .as_ref()
500            .and_then(|p| serde_json::to_value(p).ok())
501    }
502}
503
504#[cfg(feature = "protocol-2025-11-25")]
505impl HasNotificationRules for RootsListChangedNotification {}
506
507// ProgressNotification
508impl HasNotificationMetadata for ProgressNotification {
509    fn method(&self) -> &str {
510        &self.method
511    }
512}
513
514impl HasNotificationPayload for ProgressNotification {
515    fn payload(&self) -> Option<serde_json::Value> {
516        // Serialize the entire params struct (includes progressToken, progress, total, message, _meta)
517        serde_json::to_value(&self.params).ok()
518    }
519}
520
521impl HasNotificationRules for ProgressNotification {
522    fn priority(&self) -> u32 {
523        2 // Progress notifications have higher priority
524    }
525}
526
527// ResourceUpdatedNotification
528impl HasNotificationMetadata for ResourceUpdatedNotification {
529    fn method(&self) -> &str {
530        &self.method
531    }
532}
533
534impl HasNotificationPayload for ResourceUpdatedNotification {
535    fn payload(&self) -> Option<serde_json::Value> {
536        // Serialize params (includes uri, _meta)
537        serde_json::to_value(&self.params).ok()
538    }
539}
540
541impl HasNotificationRules for ResourceUpdatedNotification {}
542
543// CancelledNotification
544impl HasNotificationMetadata for CancelledNotification {
545    fn method(&self) -> &str {
546        &self.method
547    }
548}
549
550impl HasNotificationPayload for CancelledNotification {
551    fn payload(&self) -> Option<serde_json::Value> {
552        // Serialize params (includes requestId, reason, _meta)
553        serde_json::to_value(&self.params).ok()
554    }
555}
556
557impl HasNotificationRules for CancelledNotification {
558    fn priority(&self) -> u32 {
559        3 // Cancellation has highest priority
560    }
561}
562
563// InitializedNotification
564#[cfg(feature = "protocol-2025-11-25")]
565impl HasNotificationMetadata for InitializedNotification {
566    fn method(&self) -> &str {
567        &self.method
568    }
569}
570
571#[cfg(feature = "protocol-2025-11-25")]
572impl HasNotificationPayload for InitializedNotification {
573    fn payload(&self) -> Option<serde_json::Value> {
574        // Serialize params if present (includes _meta)
575        self.params
576            .as_ref()
577            .and_then(|p| serde_json::to_value(p).ok())
578    }
579}
580
581#[cfg(feature = "protocol-2025-11-25")]
582impl HasNotificationRules for InitializedNotification {
583    fn priority(&self) -> u32 {
584        3 // Initialization has highest priority
585    }
586}
587
588// NotificationDefinition is automatically implemented via blanket impl for all notification types