Skip to content

Commit 6a3b32d

Browse files
authored
chore: add #[non_exhaustive] to remaining public structs (#768)
* chore: add #[non_exhaustive] to remaining public structs * chore: add #[non_exhaustive] to remaining public types * chore: enable exhaustive_structs/enums clippy lints * test: add untagged ServerResult deserialization regression tests
1 parent ee1c63c commit 6a3b32d

53 files changed

Lines changed: 430 additions & 211 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

conformance/src/bin/client.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,8 @@ async fn perform_oauth_flow_preregistered(
252252
manager.set_metadata(metadata);
253253

254254
// Configure with pre-registered credentials
255-
let config = rmcp::transport::auth::OAuthClientConfig {
256-
client_id: client_id.to_string(),
257-
client_secret: Some(client_secret.to_string()),
258-
scopes: vec![],
259-
redirect_uri: REDIRECT_URI.to_string(),
260-
};
255+
let config = rmcp::transport::auth::OAuthClientConfig::new(client_id, REDIRECT_URI)
256+
.with_client_secret(client_secret);
261257
manager.configure_client(config)?;
262258

263259
let scopes = manager.select_scopes(None, &[]);

conformance/src/bin/server.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -818,10 +818,7 @@ async fn main() -> anyhow::Result<()> {
818818
tracing::info!("Starting conformance server on {}", bind_addr);
819819

820820
let server = ConformanceServer::new();
821-
let config = StreamableHttpServerConfig {
822-
stateful_mode: true,
823-
..Default::default()
824-
};
821+
let config = StreamableHttpServerConfig::default();
825822
let service = StreamableHttpService::new(
826823
move || Ok(server.clone()),
827824
LocalSessionManager::default().into(),

crates/rmcp/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ readme = { workspace = true }
99
description = "Rust SDK for Model Context Protocol"
1010
documentation = "https://docs.rs/rmcp"
1111

12+
[lints.clippy]
13+
exhaustive_structs = "warn"
14+
exhaustive_enums = "warn"
15+
1216
[package.metadata.docs.rs]
1317
all-features = true
1418
rustdoc-args = ["--cfg", "docsrs"]

crates/rmcp/src/handler/server/common.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ where
138138
}
139139
}
140140

141+
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
141142
pub struct Extension<T>(pub T);
142143

143144
impl<C, T> FromContextPart<C> for Extension<T>
@@ -182,6 +183,7 @@ where
182183
}
183184
}
184185

186+
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
185187
pub struct RequestId(pub crate::model::RequestId);
186188

187189
impl<C> FromContextPart<C> for RequestId

crates/rmcp/src/handler/server/prompt.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{
2020
};
2121

2222
/// Context for prompt retrieval operations
23+
#[non_exhaustive]
2324
pub struct PromptContext<'a, S> {
2425
pub server: &'a S,
2526
pub name: String,
@@ -117,6 +118,7 @@ impl<T: IntoGetPromptResult> IntoGetPromptResult for Result<T, crate::ErrorData>
117118
// Future wrapper that automatically handles IntoGetPromptResult conversion
118119
pin_project_lite::pin_project! {
119120
#[project = IntoGetPromptResultFutProj]
121+
#[non_exhaustive]
120122
pub enum IntoGetPromptResultFut<F, R> {
121123
Pending {
122124
#[pin]
@@ -151,6 +153,7 @@ where
151153
}
152154

153155
// Prompt-specific extractor for prompt name
156+
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
154157
pub struct PromptName(pub String);
155158

156159
impl<S> FromContextPart<PromptContext<'_, S>> for PromptName {

crates/rmcp/src/handler/server/router.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::{
1313
pub mod prompt;
1414
pub mod tool;
1515

16+
#[non_exhaustive]
1617
pub struct Router<S> {
1718
pub tool_router: tool::ToolRouter<S>,
1819
pub prompt_router: prompt::PromptRouter<S>,

crates/rmcp/src/handler/server/router/prompt.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
service::{MaybeBoxFuture, MaybeSend},
77
};
88

9+
#[non_exhaustive]
910
pub struct PromptRoute<S> {
1011
#[allow(clippy::type_complexity)]
1112
pub get: Arc<DynGetPromptHandler<S>>,
@@ -90,6 +91,7 @@ where
9091
}
9192

9293
/// Adapter for functions generated by the #\[prompt\] macro
94+
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
9395
pub struct PromptAttrGenerateFunctionAdapter;
9496

9597
impl<S, F> IntoPromptRoute<S, PromptAttrGenerateFunctionAdapter> for F
@@ -103,6 +105,7 @@ where
103105
}
104106

105107
#[derive(Debug)]
108+
#[non_exhaustive]
106109
pub struct PromptRouter<S> {
107110
#[allow(clippy::type_complexity)]
108111
pub map: std::collections::HashMap<Cow<'static, str>, PromptRoute<S>>,

crates/rmcp/src/handler/server/router/tool.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ use crate::{
136136
service::{MaybeBoxFuture, MaybeSend},
137137
};
138138

139+
#[non_exhaustive]
139140
pub struct ToolRoute<S> {
140141
#[allow(clippy::type_complexity)]
141142
pub call: Arc<DynCallToolHandler<S>>,
@@ -216,6 +217,7 @@ where
216217
}
217218
}
218219

220+
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
219221
pub struct ToolAttrGenerateFunctionAdapter;
220222
impl<S, F> IntoToolRoute<S, ToolAttrGenerateFunctionAdapter> for F
221223
where
@@ -251,6 +253,7 @@ where
251253
}
252254
}
253255

256+
#[non_exhaustive]
254257
pub struct WithToolAttr<C, S, A>
255258
where
256259
C: CallToolHandler<S, A> + MaybeSend + Clone + 'static,
@@ -292,6 +295,7 @@ where
292295
}
293296
}
294297
#[derive(Debug)]
298+
#[non_exhaustive]
295299
pub struct ToolRouter<S> {
296300
#[allow(clippy::type_complexity)]
297301
pub map: std::collections::HashMap<Cow<'static, str>, ToolRoute<S>>,

crates/rmcp/src/handler/server/tool.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub fn parse_json_object<T: DeserializeOwned>(input: JsonObject) -> Result<T, cr
2929
)
3030
})
3131
}
32+
#[non_exhaustive]
3233
pub struct ToolCallContext<'s, S> {
3334
pub request_context: RequestContext<RoleServer>,
3435
pub service: &'s S,
@@ -104,6 +105,7 @@ impl<T: IntoCallToolResult> IntoCallToolResult for Result<T, crate::ErrorData> {
104105

105106
pin_project_lite::pin_project! {
106107
#[project = IntoCallToolResultFutProj]
108+
#[non_exhaustive]
107109
pub enum IntoCallToolResultFut<F, R> {
108110
Pending {
109111
#[pin]
@@ -163,6 +165,7 @@ pub type DynCallToolHandler<S> =
163165
-> futures::future::LocalBoxFuture<'s, Result<CallToolResult, crate::ErrorData>>;
164166

165167
// Tool-specific extractor for tool name
168+
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
166169
pub struct ToolName(pub Cow<'static, str>);
167170

168171
impl<S> FromContextPart<ToolCallContext<'_, S>> for ToolName {

crates/rmcp/src/handler/server/wrapper/json.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::{
1414
/// serialized as structured JSON content with an associated schema.
1515
/// The framework will place the JSON in the `structured_content` field
1616
/// of the tool result rather than the regular `content` field.
17+
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
1718
pub struct Json<T>(pub T);
1819

1920
// Implement JsonSchema for Json<T> to delegate to T's schema

0 commit comments

Comments
 (0)