-
Notifications
You must be signed in to change notification settings - Fork 400
Description
Describe the bug
Hi,
I'm aiming to use this SDK to implement a small server.
I checked the examples for having an idea of how it works and can connect successfully from a client to a server.
But when I try to call the tools/list endpoint from a client like VSCode I get the following error message within VSCode:
MCP server `my-toolbox` has tools with invalid parameters which will be omitted.
The details show:
Tool `say_hello` has invalid JSON parameters:
- Unable to load schema from 'https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema': Not Found. The requested location could not be found.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-in. (at /$schema)
- Schema: {"$schema":"https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema","title":"EmptyObject","type":"object"}
In the debug logs of my server I see the response which is sent to the server:
2025-05-15T19:32:05.705088Z DEBUG rmcp::service: response message id=1 result=ListToolsResult(ListToolsResult { next_cursor: None, tools: [Tool { name: "say_hello", description: Some("Say hello to the client"), input_schema: {"$schema": String("https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema"), "title": String("EmptyObject"), "type": String("object")}, annotations: None }] })
Looks like VSCode tries to lookup the schema and follow the URL, which leads to a 404: https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema
The same is logged when using the MCP inspector and when using either SseServer or StreamableHttpServer.
But the MCP inspector seems to not follow the schema link. And can call the tools/list successfully.
To Reproduce
I've created the following small example to reproduce it:
use rmcp::{
Error as McpError, ServerHandler,
model::{CallToolResult, Content, ServerCapabilities, ServerInfo},
tool,
transport::{SseServer, StreamableHttpServer},
};
use tracing_subscriber::{
layer::SubscriberExt,
util::SubscriberInitExt,
{self},
};
const BIND_ADDRESS: &str = "127.0.0.1:8000";
#[tokio::main]
async fn main() -> anyhow::Result<()> {
/*
// Streamable
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "debug".to_string().into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
let ct = StreamableHttpServer::serve(BIND_ADDRESS.parse()?)
.await?
.with_service(MyToolBox::new);
tokio::signal::ctrl_c().await?;
ct.cancel();
Ok(())*/
// SSE
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "debug".to_string().into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
let ct = SseServer::serve(BIND_ADDRESS.parse()?)
.await?
.with_service(MyToolBox::new);
tokio::signal::ctrl_c().await?;
ct.cancel();
Ok(())
}
#[derive(Debug, Clone)]
pub struct MyToolBox;
#[tool(tool_box)]
impl MyToolBox {
pub fn new() -> Self {
MyToolBox
}
#[tool(description = "Say hello to the client")]
fn say_hello(&self) -> Result<CallToolResult, McpError> {
Ok(CallToolResult::success(vec![Content::text(
"hello".to_string(),
)]))
}
}
#[tool(tool_box)]
impl ServerHandler for MyToolBox {
fn get_info(&self) -> ServerInfo {
ServerInfo {
instructions: Some("My toolbox".into()),
capabilities: ServerCapabilities::builder().enable_tools().build(),
..Default::default()
}
}
}Cargo.toml:
[package]
name = "cargo-fails-vscode"
version = "0.1.0"
edition = "2024"
[dependencies]
rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk", branch = "main", features = ["server", "transport-sse-server", "transport-io", "transport-streamable-http-server", "auth"] }
serde_yaml = "0.9.34"
tokio = {version = "1.45.0", features = ["full"]}
anyhow = "1.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = [
"env-filter",
"std",
"fmt",
] }