Skip to main content
Glama
nizovtsevnv

Outline knowledge base MCP Server

by nizovtsevnv
mcp.rs5.53 kB
//! MCP (Model Context Protocol) handler //! //! Simple JSON-RPC 2.0 and MCP protocol implementation without complex abstractions. use serde_json::{json, Map, Value}; use tracing::{debug, error}; use crate::error::{Error, Result}; use crate::outline::Client as OutlineClient; use crate::tools; /// Handle MCP request pub async fn handle_request( request: &str, outline_client: &OutlineClient, ) -> Result<Option<String>> { debug!("📨 Received request: {}", request); // Parse JSON-RPC request let request_json: Value = serde_json::from_str(request)?; // Extract main JSON-RPC fields let method = request_json .get("method") .and_then(|v| v.as_str()) .ok_or_else(|| Error::Protocol { protocol: "JSON-RPC".to_string(), message: "Missing 'method' field".to_string(), code: Some(-32600), })?; let params = request_json.get("params").cloned().unwrap_or(Value::Null); let id = request_json.get("id").cloned(); debug!("🔧 Processing method: {}", method); // Dispatch MCP methods let result = match method { // MCP initialization "initialize" => Ok(Some(handle_initialize(params))), // Get tools list "tools/list" => Ok(Some(handle_tools_list(params))), // Call tool "tools/call" => handle_tools_call(params, outline_client).await.map(Some), // Notifications (no response required) "notifications/initialized" => { debug!("🔔 Client initialization notification received"); return Ok(None); // Return None for notifications - no response needed } // Unknown method _ => { error!("❌ Unknown method: {}", method); Err(Error::Protocol { protocol: "MCP".to_string(), message: format!("Unknown method: {method}"), code: Some(-32601), }) } }; // Create JSON-RPC response match result { Ok(Some(result_value)) => { let response = create_success_response(id.as_ref(), &result_value); let response_str = serde_json::to_string(&response)?; debug!("📤 Sending response: {}", response_str); Ok(Some(response_str)) } Ok(None) => { // No response needed (for notifications) Ok(None) } Err(error) => { let response = create_error_response_with_id(id.as_ref(), &error); let response_str = serde_json::to_string(&response)?; debug!("📤 Sending error response: {}", response_str); Ok(Some(response_str)) } } } /// Create success response pub fn create_success_response(id: Option<&Value>, result: &Value) -> Value { id.map_or_else( || { json!({ "jsonrpc": "2.0", "result": result }) }, |id_val| { json!({ "jsonrpc": "2.0", "result": result, "id": id_val }) }, ) } /// Create error response pub fn create_error_response(error: &Error) -> String { let response = json!({ "jsonrpc": "2.0", "error": { "code": -32603, "message": error.to_string() }, "id": null }); serde_json::to_string(&response).unwrap_or_else(|_| { r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error"},"id":null}"# .to_string() }) } /// Create error response with ID pub fn create_error_response_with_id(id: Option<&Value>, error: &Error) -> Value { id.map_or_else( || { json!({ "jsonrpc": "2.0", "error": { "code": -32603, "message": error.to_string() } }) }, |id_val| { json!({ "jsonrpc": "2.0", "error": { "code": -32603, "message": error.to_string() }, "id": id_val }) }, ) } /// Handle MCP initialization fn handle_initialize(_params: Value) -> Value { debug!("🚀 MCP server initialization"); json!({ "protocolVersion": "2025-06-18", "capabilities": { "tools": {} }, "serverInfo": { "name": env!("CARGO_PKG_NAME"), "version": env!("CARGO_PKG_VERSION") } }) } /// Handle tools list request fn handle_tools_list(_params: Value) -> Value { debug!("📋 Getting tools list"); let tools_list = tools::get_tools_list(); json!({ "tools": tools_list }) } /// Handle tool call async fn handle_tools_call(params: Value, outline_client: &OutlineClient) -> Result<Value> { // Extract tool name and arguments let name = params .get("name") .and_then(|v| v.as_str()) .ok_or_else(|| Error::Protocol { protocol: "MCP".to_string(), message: "Missing 'name' parameter".to_string(), code: Some(-32602), })?; let arguments = params .get("arguments") .cloned() .unwrap_or_else(|| Value::Object(Map::new())); debug!("🔨 Calling tool: {}", name); debug!("📊 Arguments: {}", arguments); // Call appropriate tool tools::call_tool(name, arguments, outline_client).await }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nizovtsevnv/outline-mcp-rs'

If you have feedback or need assistance with the MCP directory API, please join our Discord server