mcp-server-sqlite 1.0.0

An MCP server for SQLite with fine-grained access control
Documentation
//! The `backup` tool: creates a full backup of the database to a file path
//! using rusqlite's online backup API.

use std::path::PathBuf;

use rmcp::model::{Content, IntoContents};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use super::ToolError;
use crate::{mcp::McpServerSqlite, traits::SqliteServerTool};

#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Hash,
    Default,
    Serialize,
    Deserialize,
    JsonSchema,
)]
/// Back up the entire database to a file. Creates a consistent snapshot of all
/// tables, indexes, triggers, and views at the destination path. The backup
/// runs incrementally in pages so it does not block other operations for long.
pub struct BackupTool;

impl SqliteServerTool for BackupTool {
    const NAME: &str = "backup";

    type Context = McpServerSqlite;
    type Error = ToolError<BackupError>;

    type Input = BackupInput;
    type Output = BackupOutput;

    fn handle(
        ctx: &Self::Context,
        input: Self::Input,
    ) -> Result<Self::Output, Self::Error> {
        let conn = ctx
            .connection()
            .map_err(|source| ToolError::Connection { source })?;

        let mut dst = rusqlite::Connection::open(&input.destination).map_err(
            |source| ToolError::Tool(BackupError::Backup { source }),
        )?;

        let backup = rusqlite::backup::Backup::new(&conn, &mut dst).map_err(
            |source| ToolError::Tool(BackupError::Backup { source }),
        )?;

        backup
            .run_to_completion(5, std::time::Duration::from_millis(50), None)
            .map_err(|source| {
                ToolError::Tool(BackupError::Backup { source })
            })?;

        let pages_copied = backup.progress().pagecount;

        Ok(BackupOutput {
            pages_copied,
            destination: input.destination,
        })
    }
}

/// The input parameters for the `backup` tool.
#[derive(
    Clone,
    Debug,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Hash,
    Serialize,
    Deserialize,
    schemars::JsonSchema,
)]
pub struct BackupInput {
    /// The file path where the backup will be written.
    #[schemars(description = "The file path to write the backup to")]
    pub destination: PathBuf,
}

/// The result of a successful database backup.
#[derive(
    Clone,
    Debug,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Hash,
    Serialize,
    Deserialize,
    schemars::JsonSchema,
)]
pub struct BackupOutput {
    /// The total number of pages copied during the backup.
    pub pages_copied: i32,
    /// The file path the backup was written to.
    pub destination: PathBuf,
}

/// Errors specific to the `backup` tool.
#[derive(Debug, thiserror::Error)]
pub enum BackupError {
    /// The backup operation failed. This may indicate the destination path is
    /// not writable, the disk is full, or an internal SQLite error occurred
    /// during the copy.
    #[error("failed to back up database: {source}")]
    Backup {
        /// The underlying rusqlite error.
        source: rusqlite::Error,
    },
}

/// Converts the backup-specific error into MCP content by rendering the display
/// string as text.
impl IntoContents for BackupError {
    fn into_contents(self) -> Vec<Content> {
        vec![Content::text(self.to_string())]
    }
}