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 RepliesCreateParams {
pub file_id: String,
pub comment_id: String,
pub content: String,
#[serde(default)]
pub action: Option<String>,
}
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct RepliesListParams {
pub file_id: String,
pub comment_id: String,
#[serde(default)]
pub page_size: Option<i32>,
#[serde(default)]
pub page_token: Option<String>,
}
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct RepliesGetParams {
pub file_id: String,
pub comment_id: String,
pub reply_id: String,
}
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct RepliesUpdateParams {
pub file_id: String,
pub comment_id: String,
pub reply_id: String,
pub content: String,
}
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct RepliesDeleteParams {
pub file_id: String,
pub comment_id: String,
pub reply_id: String,
}
#[tool_router(router = replies_tool_router, vis = "pub")]
impl GDriveServer {
#[tool(name = "gdrive_replies_create")]
async fn replies_create(
&self,
Parameters(params): Parameters<RepliesCreateParams>,
) -> Result<CallToolResult, McpError> {
let mut reply = google_drive3::api::Reply::default();
reply.content = Some(params.content);
reply.action = params.action;
let (_, result) = self
.client
.hub()
.replies()
.create(reply, ¶ms.file_id, ¶ms.comment_id)
.param("fields", "id,content,author,createdTime,modifiedTime,action")
.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!(
"Reply created:\n{json}"
))]))
}
#[tool(name = "gdrive_replies_list")]
async fn replies_list(
&self,
Parameters(params): Parameters<RepliesListParams>,
) -> Result<CallToolResult, McpError> {
let mut req = self
.client
.hub()
.replies()
.list(¶ms.file_id, ¶ms.comment_id)
.param("fields", "replies(id,content,author,createdTime,modifiedTime,action),nextPageToken");
if let Some(ps) = params.page_size {
req = req.page_size(ps);
}
if let Some(pt) = ¶ms.page_token {
req = req.page_token(pt);
}
let (_, list) = req.doit().await.map_err(drive_err)?;
let mut json = serde_json::to_string_pretty(&list.replies)
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
if let Some(npt) = &list.next_page_token {
json.push_str(&format!("\n\n[Next page token: {npt}]"));
}
Ok(CallToolResult::success(vec![Content::text(json)]))
}
#[tool(name = "gdrive_replies_get")]
async fn replies_get(
&self,
Parameters(params): Parameters<RepliesGetParams>,
) -> Result<CallToolResult, McpError> {
let (_, reply) = self
.client
.hub()
.replies()
.get(¶ms.file_id, ¶ms.comment_id, ¶ms.reply_id)
.param("fields", "id,content,author,createdTime,modifiedTime,action")
.doit()
.await
.map_err(drive_err)?;
let json = serde_json::to_string_pretty(&reply)
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
Ok(CallToolResult::success(vec![Content::text(json)]))
}
#[tool(name = "gdrive_replies_update")]
async fn replies_update(
&self,
Parameters(params): Parameters<RepliesUpdateParams>,
) -> Result<CallToolResult, McpError> {
let mut reply = google_drive3::api::Reply::default();
reply.content = Some(params.content);
let (_, result) = self
.client
.hub()
.replies()
.update(reply, ¶ms.file_id, ¶ms.comment_id, ¶ms.reply_id)
.param("fields", "id,content,author,modifiedTime")
.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!(
"Reply updated:\n{json}"
))]))
}
#[tool(name = "gdrive_replies_delete")]
async fn replies_delete(
&self,
Parameters(params): Parameters<RepliesDeleteParams>,
) -> Result<CallToolResult, McpError> {
self.client
.hub()
.replies()
.delete(¶ms.file_id, ¶ms.comment_id, ¶ms.reply_id)
.doit()
.await
.map_err(drive_err)?;
Ok(CallToolResult::success(vec![Content::text(format!(
"Reply {} deleted from comment {} on file {}",
params.reply_id, params.comment_id, params.file_id
))]))
}
}
fn drive_err(e: google_drive3::Error) -> McpError {
McpError::internal_error(format!("Google Drive API error: {e}"), None)
}