#[derive(Debug, Deserialize, Serialize)]
struct GenerateContextArgs {
toolchain: Option<String>,
project_path: Option<String>,
format: Option<String>,
debug: Option<bool>,
debug_output: Option<PathBuf>,
skip_vendor: Option<bool>,
max_line_length: Option<usize>,
}
async fn handle_generate_context(
request_id: serde_json::Value,
arguments: serde_json::Value,
) -> McpResponse {
let (args, project_path) = match parse_generate_context_args(arguments) {
Ok(result) => result,
Err(e) => {
return McpResponse::error(
request_id,
-32602,
format!("Invalid generate_context arguments: {e}"),
);
}
};
info!("Generating comprehensive context for {:?}", project_path);
let config = build_context_generation_config(&args);
let deep_context = match run_deep_context_analysis_with_config(&project_path, config).await {
Ok(ctx) => ctx,
Err(e) => {
return McpResponse::error(
request_id,
-32000,
format!("Failed to analyze project: {e}"),
);
}
};
format_and_respond_context(request_id, args, deep_context).await
}
fn parse_generate_context_args(
arguments: serde_json::Value,
) -> Result<(GenerateContextArgs, PathBuf), Box<dyn std::error::Error>> {
let args: GenerateContextArgs = serde_json::from_value(arguments)?;
let _validated = require_project_path(args.project_path.clone())
.map_err(Box::<dyn std::error::Error>::from)?;
let raw = args
.project_path
.as_deref()
.expect("require_project_path returned Ok for None");
let project_path = match resolve_project_path_with_globs(raw) {
ResolvedProjectPath::Concrete(p) => p,
e @ ResolvedProjectPath::EmptyGlob(_) => {
return Err(Box::<dyn std::error::Error>::from(e.into_error_message()));
}
};
Ok((args, project_path))
}
fn build_context_generation_config(
args: &GenerateContextArgs,
) -> crate::services::deep_context::DeepContextConfig {
use crate::services::deep_context::DeepContextConfig;
use crate::services::file_classifier::FileClassifierConfig;
let mut config = DeepContextConfig::default();
if should_configure_file_classifier(args) {
let file_classifier_config = FileClassifierConfig {
skip_vendor: args.skip_vendor.unwrap_or(true),
max_line_length: args.max_line_length.unwrap_or(10_000),
max_file_size: 1_048_576, };
config.file_classifier_config = Some(file_classifier_config);
}
config
}
fn should_configure_file_classifier(args: &GenerateContextArgs) -> bool {
args.debug.unwrap_or(false)
|| args.skip_vendor.unwrap_or(false)
|| args.max_line_length.is_some()
}
async fn run_deep_context_analysis_with_config(
project_path: &Path,
config: crate::services::deep_context::DeepContextConfig,
) -> Result<crate::services::deep_context::DeepContext, Box<dyn std::error::Error>> {
use crate::services::deep_context::DeepContextAnalyzer;
let analyzer = DeepContextAnalyzer::new(config);
Ok(analyzer
.analyze_project(&project_path.to_path_buf())
.await?)
}
async fn format_and_respond_context(
request_id: serde_json::Value,
args: GenerateContextArgs,
deep_context: crate::services::deep_context::DeepContext,
) -> McpResponse {
let format = args.format.as_deref().unwrap_or("markdown");
let content = format_context_content(format, &deep_context).await;
let result = build_context_response(&args, format, content, &deep_context);
McpResponse::success(request_id, result)
}
async fn format_context_content(
format: &str,
deep_context: &crate::services::deep_context::DeepContext,
) -> String {
if format == "json" {
serde_json::to_string_pretty(deep_context).unwrap_or_default()
} else {
use crate::services::deep_context::{DeepContextAnalyzer, DeepContextConfig};
let analyzer = DeepContextAnalyzer::new(DeepContextConfig::default());
analyzer
.format_as_comprehensive_markdown(deep_context)
.await
.unwrap_or_else(|_| "Error formatting deep context".to_string())
}
}
fn build_context_response(
args: &GenerateContextArgs,
format: &str,
content: String,
deep_context: &crate::services::deep_context::DeepContext,
) -> serde_json::Value {
json!({
"content": [{
"type": "text",
"text": content
}],
"toolchain": args.toolchain.as_deref().unwrap_or("auto-detected"),
"format": format,
"analysis_metadata": {
"generated_at": deep_context.metadata.generated_at,
"tool_version": deep_context.metadata.tool_version,
"analysis_duration_ms": deep_context.metadata.analysis_duration.as_millis(),
"total_files": deep_context.file_tree.total_files,
"total_size_bytes": deep_context.file_tree.total_size_bytes,
},
"quality_scorecard": {
"overall_health": deep_context.quality_scorecard.overall_health,
"complexity_score": deep_context.quality_scorecard.complexity_score,
"maintainability_index": deep_context.quality_scorecard.maintainability_index,
"technical_debt_hours": deep_context.quality_scorecard.technical_debt_hours,
}
})
}