metis_mcp_server/tools/
initialize_project.rs1use metis_core::application::services::workspace::initialization::WorkspaceInitializationService;
2use crate::formatting::ToolOutput;
3use rust_mcp_sdk::{
4 macros::{mcp_tool, JsonSchema},
5 schema::{schema_utils::CallToolError, CallToolResult},
6};
7use serde::{Deserialize, Serialize};
8use std::path::Path;
9
10#[mcp_tool(
11 name = "initialize_project",
12 description = "Initialize a new Metis project by creating a 'metis' subdirectory at the specified path. Sets up project configuration including short code generation (format: PREFIX-TYPE-NNNN).",
13 idempotent_hint = true,
14 destructive_hint = false,
15 open_world_hint = false,
16 read_only_hint = false
17)]
18#[derive(Debug, Serialize, Deserialize, JsonSchema)]
19pub struct InitializeProjectTool {
20 pub project_path: String,
22 pub prefix: Option<String>,
24}
25
26impl InitializeProjectTool {
27 pub async fn call_tool(&self) -> std::result::Result<CallToolResult, CallToolError> {
28 let project_path = Path::new(&self.project_path);
29
30 let project_name = project_path
32 .file_name()
33 .and_then(|name| name.to_str())
34 .unwrap_or("Metis Project");
35
36 let result = WorkspaceInitializationService::initialize_workspace_with_prefix(
38 project_path,
39 project_name,
40 self.prefix.as_deref(),
41 )
42 .await
43 .map_err(|e| CallToolError::new(e))?;
44
45 let configured_prefix = {
47 let prefix = self.prefix.as_deref().unwrap_or("PROJ").to_uppercase();
48 if prefix.len() > 6 {
49 prefix.chars().take(6).collect()
50 } else {
51 prefix
52 }
53 };
54
55 let output = ToolOutput::new()
56 .header("Project Initialized")
57 .success(&format!(
58 "Initialized Metis workspace at {}",
59 result.metis_dir.display()
60 ))
61 .table(
62 &["Field", "Value"],
63 vec![
64 vec![
65 "Metis Directory".to_string(),
66 result.metis_dir.to_string_lossy().to_string(),
67 ],
68 vec![
69 "Database".to_string(),
70 result.database_path.to_string_lossy().to_string(),
71 ],
72 vec![
73 "Vision".to_string(),
74 result.vision_path.to_string_lossy().to_string(),
75 ],
76 vec!["Project Prefix".to_string(), configured_prefix],
77 ],
78 )
79 .build_result();
80
81 Ok(output)
82 }
83}