Skip to main content

mcp_server_sqlite/tools/
list_tables_tool.rs

1//! The `list_tables` tool: returns the names and schemas of all tables in the
2//! database. Useful for discovery before issuing queries.
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 tables in the database with their names and CREATE TABLE schemas.
26/// Returns an empty list if no tables exist. Useful for discovering the
27/// database structure before writing queries.
28pub struct ListTablesTool;
29
30impl SqliteServerTool for ListTablesTool {
31    const NAME: &str = "list_tables";
32
33    type Context = McpServerSqlite;
34    type Error = ToolError<ListTablesError>;
35
36    type Input = ListTablesInput;
37    type Output = ListTablesOutput;
38
39    fn handle(
40        ctx: &Self::Context,
41        _input: Self::Input,
42    ) -> Result<Self::Output, Self::Error> {
43        let conn = ctx
44            .connection()
45            .map_err(|source| ToolError::Connection { source })?;
46
47        let mut stmt = conn
48            .prepare(
49                "SELECT name, sql FROM sqlite_master \
50                 WHERE type = 'table' ORDER BY name",
51            )
52            .map_err(|source| {
53                ToolError::Tool(ListTablesError::Query { source })
54            })?;
55
56        let tables = stmt
57            .query_map([], |row| {
58                Ok(TableInfo {
59                    name: row.get(0)?,
60                    sql: row.get(1)?,
61                })
62            })
63            .map_err(|source| {
64                ToolError::Tool(ListTablesError::Query { source })
65            })?
66            .collect::<Result<Vec<_>, _>>()
67            .map_err(|source| {
68                ToolError::Tool(ListTablesError::Query { source })
69            })?;
70
71        Ok(ListTablesOutput { tables })
72    }
73}
74
75/// The input parameters for the `list_tables` tool.
76#[derive(
77    Clone,
78    Copy,
79    Debug,
80    Default,
81    PartialEq,
82    Eq,
83    PartialOrd,
84    Ord,
85    Hash,
86    Serialize,
87    Deserialize,
88    schemars::JsonSchema,
89)]
90pub struct ListTablesInput {}
91
92/// The result of listing tables in the database.
93#[derive(
94    Clone,
95    Debug,
96    PartialEq,
97    Eq,
98    PartialOrd,
99    Ord,
100    Hash,
101    Serialize,
102    Deserialize,
103    schemars::JsonSchema,
104)]
105pub struct ListTablesOutput {
106    /// The tables found in the database, each with its name and creation SQL.
107    pub tables: Vec<TableInfo>,
108}
109
110/// Metadata for a single table in the database.
111#[derive(
112    Clone,
113    Debug,
114    PartialEq,
115    Eq,
116    PartialOrd,
117    Ord,
118    Hash,
119    Serialize,
120    Deserialize,
121    schemars::JsonSchema,
122)]
123pub struct TableInfo {
124    /// The table name.
125    pub name: String,
126    /// The `CREATE TABLE` SQL statement that defines this table's schema.
127    /// `None` for internal SQLite tables that have no user-visible DDL.
128    pub sql: Option<String>,
129}
130
131/// Errors specific to the `list_tables` tool.
132#[derive(Debug, thiserror::Error)]
133pub enum ListTablesError {
134    /// Failed to query `sqlite_master` for the table list.
135    #[error("failed to list tables: {source}")]
136    Query {
137        /// The underlying rusqlite error.
138        source: rusqlite::Error,
139    },
140}
141
142/// Converts the list-tables-specific error into MCP content by rendering the
143/// display string as text.
144impl IntoContents for ListTablesError {
145    fn into_contents(self) -> Vec<Content> {
146        vec![Content::text(self.to_string())]
147    }
148}