Skip to content

chore: fix all clippy warnings#746

Merged
alexhancock merged 1 commit intomainfrom
chore/fix-clippy-warnings
Mar 11, 2026
Merged

chore: fix all clippy warnings#746
alexhancock merged 1 commit intomainfrom
chore/fix-clippy-warnings

Conversation

@DaleSeo
Copy link
Member

@DaleSeo DaleSeo commented Mar 11, 2026

Motivation and Context

This PR resolves all the clippy issues, allowing the CI clippy gate to pass cleanly.

❯ cargo clippy --workspace --all-targets --all-features
warning: /Users/dale.seo/work/rust-sdk/crates/rmcp/Cargo.toml: only one of `license` or `license-file` is necessary
`license` should be used if the package license can be expressed with a standard SPDX expression.
`license-file` should be used if the package uses a non-standard license.
See https://doc.rust-lang.org/cargo/reference/manifest.html#the-license-and-license-file-fields for more information.
warning: /Users/dale.seo/work/rust-sdk/crates/rmcp-macros/Cargo.toml: only one of `license` or `license-file` is necessary
`license` should be used if the package license can be expressed with a standard SPDX expression.
`license-file` should be used if the package uses a non-standard license.
See https://doc.rust-lang.org/cargo/reference/manifest.html#the-license-and-license-file-fields for more information.
   Compiling rmcp v1.2.0 (/Users/dale.seo/work/rust-sdk/crates/rmcp)
   Compiling rmcp-macros v1.2.0 (/Users/dale.seo/work/rust-sdk/crates/rmcp-macros)
    Checking simple-chat-client v0.1.0 (/Users/dale.seo/work/rust-sdk/examples/simple-chat-client)
    Checking mcp-server-examples v0.1.5 (/Users/dale.seo/work/rust-sdk/examples/servers)
    Checking mcp-client-examples v0.1.5 (/Users/dale.seo/work/rust-sdk/examples/clients)
    Checking transport v1.2.0 (/Users/dale.seo/work/rust-sdk/examples/transport)
warning: unused import: `chrono::Utc`
 --> examples/servers/src/common/counter.rs:4:5
  |
4 | use chrono::Utc;
  |     ^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused imports: `OperationDescriptor` and `OperationMessage`
  --> examples/servers/src/common/counter.rs:16:9
   |
16 |         OperationDescriptor, OperationMessage, OperationProcessor, OperationResultTransport,
   |         ^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^

warning: unused import: `tracing::info`
  --> examples/servers/src/common/counter.rs:22:5
   |
22 | use tracing::info;
   |     ^^^^^^^^^^^^^

    Checking rig-integration v1.2.0 (/Users/dale.seo/work/rust-sdk/examples/rig-integration)
    Checking wasi-mcp-example v1.2.0 (/Users/dale.seo/work/rust-sdk/examples/wasi)
warning: `mcp-server-examples` (example "counter_hyper_streamable_http") generated 3 warnings (run `cargo clippy --fix --example "counter_hyper_streamable_http"` to apply 3 suggestions)
warning: `mcp-server-examples` (example "servers_memory_stdio") generated 3 warnings (3 duplicates)
warning: unused import: `Serialize`
  --> examples/servers/src/cimd_auth_streamhttp.rs:21:26
   |
21 | use serde::{Deserialize, Serialize};
   |                          ^^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

warning: unused import: `chrono::Utc`
 --> examples/servers/src/common/counter.rs:4:5
  |
4 | use chrono::Utc;
  |     ^^^^^^^^^^^

warning: `mcp-server-examples` (example "servers_progress_demo") generated 3 warnings (3 duplicates)
warning: fields `client_id` and `redirect_uri` are never read
  --> examples/servers/src/cimd_auth_streamhttp.rs:38:5
   |
