///|
/// Tool handler callback type: receives the arguments JSON and returns a result.
pub type ToolCallback = (Json) -> CallToolResult
///|
/// High-level MCP server builder with ergonomic tool/resource/prompt registration.
pub(all) struct McpServer {
server : Server
mut tools : Array[Tool]
mut tool_callbacks : Map[String, ToolCallback]
}
///|
/// Create a new high-level server builder.
pub fn McpServer::new(name : String, version : String) -> McpServer {
let server = Server::new(name, version).with_tools()
let s : McpServer = { server, tools: [], tool_callbacks: Map([]) }
s.register_builtin_handlers()
s
}
///|
/// Register a tool with its input schema and callback.
pub fn McpServer::tool(
self : McpServer,
name : String,
schema : JsonSchema,
cb : ToolCallback,
) -> McpServer {
let t = Tool::new(name, schema)
self.tools.push(t)
self.tool_callbacks[name] = cb
self
}
///|
/// Register a tool with description.
pub fn McpServer::tool_desc(
self : McpServer,
name : String,
desc : String,
schema : JsonSchema,
cb : ToolCallback,
) -> McpServer {
let t = Tool::new(name, schema)
t.description = Some(desc)
self.tools.push(t)
self.tool_callbacks[name] = cb
self
}
///|
/// Register the built-in tools/list and tools/call handlers on the inner server.
fn McpServer::register_builtin_handlers(self : McpServer) -> Unit {
// tools/list handler
let tools_ref = self.tools
ignore(
self.server.handle_method(method_tools_list, fn(
_params : Json,
_ctx : ServerContext,
) -> Result[Json, McpError] {
let result_obj : Map[String, Json] = Map([])
result_obj["tools"] = tools_to_json(tools_ref)
Ok(Json::object(result_obj))
}),
)
// tools/call handler
let callbacks = self.tool_callbacks
ignore(
self.server.handle_method(method_tools_call, fn(
params : Json,
_ctx : ServerContext,
) -> Result[Json, McpError] {
// params: { "name": "...", "arguments": {...} }
let obj = match params {
Object(o) => o
_ => return Err(InvalidArguments("tools/call params must be an object"))
}
let tool_name = match obj["name"] {
String(s) => s
_ => return Err(InvalidArguments("tools/call requires a 'name' string"))
}
let arguments = obj["arguments"]
match callbacks.get(tool_name) {
Some(cb) => {
let result = cb(arguments)
Ok(result.to_json())
}
None => Err(UnknownTarget("tool: " + tool_name))
}
}),
)
}
///|
/// Process an incoming message (delegate to the inner server).
pub fn McpServer::process_message(self : McpServer, raw : String) -> String? {
self.server.process_message(raw)
}
///|
/// Access the underlying low-level server.
pub fn McpServer::inner(self : McpServer) -> Server {
self.server
}