feat: add missing database functions and fix tool errors
Co-authored-by: aider (openai/andrew/openrouter/anthropic/claude-sonnet-4) <aider@aider.chat>
This commit is contained in:
@@ -1,21 +1,8 @@
|
||||
use anyhow::Result;
|
||||
use rmcp::{
|
||||
handler::server::ServerHandler,
|
||||
protocol::{
|
||||
InitializeParams, InitializeResult, ServerCapabilities, ToolsCapability,
|
||||
CallToolParams, CallToolResult, ListToolsParams, ListToolsResult,
|
||||
Tool, TextContent, Content,
|
||||
},
|
||||
};
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use log::{debug, warn};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::modes::server::common::AppState;
|
||||
use crate::db;
|
||||
use super::tools::{KeepTools, ToolError};
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -29,158 +16,19 @@ impl KeepMcpServer {
|
||||
}
|
||||
}
|
||||
|
||||
#[rmcp::async_trait]
|
||||
impl ServerHandler for KeepMcpServer {
|
||||
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
|
||||
debug!("MCP: Initializing Keep MCP server with client info: {:?}", params.client_info);
|
||||
|
||||
Ok(InitializeResult {
|
||||
protocol_version: "2024-11-05".to_string(),
|
||||
capabilities: ServerCapabilities {
|
||||
tools: Some(ToolsCapability {
|
||||
list_changed: Some(false),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
server_info: rmcp::protocol::ServerInfo {
|
||||
name: "keep".to_string(),
|
||||
version: "0.1.0".to_string(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async fn list_tools(&self, _params: ListToolsParams) -> Result<ListToolsResult> {
|
||||
debug!("MCP: Listing available tools");
|
||||
|
||||
let tools = vec![
|
||||
Tool {
|
||||
name: "save_item".to_string(),
|
||||
description: Some("Save content as a new item with optional tags and metadata".to_string()),
|
||||
input_schema: serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "The content to save"
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Optional tags to associate with the item"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": {"type": "string"},
|
||||
"description": "Optional metadata key-value pairs"
|
||||
}
|
||||
},
|
||||
"required": ["content"]
|
||||
}),
|
||||
},
|
||||
Tool {
|
||||
name: "get_item".to_string(),
|
||||
description: Some("Retrieve an item by ID".to_string()),
|
||||
input_schema: serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"description": "The ID of the item to retrieve"
|
||||
}
|
||||
},
|
||||
"required": ["id"]
|
||||
}),
|
||||
},
|
||||
Tool {
|
||||
name: "get_latest_item".to_string(),
|
||||
description: Some("Retrieve the most recently saved item, optionally filtered by tags".to_string()),
|
||||
input_schema: serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Optional tags to filter by - returns latest item with ALL specified tags"
|
||||
}
|
||||
}
|
||||
}),
|
||||
},
|
||||
Tool {
|
||||
name: "list_items".to_string(),
|
||||
description: Some("List stored items with optional filtering and pagination".to_string()),
|
||||
input_schema: serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Optional tags to filter by"
|
||||
},
|
||||
"limit": {
|
||||
"type": "integer",
|
||||
"description": "Maximum number of items to return (default: 10)"
|
||||
},
|
||||
"offset": {
|
||||
"type": "integer",
|
||||
"description": "Number of items to skip (default: 0)"
|
||||
}
|
||||
}
|
||||
}),
|
||||
},
|
||||
Tool {
|
||||
name: "search_items".to_string(),
|
||||
description: Some("Search items by tags and metadata".to_string()),
|
||||
input_schema: serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Tags that items must have (AND operation)"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": {"type": "string"},
|
||||
"description": "Metadata key-value pairs that items must match"
|
||||
}
|
||||
}
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
Ok(ListToolsResult { tools })
|
||||
}
|
||||
|
||||
async fn call_tool(&self, params: CallToolParams) -> Result<CallToolResult> {
|
||||
debug!("MCP: Calling tool '{}' with arguments: {:?}", params.name, params.arguments);
|
||||
impl KeepMcpServer {
|
||||
pub async fn handle_request(&self, method: &str, params: Option<Value>) -> Result<String, ToolError> {
|
||||
debug!("MCP: Handling request '{}' with params: {:?}", method, params);
|
||||
|
||||
let tools = KeepTools::new(self.state.clone());
|
||||
|
||||
let result = match params.name.as_str() {
|
||||
"save_item" => tools.save_item(params.arguments).await,
|
||||
"get_item" => tools.get_item(params.arguments).await,
|
||||
"get_latest_item" => tools.get_latest_item(params.arguments).await,
|
||||
"list_items" => tools.list_items(params.arguments).await,
|
||||
"search_items" => tools.search_items(params.arguments).await,
|
||||
_ => Err(ToolError::UnknownTool(params.name.clone())),
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(content) => Ok(CallToolResult {
|
||||
content: vec![Content::Text(TextContent {
|
||||
text: content,
|
||||
})],
|
||||
is_error: Some(false),
|
||||
}),
|
||||
Err(e) => {
|
||||
warn!("MCP: Tool execution failed: {}", e);
|
||||
Ok(CallToolResult {
|
||||
content: vec![Content::Text(TextContent {
|
||||
text: format!("Error: {}", e),
|
||||
})],
|
||||
is_error: Some(true),
|
||||
})
|
||||
}
|
||||
match method {
|
||||
"save_item" => tools.save_item(params).await,
|
||||
"get_item" => tools.get_item(params).await,
|
||||
"get_latest_item" => tools.get_latest_item(params).await,
|
||||
"list_items" => tools.list_items(params).await,
|
||||
"search_items" => tools.search_items(params).await,
|
||||
_ => Err(ToolError::UnknownTool(method.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user