chore: add #[non_exhaustive] and mutation methods to improve compatibility (#715)

* chore: add #[non_exhaustive] to reduce backwards-incompatible changes going forward

* fix: remove ProtocolVersion import

* fix: add a few more with_ mutator methods

---------

Co-authored-by: Alex Hancock <alexhancock@block.xyz>
This commit is contained in:
Jack Amadeo 2026-03-03 10:38:01 -05:00 • committed by GitHub
commit f63718d202
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 1568 additions and 1110 deletions

View file

@ -42,9 +42,9 @@ impl ResolvedPromptAttribute {
meta,
} = self;
let description = if let Some(description) = description {
quote! { Some(#description.into()) }
quote! { Some::<String>(#description.into()) }
} else {
quote! { None }
quote! { None::<String> }
};
let title = if let Some(title) = title {
quote! { Some(#title.into()) }
@ -63,14 +63,14 @@ impl ResolvedPromptAttribute {
};
let tokens = quote! {
pub fn #fn_ident() -> rmcp::model::Prompt {
rmcp::model::Prompt {
name: #name.into(),
description: #description,
arguments: #arguments,
title: #title,
icons: #icons,
meta: #meta,
}
rmcp::model::Prompt::from_raw(
#name,
#description,
#arguments,
)
.with_title(#title)
.with_icons(#icons)
.with_meta(#meta)
}
};
syn::parse2::<ImplItemFn>(tokens)

View file

@ -42,23 +42,16 @@ pub fn task_handler(attr: TokenStream, input: TokenStream) -> syn::Result<TokenS
.into_iter()
.map(|task_id| {
let timestamp = rmcp::task_manager::current_timestamp();
rmcp::model::Task {
rmcp::model::Task::new(
task_id,
status: rmcp::model::TaskStatus::Working,
status_message: None,
created_at: timestamp.clone(),
last_updated_at: timestamp,
ttl: None,
poll_interval: None,
}
rmcp::model::TaskStatus::Working,
timestamp.clone(),
timestamp,
)
})
.collect::<Vec<_>>();
Ok(rmcp::model::ListTasksResult {
tasks,
next_cursor: None,
total: Some(total),
})
Ok(rmcp::model::ListTasksResult::new(tasks))
}
};
item_impl.items.push(syn::parse2::<ImplItem>(list_fn)?);
@ -106,17 +99,14 @@ pub fn task_handler(attr: TokenStream, input: TokenStream) -> syn::Result<TokenS
))?;
let timestamp = current_timestamp();
let task = rmcp::model::Task {
let task = rmcp::model::Task::new(
task_id,
status: rmcp::model::TaskStatus::Working,
status_message: Some("Task accepted".to_string()),
created_at: timestamp.clone(),
last_updated_at: timestamp,
ttl: None,
poll_interval: None,
};
rmcp::model::TaskStatus::Working,
timestamp.clone(),
timestamp,
).with_status_message("Task accepted");
Ok(rmcp::model::CreateTaskResult { task })
Ok(rmcp::model::CreateTaskResult::new(task))
}
};
item_impl.items.push(syn::parse2::<ImplItem>(enqueue_fn)?);
@ -151,15 +141,15 @@ pub fn task_handler(attr: TokenStream, input: TokenStream) -> syn::Result<TokenS
Err(_) => rmcp::model::TaskStatus::Failed,
};
let timestamp = current_timestamp();
let task = rmcp::model::Task {
let mut task = rmcp::model::Task::new(
task_id,
status,
status_message: None,
created_at: timestamp.clone(),
last_updated_at: timestamp,
ttl: completed_result.descriptor.ttl,
poll_interval: None,
};
timestamp.clone(),
timestamp,
);
if let Some(ttl) = completed_result.descriptor.ttl {
task = task.with_ttl(ttl);
}
return Ok(rmcp::model::GetTaskResult { meta: None, task });
}
@ -167,15 +157,12 @@ pub fn task_handler(attr: TokenStream, input: TokenStream) -> syn::Result<TokenS
let running = processor.list_running();
if running.into_iter().any(|id| id == task_id) {
let timestamp = current_timestamp();
let task = rmcp::model::Task {
let task = rmcp::model::Task::new(
task_id,
status: rmcp::model::TaskStatus::Working,
status_message: None,
created_at: timestamp.clone(),
last_updated_at: timestamp,
ttl: None,
poll_interval: None,
};
rmcp::model::TaskStatus::Working,
timestamp.clone(),
timestamp,
);
return Ok(rmcp::model::GetTaskResult { meta: None, task });
}
@ -207,7 +194,7 @@ pub fn task_handler(attr: TokenStream, input: TokenStream) -> syn::Result<TokenS
match &tool.result {
Ok(call_tool) => {
let value = ::serde_json::to_value(call_tool).unwrap_or(::serde_json::Value::Null);
return Ok(rmcp::model::GetTaskPayloadResult(value));
return Ok(rmcp::model::GetTaskPayloadResult::new(value));
}
Err(err) => return Err(McpError::internal_error(
format!("task failed: {}", err),
@ -254,15 +241,12 @@ pub fn task_handler(attr: TokenStream, input: TokenStream) -> syn::Result<TokenS
if processor.cancel_task(&task_id) {
let timestamp = current_timestamp();
let task = rmcp::model::Task {
let task = rmcp::model::Task::new(
task_id,
status: rmcp::model::TaskStatus::Cancelled,
status_message: None,
created_at: timestamp.clone(),
last_updated_at: timestamp,
ttl: None,
poll_interval: None,
};
rmcp::model::TaskStatus::Cancelled,
timestamp.clone(),
timestamp,
);
return Ok(rmcp::model::CancelTaskResult { meta: None, task });
}

View file

@ -159,17 +159,17 @@ impl ResolvedToolAttribute {
let tokens = quote! {
#doc_attr
pub fn #fn_ident() -> rmcp::model::Tool {
rmcp::model::Tool {
name: #name.into(),
title: #title,
description: #description,
input_schema: #input_schema,
output_schema: #output_schema,
annotations: #annotations,
execution: #execution,
icons: #icons,
meta: #meta,
}
rmcp::model::Tool::new_with_raw(
#name,
#description,
#input_schema,
)
.with_title(#title)
.with_raw_output_schema(#output_schema)
.with_annotations(#annotations)
.with_execution(#execution)
.with_icons(#icons)
.with_meta(#meta)
}
};
syn::parse2::<ImplItemFn>(tokens)
@ -260,13 +260,13 @@ pub fn tool(attr: TokenStream, input: TokenStream) -> syn::Result<TokenStream> {
let idempotent_hint = wrap_option(idempotent_hint);
let open_world_hint = wrap_option(open_world_hint);
let token_stream = quote! {
Some(rmcp::model::ToolAnnotations {
title: #title,
read_only_hint: #read_only_hint,
destructive_hint: #destructive_hint,
idempotent_hint: #idempotent_hint,
open_world_hint: #open_world_hint,
})
Some(rmcp::model::ToolAnnotations::from_raw(
#title,
#read_only_hint,
#destructive_hint,
#idempotent_hint,
#open_world_hint,
))
};
syn::parse2::<Expr>(token_stream)?
} else {
@ -296,9 +296,9 @@ pub fn tool(attr: TokenStream, input: TokenStream) -> syn::Result<TokenStream> {
};
let token_stream = quote! {
Some(rmcp::model::ToolExecution {
task_support: #task_support_expr,
})
Some(rmcp::model::ToolExecution::from_raw(
#task_support_expr,
))
};
syn::parse2::<Expr>(token_stream)?
} else {