database_mcp_postgres/tools/
drop_database.rs1use std::borrow::Cow;
4
5use database_mcp_server::AppError;
6use database_mcp_server::types::{DropDatabaseRequest, MessageResponse};
7use database_mcp_sql::identifier::validate_identifier;
8use database_mcp_sql::timeout::execute_with_timeout;
9use rmcp::handler::server::router::tool::{AsyncTool, ToolBase};
10use rmcp::model::{ErrorData, ToolAnnotations};
11
12use crate::PostgresHandler;
13
14pub(crate) struct DropDatabaseTool;
16
17impl DropDatabaseTool {
18 const NAME: &'static str = "drop_database";
19 const DESCRIPTION: &'static str = "Drop an existing database. Cannot drop the currently connected database.";
20}
21
22impl ToolBase for DropDatabaseTool {
23 type Parameter = DropDatabaseRequest;
24 type Output = MessageResponse;
25 type Error = ErrorData;
26
27 fn name() -> Cow<'static, str> {
28 Self::NAME.into()
29 }
30
31 fn description() -> Option<Cow<'static, str>> {
32 Some(Self::DESCRIPTION.into())
33 }
34
35 fn annotations() -> Option<ToolAnnotations> {
36 Some(
37 ToolAnnotations::new()
38 .read_only(false)
39 .destructive(true)
40 .idempotent(false)
41 .open_world(false),
42 )
43 }
44}
45
46impl AsyncTool<PostgresHandler> for DropDatabaseTool {
47 async fn invoke(handler: &PostgresHandler, params: Self::Parameter) -> Result<Self::Output, Self::Error> {
48 Ok(handler.drop_database(¶ms).await?)
49 }
50}
51
52impl PostgresHandler {
53 pub async fn drop_database(&self, request: &DropDatabaseRequest) -> Result<MessageResponse, AppError> {
65 if self.config.read_only {
66 return Err(AppError::ReadOnlyViolation);
67 }
68 let name = &request.database_name;
69 validate_identifier(name)?;
70
71 if self.default_db == *name {
73 return Err(AppError::Query(format!(
74 "Cannot drop the currently connected database '{name}'."
75 )));
76 }
77
78 let pool = self.get_pool(None).await?;
79
80 let drop_sql = format!("DROP DATABASE {}", Self::quote_identifier(name));
81 execute_with_timeout(
82 self.config.query_timeout,
83 &drop_sql,
84 sqlx::query(&drop_sql).execute(&pool),
85 )
86 .await?;
87
88 self.pools.invalidate(name).await;
91
92 Ok(MessageResponse {
93 message: format!("Database '{name}' dropped successfully."),
94 })
95 }
96}