mcp-server-sqlite 1.0.0

An MCP server for SQLite with fine-grained access control
Documentation
//! The `list_views` tool: returns the names and defining SQL of all views in
//! the database. Useful for discovery before issuing queries against views.

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,
)]
/// List all views in the database with their names and defining SQL statements.
pub struct ListViewsTool;

impl SqliteServerTool for ListViewsTool {
    const NAME: &str = "list_views";

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

    type Input = ListViewsInput;
    type Output = ListViewsOutput;

    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 stmt = conn
            .prepare(
                "SELECT name, sql FROM sqlite_master \
                 WHERE type = 'view' ORDER BY name",
            )
            .map_err(|source| {
                ToolError::Tool(ListViewsError::Query { source })
            })?;

        let views = stmt
            .query_map([], |row| {
                Ok(ViewInfo {
                    name: row.get(0)?,
                    sql: row.get(1)?,
                })
            })
            .map_err(|source| {
                ToolError::Tool(ListViewsError::Query { source })
            })?
            .collect::<Result<Vec<_>, _>>()
            .map_err(|source| {
                ToolError::Tool(ListViewsError::Query { source })
            })?;

        Ok(ListViewsOutput { views })
    }
}

/// The input parameters for the `list_views` tool.
#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Hash,
    Serialize,
    Deserialize,
    schemars::JsonSchema,
)]
pub struct ListViewsInput {}

/// The result of listing views in the database.
#[derive(
    Clone,
    Debug,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Hash,
    Serialize,
    Deserialize,
    schemars::JsonSchema,
)]
pub struct ListViewsOutput {
    /// The views found in the database, each with its name and defining SQL.
    pub views: Vec<ViewInfo>,
}

/// Metadata for a single view in the database.
#[derive(
    Clone,
    Debug,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Hash,
    Serialize,
    Deserialize,
    schemars::JsonSchema,
)]
pub struct ViewInfo {
    /// The view name.
    pub name: String,
    /// The `CREATE VIEW` SQL statement that defines this view.
    pub sql: String,
}

/// Errors specific to the `list_views` tool.
#[derive(Debug, thiserror::Error)]
pub enum ListViewsError {
    /// Failed to query `sqlite_master` for the view list.
    #[error("failed to list views: {source}")]
    Query {
        /// The underlying rusqlite error.
        source: rusqlite::Error,
    },
}

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