use metis_core::application::services::workspace::{ArchiveService, WorkspaceDetectionService};
use rust_mcp_sdk::{
macros::{mcp_tool, JsonSchema},
schema::{schema_utils::CallToolError, CallToolResult, TextContent},
};
use serde::{Deserialize, Serialize};
use std::path::Path;
#[mcp_tool(
name = "archive_document",
description = "Archive a document and all its children using its short code (e.g., PROJ-V-0001). The document and its children will be moved to the archived folder and marked as archived.",
idempotent_hint = true,
destructive_hint = true,
open_world_hint = false,
read_only_hint = false
)]
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct ArchiveDocumentTool {
pub project_path: String,
pub short_code: String,
}
impl ArchiveDocumentTool {
pub async fn call_tool(&self) -> std::result::Result<CallToolResult, CallToolError> {
let metis_dir = Path::new(&self.project_path);
let detection_service = WorkspaceDetectionService::new();
let db = detection_service
.prepare_workspace(metis_dir)
.await
.map_err(|e| {
CallToolError::new(std::io::Error::new(
std::io::ErrorKind::Other,
e.to_string(),
))
})?;
let mut db_service =
metis_core::application::services::DatabaseService::new(db.into_repository());
let archive_service = ArchiveService::new(metis_dir);
match archive_service
.is_document_archived_by_short_code(&self.short_code)
.await
{
Ok(true) => {
return Err(CallToolError::new(std::io::Error::new(
std::io::ErrorKind::AlreadyExists,
format!("Document '{}' is already archived", self.short_code),
)));
}
Ok(false) => {
}
Err(e) => {
return Err(CallToolError::new(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Failed to check archive status: {}", e),
)));
}
}
let archive_result = archive_service
.archive_document_by_short_code(&self.short_code, &mut db_service)
.await
.map_err(|e| {
CallToolError::new(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Failed to archive document: {}", e),
))
})?;
let archived_docs: Vec<serde_json::Value> = archive_result
.archived_documents
.iter()
.map(|doc| {
serde_json::json!({
"document_id": doc.document_id,
"document_type": format!("{:?}", doc.document_type),
"original_path": doc.original_path.to_string_lossy(),
"archived_path": doc.archived_path.to_string_lossy()
})
})
.collect();
let response = serde_json::json!({
"success": true,
"short_code": self.short_code,
"total_archived": archive_result.total_archived,
"archived_documents": archived_docs,
"auto_synced": true
});
Ok(CallToolResult::text_content(vec![TextContent::from(
serde_json::to_string_pretty(&response).map_err(CallToolError::new)?,
)]))
}
}