turul_mcp_protocol_2025_06_18/
traits.rs

1//! Traits for JSON-RPC types as per MCP specification (2025-06-18)
2
3use serde::Serialize;
4use serde_json::Value;
5use std::collections::HashMap;
6
7use crate::{
8    completion::CompleteArgument,
9    initialize::{ClientCapabilities, Implementation, ServerCapabilities},
10    logging::LogLevel,
11    prompts::ContentBlock,
12    meta::{Cursor, ProgressToken},
13    prompts::{Prompt, PromptMessage},
14    resources::Resource,
15    roots::Root,
16    sampling::{Role, SamplingMessage, ModelPreferences},
17    tools::{Tool, ToolResult},
18    version::McpVersion,
19};
20
21// JSON-RPC version constant
22pub const JSONRPC_VERSION: &str = "2.0";
23
24// ====================
25// === Base Traits ====
26// ====================
27
28pub trait Params {}
29
30pub trait HasRequestId {
31    fn id(&self) -> &turul_mcp_json_rpc_server::types::RequestId;
32}
33
34pub trait HasResult {
35    fn result(&self) -> &dyn RpcResult;
36}
37
38pub trait HasJsonRpcVersion {
39    fn version(&self) -> &str {
40        JSONRPC_VERSION
41    }
42}
43
44pub trait HasMethod {
45    fn method(&self) -> &str;
46}
47
48pub trait HasParams {
49    fn params(&self) -> Option<&dyn Params>;
50}
51
52pub trait HasData {
53    /// Returns an owned JSON‐object map of this value.
54    fn data(&self) -> HashMap<String, Value>;
55}
56
57pub trait HasMeta {
58    /// Returns an owned JSON‐object map of this value.
59    fn meta(&self) -> Option<HashMap<String, Value>>;
60}
61
62pub trait HasErrorObject {
63    fn error(&self) -> &turul_mcp_json_rpc_server::error::JsonRpcErrorObject;
64}
65
66// ==========================
67// === Derived Interfaces ===
68// ==========================
69
70pub trait RpcRequest: HasMethod + HasParams {}
71pub trait RpcNotification: HasMethod + HasParams {}
72pub trait RpcResult: HasMeta + HasData {}
73pub trait JsonRpcRequestTrait: HasJsonRpcVersion + HasRequestId + RpcRequest {}
74pub trait JsonRpcNotificationTrait: HasJsonRpcVersion + RpcNotification {}
75
76pub trait JsonRpcResponseTrait: HasJsonRpcVersion + HasRequestId + HasResult + Serialize {
77    fn to_bytes(&self) -> Vec<u8> {
78        serde_json::to_vec(self).unwrap()
79    }
80}
81
82pub trait JsonRpcErrorTrait: HasJsonRpcVersion + HasRequestId + HasErrorObject {}
83
84// ==========================
85// === Param Specialisations ===
86// ==========================
87
88pub trait HasRequestIdParam: Params {
89    fn request_id(&self) -> &turul_mcp_json_rpc_server::types::RequestId;
90}
91
92pub trait HasReasonParam: Params {
93    fn reason(&self) -> Option<&str>;
94}
95
96pub trait HasDataParam: Params {
97    fn data(&self) -> &HashMap<String, Value>;
98}
99
100pub trait HasMetaParam: Params {
101    fn meta(&self) -> Option<&HashMap<String, Value>>;
102}
103
104pub trait HasProgressTokenParam: Params {
105    fn progress_token(&self) -> Option<&ProgressToken>;
106}
107
108pub trait HasInitializeParams: Params {
109    fn protocol_version(&self) -> McpVersion;
110    fn capabilities(&self) -> &ClientCapabilities;
111    fn client_info(&self) -> &Implementation;
112}
113
114// ==========================
115// === Typed Traits from MCP Spec ===
116// ==========================
117
118pub trait HasCancelledParams: HasRequestIdParam + HasReasonParam {}
119pub trait CancelledNotification: RpcNotification + HasCancelledParams {}
120
121pub trait InitializeRequest: JsonRpcRequestTrait + HasInitializeParams {
122    fn method(&self) -> &str {
123        "initialize"
124    }
125}
126
127pub trait InitializeResult: RpcResult {
128    fn protocol_version(&self) -> &str;
129    fn capabilities(&self) -> &ServerCapabilities;
130    fn server_info(&self) -> &Implementation;
131    fn instructions(&self) -> Option<&str>;
132}
133
134pub trait InitializeNotification: JsonRpcNotificationTrait {
135    fn method(&self) -> &str {
136        "notifications/initialized"
137    }
138}
139
140// ---------------------- notifications/progress ------------------------
141
142/// Trait for params of `notifications/progress`
143pub trait HasProgressParams: Params {
144    fn progress_token(&self) -> &ProgressToken;
145    fn progress(&self) -> u64;
146    fn total(&self) -> Option<u64>;
147    fn message(&self) -> Option<&String>;
148}
149
150/// The notification itself
151pub trait ProgressNotification: JsonRpcNotificationTrait + HasProgressParams {
152    /// Always exactly `"notifications/progress"`
153    fn method(&self) -> &str {
154        "notifications/progress"
155    }
156}
157
158// ---------------------- resources/list ------------------------
159
160pub trait HasListResourcesParams: Params {
161    fn cursor(&self) -> Option<&Cursor>;
162}
163
164pub trait ListResourcesRequest: JsonRpcRequestTrait + HasListResourcesParams {
165    fn method(&self) -> &str {
166        "resources/list"
167    }
168}
169
170pub trait ListResourcesResult: RpcResult {
171    fn resources(&self) -> &Vec<Resource>;
172    fn next_cursor(&self) -> Option<&Cursor>;
173}
174
175pub trait ResourcesListChangedNotification: JsonRpcNotificationTrait {
176    fn method(&self) -> &str {
177        "notifications/resources/listChanged"
178    }
179}
180
181pub trait HasReadResourceParams: Params {
182    fn uri(&self) -> &String;
183}
184
185pub trait ReadResourceRequest: JsonRpcRequestTrait + HasReadResourceParams {
186    fn method(&self) -> &str {
187        "resources/read"
188    }
189}
190
191pub trait ReadResourceResult: RpcResult {
192    fn contents(&self) -> &Vec<crate::resources::ResourceContent>;
193}
194
195pub trait HasResourceUpdatedParams: Params {
196    fn uri(&self) -> &String;
197}
198
199pub trait ResourceUpdatedNotification: JsonRpcNotificationTrait + HasResourceUpdatedParams {
200    fn method(&self) -> &str {
201        "notifications/resources/updated"
202    }
203}
204
205// ---------------------- prompts/list & get ------------------------
206
207pub trait HasListPromptsParams: Params {
208    fn cursor(&self) -> Option<&Cursor>;
209}
210
211pub trait ListPromptsRequest: JsonRpcRequestTrait + HasListPromptsParams {
212    fn method(&self) -> &str {
213        "prompts/list"
214    }
215}
216
217pub trait ListPromptsResult: RpcResult {
218    fn prompts(&self) -> &Vec<Prompt>;
219    fn next_cursor(&self) -> Option<&Cursor>;
220}
221
222pub trait HasGetPromptParams: Params {
223    fn name(&self) -> &String;
224    fn arguments(&self) -> Option<&HashMap<String, String>>; // MCP spec: { [key: string]: string }
225}
226
227pub trait GetPromptRequest: JsonRpcRequestTrait + HasGetPromptParams {
228    fn method(&self) -> &str {
229        "prompts/get"
230    }
231}
232
233pub trait GetPromptResult: RpcResult {
234    fn description(&self) -> Option<&String>;
235    fn messages(&self) -> &Vec<PromptMessage>;
236}
237
238pub trait PromptListChangedNotification: JsonRpcNotificationTrait {
239    fn method(&self) -> &str {
240        "notifications/prompts/listChanged"
241    }
242}
243
244// ---------------------- tools/list & call ------------------------
245
246pub trait HasListToolsParams: Params {
247    fn cursor(&self) -> Option<&Cursor>;
248}
249
250pub trait ListToolsRequest: JsonRpcRequestTrait + HasListToolsParams {
251    fn method(&self) -> &str {
252        "tools/list"
253    }
254}
255
256pub trait ListToolsResult: RpcResult {
257    fn tools(&self) -> &Vec<Tool>;
258    fn next_cursor(&self) -> Option<&Cursor>;
259}
260
261pub trait HasCallToolParams: Params {
262    fn name(&self) -> &String;
263    fn arguments(&self) -> Option<&Value>; // Keep as Value for now for compatibility
264    fn meta(&self) -> Option<&HashMap<String, Value>>;
265}
266
267pub trait CallToolRequest: JsonRpcRequestTrait + HasCallToolParams {
268    fn method(&self) -> &str {
269        "tools/call"
270    }
271}
272
273pub trait CallToolResult: RpcResult {
274    fn content(&self) -> &Vec<ToolResult>;
275    fn is_error(&self) -> Option<bool>;
276    /// Structured content that matches the tool's output schema (MCP 2025-06-18)
277    fn structured_content(&self) -> Option<&Value>;
278}
279
280pub trait ToolListChangedNotification: JsonRpcNotificationTrait {
281    fn method(&self) -> &str {
282        "notifications/tools/listChanged"
283    }
284}
285
286// ---------------------- sampling/createMessage ------------------------
287
288pub trait HasCreateMessageParams: Params {
289    fn messages(&self) -> &Vec<SamplingMessage>;
290    fn model_preferences(&self) -> Option<&ModelPreferences>;
291    fn system_prompt(&self) -> Option<&String>;
292    fn include_context(&self) -> Option<&String>;
293    fn temperature(&self) -> Option<&f64>;
294    fn max_tokens(&self) -> u32;
295    fn stop_sequences(&self) -> Option<&Vec<String>>;
296    fn metadata(&self) -> Option<&Value>;
297}
298
299pub trait CreateMessageRequest: JsonRpcRequestTrait + HasCreateMessageParams {
300    fn method(&self) -> &str {
301        "sampling/createMessage"
302    }
303}
304
305pub trait CreateMessageResult: RpcResult {
306    fn role(&self) -> &Role;
307    fn content(&self) -> &ContentBlock;
308    fn model(&self) -> &String;
309    fn stop_reason(&self) -> Option<&String>;
310}
311
312// ---------------------- completion/complete ------------------------
313
314/// The `params` object for `completion/complete`
315pub trait HasCompleteParams: Params {
316    /// The prompt or resource reference to complete against.
317    fn reference(&self) -> &Value;
318    /// The name/value pair to complete.
319    fn argument(&self) -> &CompleteArgument;
320    /// Optional additional context.
321    fn context(&self) -> Option<&Value>;
322}
323
324/// The JSON-RPC request for `completion/complete`
325pub trait CompleteRequestTrait: JsonRpcRequestTrait + HasCompleteParams {
326    /// Always exactly `"completion/complete"`
327    fn method(&self) -> &str {
328        "completion/complete"
329    }
330}
331
332/// Exposes the inner `completion` field of the response payload.
333pub trait HasCompletionResult: RpcResult {
334    fn completion(&self) -> &Value;
335}
336
337/// The JSON-RPC result for `completion/complete`
338pub trait CompleteResult: RpcResult + HasCompletionResult {}
339
340// ---------------------- templates/list ------------------------
341
342pub trait HasListResourceTemplatesParams: Params {
343    fn cursor(&self) -> Option<&Cursor>;
344}
345
346pub trait ListResourceTemplatesRequest:
347    JsonRpcRequestTrait + HasListResourceTemplatesParams
348{
349    fn method(&self) -> &str {
350        "resources/templates/list"
351    }
352}
353
354pub trait ListResourceTemplatesResult: RpcResult {
355    fn resource_templates(&self) -> &Vec<crate::resources::ResourceTemplate>;
356    fn next_cursor(&self) -> Option<&Cursor>;
357}
358
359// ---------------------- roots/list ------------------------
360
361pub trait HasListRootsParams: Params {}
362
363pub trait ListRootsRequest: JsonRpcRequestTrait + HasListRootsParams {
364    fn method(&self) -> &str {
365        "roots/list"
366    }
367}
368
369pub trait ListRootsResult: RpcResult {
370    fn roots(&self) -> &Vec<Root>;
371}
372
373pub trait RootsListChangedNotification: JsonRpcNotificationTrait {
374    fn method(&self) -> &str {
375        "notifications/roots/listChanged"
376    }
377}
378
379// ---------------------- logging ------------------------
380
381pub trait HasSetLevelParams: Params {
382    fn level(&self) -> &LogLevel;
383}
384
385pub trait SetLevelRequest: JsonRpcRequestTrait + HasSetLevelParams {
386    fn method(&self) -> &str {
387        "logging/setLevel"
388    }
389}
390
391// Field-getter traits you already have; if not, add:
392pub trait HasLevelParam: Params {
393    fn level(&self) -> &LogLevel;
394}
395pub trait HasLoggerParam: Params {
396    fn logger(&self) -> Option<&String>;
397}
398
399pub trait LoggingMessageNotificationTrait: JsonRpcNotificationTrait + HasParams {
400    fn method(&self) -> &str {
401        "notifications/message"
402    }
403}
404
405// ---------------------- elicitation ------------------------
406
407pub trait HasElicitParams: Params {
408    fn message(&self) -> &String;
409    fn requested_schema(&self) -> &Value;
410}
411
412pub trait ElicitRequest: JsonRpcRequestTrait + HasElicitParams {
413    fn method(&self) -> &str {
414        "elicitation/create"
415    }
416}
417
418pub trait ElicitResult: RpcResult {
419    fn action(&self) -> &Value;
420    fn content(&self) -> Option<&HashMap<String, Value>>;
421}
422
423// ---------------------- trait-based parameter extraction ------------------------
424
425/// Trait for extracting parameters from RequestParams using trait constraints
426pub trait ParamExtractor<T: Params> {
427    type Error;
428
429    /// Extract parameters from RequestParams using trait-based conversion
430    fn extract(params: turul_mcp_json_rpc_server::RequestParams) -> Result<T, Self::Error>;
431}
432
433/// Trait for serde-based parameter extraction (simpler cases)
434pub trait SerdeParamExtractor<T: Params> {
435    type Error;
436
437    /// Extract parameters using serde deserialization
438    fn extract_serde(params: turul_mcp_json_rpc_server::RequestParams) -> Result<T, Self::Error>;
439}
440
441/// Trait for field-by-field parameter extraction (complex cases)
442pub trait FieldParamExtractor<T: Params> {
443    type Error;
444
445    /// Extract parameters field by field with validation
446    fn extract_fields(params: turul_mcp_json_rpc_server::RequestParams) -> Result<T, Self::Error>;
447}