Skip to main content

mcp_server_sqlite/tools/
list_views_tool.rs

1//! The `list_views` tool: returns the names and defining SQL of all views in
2//! the database. Useful for discovery before issuing queries against views.
3
4use rmcp::model::{Content, IntoContents};
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7
8use super::ToolError;
9use crate::{mcp::McpServerSqlite, traits::SqliteServerTool};
10
11#[derive(
12    Clone,
13    Copy,
14    Debug,
15    PartialEq,
16    Eq,
17    PartialOrd,
18    Ord,
19    Hash,
20    Default,
21    Serialize,
22    Deserialize,
23    JsonSchema,
24)]
25/// List all views in the database with their names and defining SQL statements.
26pub struct ListViewsTool;
27
28impl SqliteServerTool for ListViewsTool {
29    const NAME: &str = "list_views";
30
31    type Context = McpServerSqlite;
32    type Error = ToolError<ListViewsError>;
33
34    type Input = ListViewsInput;
35    type Output = ListViewsOutput;
36
37    fn handle(
38        ctx: &Self::Context,
39        _input: Self::Input,
40    ) -> Result<Self::Output, Self::Error> {
41        let conn = ctx
42            .connection()
43            .map_err(|source| ToolError::Connection { source })?;
44
45        let mut stmt = conn
46            .prepare(
47                "SELECT name, sql FROM sqlite_master \
48                 WHERE type = 'view' ORDER BY name",
49            )
50            .map_err(|source| {
51                ToolError::Tool(ListViewsError::Query { source })
52            })?;
53
54        let views = stmt
55            .query_map([], |row| {
56                Ok(ViewInfo {
57                    name: row.get(0)?,
58                    sql: row.get(1)?,
59                })
60            })
61            .map_err(|source| {
62                ToolError::Tool(ListViewsError::Query { source })
63            })?
64            .collect::<Result<Vec<_>, _>>()
65            .map_err(|source| {
66                ToolError::Tool(ListViewsError::Query { source })
67            })?;
68
69        Ok(ListViewsOutput { views })
70    }
71}
72
73/// The input parameters for the `list_views` tool.
74#[derive(
75    Clone,
76    Copy,
77    Debug,
78    Default,
79    PartialEq,
80    Eq,
81    PartialOrd,
82    Ord,
83    Hash,
84    Serialize,
85    Deserialize,
86    schemars::JsonSchema,
87)]
88pub struct ListViewsInput {}
89
90/// The result of listing views in the database.
91#[derive(
92    Clone,
93    Debug,
94    PartialEq,
95    Eq,
96    PartialOrd,
97    Ord,
98    Hash,
99    Serialize,
100    Deserialize,
101    schemars::JsonSchema,
102)]
103pub struct ListViewsOutput {
104    /// The views found in the database, each with its name and defining SQL.
105    pub views: Vec<ViewInfo>,
106}
107
108/// Metadata for a single view in the database.
109#[derive(
110    Clone,
111    Debug,
112    PartialEq,
113    Eq,
114    PartialOrd,
115    Ord,
116    Hash,
117    Serialize,
118    Deserialize,
119    schemars::JsonSchema,
120)]
121pub struct ViewInfo {
122    /// The view name.
123    pub name: String,
124    /// The `CREATE VIEW` SQL statement that defines this view.
125    pub sql: String,
126}
127
128/// Errors specific to the `list_views` tool.
129#[derive(Debug, thiserror::Error)]
130pub enum ListViewsError {
131    /// Failed to query `sqlite_master` for the view list.
132    #[error("failed to list views: {source}")]
133    Query {
134        /// The underlying rusqlite error.
135        source: rusqlite::Error,
136    },
137}
138
139/// Converts the list-views-specific error into MCP content by rendering the
140/// display string as text.
141impl IntoContents for ListViewsError {
142    fn into_contents(self) -> Vec<Content> {
143        vec![Content::text(self.to_string())]
144    }
145}