mod framing;
mod jsonrpc;
mod mcp;
mod tools;
use std::io::{self, Write};
use std::path::PathBuf;
use std::sync::Arc;
use tracing::{Level, error, info};
use tracing_subscriber::FmtSubscriber;
use toondb::connection::EmbeddedConnection;
use crate::framing::{read_message, write_message_format, WireFormat};
use crate::jsonrpc::{RpcRequest, RpcResponse};
use crate::mcp::McpServer;
fn main() {
let subscriber = FmtSubscriber::builder()
.with_max_level(Level::INFO)
.with_writer(io::stderr)
.finish();
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber");
let args: Vec<String> = std::env::args().collect();
let db_path = args
.iter()
.position(|a| a == "--db")
.and_then(|i| args.get(i + 1))
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("./toondb_data"));
info!("ToonDB MCP server starting, db_path={:?}", db_path);
let conn = match EmbeddedConnection::open(&db_path) {
Ok(c) => Arc::new(c),
Err(e) => {
error!("Failed to open ToonDB: {}", e);
std::process::exit(1);
}
};
let server = McpServer::new(conn);
let stdin = io::stdin();
let mut stdout = io::stdout();
let mut reader = stdin.lock();
#[allow(unused_assignments)]
let mut wire_format = WireFormat::ContentLength;
loop {
let (msg, _format) = match read_message(&mut reader) {
Ok(Some((m, f))) => {
wire_format = f;
(m, f)
}
Ok(None) => {
info!("EOF on stdin, shutting down");
break;
}
Err(e) => {
error!("Failed to read message: {}", e);
continue;
}
};
let req: RpcRequest = match serde_json::from_slice(&msg) {
Ok(r) => r,
Err(e) => {
error!("Invalid JSON-RPC: {}", e);
let resp = RpcResponse::parse_error();
if let Err(e) = write_message_format(&mut stdout, &resp, wire_format) {
error!("Failed to write error response: {}", e);
}
continue;
}
};
let is_notification = req.is_notification();
let resp = server.dispatch(&req);
if !is_notification {
if let Err(e) = write_message_format(&mut stdout, &resp, wire_format) {
error!("Failed to write response: {}", e);
}
if let Err(e) = stdout.flush() {
error!("Failed to flush stdout: {}", e);
}
}
}
info!("ToonDB MCP server shutting down");
}