feat: Add prompt support (#351)
* feat: add prompt support with typed argument handling - Implement #[prompt], #[prompt_router], and #[prompt_handler] macros - Add automatic JSON schema generation from Rust types for arguments - Support flexible async handler signatures with automatic adaptation - Create PromptRouter for efficient prompt dispatch - Include comprehensive tests and example implementation This enables MCP servers to provide reusable prompt templates that LLMs can discover and invoke with strongly-typed parameters, similar to the existing tool system but optimized for prompt use cases. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * refactor: unify parameter handling between tools and prompts - Replace Arguments<T> with Parameters<T> for consistent API - Create shared common module for tool/prompt utilities - Modernize async handling with futures::future::BoxFuture - Move cached_schema_for_type to common module for reuse - Update error types from rmcp::Error to rmcp::ErrorData - Add comprehensive trait implementations for parameter extraction 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * refactor: extract Parameters wrapper to shared module and unify trait usage - Move Parameters type from common.rs to dedicated wrapper/parameters.rs module - Unify extractor traits by using FromContextPart for both tools and prompts - Remove duplicate FromToolCallContextPart and FromPromptContextPart traits - Add structured output support to Json wrapper with IntoCallToolResult impl - Improve error messages with more descriptive panic for schema serialization - Update all imports across codebase to use new module path - Clean up trailing whitespace and formatting inconsistencies This consolidates parameter extraction logic and reduces code duplication between tool and prompt handlers while maintaining backward compatibility. * chore: remove committed .egg-info directory and update gitignore * docs: fix documentation formatting
This commit is contained in:
parent
c0452f93a4
commit
9349f5cb26
1 changed files with 3191 additions and 464 deletions
65
crates/rmcp-macros/src/common.rs
Normal file
65
crates/rmcp-macros/src/common.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
//! Common utilities shared between different macro implementations
|
||||
|
||||
use quote::quote;
|
||||
use syn::{Attribute, Expr, FnArg, ImplItemFn, Signature, Type};
|
||||
|
||||
/// Parse a None expression
|
||||
pub fn none_expr() -> syn::Result<Expr> {
|
||||
syn::parse2::<Expr>(quote! { None })
|
||||
}
|
||||
|
||||
/// Extract documentation from doc attributes
|
||||
pub fn extract_doc_line(existing_docs: Option<String>, attr: &Attribute) -> Option<String> {
|
||||
if !attr.path().is_ident("doc") {
|
||||
return None;
|
||||
}
|
||||
|
||||
let syn::Meta::NameValue(name_value) = &attr.meta else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let syn::Expr::Lit(expr_lit) = &name_value.value else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let syn::Lit::Str(lit_str) = &expr_lit.lit else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let content = lit_str.value().trim().to_string();
|
||||
match (existing_docs, content) {
|
||||
(Some(mut existing_docs), content) if !content.is_empty() => {
|
||||
existing_docs.push('\n');
|
||||
existing_docs.push_str(&content);
|
||||
Some(existing_docs)
|
||||
}
|
||||
(Some(existing_docs), _) => Some(existing_docs),
|
||||
(None, content) if !content.is_empty() => Some(content),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Find Parameters<T> type in function signature
|
||||
/// Returns the full Parameters<T> type if found
|
||||
pub fn find_parameters_type_in_sig(sig: &Signature) -> Option<Box<Type>> {
|
||||
sig.inputs.iter().find_map(|input| {
|
||||
if let FnArg::Typed(pat_type) = input {
|
||||
if let Type::Path(type_path) = &*pat_type.ty {
|
||||
if type_path
|
||||
.path
|
||||
.segments
|
||||
.last()
|
||||
.is_some_and(|type_name| type_name.ident == "Parameters")
|
||||
{
|
||||
return Some(pat_type.ty.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
/// Find Parameters<T> type in ImplItemFn
|
||||
pub fn find_parameters_type_impl(fn_item: &ImplItemFn) -> Option<Box<Type>> {
|
||||
find_parameters_type_in_sig(&fn_item.sig)
|
||||
}
|
||||
Loading…
Reference in a new issue