fix: strip and validate tool outputSchema and inputSchema (#860)
* fix: remove unnecessary fields from tools' outputSchema * fix: validate input schema root type per MCP spec
This commit is contained in:
parent
8f558d83be
commit
254f04a764
3 changed files with 158 additions and 65 deletions
|
|
@ -1,6 +1,7 @@
|
|||
#![cfg(all(feature = "server", feature = "macros", not(feature = "local")))]
|
||||
|
||||
use rmcp::{
|
||||
Json,
|
||||
handler::server::wrapper::Parameters,
|
||||
model::{ListToolsResult, NumberOrString, ServerJsonRpcMessage, ServerResult},
|
||||
};
|
||||
|
|
@ -14,10 +15,17 @@ struct AddRequest {
|
|||
b: f64,
|
||||
}
|
||||
|
||||
/// Result of adding two numbers.
|
||||
#[derive(Debug, serde::Serialize, schemars::JsonSchema)]
|
||||
struct AddResult {
|
||||
/// The sum of the two numbers.
|
||||
sum: f64,
|
||||
}
|
||||
|
||||
/// Add two numbers.
|
||||
#[rmcp::tool]
|
||||
fn add(Parameters(AddRequest { a, b }): Parameters<AddRequest>) -> String {
|
||||
(a + b).to_string()
|
||||
fn add(Parameters(AddRequest { a, b }): Parameters<AddRequest>) -> Json<AddResult> {
|
||||
Json(AddResult { sum: a + b })
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -27,7 +35,7 @@ fn list_tools_result_matches_expected_json() {
|
|||
let expected: serde_json::Value =
|
||||
serde_json::from_slice(&expected_json).expect("invalid expected JSON fixture");
|
||||
|
||||
assert_eq!(add(Parameters(AddRequest { a: 1.0, b: 2.0 })), "3");
|
||||
assert_eq!(add(Parameters(AddRequest { a: 1.0, b: 2.0 })).0.sum, 3.0);
|
||||
|
||||
let result = ListToolsResult::with_all_items(vec![add_tool_attr()]);
|
||||
let response = ServerJsonRpcMessage::response(
|
||||
|
|
|
|||
|
|
@ -23,6 +23,20 @@
|
|||
"a",
|
||||
"b"
|
||||
]
|
||||
},
|
||||
"outputSchema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sum": {
|
||||
"description": "The sum of the two numbers.",
|
||||
"format": "double",
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"sum"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -28,6 +28,16 @@ pub struct UserInfo {
|
|||
pub age: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GreetingRequest {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GetUserRequest {
|
||||
pub user_id: String,
|
||||
}
|
||||
|
||||
#[tool_handler(router = self.tool_router)]
|
||||
impl ServerHandler for TestServer {}
|
||||
|
||||
|
|
@ -64,14 +74,17 @@ impl TestServer {
|
|||
|
||||
/// Tool that returns regular string output
|
||||
#[tool(name = "get-greeting", description = "Get a greeting")]
|
||||
pub async fn get_greeting(&self, name: Parameters<String>) -> String {
|
||||
format!("Hello, {}!", name.0)
|
||||
pub async fn get_greeting(&self, params: Parameters<GreetingRequest>) -> String {
|
||||
format!("Hello, {}!", params.0.name)
|
||||
}
|
||||
|
||||
/// Tool that returns structured user info
|
||||
#[tool(name = "get-user", description = "Get user info")]
|
||||
pub async fn get_user(&self, user_id: Parameters<String>) -> Result<Json<UserInfo>, String> {
|
||||
if user_id.0 == "123" {
|
||||
pub async fn get_user(
|
||||
&self,
|
||||
params: Parameters<GetUserRequest>,
|
||||
) -> Result<Json<UserInfo>, String> {
|
||||
if params.0.user_id == "123" {
|
||||
Ok(Json(UserInfo {
|
||||
name: "Alice".to_string(),
|
||||
age: 30,
|
||||
|
|
|
|||
Loading…
Reference in a new issue