This document summarizes the key changes made to fix the rmcp syntax based on the official examples from the rust-sdk repository.
Before:
use rmcp::{
tool, tool_router,
ErrorData as McpError,
model::{CallToolResult, ServerCapabilities, ServerInfo, TextContent},
handler::server::ServerHandler,
};After:
use rmcp::{
tool, tool_router, tool_handler,
ErrorData as McpError, ServerHandler,
handler::server::{router::tool::ToolRouter, tool::Parameters},
model::{CallToolResult, Content, ServerCapabilities, ServerInfo, ProtocolVersion, Implementation, ErrorCode},
schemars,
};Before:
#[tool(description = "List all available recipes in the justfile")]
async fn list_recipes(
&self,
#[tool(param)]
#[schemars(description = "Optional path to justfile")]
justfile_path: Option<String>
) -> Result<CallToolResult, McpError>After:
// Define parameter struct
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct ListRecipesRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub justfile_path: Option<String>,
}
#[tool(description = "List all available recipes in the justfile")]
async fn list_recipes(
&self,
Parameters(ListRecipesRequest { justfile_path }): Parameters<ListRecipesRequest>
) -> Result<CallToolResult, McpError>Before:
#[derive(Clone)]
pub struct JustMcpServer {
working_dir: std::path::PathBuf,
}After:
#[derive(Clone)]
pub struct JustMcpServer {
working_dir: std::path::PathBuf,
tool_router: ToolRouter<JustMcpServer>,
}
impl JustMcpServer {
pub fn new(working_dir: impl AsRef<Path>) -> Self {
Self {
working_dir: working_dir.as_ref().to_path_buf(),
tool_router: Self::tool_router(),
}
}
}Before:
Ok(CallToolResult {
content: vec![TextContent {
type_: "text".to_string(),
text: content,
}],
is_error: false,
})After:
Ok(CallToolResult::success(vec![Content::text(content)]))
// Or for errors:
Ok(CallToolResult::error(vec![Content::text(content)]))Before:
McpError {
code: -1,
message: err.to_string(),
data: None,
}After:
McpError {
code: ErrorCode(-1),
message: err.to_string().into(),
data: None,
}Before:
impl ServerHandler for JustMcpServer {
fn get_info(&self) -> ServerInfo {
ServerInfo {
instructions: Some("...".to_string()),
capabilities: ServerCapabilities::builder()
.enable_tools()
.build(),
..Default::default()
}
}
}After:
#[tool_handler]
impl ServerHandler for JustMcpServer {
fn get_info(&self) -> ServerInfo {
ServerInfo {
protocol_version: ProtocolVersion::V_2024_11_05,
capabilities: ServerCapabilities::builder()
.enable_tools()
.build(),
server_info: Implementation::from_build_env(),
instructions: Some("...".to_string()),
}
}
}- Parameter Handling: Use dedicated structs with
#[derive(JsonSchema, Deserialize)]and wrap withParameters<T> - Tool Router: Add
tool_router: ToolRouter<Self>field and initialize withSelf::tool_router() - Attributes: Use
#[tool_router]and#[tool_handler]on impl blocks - Content Creation: Use
Content::text()helper instead of manualTextContentconstruction - Result Methods: Use
CallToolResult::success()andCallToolResult::error()helpers
See /examples/mcp_server_demo.rs for a complete working example that demonstrates the corrected syntax.
All tests pass after these changes:
cargo check- No compilation errorscargo build- Successful buildcargo test- All existing tests continue to passcargo run --example mcp_server_demo- Demo runs successfully