37 | struct AuthCodeRecord {
   |        -------------- fields in this struct
38 |     client_id: String,
   |     ^^^^^^^^^
39 |     redirect_uri: String,
   |     ^^^^^^^^^^^^
   |
   = note: `AuthCodeRecord` has derived impls for the traits `Debug` and `Clone`, but these are intentionally ignored during dead code analysis
   = note: `#[warn(dead_code)]` on by default

warning: `mcp-server-examples` (example "servers_cimd_auth_streamhttp") generated 5 warnings (2 duplicates) (run `cargo clippy --fix --example "servers_cimd_auth_streamhttp"` to apply 2 suggestions)
    Checking mcp-conformance v0.1.0 (/Users/dale.seo/work/rust-sdk/conformance)
warning: `mcp-server-examples` (example "servers_calculator_stdio") generated 3 warnings (3 duplicates)
warning: `mcp-server-examples` (example "servers_counter_stdio") generated 3 warnings (3 duplicates)
warning: `mcp-server-examples` (example "servers_counter_streamhttp") generated 3 warnings (3 duplicates)
warning: `mcp-server-examples` (example "servers_simple_auth_streamhttp") generated 3 warnings (3 duplicates)
warning: this function can be simplified using the `async fn` syntax
  --> conformance/src/bin/client.rs:58:5
   |
58 | /     fn create_elicitation(
59 | |         &self,
60 | |         request: CreateElicitationRequestParams,
61 | |         _cx: RequestContext<RoleClient>,
62 | |     ) -> impl Future<Output = Result<CreateElicitationResult, ErrorData>> + Send + '_ {
   | |_____________________________________________________________________________________^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
   = note: `#[warn(clippy::manual_async_fn)]` on by default
help: make the function `async` and return the output of the future directly
   |
58 ~     async fn create_elicitation(
59 +         &self,
60 +         request: CreateElicitationRequestParams,
61 +         _cx: RequestContext<RoleClient>,
62 ~     ) -> Result<CreateElicitationResult, ErrorData> {
63 +         let content = match &request {
64 +             CreateElicitationRequestParams::FormElicitationParams {
65 +                 requested_schema, ..
66 +             } => {
67 +                 let mut defaults = serde_json::Map::new();
68 +                 for (name, prop) in &requested_schema.properties {
69 +                     match prop {
70 +                         PrimitiveSchema::String(s) => {
71 +                             if let Some(d) = &s.default {
72 +                                 defaults.insert(name.clone(), Value::String(d.clone()));
73 +                             }
74 +                         }
75 +                         PrimitiveSchema::Number(n) => {
76 +                             if let Some(d) = n.default {
77 +                                 defaults.insert(name.clone(), json!(d));
78 +                             }
79 +                         }
80 +                         PrimitiveSchema::Integer(i) => {
81 +                             if let Some(d) = i.default {
82 +                                 defaults.insert(name.clone(), json!(d));
83 +                             }
84 +                         }
85 +                         PrimitiveSchema::Boolean(b) => {
86 +                             if let Some(d) = b.default {
87 +                                 defaults.insert(name.clone(), Value::Bool(d));
88 +                             }
89 +                         }
90 +                         PrimitiveSchema::Enum(e) => {
91 +                             let val = match e {
92 +                                 EnumSchema::Single(SingleSelectEnumSchema::Untitled(u)) => {
93 +                                     u.default.as_ref().map(|d| Value::String(d.clone()))
94 +                                 }
95 +                                 EnumSchema::Single(SingleSelectEnumSchema::Titled(t)) => {
96 +                                     t.default.as_ref().map(|d| Value::String(d.clone()))
97 +                                 }
98 +                                 EnumSchema::Multi(MultiSelectEnumSchema::Untitled(u)) => {
99 +                                     u.default.as_ref().map(|d| {
100+                                         Value::Array(
101+                                             d.iter()
102+                                                 .map(|s| Value::String(s.clone()))
103+                                                 .collect(),
104+                                         )
105+                                     })
106+                                 }
107+                                 EnumSchema::Multi(MultiSelectEnumSchema::Titled(t)) => {
108+                                     t.default.as_ref().map(|d| {
109+                                         Value::Array(
110+                                             d.iter()
111+                                                 .map(|s| Value::String(s.clone()))
112+                                                 .collect(),
113+                                         )
114+                                     })
115+                                 }
116+                                 EnumSchema::Legacy(_) => None,
117+                             };
118+                             if let Some(v) = val {
119+                                 defaults.insert(name.clone(), v);
120+                             }
121+                         }
122+                     }
123+                 }
124+                 Some(Value::Object(defaults))
125+             }
126+             _ => Some(json!({})),
127+         };
128+         Ok(CreateElicitationResult {
129+             action: ElicitationAction::Accept,
130+             content,
131+         })
132+     }
   |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/client.rs:152:5
    |
152 | /     fn create_message(
153 | |         &self,
154 | |         params: CreateMessageRequestParams,
155 | |         _cx: RequestContext<RoleClient>,
156 | |     ) -> impl Future<Output = Result<CreateMessageResult, ErrorData>> + Send + '_ {
    | |_________________________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
152 ~     async fn create_message(
153 +         &self,
154 +         params: CreateMessageRequestParams,
155 +         _cx: RequestContext<RoleClient>,
156 ~     ) -> Result<CreateMessageResult, ErrorData> {
157 +         let prompt_text = params
158 +             .messages
159 +             .first()
160 +             .and_then(|m| m.content.first())
161 +             .and_then(|c| c.as_text())
162 +             .map(|t| t.text.clone())
163 +             .unwrap_or_default();
164 +         Ok(CreateMessageResult::new(
165 +             SamplingMessage::new(
166 +                 Role::Assistant,
167 +                 SamplingMessageContent::text(format!(
168 +                     "This is a mock LLM response to: {}",
169 +                     prompt_text
170 +                 )),
171 +             ),
172 +             "mock-model".into(),
173 +         )
174 +         .with_stop_reason("endTurn"))
175 +     }
    |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/client.rs:179:5
    |
179 | /     fn create_elicitation(
180 | |         &self,
181 | |         _request: CreateElicitationRequestParams,
182 | |         _cx: RequestContext<RoleClient>,
183 | |     ) -> impl Future<Output = Result<CreateElicitationResult, ErrorData>> + Send + '_ {
    | |_____________________________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
179 ~     async fn create_elicitation(
180 +         &self,
181 +         _request: CreateElicitationRequestParams,
182 +         _cx: RequestContext<RoleClient>,
183 ~     ) -> Result<CreateElicitationResult, ErrorData> {
184 +         Ok(CreateElicitationResult {
185 +             action: ElicitationAction::Accept,
186 +             content: Some(json!({"username": "testuser", "email": "test@example.com"})),
187 +         })
188 +     }
    |

warning: this `let...else` may be rewritten with the `?` operator
   --> conformance/src/bin/client.rs:764:5
    |
764 | /     let Some(properties) = properties else {
765 | |         return None;
766 | |     };
    | |______^ help: replace it with: `let properties = properties?;`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
    = note: `#[warn(clippy::question_mark)]` on by default

warning: `mcp-conformance` (bin "conformance-client") generated 4 warnings (run `cargo clippy --fix --bin "conformance-client"` to apply 3 suggestions)
warning: doc list item without indentation
 --> examples/servers/src/elicitation_enum_inference.rs:8:5
  |
8 | //! For more details, see: https://docs.rs/schemars/latest/schemars/
  |     ^
  |
  = help: if this is supposed to be its own paragraph, add a blank line
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation
  = note: `#[warn(clippy::doc_lazy_continuation)]` on by default
help: indent this line
  |
8 | //!   For more details, see: https://docs.rs/schemars/latest/schemars/
  |     ++

warning: `mcp-server-examples` (example "elicitation_enum_select") generated 1 warning
warning: `mcp-server-examples` (example "servers_complex_auth_streamhttp") generated 3 warnings (3 duplicates)
warning: `mcp-conformance` (bin "conformance-client" test) generated 4 warnings (4 duplicates)
warning: this function can be simplified using the `async fn` syntax
  --> conformance/src/bin/server.rs:45:5
   |
45 | /     fn initialize(
46 | |         &self,
47 | |         _request: InitializeRequestParams,
48 | |         _cx: RequestContext<RoleServer>,
49 | |     ) -> impl Future<Output = Result<InitializeResult, ErrorData>> + Send + '_ {
   | |______________________________________________________________________________^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
   = note: `#[warn(clippy::manual_async_fn)]` on by default
help: make the function `async` and return the output of the future directly
   |
45 ~     async fn initialize(
46 +         &self,
47 +         _request: InitializeRequestParams,
48 +         _cx: RequestContext<RoleServer>,
49 ~     ) -> Result<InitializeResult, ErrorData> {
50 +         Ok(InitializeResult::new(
51 +             ServerCapabilities::builder()
52 +                 .enable_prompts()
53 +                 .enable_resources()
54 +                 .enable_tools()
55 +                 .enable_logging()
56 +                 .build(),
57 +         )
58 +         .with_server_info(Implementation::new("rust-conformance-server", "0.1.0"))
59 +         .with_instructions("Rust MCP conformance test server"))
60 +     }
   |

warning: this function can be simplified using the `async fn` syntax
  --> conformance/src/bin/server.rs:64:5
   |
64 | /     fn ping(
65 | |         &self,
66 | |         _cx: RequestContext<RoleServer>,
67 | |     ) -> impl Future<Output = Result<(), ErrorData>> + Send + '_ {
   | |________________________________________________________________^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
   |
64 ~     async fn ping(
65 +         &self,
66 +         _cx: RequestContext<RoleServer>,
67 ~     ) -> Result<(), ErrorData> { Ok(()) }
   |

warning: this function can be simplified using the `async fn` syntax
  --> conformance/src/bin/server.rs:71:5
   |
71 | /     fn list_tools(
72 | |         &self,
73 | |         _request: Option<PaginatedRequestParams>,
74 | |         _cx: RequestContext<RoleServer>,
75 | |     ) -> impl Future<Output = Result<ListToolsResult, ErrorData>> + Send + '_ {
   | |_____________________________________________________________________________^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
   |
71 ~     async fn list_tools(
72 +         &self,
73 +         _request: Option<PaginatedRequestParams>,
74 +         _cx: RequestContext<RoleServer>,
75 ~     ) -> Result<ListToolsResult, ErrorData> {
76 +         let tools = vec![
77 +             Tool::new(
78 +                 "test_simple_text",
79 +                 "Returns simple text content",
80 +                 json_object(json!({
81 +                     "type": "object",
82 +                     "properties": {}
83 +                 })),
84 +             ),
85 +             Tool::new(
86 +                 "test_image_content",
87 +                 "Returns image content",
88 +                 json_object(json!({
89 +                     "type": "object",
90 +                     "properties": {}
91 +                 })),
92 +             ),
93 +             Tool::new(
94 +                 "test_audio_content",
95 +                 "Returns audio content",
96 +                 json_object(json!({
97 +                     "type": "object",
98 +                     "properties": {}
99 +                 })),
100+             ),
101+             Tool::new(
102+                 "test_embedded_resource",
103+                 "Returns embedded resource content",
104+                 json_object(json!({
105+                     "type": "object",
106+                     "properties": {}
107+                 })),
108+             ),
109+             Tool::new(
110+                 "test_multiple_content_types",
111+                 "Returns multiple content types",
112+                 json_object(json!({
113+                     "type": "object",
114+                     "properties": {}
115+                 })),
116+             ),
117+             Tool::new(
118+                 "test_tool_with_logging",
119+                 "Sends logging notifications during execution",
120+                 json_object(json!({
121+                     "type": "object",
122+                     "properties": {}
123+                 })),
124+             ),
125+             Tool::new(
126+                 "test_error_handling",
127+                 "Always returns an error",
128+                 json_object(json!({
129+                     "type": "object",
130+                     "properties": {}
131+                 })),
132+             ),
133+             Tool::new(
134+                 "test_tool_with_progress",
135+                 "Reports progress notifications",
136+                 json_object(json!({
137+                     "type": "object",
138+                     "properties": {}
139+                 })),
140+             ),
141+             Tool::new(
142+                 "test_sampling",
143+                 "Requests LLM sampling from client",
144+                 json_object(json!({
145+                     "type": "object",
146+                     "properties": {
147+                         "prompt": { "type": "string", "description": "The prompt to send" }
148+                     },
149+                     "required": ["prompt"]
150+                 })),
151+             ),
152+             Tool::new(
153+                 "test_elicitation",
154+                 "Requests user input from client",
155+                 json_object(json!({
156+                     "type": "object",
157+                     "properties": {
158+                         "message": { "type": "string", "description": "The message to show" }
159+                     },
160+                     "required": ["message"]
161+                 })),
162+             ),
163+             Tool::new(
164+                 "test_elicitation_sep1034_defaults",
165+                 "Tests elicitation with default values (SEP-1034)",
166+                 json_object(json!({
167+                     "type": "object",
168+                     "properties": {}
169+                 })),
170+             ),
171+             Tool::new(
172+                 "test_elicitation_sep1330_enums",
173+                 "Tests enum schema improvements (SEP-1330)",
174+                 json_object(json!({
175+                     "type": "object",
176+                     "properties": {}
177+                 })),
178+             ),
179+             Tool::new(
180+                 "json_schema_2020_12_tool",
181+                 "Tool with JSON Schema 2020-12 features",
182+                 json_object(json!({
183+                     "$schema": "https://json-schema.org/draft/2020-12/schema",
184+                     "type": "object",
185+                     "$defs": {
186+                         "address": {
187+                             "type": "object",
188+                             "properties": {
189+                                 "street": { "type": "string" },
190+                                 "city": { "type": "string" }
191+                             }
192+                         }
193+                     },
194+                     "properties": {
195+                         "name": { "type": "string" },
196+                         "address": { "$ref": "#/$defs/address" }
197+                     },
198+                     "additionalProperties": false
199+                 })),
200+             ),
201+             Tool::new(
202+                 "test_reconnection",
203+                 "Tests SSE reconnection behavior",
204+                 json_object(json!({
205+                     "type": "object",
206+                     "properties": {}
207+                 })),
208+             ),
209+         ];
210+         Ok(ListToolsResult {
211+             meta: None,
212+             tools,
213+             next_cursor: None,
214+         })
215+     }
   |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/server.rs:219:5
    |
219 | /     fn call_tool(
220 | |         &self,
221 | |         request: CallToolRequestParams,
222 | |         cx: RequestContext<RoleServer>,
223 | |     ) -> impl Future<Output = Result<CallToolResult, ErrorData>> + Send + '_ {
    | |____________________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
219 ~     async fn call_tool(
220 +         &self,
221 +         request: CallToolRequestParams,
222 +         cx: RequestContext<RoleServer>,
223 ~     ) -> Result<CallToolResult, ErrorData> {
224 +         let args = request.arguments.unwrap_or_default();
225 +         match request.name.as_ref() {
226 +             "test_simple_text" => Ok(CallToolResult::success(vec![Content::text(
227 +                 "This is a simple text response for testing.",
228 +             )])),
229 + 
230 +             "test_image_content" => Ok(CallToolResult::success(vec![Content::image(
231 +                 TEST_IMAGE_DATA,
232 +                 "image/png",
233 +             )])),
234 + 
235 +             "test_audio_content" => {
236 +                 // No Content::audio() helper, construct manually
237 +                 let audio = RawContent::Audio(RawAudioContent {
238 +                     data: TEST_AUDIO_DATA.into(),
239 +                     mime_type: "audio/wav".into(),
240 +                 })
241 +                 .no_annotation();
242 +                 Ok(CallToolResult::success(vec![audio]))
243 +             }
244 + 
245 +             "test_embedded_resource" => Ok(CallToolResult::success(vec![Content::resource(
246 +                 ResourceContents::TextResourceContents {
247 +                     uri: "test://embedded-resource".into(),
248 +                     mime_type: Some("text/plain".into()),
249 +                     text: "This is an embedded resource content.".into(),
250 +                     meta: None,
251 +                 },
252 +             )])),
253 + 
254 +             "test_multiple_content_types" => Ok(CallToolResult::success(vec![
255 +                 Content::text("Multiple content types test:"),
256 +                 Content::image(TEST_IMAGE_DATA, "image/png"),
257 +                 Content::resource(ResourceContents::TextResourceContents {
258 +                     uri: "test://mixed-content-resource".into(),
259 +                     mime_type: Some("application/json".into()),
260 +                     text: r#"{"test":"data","value":123}"#.into(),
261 +                     meta: None,
262 +                 }),
263 +             ])),
264 + 
265 +             "test_tool_with_logging" => {
266 +                 for msg in [
267 +                     "Tool execution started",
268 +                     "Tool processing data",
269 +                     "Tool execution completed",
270 +                 ] {
271 +                     let _ = cx
272 +                         .peer
273 +                         .notify_logging_message(LoggingMessageNotificationParam {
274 +                             level: LoggingLevel::Info,
275 +                             logger: Some("conformance-server".into()),
276 +                             data: json!(msg),
277 +                         })
278 +                         .await;
279 +                     tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
280 +                 }
281 + 
282 +                 Ok(CallToolResult::success(vec![Content::text(
283 +                     "Logging test completed",
284 +                 )]))
285 +             }
286 + 
287 +             "test_error_handling" => Ok(CallToolResult::error(vec![Content::text(
288 +                 "This tool intentionally returns an error for testing",
289 +             )])),
290 + 
291 +             "test_tool_with_progress" => {
292 +                 let progress_token = cx.meta.get_progress_token();
293 + 
294 +                 for (progress, message) in
295 +                     [(0.0, "Starting"), (50.0, "Halfway"), (100.0, "Complete")]
296 +                 {
297 +                     if let Some(token) = &progress_token {
298 +                         let _ = cx
299 +                             .peer
300 +                             .notify_progress(ProgressNotificationParam {
301 +                                 progress_token: token.clone(),
302 +                                 progress,
303 +                                 total: Some(100.0),
304 +                                 message: Some(message.into()),
305 +                             })
306 +                             .await;
307 +                     }
308 +                     tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
309 +                 }
310 + 
311 +                 Ok(CallToolResult::success(vec![Content::text(
312 +                     "Progress test completed",
313 +                 )]))
314 +             }
315 + 
316 +             "test_sampling" => {
317 +                 let prompt = args
318 +                     .get("prompt")
319 +                     .and_then(|v| v.as_str())
320 +                     .unwrap_or("Hello");
321 + 
322 +                 match cx
323 +                     .peer
324 +                     .create_message(CreateMessageRequestParams::new(
325 +                         vec![SamplingMessage::user_text(prompt)],
326 +                         100,
327 +                     ))
328 +                     .await
329 +                 {
330 +                     Ok(result) => {
331 +                         let text = result
332 +                             .message
333 +                             .content
334 +                             .first()
335 +                             .and_then(|c| c.as_text())
336 +                             .map(|t| t.text.clone())
337 +                             .unwrap_or_else(|| "No text response".into());
338 +                         Ok(CallToolResult::success(vec![Content::text(format!(
339 +                             "LLM response: {}",
340 +                             text
341 +                         ))]))
342 +                     }
343 +                     Err(e) => Ok(CallToolResult::error(vec![Content::text(format!(
344 +                         "Sampling error: {}",
345 +                         e
346 +                     ))])),
347 +                 }
348 +             }
349 + 
350 +             "test_elicitation" => {
351 +                 let message = args
352 +                     .get("message")
353 +                     .and_then(|v| v.as_str())
354 +                     .unwrap_or("Please provide your information");
355 + 
356 +                 let schema_json = json!({
357 +                     "type": "object",
358 +                     "properties": {
359 +                         "username": {
360 +                             "type": "string",
361 +                             "description": "User's response"
362 +                         },
363 +                         "email": {
364 +                             "type": "string",
365 +                             "description": "User's email address"
366 +                         }
367 +                     },
368 +                     "required": ["username", "email"]
369 +                 });
370 + 
371 +                 let schema: ElicitationSchema = serde_json::from_value(schema_json).unwrap();
372 + 
373 +                 match cx
374 +                     .peer
375 +                     .create_elicitation(CreateElicitationRequestParams::FormElicitationParams {
376 +                         meta: None,
377 +                         message: message.into(),
378 +                         requested_schema: schema,
379 +                     })
380 +                     .await
381 +                 {
382 +                     Ok(result) => Ok(CallToolResult::success(vec![Content::text(format!(
383 +                         "User response: action={}, content={:?}",
384 +                         match result.action {
385 +                             ElicitationAction::Accept => "accept",
386 +                             ElicitationAction::Decline => "decline",
387 +                             ElicitationAction::Cancel => "cancel",
388 +                         },
389 +                         result.content
390 +                     ))])),
391 +                     Err(e) => Ok(CallToolResult::error(vec![Content::text(format!(
392 +                         "Elicitation error: {}",
393 +                         e
394 +                     ))])),
395 +                 }
396 +             }
397 + 
398 +             "test_elicitation_sep1034_defaults" => {
399 +                 let schema_json = json!({
400 +                     "type": "object",
401 +                     "properties": {
402 +                         "name": {
403 +                             "type": "string",
404 +                             "description": "User's name",
405 +                             "default": "John Doe"
406 +                         },
407 +                         "age": {
408 +                             "type": "integer",
409 +                             "description": "User's age",
410 +                             "default": 30
411 +                         },
412 +                         "score": {
413 +                             "type": "number",
414 +                             "description": "User's score",
415 +                             "default": 95.5
416 +                         },
417 +                         "status": {
418 +                             "type": "string",
419 +                             "description": "User's status",
420 +                             "enum": ["active", "inactive", "pending"],
421 +                             "default": "active"
422 +                         },
423 +                         "verified": {
424 +                             "type": "boolean",
425 +                             "description": "Whether user is verified",
426 +                             "default": true
427 +                         }
428 +                     }
429 +                 });
430 + 
431 +                 let schema: ElicitationSchema = serde_json::from_value(schema_json).unwrap();
432 + 
433 +                 match cx
434 +                     .peer
435 +                     .create_elicitation(CreateElicitationRequestParams::FormElicitationParams {
436 +                         meta: None,
437 +                         message: "Please provide values (all have defaults)".into(),
438 +                         requested_schema: schema,
439 +                     })
440 +                     .await
441 +                 {
442 +                     Ok(result) => Ok(CallToolResult::success(vec![Content::text(format!(
443 +                         "Elicitation completed: action={}, content={:?}",
444 +                         match result.action {
445 +                             ElicitationAction::Accept => "accept",
446 +                             ElicitationAction::Decline => "decline",
447 +                             ElicitationAction::Cancel => "cancel",
448 +                         },
449 +                         result.content
450 +                     ))])),
451 +                     Err(e) => Ok(CallToolResult::error(vec![Content::text(format!(
452 +                         "Elicitation error: {}",
453 +                         e
454 +                     ))])),
455 +                 }
456 +             }
457 + 
458 +             "test_elicitation_sep1330_enums" => {
459 +                 let schema_json = json!({
460 +                     "type": "object",
461 +                     "properties": {
462 +                         "untitledSingle": {
463 +                             "type": "string",
464 +                             "enum": ["option1", "option2", "option3"]
465 +                         },
466 +                         "titledSingle": {
467 +                             "type": "string",
468 +                             "oneOf": [
469 +                                 { "const": "value1", "title": "First Option" },
470 +                                 { "const": "value2", "title": "Second Option" },
471 +                                 { "const": "value3", "title": "Third Option" }
472 +                             ]
473 +                         },
474 +                         "legacyEnum": {
475 +                             "type": "string",
476 +                             "enum": ["opt1", "opt2", "opt3"],
477 +                             "enumNames": ["Option One", "Option Two", "Option Three"]
478 +                         },
479 +                         "untitledMulti": {
480 +                             "type": "array",
481 +                             "items": {
482 +                                 "type": "string",
483 +                                 "enum": ["option1", "option2", "option3"]
484 +                             }
485 +                         },
486 +                         "titledMulti": {
487 +                             "type": "array",
488 +                             "items": {
489 +                                 "anyOf": [
490 +                                     { "const": "value1", "title": "First Choice" },
491 +                                     { "const": "value2", "title": "Second Choice" },
492 +                                     { "const": "value3", "title": "Third Choice" }
493 +                                 ]
494 +                             }
495 +                         }
496 +                     }
497 +                 });
498 + 
499 +                 let schema: ElicitationSchema = serde_json::from_value(schema_json).unwrap();
500 + 
501 +                 match cx
502 +                     .peer
503 +                     .create_elicitation(CreateElicitationRequestParams::FormElicitationParams {
504 +                         meta: None,
505 +                         message: "Test enum schema improvements".into(),
506 +                         requested_schema: schema,
507 +                     })
508 +                     .await
509 +                 {
510 +                     Ok(result) => Ok(CallToolResult::success(vec![Content::text(format!(
511 +                         "Enum elicitation completed: action={}",
512 +                         match result.action {
513 +                             ElicitationAction::Accept => "accept",
514 +                             ElicitationAction::Decline => "decline",
515 +                             ElicitationAction::Cancel => "cancel",
516 +                         }
517 +                     ))])),
518 +                     Err(e) => Ok(CallToolResult::error(vec![Content::text(format!(
519 +                         "Elicitation error: {}",
520 +                         e
521 +                     ))])),
522 +                 }
523 +             }
524 + 
525 +             "json_schema_2020_12_tool" => {
526 +                 let name = args.get("name").and_then(|v| v.as_str()).unwrap_or("world");
527 +                 Ok(CallToolResult::success(vec![Content::text(format!(
528 +                     "Hello, {}!",
529 +                     name
530 +                 ))]))
531 +             }
532 + 
533 +             "test_reconnection" => {
534 +                 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
535 +                 Ok(CallToolResult::success(vec![Content::text(
536 +                     "Reconnection test completed",
537 +                 )]))
538 +             }
539 + 
540 +             _ => Err(ErrorData::invalid_params(
541 +                 format!("Unknown tool: {}", request.name),
542 +                 None,
543 +             )),
544 +         }
545 +     }
    |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/server.rs:549:5
    |
549 | /     fn list_resources(
550 | |         &self,
551 | |         _request: Option<PaginatedRequestParams>,
552 | |         _cx: RequestContext<RoleServer>,
553 | |     ) -> impl Future<Output = Result<ListResourcesResult, ErrorData>> + Send + '_ {
    | |_________________________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
549 ~     async fn list_resources(
550 +         &self,
551 +         _request: Option<PaginatedRequestParams>,
552 +         _cx: RequestContext<RoleServer>,
553 ~     ) -> Result<ListResourcesResult, ErrorData> {
554 +         Ok(ListResourcesResult {
555 +             meta: None,
556 +             resources: vec![
557 +                 RawResource {
558 +                     uri: "test://static-text".into(),
559 +                     name: "Static Text Resource".into(),
560 +                     title: None,
561 +                     description: Some("A static text resource for testing".into()),
562 +                     mime_type: Some("text/plain".into()),
563 +                     size: None,
564 +                     icons: None,
565 +                     meta: None,
566 +                 }
567 +                 .no_annotation(),
568 +                 RawResource {
569 +                     uri: "test://static-binary".into(),
570 +                     name: "Static Binary Resource".into(),
571 +                     title: None,
572 +                     description: Some("A static binary/blob resource for testing".into()),
573 +                     mime_type: Some("image/png".into()),
574 +                     size: None,
575 +                     icons: None,
576 +                     meta: None,
577 +                 }
578 +                 .no_annotation(),
579 +             ],
580 +             next_cursor: None,
581 +         })
582 +     }
    |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/server.rs:586:5
    |
586 | /     fn read_resource(
587 | |         &self,
588 | |         request: ReadResourceRequestParams,
589 | |         _cx: RequestContext<RoleServer>,
590 | |     ) -> impl Future<Output = Result<ReadResourceResult, ErrorData>> + Send + '_ {
    | |________________________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
586 ~     async fn read_resource(
587 +         &self,
588 +         request: ReadResourceRequestParams,
589 +         _cx: RequestContext<RoleServer>,
590 ~     ) -> Result<ReadResourceResult, ErrorData> {
591 +         let uri = request.uri.as_str();
592 +         match uri {
593 +             "test://static-text" => Ok(ReadResourceResult::new(vec![
594 +                 ResourceContents::TextResourceContents {
595 +                     uri: uri.into(),
596 +                     mime_type: Some("text/plain".into()),
597 +                     text: "This is the content of the static text resource.".into(),
598 +                     meta: None,
599 +                 },
600 +             ])),
601 +             "test://static-binary" => Ok(ReadResourceResult::new(vec![
602 +                 ResourceContents::BlobResourceContents {
603 +                     uri: uri.into(),
604 +                     mime_type: Some("image/png".into()),
605 +                     blob: TEST_IMAGE_DATA.into(),
606 +                     meta: None,
607 +                 },
608 +             ])),
609 +             _ => {
610 +                 // Check if it matches template: test://template/{id}/data
611 +                 if uri.starts_with("test://template/") && uri.ends_with("/data") {
612 +                     let id = uri
613 +                         .strip_prefix("test://template/")
614 +                         .and_then(|s| s.strip_suffix("/data"))
615 +                         .unwrap_or("unknown");
616 +                     Ok(ReadResourceResult::new(vec![
617 +                         ResourceContents::TextResourceContents {
618 +                             uri: uri.into(),
619 +                             mime_type: Some("application/json".into()),
620 +                             text: format!(
621 +                                 r#"{{"id":"{}","templateTest":true,"data":"Data for ID: {}"}}"#,
622 +                                 id, id
623 +                             ),
624 +                             meta: None,
625 +                         },
626 +                     ]))
627 +                 } else {
628 +                     Err(ErrorData::resource_not_found(
629 +                         format!("Resource not found: {}", uri),
630 +                         None,
631 +                     ))
632 +                 }
633 +             }
634 +         }
635 +     }
    |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/server.rs:639:5
    |
639 | /     fn list_resource_templates(
640 | |         &self,
641 | |         _request: Option<PaginatedRequestParams>,
642 | |         _cx: RequestContext<RoleServer>,
643 | |     ) -> impl Future<Output = Result<ListResourceTemplatesResult, ErrorData>> + Send + '_ {
    | |_________________________________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
639 ~     async fn list_resource_templates(
640 +         &self,
641 +         _request: Option<PaginatedRequestParams>,
642 +         _cx: RequestContext<RoleServer>,
643 ~     ) -> Result<ListResourceTemplatesResult, ErrorData> {
644 +         Ok(ListResourceTemplatesResult {
645 +             meta: None,
646 +             resource_templates: vec![
647 +                 RawResourceTemplate {
648 +                     uri_template: "test://template/{id}/data".into(),
649 +                     name: "Dynamic Resource".into(),
650 +                     title: None,
651 +                     description: Some("A dynamic resource with parameter substitution".into()),
652 +                     mime_type: Some("application/json".into()),
653 +                     icons: None,
654 +                 }
655 +                 .no_annotation(),
656 +             ],
657 +             next_cursor: None,
658 +         })
659 +     }
    |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/server.rs:663:5
    |
663 | /     fn subscribe(
664 | |         &self,
665 | |         request: SubscribeRequestParams,
666 | |         _cx: RequestContext<RoleServer>,
667 | |     ) -> impl Future<Output = Result<(), ErrorData>> + Send + '_ {
    | |________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
663 ~     async fn subscribe(
664 +         &self,
665 +         request: SubscribeRequestParams,
666 +         _cx: RequestContext<RoleServer>,
667 ~     ) -> Result<(), ErrorData> {
668 +         let mut subs = self.subscriptions.lock().await;
669 +         subs.insert(request.uri.to_string());
670 +         Ok(())
671 +     }
    |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/server.rs:675:5
    |
675 | /     fn unsubscribe(
676 | |         &self,
677 | |         request: UnsubscribeRequestParams,
678 | |         _cx: RequestContext<RoleServer>,
679 | |     ) -> impl Future<Output = Result<(), ErrorData>> + Send + '_ {
    | |________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
675 ~     async fn unsubscribe(
676 +         &self,
677 +         request: UnsubscribeRequestParams,
678 +         _cx: RequestContext<RoleServer>,
679 ~     ) -> Result<(), ErrorData> {
680 +         let mut subs = self.subscriptions.lock().await;
681 +         subs.remove(request.uri.as_str());
682 +         Ok(())
683 +     }
    |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/server.rs:687:5
    |
687 | /     fn list_prompts(
688 | |         &self,
689 | |         _request: Option<PaginatedRequestParams>,
690 | |         _cx: RequestContext<RoleServer>,
691 | |     ) -> impl Future<Output = Result<ListPromptsResult, ErrorData>> + Send + '_ {
    | |_______________________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
687 ~     async fn list_prompts(
688 +         &self,
689 +         _request: Option<PaginatedRequestParams>,
690 +         _cx: RequestContext<RoleServer>,
691 ~     ) -> Result<ListPromptsResult, ErrorData> {
692 +         Ok(ListPromptsResult {
693 +             meta: None,
694 +             prompts: vec![
695 +                 Prompt::new(
696 +                     "test_simple_prompt",
697 +                     Some("A simple test prompt with no arguments"),
698 +                     None,
699 +                 ),
700 +                 Prompt::new(
701 +                     "test_prompt_with_arguments",
702 +                     Some("A test prompt that accepts arguments"),
703 +                     Some(vec![
704 +                         PromptArgument::new("name")
705 +                             .with_description("The name to greet")
706 +                             .with_required(true),
707 +                         PromptArgument::new("style")
708 +                             .with_description("The greeting style")
709 +                             .with_required(false),
710 +                     ]),
711 +                 ),
712 +                 Prompt::new(
713 +                     "test_prompt_with_embedded_resource",
714 +                     Some("A test prompt that includes an embedded resource"),
715 +                     None,
716 +                 ),
717 +                 Prompt::new(
718 +                     "test_prompt_with_image",
719 +                     Some("A test prompt that includes an image"),
720 +                     None,
721 +                 ),
722 +             ],
723 +             next_cursor: None,
724 +         })
725 +     }
    |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/server.rs:729:5
    |
729 | /     fn get_prompt(
730 | |         &self,
731 | |         request: GetPromptRequestParams,
732 | |         _cx: RequestContext<RoleServer>,
733 | |     ) -> impl Future<Output = Result<GetPromptResult, ErrorData>> + Send + '_ {
    | |_____________________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
729 ~     async fn get_prompt(
730 +         &self,
731 +         request: GetPromptRequestParams,
732 +         _cx: RequestContext<RoleServer>,
733 ~     ) -> Result<GetPromptResult, ErrorData> {
734 +         match request.name.as_str() {
735 +             "test_simple_prompt" => Ok(GetPromptResult::new(vec![PromptMessage::new_text(
736 +                 PromptMessageRole::User,
737 +                 "This is a simple test prompt.",
738 +             )])
739 +             .with_description("A simple test prompt")),
740 +             "test_prompt_with_arguments" => {
741 +                 let args = request.arguments.unwrap_or_default();
742 +                 let name = args.get("name").and_then(|v| v.as_str()).unwrap_or("World");
743 +                 let style = args
744 +                     .get("style")
745 +                     .and_then(|v| v.as_str())
746 +                     .unwrap_or("friendly");
747 +                 Ok(GetPromptResult::new(vec![PromptMessage::new_text(
748 +                     PromptMessageRole::User,
749 +                     format!("Please greet {} in a {} style.", name, style),
750 +                 )])
751 +                 .with_description("A prompt with arguments"))
752 +             }
753 +             "test_prompt_with_embedded_resource" => Ok(GetPromptResult::new(vec![
754 +                 PromptMessage::new_text(PromptMessageRole::User, "Here is a resource:"),
755 +                 PromptMessage::new_resource(
756 +                     PromptMessageRole::User,
757 +                     "test://static-text".into(),
758 +                     Some("text/plain".into()),
759 +                     Some("Resource content for prompt".into()),
760 +                     None,
761 +                     None,
762 +                     None,
763 +                 ),
764 +             ])
765 +             .with_description("A prompt with an embedded resource")),
766 +             "test_prompt_with_image" => {
767 +                 let image_content = RawImageContent {
768 +                     data: TEST_IMAGE_DATA.into(),
769 +                     mime_type: "image/png".into(),
770 +                     meta: None,
771 +                 };
772 +                 Ok(GetPromptResult::new(vec![
773 +                     PromptMessage::new_text(PromptMessageRole::User, "Here is an image:"),
774 +                     PromptMessage::new(
775 +                         PromptMessageRole::User,
776 +                         PromptMessageContent::Image {
777 +                             image: image_content.no_annotation(),
778 +                         },
779 +                     ),
780 +                 ])
781 +                 .with_description("A prompt with an image"))
782 +             }
783 +             _ => Err(ErrorData::invalid_params(
784 +                 format!("Unknown prompt: {}", request.name),
785 +                 None,
786 +             )),
787 +         }
788 +     }
    |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/server.rs:792:5
    |
792 | /     fn complete(
793 | |         &self,
794 | |         request: CompleteRequestParams,
795 | |         _cx: RequestContext<RoleServer>,
796 | |     ) -> impl Future<Output = Result<CompleteResult, ErrorData>> + Send + '_ {
    | |____________________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
792 ~     async fn complete(
793 +         &self,
794 +         request: CompleteRequestParams,
795 +         _cx: RequestContext<RoleServer>,
796 ~     ) -> Result<CompleteResult, ErrorData> {
797 +         let values = match &request.r#ref {
798 +             Reference::Resource(_) => {
799 +                 if request.argument.name == "id" {
800 +                     vec!["1".into(), "2".into(), "3".into()]
801 +                 } else {
802 +                     vec![]
803 +                 }
804 +             }
805 +             Reference::Prompt(prompt_ref) => {
806 +                 if request.argument.name == "name" {
807 +                     vec!["Alice".into(), "Bob".into(), "Charlie".into()]
808 +                 } else if request.argument.name == "style" {
809 +                     vec!["friendly".into(), "formal".into(), "casual".into()]
810 +                 } else {
811 +                     vec![prompt_ref.name.clone()]
812 +                 }
813 +             }
814 +         };
815 +         Ok(CompleteResult::new(
816 +             CompletionInfo::new(values).map_err(|e| ErrorData::internal_error(e, None))?,
817 +         ))
818 +     }
    |

