Remove mcp_macros and unused types (#3581)
This commit is contained in:
Generated
-17
@@ -5428,22 +5428,6 @@ dependencies = [
|
|||||||
"utoipa",
|
"utoipa",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mcp-macros"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"async-trait",
|
|
||||||
"convert_case",
|
|
||||||
"mcp-core",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"schemars",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"syn 2.0.99",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mcp-server"
|
name = "mcp-server"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -5452,7 +5436,6 @@ dependencies = [
|
|||||||
"async-trait",
|
"async-trait",
|
||||||
"futures",
|
"futures",
|
||||||
"mcp-core",
|
"mcp-core",
|
||||||
"mcp-macros",
|
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"rmcp",
|
"rmcp",
|
||||||
"schemars",
|
"schemars",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ use goose::permission::permission_confirmation::PrincipalType;
|
|||||||
use goose::providers::base::{ConfigKey, ModelInfo, ProviderMetadata};
|
use goose::providers::base::{ConfigKey, ModelInfo, ProviderMetadata};
|
||||||
use goose::session::info::SessionInfo;
|
use goose::session::info::SessionInfo;
|
||||||
use goose::session::SessionMetadata;
|
use goose::session::SessionMetadata;
|
||||||
use mcp_core::handler::ToolResultSchema;
|
|
||||||
use mcp_core::tool::{Tool, ToolAnnotations};
|
use mcp_core::tool::{Tool, ToolAnnotations};
|
||||||
use rmcp::model::ResourceContents;
|
use rmcp::model::ResourceContents;
|
||||||
use rmcp::model::{Annotations, Content, EmbeddedResource, ImageContent, Role, TextContent};
|
use rmcp::model::{Annotations, Content, EmbeddedResource, ImageContent, Role, TextContent};
|
||||||
@@ -348,7 +347,6 @@ derive_utoipa!(ResourceContents as ResourceContentsSchema);
|
|||||||
TextContentSchema,
|
TextContentSchema,
|
||||||
ToolResponse,
|
ToolResponse,
|
||||||
ToolRequest,
|
ToolRequest,
|
||||||
ToolResultSchema,
|
|
||||||
ToolConfirmationRequest,
|
ToolConfirmationRequest,
|
||||||
ThinkingContent,
|
ThinkingContent,
|
||||||
RedactedThinkingContent,
|
RedactedThinkingContent,
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
use async_trait::async_trait;
|
|
||||||
use schemars::JsonSchema;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
#[allow(unused_imports)] // this is used in schema below
|
#[allow(unused_imports)] // this is used in schema below
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use serde_json::Value;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use utoipa::ToSchema;
|
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Error, Debug, Clone, Deserialize, Serialize, PartialEq)]
|
#[derive(Error, Debug, Clone, Deserialize, Serialize, PartialEq)]
|
||||||
@@ -22,18 +18,6 @@ pub enum ToolError {
|
|||||||
|
|
||||||
pub type ToolResult<T> = std::result::Result<T, ToolError>;
|
pub type ToolResult<T> = std::result::Result<T, ToolError>;
|
||||||
|
|
||||||
// Define schema manually without generics issues
|
|
||||||
#[derive(ToSchema)]
|
|
||||||
#[schema(example = json!({"success": true, "data": {}}))]
|
|
||||||
pub struct ToolResultSchema {
|
|
||||||
#[schema(example = "Operation completed successfully")]
|
|
||||||
pub message: Option<String>,
|
|
||||||
#[schema(example = true)]
|
|
||||||
pub success: bool,
|
|
||||||
#[schema(value_type = Object)]
|
|
||||||
pub data: Option<serde_json::Value>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum ResourceError {
|
pub enum ResourceError {
|
||||||
#[error("Execution failed: {0}")]
|
#[error("Execution failed: {0}")]
|
||||||
@@ -51,38 +35,3 @@ pub enum PromptError {
|
|||||||
#[error("Prompt not found: {0}")]
|
#[error("Prompt not found: {0}")]
|
||||||
NotFound(String),
|
NotFound(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for implementing MCP tools
|
|
||||||
#[async_trait]
|
|
||||||
pub trait ToolHandler: Send + Sync + 'static {
|
|
||||||
/// The name of the tool
|
|
||||||
fn name(&self) -> &'static str;
|
|
||||||
|
|
||||||
/// A description of what the tool does
|
|
||||||
fn description(&self) -> &'static str;
|
|
||||||
|
|
||||||
/// JSON schema describing the tool's parameters
|
|
||||||
fn schema(&self) -> Value;
|
|
||||||
|
|
||||||
/// Execute the tool with the given parameters
|
|
||||||
async fn call(&self, params: Value) -> ToolResult<Value>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait for implementing MCP resources
|
|
||||||
#[async_trait]
|
|
||||||
pub trait ResourceTemplateHandler: Send + Sync + 'static {
|
|
||||||
/// The URL template for this resource
|
|
||||||
fn template() -> &'static str;
|
|
||||||
|
|
||||||
/// JSON schema describing the resource parameters
|
|
||||||
fn schema() -> Value;
|
|
||||||
|
|
||||||
/// Get the resource value
|
|
||||||
async fn get(&self, params: Value) -> ToolResult<String>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper function to generate JSON schema for a type
|
|
||||||
pub fn generate_schema<T: JsonSchema>() -> ToolResult<Value> {
|
|
||||||
let schema = schemars::schema_for!(T);
|
|
||||||
serde_json::to_value(schema).map_err(|e| ToolError::SchemaError(e.to_string()))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "mcp-macros"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
syn = { version = "2.0", features = ["full", "extra-traits"] }
|
|
||||||
quote = "1.0"
|
|
||||||
proc-macro2 = "1.0"
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
serde_json = "1.0"
|
|
||||||
mcp-core = { path = "../mcp-core" }
|
|
||||||
async-trait = "0.1"
|
|
||||||
schemars = "0.8"
|
|
||||||
convert_case = "0.6.0"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
tokio = { version = "1.43", features = ["full"] }
|
|
||||||
async-trait = "0.1"
|
|
||||||
serde_json = "1.0"
|
|
||||||
schemars = "0.8"
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
use mcp_core::handler::{ToolError, ToolHandler};
|
|
||||||
use mcp_macros::tool;
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
|
||||||
// Create an instance of our tool
|
|
||||||
let calculator = Calculator;
|
|
||||||
|
|
||||||
// Print tool information
|
|
||||||
println!("Tool name: {}", calculator.name());
|
|
||||||
println!("Tool description: {}", calculator.description());
|
|
||||||
println!("Tool schema: {}", calculator.schema());
|
|
||||||
|
|
||||||
// Test the tool with some sample input
|
|
||||||
let input = serde_json::json!({
|
|
||||||
"x": 5,
|
|
||||||
"y": 3,
|
|
||||||
"operation": "multiply"
|
|
||||||
});
|
|
||||||
|
|
||||||
let result = calculator.call(input).await?;
|
|
||||||
println!("Result: {}", result);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tool(
|
|
||||||
name = "calculator",
|
|
||||||
description = "Perform basic arithmetic operations",
|
|
||||||
params(
|
|
||||||
x = "First number in the calculation",
|
|
||||||
y = "Second number in the calculation",
|
|
||||||
operation = "The operation to perform (add, subtract, multiply, divide)"
|
|
||||||
)
|
|
||||||
)]
|
|
||||||
async fn calculator(x: i32, y: i32, operation: String) -> Result<i32, ToolError> {
|
|
||||||
match operation.as_str() {
|
|
||||||
"add" => Ok(x + y),
|
|
||||||
"subtract" => Ok(x - y),
|
|
||||||
"multiply" => Ok(x * y),
|
|
||||||
"divide" => {
|
|
||||||
if y == 0 {
|
|
||||||
Err(ToolError::ExecutionError("Division by zero".into()))
|
|
||||||
} else {
|
|
||||||
Ok(x / y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(ToolError::InvalidParameters(format!(
|
|
||||||
"Unknown operation: {}",
|
|
||||||
operation
|
|
||||||
))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
use convert_case::{Case, Casing};
|
|
||||||
use proc_macro::TokenStream;
|
|
||||||
use quote::{format_ident, quote};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use syn::{
|
|
||||||
parse::Parse, parse::ParseStream, parse_macro_input, punctuated::Punctuated, Expr, ExprLit,
|
|
||||||
FnArg, ItemFn, Lit, Meta, Pat, PatType, Token,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MacroArgs {
|
|
||||||
name: Option<String>,
|
|
||||||
description: Option<String>,
|
|
||||||
param_descriptions: HashMap<String, String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for MacroArgs {
|
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
|
||||||
let mut name = None;
|
|
||||||
let mut description = None;
|
|
||||||
let mut param_descriptions = HashMap::new();
|
|
||||||
|
|
||||||
let meta_list: Punctuated<Meta, Token![,]> = Punctuated::parse_terminated(input)?;
|
|
||||||
|
|
||||||
for meta in meta_list {
|
|
||||||
match meta {
|
|
||||||
Meta::NameValue(nv) => {
|
|
||||||
let ident = nv.path.get_ident().unwrap().to_string();
|
|
||||||
if let Expr::Lit(ExprLit {
|
|
||||||
lit: Lit::Str(lit_str),
|
|
||||||
..
|
|
||||||
}) = nv.value
|
|
||||||
{
|
|
||||||
match ident.as_str() {
|
|
||||||
"name" => name = Some(lit_str.value()),
|
|
||||||
"description" => description = Some(lit_str.value()),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Meta::List(list) if list.path.is_ident("params") => {
|
|
||||||
let nested: Punctuated<Meta, Token![,]> =
|
|
||||||
list.parse_args_with(Punctuated::parse_terminated)?;
|
|
||||||
|
|
||||||
for meta in nested {
|
|
||||||
if let Meta::NameValue(nv) = meta {
|
|
||||||
if let Expr::Lit(ExprLit {
|
|
||||||
lit: Lit::Str(lit_str),
|
|
||||||
..
|
|
||||||
}) = nv.value
|
|
||||||
{
|
|
||||||
let param_name = nv.path.get_ident().unwrap().to_string();
|
|
||||||
param_descriptions.insert(param_name, lit_str.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(MacroArgs {
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
param_descriptions,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn tool(args: TokenStream, input: TokenStream) -> TokenStream {
|
|
||||||
let args = parse_macro_input!(args as MacroArgs);
|
|
||||||
let input_fn = parse_macro_input!(input as ItemFn);
|
|
||||||
|
|
||||||
// Extract function details
|
|
||||||
let fn_name = &input_fn.sig.ident;
|
|
||||||
let fn_name_str = fn_name.to_string();
|
|
||||||
|
|
||||||
// Generate PascalCase struct name from the function name
|
|
||||||
let struct_name = format_ident!("{}", { fn_name_str.to_case(Case::Pascal) });
|
|
||||||
|
|
||||||
// Use provided name or function name as default
|
|
||||||
let tool_name = args.name.unwrap_or(fn_name_str);
|
|
||||||
let tool_description = args.description.unwrap_or_default();
|
|
||||||
|
|
||||||
// Extract parameter names, types, and descriptions
|
|
||||||
let mut param_defs = Vec::new();
|
|
||||||
let mut param_names = Vec::new();
|
|
||||||
|
|
||||||
for arg in input_fn.sig.inputs.iter() {
|
|
||||||
if let FnArg::Typed(PatType { pat, ty, .. }) = arg {
|
|
||||||
if let Pat::Ident(param_ident) = &**pat {
|
|
||||||
let param_name = ¶m_ident.ident;
|
|
||||||
let param_name_str = param_name.to_string();
|
|
||||||
let description = args
|
|
||||||
.param_descriptions
|
|
||||||
.get(¶m_name_str)
|
|
||||||
.map(|s| s.as_str())
|
|
||||||
.unwrap_or("");
|
|
||||||
|
|
||||||
param_names.push(param_name);
|
|
||||||
param_defs.push(quote! {
|
|
||||||
#[schemars(description = #description)]
|
|
||||||
#param_name: #ty
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate the implementation
|
|
||||||
let params_struct_name = format_ident!("{}Parameters", struct_name);
|
|
||||||
let expanded = quote! {
|
|
||||||
#[derive(serde::Deserialize, schemars::JsonSchema)]
|
|
||||||
struct #params_struct_name {
|
|
||||||
#(#param_defs,)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#input_fn
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct #struct_name;
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl mcp_core::handler::ToolHandler for #struct_name {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
#tool_name
|
|
||||||
}
|
|
||||||
|
|
||||||
fn description(&self) -> &'static str {
|
|
||||||
#tool_description
|
|
||||||
}
|
|
||||||
|
|
||||||
fn schema(&self) -> serde_json::Value {
|
|
||||||
mcp_core::handler::generate_schema::<#params_struct_name>()
|
|
||||||
.expect("Failed to generate schema")
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn call(&self, params: serde_json::Value) -> Result<serde_json::Value, mcp_core::handler::ToolError> {
|
|
||||||
let params: #params_struct_name = serde_json::from_value(params)
|
|
||||||
.map_err(|e| mcp_core::handler::ToolError::InvalidParameters(e.to_string()))?;
|
|
||||||
|
|
||||||
// Extract parameters and call the function
|
|
||||||
let result = #fn_name(#(params.#param_names,)*).await
|
|
||||||
.map_err(|e| mcp_core::handler::ToolError::ExecutionError(e.to_string()))?;
|
|
||||||
|
|
||||||
Ok(serde_json::to_value(result).expect("should serialize"))
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TokenStream::from(expanded)
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,6 @@ workspace = true
|
|||||||
anyhow = "1.0.94"
|
anyhow = "1.0.94"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
mcp-core = { path = "../mcp-core" }
|
mcp-core = { path = "../mcp-core" }
|
||||||
mcp-macros = { path = "../mcp-macros" }
|
|
||||||
rmcp = { workspace = true }
|
rmcp = { workspace = true }
|
||||||
serde = { version = "1.0.216", features = ["derive"] }
|
serde = { version = "1.0.216", features = ["derive"] }
|
||||||
serde_json = "1.0.133"
|
serde_json = "1.0.133"
|
||||||
|
|||||||
@@ -2975,31 +2975,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ToolResultSchema": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"success",
|
|
||||||
"data"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"data": {
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Operation completed successfully",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"success": {
|
|
||||||
"type": "boolean",
|
|
||||||
"example": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"example": {
|
|
||||||
"data": {},
|
|
||||||
"success": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"UpdateScheduleRequest": {
|
"UpdateScheduleRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
@@ -763,14 +763,6 @@ export type ToolResponse = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ToolResultSchema = {
|
|
||||||
data: {
|
|
||||||
[key: string]: unknown;
|
|
||||||
};
|
|
||||||
message?: string | null;
|
|
||||||
success: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UpdateScheduleRequest = {
|
export type UpdateScheduleRequest = {
|
||||||
cron: string;
|
cron: string;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user