database_mcp_sqlite/
tools.rs1use super::types::{GetTableSchemaRequest, QueryRequest};
8use rmcp::handler::server::tool::ToolRouter;
9use rmcp::handler::server::wrapper::Parameters;
10use rmcp::model::{CallToolResult, Content, ErrorData};
11use rmcp::tool;
12
13use database_mcp_sql::validation::validate_read_only_with_dialect;
14
15use super::SqliteAdapter;
16
17impl SqliteAdapter {
18 const WRITE_TOOL_NAMES: &[&str] = &["write_query"];
20
21 #[must_use]
23 pub fn build_tool_router(&self) -> ToolRouter<Self> {
24 let mut router = Self::tool_router();
25 if self.config.read_only {
26 for name in Self::WRITE_TOOL_NAMES {
27 router.remove_route(name);
28 }
29 }
30 router
31 }
32}
33
34#[rmcp::tool_router]
35impl SqliteAdapter {
36 #[tool(
38 name = "list_tables",
39 annotations(
40 read_only_hint = true,
41 destructive_hint = false,
42 idempotent_hint = true,
43 open_world_hint = false
44 )
45 )]
46 pub async fn tool_list_tables(&self) -> Result<CallToolResult, ErrorData> {
47 let result = self.list_tables().await?;
48 Ok(CallToolResult::success(vec![Content::json(result)?]))
49 }
50
51 #[tool(
54 name = "get_table_schema",
55 annotations(
56 read_only_hint = true,
57 destructive_hint = false,
58 idempotent_hint = true,
59 open_world_hint = false
60 )
61 )]
62 pub async fn tool_get_table_schema(
63 &self,
64 Parameters(request): Parameters<GetTableSchemaRequest>,
65 ) -> Result<CallToolResult, ErrorData> {
66 let result = self.get_table_schema(&request.table_name).await?;
67 Ok(CallToolResult::success(vec![Content::json(result)?]))
68 }
69
70 #[tool(
72 name = "read_query",
73 annotations(
74 read_only_hint = true,
75 destructive_hint = false,
76 idempotent_hint = true,
77 open_world_hint = true
78 )
79 )]
80 pub async fn tool_read_query(
81 &self,
82 Parameters(request): Parameters<QueryRequest>,
83 ) -> Result<CallToolResult, ErrorData> {
84 validate_read_only_with_dialect(&request.query, &sqlparser::dialect::SQLiteDialect {})?;
85
86 let result = self.execute_query(&request.query).await?;
87 Ok(CallToolResult::success(vec![Content::json(result)?]))
88 }
89
90 #[tool(
92 name = "write_query",
93 annotations(
94 read_only_hint = false,
95 destructive_hint = true,
96 idempotent_hint = false,
97 open_world_hint = true
98 )
99 )]
100 pub async fn tool_write_query(
101 &self,
102 Parameters(request): Parameters<QueryRequest>,
103 ) -> Result<CallToolResult, ErrorData> {
104 let result = self.execute_query(&request.query).await?;
105 Ok(CallToolResult::success(vec![Content::json(result)?]))
106 }
107}