use crate::bear::BearDatabase;
use rmcp::{
ErrorData as McpError,
handler::server::tool::{Parameters, ToolRouter},
model::*,
tool, tool_handler, tool_router,
};
use std::sync::Arc;
use tokio::sync::Mutex;
#[derive(Clone)]
pub struct BearMcpServer {
bear_database: Arc<Mutex<BearDatabase>>,
tool_router: ToolRouter<Self>,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct SearchRequest {
#[schemars(description = "search query")]
pub query: String,
}
#[tool_router]
impl BearMcpServer {
pub async fn new(db_path: std::path::PathBuf) -> crate::Result<Self> {
let bear_database = Arc::new(Mutex::new(BearDatabase::new(db_path).await?));
Ok(Self {
bear_database,
tool_router: Self::tool_router(),
})
}
#[tool(description = "List all notes")]
async fn get_notes(&self) -> std::result::Result<CallToolResult, McpError> {
#[derive(serde::Serialize)]
struct NotesResponse<T> {
notes: T,
}
let database = self.bear_database.lock().await;
let notes = database.get_notes().await?;
let response = NotesResponse { notes };
Ok(CallToolResult::success(vec![Content::json(&response)?]))
}
#[tool(description = "Search all notes")]
async fn search_notes(
&self,
Parameters(SearchRequest { query }): Parameters<SearchRequest>,
) -> std::result::Result<CallToolResult, McpError> {
#[derive(serde::Serialize)]
struct NotesResponse<T> {
notes: T,
}
let database = self.bear_database.lock().await;
let notes = database
.get_notes_like(&query)
.await?;
let response = NotesResponse { notes };
Ok(CallToolResult::success(vec![Content::json(&response)?]))
}
#[tool(description = "List tags")]
async fn list_tags(&self) -> std::result::Result<CallToolResult, McpError> {
#[derive(serde::Serialize)]
struct TagsResponse<T> {
tags: T,
}
let database = self.bear_database.lock().await;
let tags = database.get_tags().await?;
let response = TagsResponse { tags };
Ok(CallToolResult::success(vec![Content::json(&response)?]))
}
}
#[tool_handler]
impl rmcp::ServerHandler for BearMcpServer {
fn get_info(&self) -> ServerInfo {
ServerInfo {
protocol_version: ProtocolVersion::V_2025_03_26,
capabilities: ServerCapabilities::builder().enable_tools().build(),
server_info: Implementation::from_build_env(),
instructions: Some("A server for notes stored in the Bear app".into()),
}
}
}