turul_mcp_builders/traits/tool_traits.rs
1//! Framework traits for MCP tool construction
2//!
3//! **IMPORTANT**: These are framework features, NOT part of the MCP specification.
4//! The MCP specification defines concrete types only.
5
6use serde_json::Value;
7use std::collections::HashMap;
8
9// Import protocol types (spec-defined)
10use turul_mcp_protocol::tools::ToolAnnotations;
11use turul_mcp_protocol::{Tool, ToolSchema};
12
13/// Base metadata trait - matches TypeScript BaseMetadata interface
14pub trait HasBaseMetadata {
15 /// Programmatic identifier (fallback display name)
16 fn name(&self) -> &str;
17
18 /// Human-readable display name (UI contexts)
19 fn title(&self) -> Option<&str> {
20 None
21 }
22}
23
24/// Tool description trait
25pub trait HasDescription {
26 fn description(&self) -> Option<&str> {
27 None
28 }
29}
30
31/// Input schema trait
32pub trait HasInputSchema {
33 fn input_schema(&self) -> &ToolSchema;
34}
35
36/// Output schema trait
37pub trait HasOutputSchema {
38 fn output_schema(&self) -> Option<&ToolSchema> {
39 None
40 }
41}
42
43/// Annotations trait
44pub trait HasAnnotations {
45 fn annotations(&self) -> Option<&ToolAnnotations> {
46 None
47 }
48}
49
50/// Tool-specific meta trait (separate from RPC _meta)
51pub trait HasToolMeta {
52 fn tool_meta(&self) -> Option<&HashMap<String, Value>> {
53 None
54 }
55}
56
57/// Complete tool definition - composed from fine-grained traits
58///
59/// This trait represents a complete MCP tool that can be registered with a server
60/// and invoked by clients. When you implement the required metadata traits, you automatically
61/// get `ToolDefinition` for free via blanket implementation.
62pub trait ToolDefinition:
63 HasBaseMetadata + // name, title
64 HasDescription + // description
65 HasInputSchema + // inputSchema
66 HasOutputSchema + // outputSchema
67 HasAnnotations + // annotations
68 HasToolMeta + // _meta (tool-specific)
69 super::icon_traits::HasIcons + // icons (MCP 2025-11-25)
70 Send +
71 Sync
72{
73 /// Display name precedence: title > name (matches TypeScript spec)
74 fn display_name(&self) -> &str {
75 if let Some(title) = self.title() {
76 title
77 } else {
78 self.name()
79 }
80 }
81
82 /// Convert to concrete Tool struct for protocol serialization
83 fn to_tool(&self) -> Tool {
84 Tool {
85 name: self.name().to_string(),
86 title: self.title().map(String::from),
87 description: self.description().map(String::from),
88 input_schema: self.input_schema().clone(),
89 output_schema: self.output_schema().cloned(),
90 annotations: self.annotations().cloned(),
91 execution: None,
92 icons: self.icons().cloned(),
93 meta: self.tool_meta().cloned(),
94 }
95 }
96}
97
98/// Blanket implementation: any type implementing all required traits gets ToolDefinition
99impl<T> ToolDefinition for T
100where
101 T: HasBaseMetadata
102 + HasDescription
103 + HasInputSchema
104 + HasOutputSchema
105 + HasAnnotations
106 + HasToolMeta
107 + super::icon_traits::HasIcons
108 + Send
109 + Sync,
110{
111 // Default implementations provided by trait definition
112}