mcp_server_sqlite/tools/
describe_table_tool.rs1use rmcp::model::{Content, IntoContents};
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8
9use super::ToolError;
10use crate::{mcp::McpServerSqlite, traits::SqliteServerTool};
11
12#[derive(
13 Clone,
14 Copy,
15 Debug,
16 PartialEq,
17 Eq,
18 PartialOrd,
19 Ord,
20 Hash,
21 Default,
22 Serialize,
23 Deserialize,
24 JsonSchema,
25)]
26pub struct DescribeTableTool;
30
31impl SqliteServerTool for DescribeTableTool {
32 const NAME: &str = "describe_table";
33
34 type Context = McpServerSqlite;
35 type Error = ToolError<DescribeTableError>;
36
37 type Input = DescribeTableInput;
38 type Output = DescribeTableOutput;
39
40 fn handle(
41 ctx: &Self::Context,
42 input: Self::Input,
43 ) -> Result<Self::Output, Self::Error> {
44 let conn = ctx
45 .connection()
46 .map_err(|source| ToolError::Connection { source })?;
47
48 let mut stmt = conn
49 .prepare(&format!(
50 "PRAGMA table_info({})",
51 enquote_identifier(&input.table_name),
52 ))
53 .map_err(|source| {
54 ToolError::Tool(DescribeTableError::Query { source })
55 })?;
56
57 let columns = stmt
58 .query_map([], |row| {
59 Ok(ColumnInfo {
60 name: row.get(1)?,
61 column_type: row.get(2)?,
62 not_null: row.get::<_, i32>(3)? != 0,
63 default_value: row.get(4)?,
64 primary_key: row.get::<_, i32>(5)? != 0,
65 })
66 })
67 .map_err(|source| {
68 ToolError::Tool(DescribeTableError::Query { source })
69 })?
70 .collect::<Result<Vec<_>, _>>()
71 .map_err(|source| {
72 ToolError::Tool(DescribeTableError::Query { source })
73 })?;
74
75 Ok(DescribeTableOutput { columns })
76 }
77}
78
79fn enquote_identifier(name: &str) -> String {
82 format!("\"{}\"", name.replace('"', "\"\""))
83}
84
85#[derive(
87 Clone,
88 Debug,
89 PartialEq,
90 Eq,
91 PartialOrd,
92 Ord,
93 Hash,
94 Serialize,
95 Deserialize,
96 schemars::JsonSchema,
97)]
98pub struct DescribeTableInput {
99 #[schemars(description = "The name of the table to describe")]
101 pub table_name: String,
102}
103
104#[derive(
106 Clone,
107 Debug,
108 PartialEq,
109 Eq,
110 PartialOrd,
111 Ord,
112 Hash,
113 Serialize,
114 Deserialize,
115 schemars::JsonSchema,
116)]
117pub struct DescribeTableOutput {
118 pub columns: Vec<ColumnInfo>,
121}
122
123#[derive(
126 Clone,
127 Debug,
128 PartialEq,
129 Eq,
130 PartialOrd,
131 Ord,
132 Hash,
133 Serialize,
134 Deserialize,
135 schemars::JsonSchema,
136)]
137pub struct ColumnInfo {
138 pub name: String,
140 pub column_type: String,
143 pub not_null: bool,
145 pub default_value: Option<String>,
148 pub primary_key: bool,
150}
151
152#[derive(Debug, thiserror::Error)]
154pub enum DescribeTableError {
155 #[error("failed to describe table: {source}")]
157 Query {
158 source: rusqlite::Error,
160 },
161}
162
163impl IntoContents for DescribeTableError {
166 fn into_contents(self) -> Vec<Content> {
167 vec![Content::text(self.to_string())]
168 }
169}