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
This commit is contained in:
Dale Seo 2026-03-26 10:23:58 -04:00 • committed by GitHub
commit 6a3b32d3ab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 430 additions and 211 deletions

View file

@ -252,12 +252,8 @@ async fn perform_oauth_flow_preregistered(
manager.set_metadata(metadata);
// Configure with pre-registered credentials
let config = rmcp::transport::auth::OAuthClientConfig {
client_id: client_id.to_string(),
client_secret: Some(client_secret.to_string()),
scopes: vec![],
redirect_uri: REDIRECT_URI.to_string(),
};
let config = rmcp::transport::auth::OAuthClientConfig::new(client_id, REDIRECT_URI)
.with_client_secret(client_secret);
manager.configure_client(config)?;
let scopes = manager.select_scopes(None, &[]);

View file

@ -818,10 +818,7 @@ async fn main() -> anyhow::Result<()> {
tracing::info!("Starting conformance server on {}", bind_addr);
let server = ConformanceServer::new();
let config = StreamableHttpServerConfig {
stateful_mode: true,
..Default::default()
};
let config = StreamableHttpServerConfig::default();
let service = StreamableHttpService::new(
move || Ok(server.clone()),
LocalSessionManager::default().into(),

View file

@ -9,6 +9,10 @@ readme = { workspace = true }
description = "Rust SDK for Model Context Protocol"
documentation = "https://docs.rs/rmcp"
[lints.clippy]
exhaustive_structs = "warn"
exhaustive_enums = "warn"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

View file

@ -138,6 +138,7 @@ where
}
}
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct Extension<T>(pub T);
impl<C, T> FromContextPart<C> for Extension<T>
@ -182,6 +183,7 @@ where
}
}
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RequestId(pub crate::model::RequestId);
impl<C> FromContextPart<C> for RequestId

View file

