database_mcp_sqlite/tools/
write_query.rs1use std::borrow::Cow;
4
5use database_mcp_server::types::QueryResponse;
6
7use database_mcp_sql::Connection as _;
8use database_mcp_sql::SqlError;
9use rmcp::handler::server::router::tool::{AsyncTool, ToolBase};
10use rmcp::model::{ErrorData, ToolAnnotations};
11
12use crate::SqliteHandler;
13use crate::types::QueryRequest;
14
15pub(crate) struct WriteQueryTool;
17
18impl WriteQueryTool {
19 const NAME: &'static str = "writeQuery";
20 const TITLE: &'static str = "Write Query";
21 const DESCRIPTION: &'static str = r#"Execute a write SQL query (INSERT, UPDATE, DELETE, CREATE, ALTER, DROP).
22
23<usecase>
24Use when:
25- Inserting, updating, or deleting rows
26- Creating or altering tables, indexes, views, or other schema objects
27- Any data modification operation
28</usecase>
29
30<when_not_to_use>
31- Read-only queries (SELECT) → use readQuery
32- Query performance analysis → use explainQuery
33</when_not_to_use>
34
35<examples>
36✓ "INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')"
37✓ "UPDATE orders SET status = 'shipped' WHERE id = 42"
38✓ "CREATE TABLE logs (id INTEGER PRIMARY KEY, message TEXT)"
39✗ "SELECT * FROM users" → use readQuery
40</examples>
41
42<what_it_returns>
43A JSON array of affected/returning row objects, each keyed by column name.
44</what_it_returns>"#;
45}
46
47impl ToolBase for WriteQueryTool {
48 type Parameter = QueryRequest;
49 type Output = QueryResponse;
50 type Error = ErrorData;
51
52 fn name() -> Cow<'static, str> {
53 Self::NAME.into()
54 }
55
56 fn title() -> Option<String> {
57 Some(Self::TITLE.into())
58 }
59
60 fn description() -> Option<Cow<'static, str>> {
61 Some(Self::DESCRIPTION.into())
62 }
63
64 fn annotations() -> Option<ToolAnnotations> {
65 Some(
66 ToolAnnotations::new()
67 .read_only(false)
68 .destructive(true)
69 .idempotent(false)
70 .open_world(true),
71 )
72 }
73}
74
75impl AsyncTool<SqliteHandler> for WriteQueryTool {
76 async fn invoke(handler: &SqliteHandler, params: Self::Parameter) -> Result<Self::Output, Self::Error> {
77 Ok(handler.write_query(params).await?)
78 }
79}
80
81impl SqliteHandler {
82 pub async fn write_query(&self, QueryRequest { query }: QueryRequest) -> Result<QueryResponse, SqlError> {
88 let rows = self.connection.fetch_json(query.as_str(), None).await?;
89 Ok(QueryResponse { rows })
90 }
91}