use super::args::*;
use super::tool_impl;
use rmcp::{
ErrorData as McpError, ServerHandler, ServiceExt,
handler::server::{tool::ToolRouter, wrapper::Parameters},
model::{CallToolResult, Implementation, ServerCapabilities, ServerInfo},
tool, tool_handler, tool_router,
transport::stdio,
};
#[derive(Clone)]
pub struct EbookMcp {
tool_router: ToolRouter<Self>,
}
#[tool_router]
impl EbookMcp {
pub fn new() -> Self {
Self {
tool_router: Self::tool_router(),
}
}
#[tool(
name = "read_ebook",
description = "Read an ebook file and extract content/metadata/TOC (supports: epub, pdf, txt, mobi, fb2, azw, cbz)"
)]
async fn read_ebook(
&self,
Parameters(args): Parameters<ReadEbookArgs>,
) -> Result<CallToolResult, McpError> {
Ok(tool_impl::read_ebook(args).await)
}
#[tool(
name = "write_ebook",
description = "Create a new ebook file from text content (supports: epub, pdf, txt, mobi, fb2, azw)"
)]
async fn write_ebook(
&self,
Parameters(args): Parameters<WriteEbookArgs>,
) -> Result<CallToolResult, McpError> {
Ok(tool_impl::write_ebook(args).await)
}
#[tool(name = "extract_images", description = "Extract images from an ebook (EPUB, CBZ)")]
async fn extract_images(
&self,
Parameters(args): Parameters<ExtractImagesArgs>,
) -> Result<CallToolResult, McpError> {
Ok(tool_impl::extract_images(args).await)
}
#[tool(
name = "validate_ebook",
description = "Validate an ebook file structure (supports: epub, pdf, txt, mobi, fb2, azw, cbz)"
)]
async fn validate_ebook(
&self,
Parameters(args): Parameters<ValidateEbookArgs>,
) -> Result<CallToolResult, McpError> {
Ok(tool_impl::validate_ebook(args).await)
}
#[tool(
name = "get_ebook_info",
description = "Get detailed information about an ebook file"
)]
async fn get_ebook_info(
&self,
Parameters(args): Parameters<GetEbookInfoArgs>,
) -> Result<CallToolResult, McpError> {
Ok(tool_impl::get_ebook_info(args).await)
}
#[tool(
name = "convert_ebook",
description = "Convert an ebook from one format to another"
)]
async fn convert_ebook(
&self,
Parameters(args): Parameters<ConvertEbookArgs>,
) -> Result<CallToolResult, McpError> {
Ok(tool_impl::convert_ebook(args).await)
}
#[tool(
name = "optimize_images",
description = "Optimize images in EPUB or CBZ by resizing and compressing"
)]
async fn optimize_images(
&self,
Parameters(args): Parameters<OptimizeImagesArgs>,
) -> Result<CallToolResult, McpError> {
Ok(tool_impl::optimize_images(args).await)
}
}
#[tool_handler]
impl ServerHandler for EbookMcp {
fn get_info(&self) -> ServerInfo {
ServerInfo {
server_info: Implementation {
name: "ebook-mcp".to_string(),
title: Some("ebook MCP".to_string()),
version: env!("CARGO_PKG_VERSION").to_string(),
..Default::default()
},
capabilities: ServerCapabilities::builder().enable_tools().build(),
instructions: Some(
"Read, validate, convert, and author ebook files (EPUB, MOBI, PDF, CBZ, FB2, TXT, AZW). \
Use local absolute paths the host can access."
.to_string(),
),
..Default::default()
}
}
}
impl Default for EbookMcp {
fn default() -> Self {
Self::new()
}
}
pub struct McpServer;
impl McpServer {
pub fn new() -> Self {
Self
}
pub async fn run(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let service = EbookMcp::new().serve(stdio()).await?;
service.waiting().await?;
Ok(())
}
}
impl Default for McpServer {
fn default() -> Self {
Self::new()
}
}