1use crate::impl_mcp_tool;
4use clap::Args;
5
6#[derive(Args, Debug)]
8pub struct CreateProjectArgs {
9 pub project_name: String,
14
15 #[arg(long, required = true)]
32 pub vision: String,
33
34 #[arg(long, required = true)]
52 pub tech_stack: String,
53
54 #[arg(long, required = true)]
70 pub summary: String,
71}
72
73impl_mcp_tool! {
75 name = "create_project",
76 description = "Create new project structure with LLM-provided content. Creates ~/.foundry/PROJECT_NAME/ with vision.md, tech-stack.md, and summary.md",
77 struct CreateProjectArgs {
78 project_name: String {
79 description = "Descriptive project name using kebab-case (e.g., 'my-awesome-app')"
80 },
81 vision: String {
82 description = "**CONTEXT FOR FUTURE IMPLEMENTATION**: High-level product vision (2-4 paragraphs, 200+ chars) that will serve as the COMPLETE implementation context for future LLMs who have NO prior knowledge of this project. Must include comprehensive problem definition, target users, unique value proposition, and key roadmap priorities. This document will be loaded as the PRIMARY reference for all future development work. Apply 'Cold Start Test': Could a skilled developer understand the project purpose using only this document? Use markdown with ## headers, bullet points, and clear structure. Include specific examples and architectural context. Goes into vision.md",
83 min_length = 200
84 },
85 tech_stack: String {
86 description = "**CONTEXT FOR FUTURE IMPLEMENTATION**: Comprehensive technology decisions (150+ chars) that will serve as the COMPLETE technical architecture guide for future LLMs with NO prior project knowledge. Must include languages, frameworks, databases, deployment platforms, and detailed rationale for each choice. This document will be the PRIMARY reference for all technical implementation decisions. Include integration patterns, dependencies, constraints, team standards, and architectural context. Future implementers must understand the complete technical landscape from this document alone. Use markdown with ## headers for categories, bullet points for technologies, and comprehensive explanations. Goes into tech-stack.md",
87 min_length = 150
88 },
89 summary: String {
90 description = "**CONTEXT FOR FUTURE IMPLEMENTATION**: Concise summary (100+ chars) of vision and tech-stack for quick context loading by future LLMs. This will be the FIRST document loaded to provide immediate project understanding for implementers with NO prior knowledge. Should capture essential project essence, main value proposition, and primary technology in 2-3 sentences using clear, professional language. Must enable rapid context acquisition for future development sessions. Goes into summary.md",
91 min_length = 100
92 }
93 }
94}
95
96#[derive(Args, Debug)]
98pub struct AnalyzeProjectArgs {
99 pub project_name: String,
104
105 #[arg(long, required = true)]
122 pub vision: String,
123
124 #[arg(long, required = true)]
141 pub tech_stack: String,
142
143 #[arg(long, required = true)]
149 pub summary: String,
150}
151
152impl_mcp_tool! {
154 name = "analyze_project",
155 description = "Create project structure by analyzing existing codebase. You analyze codebase and provide vision, tech-stack, and summary content as arguments.",
156 struct AnalyzeProjectArgs {
157 project_name: String {
158 description = "Descriptive project name using kebab-case (e.g., 'my-analyzed-project')"
159 },
160 vision: String {
161 description = "Your analyzed product vision (200+ chars) based on codebase examination. Use Search/Grep/Read tools first. Structure with ## headers, bullet points, and specific examples from code. Cover problem solved, target users, and value proposition derived from actual functionality. Goes into vision.md",
162 min_length = 200
163 },
164 tech_stack: String {
165 description = "Your detected technology stack (150+ chars) based on codebase analysis. Examine package files, configs, and code patterns. Structure with ## headers for categories, list technologies with versions, include rationale from observed patterns. Reference specific files discovered. Goes into tech-stack.md",
166 min_length = 150
167 },
168 summary: String {
169 description = "Your created concise summary (100+ chars) of analyzed project combining vision and tech-stack insights for quick context loading. Goes into summary.md",
170 min_length = 100
171 }
172 }
173}
174
175#[derive(Args, Debug)]
177pub struct CreateSpecArgs {
178 pub project_name: String,
183
184 pub feature_name: String,
189
190 #[arg(long, required = true)]
209 pub spec: String,
210
211 #[arg(long, required = true)]
229 pub notes: String,
230
231 #[arg(long, required = true)]
249 pub tasks: String,
250}
251
252impl_mcp_tool! {
254 name = "create_spec",
255 description = "Create timestamped specification for a feature. Creates YYYYMMDD_HHMMSS_FEATURE_NAME directory with spec.md, task-list.md, and notes.md. You provide complete specification content as arguments.",
256 struct CreateSpecArgs {
257 project_name: String {
258 description = "Name of the existing project to create spec for"
259 },
260 feature_name: String {
261 description = "Descriptive feature name using snake_case (e.g., 'user_authentication')"
262 },
263 spec: String {
264 description = "**CONTEXT FOR FUTURE IMPLEMENTATION**: Detailed feature specification (200+ chars) that will serve as the COMPLETE implementation guide for future LLMs who have NO prior knowledge of this feature. Must include comprehensive requirements, architectural context, implementation approach with component interactions, dependencies, edge cases, and everything needed for successful implementation. This document will be the PRIMARY reference for feature development. Apply 'Cold Start Test': Could a skilled developer implement this feature using only this document? Use # for feature name, ## for major sections (Overview, Requirements, Implementation, Testing). Include code blocks, bullet points, tables, and detailed technical context. Goes into spec.md",
265 min_length = 200
266 },
267 notes: String {
268 description = "**CONTEXT FOR FUTURE IMPLEMENTATION**: Additional context and design decisions (50+ chars) that will provide COMPLETE implementation context for future LLMs with NO prior feature knowledge. Must include comprehensive design rationale, architectural tradeoffs, dependency analysis, implementation constraints, and future opportunities. This document will be loaded alongside the spec to provide full context for implementation decisions. Include business context, technical constraints, and decision history that future implementers need to understand. Use ## headers for categories, bullet points for considerations. Keep technical but conversational. Goes into notes.md",
269 min_length = 50
270 },
271 tasks: String {
272 description = "**CONTEXT FOR FUTURE IMPLEMENTATION**: Markdown checklist (100+ chars) of implementation steps that will guide future LLMs through COMPLETE feature implementation with NO prior knowledge. Must include comprehensive, actionable phases covering setup, development, testing, and deployment. This task list will be the PRIMARY implementation roadmap for future development sessions. Break feature into specific, measurable tasks that provide complete implementation guidance. Use ## headers for phases, - [ ] for uncompleted tasks, - [x] for completed. Include dependencies, prerequisites, and validation steps. Goes into task-list.md",
273 min_length = 100
274 }
275 }
276}
277
278#[derive(Args, Debug)]
280pub struct LoadSpecArgs {
281 pub project_name: String,
286
287 pub spec_name: Option<String>,
298}
299
300impl crate::mcp::traits::McpToolDefinition for LoadSpecArgs {
302 fn tool_definition() -> rust_mcp_sdk::schema::Tool {
303 let mut properties = std::collections::HashMap::new();
304
305 let mut project_name_prop = serde_json::Map::new();
306 project_name_prop.insert("type".to_string(), serde_json::json!("string"));
307 project_name_prop.insert(
308 "description".to_string(),
309 serde_json::json!("Name of the project containing the spec"),
310 );
311 properties.insert("project_name".to_string(), project_name_prop);
312
313 let mut spec_name_prop = serde_json::Map::new();
314 spec_name_prop.insert("type".to_string(), serde_json::json!("string"));
315 spec_name_prop.insert("description".to_string(), serde_json::json!("Optional: specific spec to load. Supports exact spec names (YYYYMMDD_HHMMSS_feature_name format) or fuzzy matching with natural language queries like 'auth' or 'user management'. If omitted, lists available specs"));
316 properties.insert("spec_name".to_string(), spec_name_prop);
317
318 rust_mcp_sdk::schema::Tool {
319 name: "load_spec".to_string(),
320 description: Some("Load specific specification content with project context. Supports fuzzy matching on feature names (e.g., 'auth' matches 'user_authentication'). You can use this to review full specification details, task lists, and implementation notes. If spec_name is omitted, lists available specs.".to_string()),
321 title: None,
322 input_schema: rust_mcp_sdk::schema::ToolInputSchema::new(
323 vec!["project_name".to_string()], Some(properties),
325 ),
326 annotations: None,
327 meta: None,
328 output_schema: None,
329 }
330 }
331
332 fn from_mcp_params(params: &serde_json::Value) -> anyhow::Result<Self> {
333 Ok(Self {
334 project_name: params["project_name"]
335 .as_str()
336 .ok_or_else(|| anyhow::anyhow!("Missing project_name parameter"))?
337 .to_string(),
338 spec_name: params["spec_name"].as_str().map(|s| s.to_string()),
339 })
340 }
341}
342
343#[derive(Args, Debug)]
345pub struct LoadProjectArgs {
346 pub project_name: String,
352}
353
354impl_mcp_tool! {
356 name = "load_project",
357 description = "Load complete project context (vision, tech-stack, summary) for LLM sessions. Essential for resuming work on existing projects. You can use this to get full project context before creating specifications or continuing development work.",
358 struct LoadProjectArgs {
359 project_name: String {
360 description = "Name of the existing project to load (must exist in ~/.foundry/)"
361 }
362 }
363}
364
365#[derive(Args, Debug)]
367pub struct ListProjectsArgs;
368
369#[derive(Args, Debug)]
375pub struct ListSpecsArgs {
376 pub project_name: String,
386}
387
388impl_mcp_tool! {
390 name = "list_specs",
391 description = "List available specifications for a project without loading full context. Returns lightweight spec metadata including names, feature names, and creation dates for efficient spec discovery.",
392 struct ListSpecsArgs {
393 project_name: String {
394 description = "Name of the existing project to list specs for (must exist in ~/.foundry/)"
395 }
396 }
397}
398
399#[derive(Args, Debug)]
401pub struct GetFoundryHelpArgs {
402 pub topic: Option<String>,
414}
415
416impl crate::mcp::traits::McpToolDefinition for GetFoundryHelpArgs {
418 fn tool_definition() -> rust_mcp_sdk::schema::Tool {
419 let mut properties = std::collections::HashMap::new();
420
421 let mut topic_prop = serde_json::Map::new();
422 topic_prop.insert("type".to_string(), serde_json::json!("string"));
423 topic_prop.insert("description".to_string(), serde_json::json!("Optional: specific help topic (workflows, decision-points, content-examples, project-structure, parameter-guidance, tool-capabilities). If omitted, provides general guidance"));
424 properties.insert("topic".to_string(), topic_prop);
425
426 rust_mcp_sdk::schema::Tool {
427 name: "get_foundry_help".to_string(),
428 description: Some("Get comprehensive workflow guidance, content examples, and usage patterns. You can use this to understand foundry workflows and content standards. Essential for effective tool selection and workflow optimization.".to_string()),
429 title: None,
430 input_schema: rust_mcp_sdk::schema::ToolInputSchema::new(
431 vec![], Some(properties),
433 ),
434 annotations: None,
435 meta: None,
436 output_schema: None,
437 }
438 }
439
440 fn from_mcp_params(params: &serde_json::Value) -> anyhow::Result<Self> {
441 Ok(Self {
442 topic: params["topic"].as_str().map(|s| s.to_string()),
443 })
444 }
445}
446
447#[derive(Args, Debug)]
449pub struct ValidateContentArgs {
450 #[arg(long, required = true)]
456 pub content: String,
457
458 pub content_type: String,
464}
465
466impl_mcp_tool! {
468 name = "validate_content",
469 description = "Validate content against schema requirements with improvement suggestions. You can use this to ensure your content meets foundry standards before creating projects or specifications. Provides detailed feedback for content improvement.",
470 struct ValidateContentArgs {
471 content: String {
472 description = "Content to validate against the specified type's requirements"
473 },
474 content_type: String {
475 description = "Type of content to validate (vision, tech-stack, summary, spec, notes, tasks)"
476 }
477 }
478}
479
480#[derive(Args, Debug)]
482pub struct UpdateSpecArgs {
483 pub project_name: String,
488
489 pub spec_name: String,
494
495 #[arg(long, required = true)]
497 pub commands: String,
498}
499
500impl crate::mcp::traits::McpToolDefinition for UpdateSpecArgs {
502 fn tool_definition() -> rust_mcp_sdk::schema::Tool {
503 let mut properties = std::collections::HashMap::new();
504
505 let mut project_name_prop = serde_json::Map::new();
506 project_name_prop.insert("type".to_string(), serde_json::json!("string"));
507 project_name_prop.insert(
508 "description".to_string(),
509 serde_json::json!("Name of the existing project containing the spec"),
510 );
511 properties.insert("project_name".to_string(), project_name_prop);
512
513 let mut spec_name_prop = serde_json::Map::new();
514 spec_name_prop.insert("type".to_string(), serde_json::json!("string"));
515 spec_name_prop.insert(
516 "description".to_string(),
517 serde_json::json!(
518 "Name of the existing spec to update (YYYYMMDD_HHMMSS_feature_name format)"
519 ),
520 );
521 properties.insert("spec_name".to_string(), spec_name_prop);
522
523 let mut commands_prop = serde_json::Map::new();
524 commands_prop.insert("type".to_string(), serde_json::json!("array"));
525 commands_prop.insert(
527 "items".to_string(),
528 serde_json::json!({
529 "type": "object"
530 }),
531 );
532 commands_prop.insert("description".to_string(), serde_json::json!("Array of edit commands to apply. Each command must include target (spec|tasks|notes), command (set_task_status|upsert_task|append_to_section), selector (task_text|section), and relevant fields (status|content)."));
533 properties.insert("commands".to_string(), commands_prop);
534
535 rust_mcp_sdk::schema::Tool {
536 name: "update_spec".to_string(),
537 description: Some("Edit Foundry spec files using intent-based commands; precise anchors; idempotent updates. Provide a 'commands' array of edit operations.".to_string()),
538 title: None,
539 input_schema: rust_mcp_sdk::schema::ToolInputSchema::new(
540 vec!["project_name".to_string(), "spec_name".to_string(), "commands".to_string()], Some(properties),
542 ),
543 annotations: None,
544 meta: None,
545 output_schema: None,
546 }
547 }
548
549 fn from_mcp_params(params: &serde_json::Value) -> anyhow::Result<Self> {
550 Ok(Self {
551 project_name: params["project_name"]
552 .as_str()
553 .ok_or_else(|| anyhow::anyhow!("Missing project_name parameter"))?
554 .to_string(),
555 spec_name: params["spec_name"]
556 .as_str()
557 .ok_or_else(|| anyhow::anyhow!("Missing spec_name parameter"))?
558 .to_string(),
559 commands: serde_json::to_string(
560 params["commands"]
561 .as_array()
562 .ok_or_else(|| anyhow::anyhow!("Missing commands array"))?,
563 )?,
564 })
565 }
566}
567
568#[derive(Args, Debug)]
570pub struct DeleteSpecArgs {
571 pub project_name: String,
576
577 pub spec_name: String,
583
584 #[arg(long, required = true)]
589 pub confirm: String,
590}
591
592impl_mcp_tool! {
594 name = "delete_spec",
595 description = "Delete an existing specification and all its files (spec.md, task-list.md, notes.md). You can use this to permanently remove specifications that are no longer needed. This action cannot be undone.",
596 struct DeleteSpecArgs {
597 project_name: String {
598 description = "Name of the existing project containing the spec"
599 },
600 spec_name: String {
601 description = "Name of the spec to delete (YYYYMMDD_HHMMSS_feature_name format). WARNING: This permanently deletes all spec files."
602 },
603 confirm: String {
604 description = "Confirmation flag - must be set to 'true' to proceed with deletion (safety mechanism)"
605 }
606 }
607}
608
609#[derive(Args, Debug)]
611pub struct ServeArgs {
612 #[arg(long, short)]
614 pub verbose: bool,
615}
616
617#[derive(Args, Debug)]
619pub struct InstallArgs {
620 pub target: String,
628
629 #[arg(long)]
634 pub binary_path: Option<String>,
635
636 #[arg(long)]
641 pub json: bool,
642}
643
644#[derive(Args, Debug)]
646pub struct UninstallArgs {
647 pub target: String,
653
654 #[arg(long)]
659 pub remove_config: bool,
660
661 #[arg(long)]
666 pub json: bool,
667}
668
669#[derive(Args, Debug, Clone)]
671pub struct StatusArgs {
672 #[arg(long)]
677 pub detailed: bool,
678
679 #[arg(long)]
684 pub target: Option<String>,
685
686 #[arg(long)]
691 pub json: bool,
692}
693
694impl crate::mcp::traits::McpToolDefinition for ListProjectsArgs {
699 fn tool_definition() -> rust_mcp_sdk::schema::Tool {
700 rust_mcp_sdk::schema::Tool {
701 name: "list_projects".to_string(),
702 description: Some("List all available projects with metadata including creation dates, spec counts, and validation status. You can use this to discover available projects before loading or creating specifications.".to_string()),
703 title: None,
704 input_schema: rust_mcp_sdk::schema::ToolInputSchema::new(
705 vec![],
706 Some(std::collections::HashMap::new()),
707 ),
708 annotations: None,
709 meta: None,
710 output_schema: None,
711 }
712 }
713
714 fn from_mcp_params(_params: &serde_json::Value) -> anyhow::Result<Self> {
715 Ok(Self)
716 }
717}