@ -20,6 +20,7 @@ use crate::{
};
/// Context for prompt retrieval operations
#[non_exhaustive]
pub struct PromptContext<'a, S> {
pub server: &'a S,
pub name: String,
@ -117,6 +118,7 @@ impl<T: IntoGetPromptResult> IntoGetPromptResult for Result<T, crate::ErrorData>
// Future wrapper that automatically handles IntoGetPromptResult conversion
pin_project_lite::pin_project! {
#[project = IntoGetPromptResultFutProj]
#[non_exhaustive]
pub enum IntoGetPromptResultFut<F, R> {
Pending {
#[pin]
@ -151,6 +153,7 @@ where
}
// Prompt-specific extractor for prompt name
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct PromptName(pub String);
impl<S> FromContextPart<PromptContext<'_, S>> for PromptName {

View file

@ -13,6 +13,7 @@ use crate::{
pub mod prompt;
pub mod tool;
#[non_exhaustive]
pub struct Router<S> {
pub tool_router: tool::ToolRouter<S>,
pub prompt_router: prompt::PromptRouter<S>,

View file

@ -6,6 +6,7 @@ use crate::{
service::{MaybeBoxFuture, MaybeSend},
};
#[non_exhaustive]
pub struct PromptRoute<S> {
#[allow(clippy::type_complexity)]
pub get: Arc<DynGetPromptHandler<S>>,
@ -90,6 +91,7 @@ where
}
/// Adapter for functions generated by the #\[prompt\] macro
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct PromptAttrGenerateFunctionAdapter;
impl<S, F> IntoPromptRoute<S, PromptAttrGenerateFunctionAdapter> for F
@ -103,6 +105,7 @@ where
}
#[derive(Debug)]
#[non_exhaustive]
pub struct PromptRouter<S> {
#[allow(clippy::type_complexity)]
pub map: std::collections::HashMap<Cow<'static, str>, PromptRoute<S>>,

View file

@ -136,6 +136,7 @@ use crate::{
service::{MaybeBoxFuture, MaybeSend},
};
#[non_exhaustive]
pub struct ToolRoute<S> {
#[allow(clippy::type_complexity)]
pub call: Arc<DynCallToolHandler<S>>,
@ -216,6 +217,7 @@ where
}
}
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ToolAttrGenerateFunctionAdapter;
impl<S, F> IntoToolRoute<S, ToolAttrGenerateFunctionAdapter> for F
where
@ -251,6 +253,7 @@ where
}
}
#[non_exhaustive]
pub struct WithToolAttr<C, S, A>
where
C: CallToolHandler<S, A> + MaybeSend + Clone + 'static,
@ -292,6 +295,7 @@ where
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct ToolRouter<S> {
#[allow(clippy::type_complexity)]
pub map: std::collections::HashMap<Cow<'static, str>, ToolRoute<S>>,

View file

@ -29,6 +29,7 @@ pub fn parse_json_object<T: DeserializeOwned>(input: JsonObject) -> Result<T, cr
)
})
}
#[non_exhaustive]
pub struct ToolCallContext<'s, S> {
pub request_context: RequestContext<RoleServer>,
pub service: &'s S,
@ -104,6 +105,7 @@ impl<T: IntoCallToolResult> IntoCallToolResult for Result<T, crate::ErrorData> {
pin_project_lite::pin_project! {
#[project = IntoCallToolResultFutProj]
#[non_exhaustive]
pub enum IntoCallToolResultFut<F, R> {
Pending {
#[pin]
@ -163,6 +165,7 @@ pub type DynCallToolHandler<S> =
-> futures::future::LocalBoxFuture<'s, Result<CallToolResult, crate::ErrorData>>;
// Tool-specific extractor for tool name
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ToolName(pub Cow<'static, str>);
impl<S> FromContextPart<ToolCallContext<'_, S>> for ToolName {

View file

@ -14,6 +14,7 @@ use crate::{
/// serialized as structured JSON content with an associated schema.
/// The framework will place the JSON in the `structured_content` field
/// of the tool result rather than the regular `content` field.
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct Json<T>(pub T);
// Implement JsonSchema for Json<T> to delegate to T's schema

View file

@ -42,6 +42,7 @@ use schemars::JsonSchema;
/// - Returns appropriate error responses if deserialization fails
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct Parameters<P>(pub P);
impl<P: JsonSchema> JsonSchema for Parameters<P> {

View file

@ -58,6 +58,7 @@ macro_rules! object {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, Eq)]
#[serde(deny_unknown_fields)]
#[cfg_attr(feature = "server", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct EmptyObject {}
pub trait ConstString: Default {
@ -70,6 +71,7 @@ pub trait ConstString: Default {
macro_rules! const_string {
($name:ident = $value:literal) => {
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct $name;
impl ConstString for $name {
@ -196,6 +198,7 @@ impl<'de> Deserialize<'de> for ProtocolVersion {
/// This is commonly used for request IDs and other identifiers in JSON-RPC
/// where the specification allows both numeric and string values.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum NumberOrString {
/// A numeric identifier
Number(i64),
@ -292,6 +295,7 @@ pub type RequestId = NumberOrString;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Hash, Eq)]
#[serde(transparent)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ProgressToken(pub NumberOrString);
// =============================================================================
@ -338,6 +342,7 @@ impl<M, P> GetExtensions for Request<M, P> {
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RequestOptionalParam<M = String, P = JsonObject> {
pub method: M,
// #[serde(skip_serializing_if = "Option::is_none")]
@ -361,6 +366,7 @@ impl<M: Default, P> RequestOptionalParam<M, P> {
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RequestNoParam<M = String> {
pub method: M,
/// extensions will carry anything possible in the context, including [`Meta`]
@ -403,6 +409,7 @@ impl<M: Default, P> Notification<M, P> {
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct NotificationNoParam<M = String> {
pub method: M,
/// extensions will carry anything possible in the context, including [`Meta`]
@ -414,6 +421,7 @@ pub struct NotificationNoParam<M = String> {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct JsonRpcRequest<R = Request> {
pub jsonrpc: JsonRpcVersion2_0,
pub id: RequestId,
@ -435,6 +443,7 @@ impl<R> JsonRpcRequest<R> {
type DefaultResponse = JsonObject;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct JsonRpcResponse<R = JsonObject> {
pub jsonrpc: JsonRpcVersion2_0,
pub id: RequestId,
@ -443,6 +452,7 @@ pub struct JsonRpcResponse<R = JsonObject> {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct JsonRpcError {
pub jsonrpc: JsonRpcVersion2_0,
pub id: RequestId,
@ -462,6 +472,7 @@ impl JsonRpcError {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct JsonRpcNotification<N = Notification> {
pub jsonrpc: JsonRpcVersion2_0,
#[serde(flatten)]
@ -475,6 +486,7 @@ pub struct JsonRpcNotification<N = Notification> {
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(transparent)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ErrorCode(pub i32);
impl ErrorCode {
@ -493,6 +505,7 @@ impl ErrorCode {
/// providing a standardized way to communicate errors between clients and servers.
#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ErrorData {
/// The error type that occurred (using standard JSON-RPC error codes)
pub code: ErrorCode,
@ -552,6 +565,7 @@ impl ErrorData {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(untagged)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum JsonRpcMessage<Req = Request, Resp = DefaultResponse, Noti = Notification> {
/// A single request expecting a response
Request(JsonRpcRequest<Req>),
@ -651,6 +665,7 @@ impl From<EmptyResult> for () {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(transparent)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CustomResult(pub Value);
impl CustomResult {
@ -667,6 +682,7 @@ impl CustomResult {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CancelledNotificationParam {
pub request_id: RequestId,
pub reason: Option<String>,
@ -691,6 +707,7 @@ pub type CancelledNotification =
/// deserialize them into domain-specific types.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CustomNotification {
pub method: String,
pub params: Option<Value>,
@ -725,6 +742,7 @@ impl CustomNotification {
/// deserialize them into domain-specific types.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CustomRequest {
pub method: String,
pub params: Option<Value>,
@ -1050,6 +1068,7 @@ const_string!(ProgressNotificationMethod = "notifications/progress");
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ProgressNotificationParam {
pub progress_token: ProgressToken,
/// The progress thus far. This should increase every time progress is made, even if the total is unknown.
@ -1097,6 +1116,7 @@ macro_rules! paginated_result {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct $t {
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
pub meta: Option<Meta>,
@ -1293,6 +1313,7 @@ const_string!(ResourceUpdatedNotificationMethod = "notifications/resources/updat
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ResourceUpdatedNotificationParam {
/// The URI of the resource that was updated
pub uri: String,
@ -1392,6 +1413,7 @@ pub type ToolListChangedNotification = NotificationNoParam<ToolListChangedNotifi
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
#[serde(rename_all = "lowercase")] //match spec
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum LoggingLevel {
Debug,
Info,
@ -1445,6 +1467,7 @@ const_string!(LoggingMessageNotificationMethod = "notifications/message");
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct LoggingMessageNotificationParam {
/// The severity level of this log message
pub level: LoggingLevel,
@ -1490,6 +1513,7 @@ pub type CreateMessageRequest = Request<CreateMessageRequestMethod, CreateMessag
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum Role {
/// A human user or client making a request
User,
@ -1501,6 +1525,7 @@ pub enum Role {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum ToolChoiceMode {
/// Model decides whether to use tools
Auto,
@ -1550,6 +1575,7 @@ impl ToolChoice {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum SamplingContent<T> {
Single(T),
Multiple(Vec<T>),
@ -1665,6 +1691,7 @@ pub struct SamplingMessage {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum SamplingMessageContent {
Text(RawTextContent),
Image(RawImageContent),
@ -1792,6 +1819,7 @@ impl TryFrom<Content> for SamplingContent<SamplingMessageContent> {
/// should be provided to the LLM when processing sampling requests.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum ContextInclusion {
/// Include context from all connected MCP servers
#[serde(rename = "allServers")]
@ -2119,6 +2147,7 @@ impl ModelHint {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CompletionContext {
/// Previously resolved argument values that can inform completion suggestions
#[serde(skip_serializing_if = "Option::is_none")]
@ -2209,6 +2238,7 @@ pub type CompleteRequest = Request<CompleteRequestMethod, CompleteRequestParams>
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CompletionInfo {
pub values: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
@ -2302,6 +2332,7 @@ impl CompleteResult {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(tag = "type")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum Reference {
#[serde(rename = "ref/resource")]
Resource(ResourceReference),
@ -2353,6 +2384,7 @@ impl Reference {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ResourceReference {
pub uri: String,
}
@ -2386,6 +2418,7 @@ const_string!(CompleteRequestMethod = "completion/complete");
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ArgumentInfo {
pub name: String,
pub value: String,
@ -2460,6 +2493,7 @@ const_string!(ElicitationCompletionNotificationMethod = "notifications/elicitati
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum ElicitationAction {
/// User accepts the request and provides the requested information
Accept,
@ -2571,6 +2605,7 @@ impl TryFrom<CreateElicitationRequestParamDeserializeHelper> for CreateElicitati
try_from = "CreateElicitationRequestParamDeserializeHelper"
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum CreateElicitationRequestParams {
#[serde(rename = "form", rename_all = "camelCase")]
FormElicitationParams {
@ -2631,6 +2666,7 @@ pub type CreateElicitationRequestParam = CreateElicitationRequestParams;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CreateElicitationResult {
/// The user's decision on how to handle the elicitation request
pub action: ElicitationAction,
@ -2666,6 +2702,7 @@ pub type CreateElicitationRequest =
#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ElicitationResponseNotificationParam {
pub elicitation_id: String,
}
@ -3032,6 +3069,7 @@ pub type GetTaskInfoRequest = Request<GetTaskInfoMethod, GetTaskInfoParams>;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct GetTaskInfoParams {
/// Protocol-level metadata for this request (SEP-1319)
#[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
@ -3061,6 +3099,7 @@ pub type GetTaskResultRequest = Request<GetTaskResultMethod, GetTaskResultParams
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct GetTaskResultParams {
/// Protocol-level metadata for this request (SEP-1319)
#[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
@ -3087,6 +3126,7 @@ pub type CancelTaskRequest = Request<CancelTaskMethod, CancelTaskParams>;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CancelTaskParams {
/// Protocol-level metadata for this request (SEP-1319)
#[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
@ -3161,6 +3201,7 @@ macro_rules! ts_union {
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum $U {
$($declared)*

View file

@ -39,6 +39,7 @@ impl Annotations {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct Annotated<T: AnnotateAble> {
#[serde(flatten)]
pub raw: T,

View file

@ -34,6 +34,7 @@ pub type ExtensionCapabilities = BTreeMap<String, JsonObject>;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct PromptsCapability {
#[serde(skip_serializing_if = "Option::is_none")]
pub list_changed: Option<bool>,
@ -42,6 +43,7 @@ pub struct PromptsCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ResourcesCapability {
#[serde(skip_serializing_if = "Option::is_none")]
pub subscribe: Option<bool>,
@ -52,6 +54,7 @@ pub struct ResourcesCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ToolsCapability {
#[serde(skip_serializing_if = "Option::is_none")]
pub list_changed: Option<bool>,
@ -60,6 +63,7 @@ pub struct ToolsCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RootsCapabilities {
#[serde(skip_serializing_if = "Option::is_none")]
pub list_changed: Option<bool>,
@ -69,6 +73,7 @@ pub struct RootsCapabilities {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct TasksCapability {
#[serde(skip_serializing_if = "Option::is_none")]
pub requests: Option<TaskRequestsCapability>,
@ -82,6 +87,7 @@ pub struct TasksCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct TaskRequestsCapability {
#[serde(skip_serializing_if = "Option::is_none")]
pub sampling: Option<SamplingTaskCapability>,
@ -94,6 +100,7 @@ pub struct TaskRequestsCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct SamplingTaskCapability {
#[serde(skip_serializing_if = "Option::is_none")]
pub create_message: Option<JsonObject>,
@ -102,6 +109,7 @@ pub struct SamplingTaskCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ElicitationTaskCapability {
#[serde(skip_serializing_if = "Option::is_none")]
pub create: Option<JsonObject>,
@ -110,6 +118,7 @@ pub struct ElicitationTaskCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ToolsTaskCapability {
#[serde(skip_serializing_if = "Option::is_none")]
pub call: Option<JsonObject>,
@ -190,6 +199,7 @@ impl TasksCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct FormElicitationCapability {
/// Whether the client supports JSON Schema validation for elicitation responses.
/// When true, the client will validate user input against the requested_schema
@ -201,6 +211,7 @@ pub struct FormElicitationCapability {
/// Capability for URL mode elicitation.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct UrlElicitationCapability {}
/// Elicitation allows servers to request interactive input from users during tool execution.
@ -209,6 +220,7 @@ pub struct UrlElicitationCapability {}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ElicitationCapability {
/// Whether client supports form-based elicitation.
#[serde(skip_serializing_if = "Option::is_none")]
@ -222,6 +234,7 @@ pub struct ElicitationCapability {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct SamplingCapability {
/// Support for `tools` and `toolChoice` parameters
#[serde(skip_serializing_if = "Option::is_none")]
@ -310,10 +323,12 @@ macro_rules! builder {
($Target: ident {$($f: ident: $T: ty),* $(,)?}) => {
paste! {
#[derive(Default, Clone, Copy, Debug)]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct [<$Target BuilderState>]<
$(const [<$f:upper>]: bool = false,)*
>;
#[derive(Debug, Default)]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct [<$Target Builder>]<S = [<$Target BuilderState>]> {
$(pub $f: Option<$T>,)*
pub state: PhantomData<S>

View file

@ -9,6 +9,7 @@ use super::{AnnotateAble, Annotated, resource::ResourceContents};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RawTextContent {
pub text: String,
/// Optional protocol-level metadata for this content block
@ -19,6 +20,7 @@ pub type TextContent = Annotated<RawTextContent>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RawImageContent {
/// The base64-encoded image
pub data: String,
@ -32,6 +34,7 @@ pub type ImageContent = Annotated<RawImageContent>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RawEmbeddedResource {
/// Optional protocol-level metadata for this content block
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
@ -63,6 +66,7 @@ impl EmbeddedResource {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RawAudioContent {
pub data: String,
pub mime_type: String,
@ -145,6 +149,7 @@ impl ToolResultContent {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum RawContent {
Text(RawTextContent),
Image(RawImageContent),

View file

@ -49,6 +49,7 @@ const_string!(ArrayTypeConst = "array");
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(untagged)]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum PrimitiveSchema {
/// Enum property (explicit enum schema)
Enum(EnumSchema),
@ -70,6 +71,7 @@ pub enum PrimitiveSchema {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "kebab-case")]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum StringFormat {
/// Email address format
Email,
@ -344,6 +346,7 @@ impl NumberSchema {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct IntegerSchema {
/// Type discriminator
#[serde(rename = "type")]
@ -510,6 +513,7 @@ impl BooleanSchema {
/// Represent single entry for titled item
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ConstTitle {
#[serde(rename = "const")]
pub const_: String,
@ -530,6 +534,7 @@ impl ConstTitle {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct LegacyEnumSchema {
#[serde(rename = "type")]
pub type_: StringTypeConst,
@ -595,6 +600,7 @@ impl TitledSingleSelectEnumSchema {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(untagged)]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum SingleSelectEnumSchema {
Untitled(UntitledSingleSelectEnumSchema),
Titled(TitledSingleSelectEnumSchema),
@ -603,6 +609,7 @@ pub enum SingleSelectEnumSchema {
/// Items for untitled multi-select options
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct UntitledItems {
#[serde(rename = "type")]
pub type_: StringTypeConst,
@ -613,6 +620,7 @@ pub struct UntitledItems {
/// Items for titled multi-select options
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct TitledItems {
// MCP spec requires "anyOf" for multi-select enums (allows any combination)
// Alias "oneOf" for compatibility with schemars
@ -718,6 +726,7 @@ impl TitledMultiSelectEnumSchema {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(untagged)]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum MultiSelectEnumSchema {
Untitled(UntitledMultiSelectEnumSchema),
Titled(TitledMultiSelectEnumSchema),
@ -741,6 +750,7 @@ pub enum MultiSelectEnumSchema {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(untagged)]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum EnumSchema {
Single(SingleSelectEnumSchema),
Multi(MultiSelectEnumSchema),
@ -749,9 +759,11 @@ pub enum EnumSchema {
/// Marker type for single-select enum builder
#[derive(Debug)]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct SingleSelect;
/// Marker type for multi-select enum builder
#[derive(Debug)]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct MultiSelect;
/// Builder for EnumSchema
/// Allows to create various enum schema types (single/multi select, titled/untitled)
@ -1077,6 +1089,7 @@ impl EnumSchema {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ElicitationSchema {
/// Always "object" for elicitation schemas
#[serde(rename = "type")]
@ -1221,6 +1234,7 @@ impl ElicitationSchema {
/// .build();
/// ```
#[derive(Debug, Default)]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ElicitationSchemaBuilder {
pub properties: BTreeMap<String, PrimitiveSchema>,
pub required: Vec<String>,

View file

@ -195,6 +195,7 @@ variant_extension! {
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(transparent)]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct Meta(pub JsonObject);
const PROGRESS_TOKEN_FIELD: &str = "progressToken";
impl Meta {

View file

@ -138,6 +138,7 @@ impl PromptArgument {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum PromptMessageRole {
User,
Assistant,
@ -147,6 +148,7 @@ pub enum PromptMessageRole {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum PromptMessageContent {
/// Plain text content
Text { text: String },

View file

@ -6,6 +6,7 @@ use super::{Annotated, Icon, Meta};
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RawResource {
/// URI representing the resource location (e.g., "file:///path/to/file" or "str:///content")
pub uri: String,
@ -39,6 +40,7 @@ pub type Resource = Annotated<RawResource>;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RawResourceTemplate {
pub uri_template: String,
pub name: String,
@ -58,6 +60,7 @@ pub type ResourceTemplate = Annotated<RawResourceTemplate>;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(untagged)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum ResourceContents {
#[serde(rename_all = "camelCase")]
TextResourceContents {

View file

@ -7,6 +7,7 @@ use super::Meta;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum TaskStatus {
/// The receiver accepted the request and is currently working on it.
#[default]
@ -110,6 +111,7 @@ impl CreateTaskResult {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct GetTaskResult {
#[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
pub meta: Option<Meta>,
@ -160,6 +162,7 @@ impl<'de> serde::Deserialize<'de> for GetTaskPayloadResult {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CancelTaskResult {
#[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
pub meta: Option<Meta>,
@ -171,6 +174,7 @@ pub struct CancelTaskResult {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct TaskList {
pub tasks: Vec<Task>,
#[serde(skip_serializing_if = "Option::is_none")]

Some files were not shown because too many files have changed in this diff Show more