use rmcp::{
ErrorData as McpError,
handler::server::wrapper::Parameters,
model::*,
tool, tool_router,
};
use serde::Deserialize;
use crate::server::GDriveServer;
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct DrivesCreateParams {
pub name: String,
}
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct DrivesListParams {
#[serde(default)]
pub page_size: Option<i32>,
#[serde(default)]
pub page_token: Option<String>,
#[serde(default)]
pub query: Option<String>,
}
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct DrivesGetParams {
pub drive_id: String,
}
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct DrivesUpdateParams {
pub drive_id: String,
#[serde(default)]
pub name: Option<String>,
}
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct DrivesDeleteParams {
pub drive_id: String,
}
#[tool_router(router = drives_tool_router, vis = "pub")]
impl GDriveServer {
#[tool(name = "gdrive_drives_create")]
async fn drives_create(
&self,
Parameters(params): Parameters<DrivesCreateParams>,
) -> Result<CallToolResult, McpError> {
let mut drive = google_drive3::api::Drive::default();
drive.name = Some(params.name);
let request_id = format!("mcp-{}", std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis());
let (_, result) = self
.client
.hub()
.drives()
.create(drive, &request_id)
.doit()
.await
.map_err(drive_err)?;
let json = serde_json::to_string_pretty(&result)
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
Ok(CallToolResult::success(vec![Content::text(format!(
"Shared drive created:\n{json}"
))]))
}
#[tool(name = "gdrive_drives_list")]
async fn drives_list(
&self,
Parameters(params): Parameters<DrivesListParams>,
) -> Result<CallToolResult, McpError> {
let mut req = self.client.hub().drives().list();
if let Some(ps) = params.page_size {
req = req.page_size(ps);
}
if let Some(pt) = ¶ms.page_token {
req = req.page_token(pt);
}
if let Some(q) = ¶ms.query {
req = req.q(q);
}
let (_, list) = req.doit().await.map_err(drive_err)?;
let drives = list.drives.unwrap_or_default();
let mut result = if drives.is_empty() {
"No shared drives found.".to_string()
} else {
drives
.iter()
.map(|d| {
let name = d.name.as_deref().unwrap_or("(unnamed)");
let id = d.id.as_deref().unwrap_or("(no id)");
format!("{name} (id: {id})")
})
.collect::<Vec<_>>()
.join("\n")
};
if let Some(npt) = &list.next_page_token {
result.push_str(&format!("\n\n[Next page token: {npt}]"));
}
Ok(CallToolResult::success(vec![Content::text(result)]))
}
#[tool(name = "gdrive_drives_get")]
async fn drives_get(
&self,
Parameters(params): Parameters<DrivesGetParams>,
) -> Result<CallToolResult, McpError> {
let (_, drive) = self
.client
.hub()
.drives()
.get(¶ms.drive_id)
.doit()
.await
.map_err(drive_err)?;
let json = serde_json::to_string_pretty(&drive)
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
Ok(CallToolResult::success(vec![Content::text(json)]))
}
#[tool(name = "gdrive_drives_update")]
async fn drives_update(
&self,
Parameters(params): Parameters<DrivesUpdateParams>,
) -> Result<CallToolResult, McpError> {
let mut drive = google_drive3::api::Drive::default();
if let Some(name) = ¶ms.name {
drive.name = Some(name.clone());
}
let (_, result) = self
.client
.hub()
.drives()
.update(drive, ¶ms.drive_id)
.doit()
.await
.map_err(drive_err)?;
let json = serde_json::to_string_pretty(&result)
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
Ok(CallToolResult::success(vec![Content::text(format!(
"Shared drive updated:\n{json}"
))]))
}
#[tool(name = "gdrive_drives_delete")]
async fn drives_delete(
&self,
Parameters(params): Parameters<DrivesDeleteParams>,
) -> Result<CallToolResult, McpError> {
self.client
.hub()
.drives()
.delete(¶ms.drive_id)
.doit()
.await
.map_err(drive_err)?;
Ok(CallToolResult::success(vec![Content::text(format!(
"Shared drive {} deleted",
params.drive_id
))]))
}
}
fn drive_err(e: google_drive3::Error) -> McpError {
McpError::internal_error(format!("Google Drive API error: {e}"), None)
}