warning: this function can be simplified using the `async fn` syntax
   --> conformance/src/bin/server.rs:822:5
    |
822 | /     fn set_level(
823 | |         &self,
824 | |         request: SetLevelRequestParams,
825 | |         _cx: RequestContext<RoleServer>,
826 | |     ) -> impl Future<Output = Result<(), ErrorData>> + Send + '_ {
    | |________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
help: make the function `async` and return the output of the future directly
    |
822 ~     async fn set_level(
823 +         &self,
824 +         request: SetLevelRequestParams,
825 +         _cx: RequestContext<RoleServer>,
826 ~     ) -> Result<(), ErrorData> {
827 +         let mut level = self.log_level.lock().await;
828 +         *level = request.level;
829 +         Ok(())
830 +     }
    |

warning: `mcp-conformance` (bin "conformance-server" test) generated 13 warnings (run `cargo clippy --fix --bin "conformance-server" --tests` to apply 13 suggestions)
warning: `mcp-conformance` (bin "conformance-server") generated 13 warnings (13 duplicates)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 11.07s

How Has This Been Tested?

$ cargo clippy --workspace --all-targets --all-features
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.69s

Breaking Changes

No

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

@DaleSeo DaleSeo self-assigned this Mar 11, 2026
@github-actions github-actions bot added T-dependencies Dependencies related changes T-config Configuration file changes T-examples Example code changes T-macros Macro changes labels Mar 11, 2026
@DaleSeo DaleSeo marked this pull request as ready for review March 11, 2026 15:55
@DaleSeo DaleSeo requested a review from a team as a code owner March 11, 2026 15:55
@alexhancock alexhancock merged commit 8700e5c into main Mar 11, 2026
16 checks passed
@alexhancock alexhancock deleted the chore/fix-clippy-warnings branch March 11, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-config Configuration file changes T-dependencies Dependencies related changes T-examples Example code changes T-macros Macro changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants