fix(test): fix tool deserialization error (#68)

This commit is contained in:
4t145 2025-03-31 13:05:35 +08:00 • committed by GitHub
commit 0eea9aad4a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 63 additions and 34 deletions

View file

@ -1,4 +1,4 @@
cargo-features = ["edition2024"]
[workspace] [workspace]
members = ["crates/rmcp", "crates/rmcp-macros", "examples/*"] members = ["crates/rmcp", "crates/rmcp-macros", "examples/*"]

View file

@ -1,4 +1,4 @@
cargo-features = ["edition2024"]
[package] [package]
name = "rmcp-macros" name = "rmcp-macros"

View file

@ -347,7 +347,7 @@ pub(crate) fn tool_fn_item(attr: TokenStream, mut input_fn: ItemFn) -> syn::Resu
#input_fn_vis fn #tool_attr_fn_ident() -> rmcp::model::Tool { #input_fn_vis fn #tool_attr_fn_ident() -> rmcp::model::Tool {
rmcp::model::Tool { rmcp::model::Tool {
name: #name.into(), name: #name.into(),
description: #description.into(), description: Some(#description.into()),
input_schema: #schema.into(), input_schema: #schema.into(),
} }
} }

View file

@ -1,4 +1,4 @@
cargo-features = ["edition2024"]
[package] [package]
name = "rmcp" name = "rmcp"
@ -95,5 +95,5 @@ path = "tests/test_with_python.rs"
[[test]] [[test]]
name = "test_with_js" name = "test_with_js"
required-features = ["server", "transport-sse-server"] required-features = ["server", "client", "transport-sse-server", "transport-child-process"]
path = "tests/test_with_js.rs" path = "tests/test_with_js.rs"

View file

@ -14,7 +14,8 @@ pub struct Tool {
/// The name of the tool /// The name of the tool
pub name: Cow<'static, str>, pub name: Cow<'static, str>,
/// A description of what the tool does /// A description of what the tool does
pub description: Cow<'static, str>, #[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<Cow<'static, str>>,
/// A JSON Schema object defining the expected parameters for the tool /// A JSON Schema object defining the expected parameters for the tool
pub input_schema: Arc<JsonObject>, pub input_schema: Arc<JsonObject>,
} }
@ -29,7 +30,7 @@ impl Tool {
{ {
Tool { Tool {
name: name.into(), name: name.into(),
description: description.into(), description: Some(description.into()),
input_schema: input_schema.into(), input_schema: input_schema.into(),
} }
} }

View file

@ -0,0 +1,15 @@
use rmcp::model::{JsonRpcResponse, ServerJsonRpcMessage, ServerResult};
#[test]
fn test_tool_list_result() {
let json = std::fs::read("tests/test_deserialization/tool_list_result.json").unwrap();
let result: ServerJsonRpcMessage = serde_json::from_slice(&json).unwrap();
println!("{result:#?}");
assert!(matches!(
result,
ServerJsonRpcMessage::Response(JsonRpcResponse {
result: ServerResult::ListToolsResult(_),
..
})
));
}

View file

@ -0,0 +1,28 @@
{
"result": {
"tools": [
{
"name": "add",
"inputSchema": {
"type": "object",
"properties": {
"a": {
"type": "number"
},
"b": {
"type": "number"
}
},
"required": [
"a",
"b"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
]
},
"jsonrpc": "2.0",
"id": 2
}

View file

@ -10,13 +10,13 @@ const BIND_ADDRESS: &str = "127.0.0.1:8000";
#[tokio::test] #[tokio::test]
async fn test_with_js_client() -> anyhow::Result<()> { async fn test_with_js_client() -> anyhow::Result<()> {
tracing_subscriber::registry() let _ = tracing_subscriber::registry()
.with( .with(
tracing_subscriber::EnvFilter::try_from_default_env() tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "debug".to_string().into()), .unwrap_or_else(|_| "debug".to_string().into()),
) )
.with(tracing_subscriber::fmt::layer()) .with(tracing_subscriber::fmt::layer())
.init(); .try_init();
tokio::process::Command::new("npm") tokio::process::Command::new("npm")
.arg("install") .arg("install")
.current_dir("tests/test_with_js") .current_dir("tests/test_with_js")

View file

@ -1,4 +1,4 @@
cargo-features = ["edition2024"]
[package] [package]
name = "mcp-client-examples" name = "mcp-client-examples"

View file

@ -1,5 +1,3 @@
cargo-features = ["edition2024"]
[package] [package]
name = "rig-integration" name = "rig-integration"
edition = { workspace = true } edition = { workspace = true }

View file

@ -1,6 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use rig::tool::{ToolDyn as RigTool, ToolEmbeddingDyn, ToolSet}; use rig::tool::{ToolDyn as RigTool, ToolSet};
use rmcp::{ use rmcp::{
RoleClient, RoleClient,
model::{CallToolRequestParam, CallToolResult, Tool as McpTool}, model::{CallToolRequestParam, CallToolResult, Tool as McpTool},
@ -24,7 +24,12 @@ impl RigTool for McpToolAdaptor {
{ {
Box::pin(std::future::ready(rig::completion::ToolDefinition { Box::pin(std::future::ready(rig::completion::ToolDefinition {
name: self.name(), name: self.name(),
description: self.tool.description.to_string(), description: self
.tool
.description
.as_deref()
.unwrap_or_default()
.to_string(),
parameters: self.tool.schema_as_json_value(), parameters: self.tool.schema_as_json_value(),
})) }))
} }
@ -51,22 +56,6 @@ impl RigTool for McpToolAdaptor {
} }
} }
impl ToolEmbeddingDyn for McpToolAdaptor {
fn embedding_docs(&self) -> Vec<String> {
vec![
self.tool.description.clone().to_string(),
format!("Tool name: {}", self.tool.name),
format!("Tool capability: {}", self.tool.description),
]
}
fn context(&self) -> serde_json::Result<serde_json::Value> {
Ok(serde_json::json!({
"tool_name": self.tool.name,
}))
}
}
pub struct McpManager { pub struct McpManager {
pub clients: HashMap<String, RunningService<RoleClient, ()>>, pub clients: HashMap<String, RunningService<RoleClient, ()>>,
} }

View file

@ -1,4 +1,4 @@
cargo-features = ["edition2024"]
[package] [package]
name = "mcp-server-examples" name = "mcp-server-examples"

View file

@ -1,5 +1,3 @@
cargo-features = ["edition2024"]
[package] [package]
name = "transport" name = "transport"
edition = { workspace = true } edition = { workspace = true }

View file

@ -1,4 +1,4 @@
cargo-features = ["edition2024"]
[package] [package]
name = "wasi" name = "wasi"