pmat 3.11.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
//! MCP server implementation using uniform contracts
//! This ensures MCP tools use exactly the same contracts as CLI and HTTP

use super::*;
use super::service::ContractService;
use anyhow::Result;
use pmcp::{
    Server, ServerBuilder, Tool, ToolHandler, ToolResult,
    types::{JsonValue, ToolDefinition},
};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::sync::Arc;
use async_trait::async_trait;

// Types: McpOperationResult struct and impl
include!("mcp_impl_types.rs");

// Server: ContractMcpServer struct and core impl (new, run, handle_tool_call, analysis handlers)
include!("mcp_impl_server.rs");

// Tool definitions for analysis tools (complexity, satd, dead_code, tdg, lint_hotspot, entropy, quality_gate, refactor_auto)
include!("mcp_impl_analysis_tools.rs");

// Scaffold and maintenance handler implementations (scaffold_agent, scaffold_wasm, validate_roadmap, health_check, generate_tickets)
include!("mcp_impl_scaffold_handlers.rs");

// Tool definitions for scaffold and maintenance tools
include!("mcp_impl_scaffold_tools.rs");

#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
    use proptest::prelude::*;

    proptest! {
        #[test]
        fn basic_property_stability(_input in ".*") {
            // Basic property test for coverage
            prop_assert!(true);
        }

        #[test]
        fn module_consistency_check(_x in 0u32..1000) {
            // Module consistency verification
            prop_assert!(_x < 1001);
        }
    }
}

#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::json;

    #[test]
    fn test_mcp_operation_result_success() {
        let data = json!({"result": "ok"});
        let result = McpOperationResult::success(data.clone());
        assert!(result.success);
        assert_eq!(result.data, Some(data));
        assert!(result.error.is_none());
        assert!(result.error_details.is_none());
    }

    #[test]
    fn test_mcp_operation_result_error() {
        let result = McpOperationResult::error("test error".to_string(), None);
        assert!(!result.success);
        assert!(result.data.is_none());
        assert_eq!(result.error, Some("test error".to_string()));
        assert!(result.error_details.is_none());
    }

    #[test]
    fn test_mcp_operation_result_error_with_details() {
        let details = vec!["detail 1".to_string(), "detail 2".to_string()];
        let result = McpOperationResult::error("test error".to_string(), Some(details.clone()));
        assert!(!result.success);
        assert_eq!(result.error_details, Some(details));
    }

    #[test]
    fn test_mcp_operation_result_from_error() {
        let err = anyhow::anyhow!("test error");
        let result = McpOperationResult::from_error(err);
        assert!(!result.success);
        assert!(result.error.is_some());
    }

    #[test]
    fn test_mcp_operation_result_from_error_with_chain() {
        let err = anyhow::anyhow!("root error").context("middle error").context("top error");
        let result = McpOperationResult::from_error(err);
        assert!(!result.success);
        assert!(result.error.is_some());
        // Error chain should be captured
        assert!(result.error_details.is_some());
        let details = result.error_details.unwrap();
        assert!(details.len() > 1);
    }

    #[test]
    fn test_create_analyze_complexity_tool() {
        let tool = create_analyze_complexity_tool();
        assert_eq!(tool.name, "analyze_complexity");
        assert!(!tool.description.is_empty());
        assert!(tool.input_schema.is_object());
    }

    #[test]
    fn test_create_analyze_satd_tool() {
        let tool = create_analyze_satd_tool();
        assert_eq!(tool.name, "analyze_satd");
        assert!(tool.input_schema["properties"]["path"].is_object());
    }

    #[test]
    fn test_create_analyze_dead_code_tool() {
        let tool = create_analyze_dead_code_tool();
        assert_eq!(tool.name, "analyze_dead_code");
        assert!(tool.input_schema["required"].is_array());
    }

    #[test]
    fn test_create_analyze_tdg_tool() {
        let tool = create_analyze_tdg_tool();
        assert_eq!(tool.name, "analyze_tdg");
        assert!(tool.input_schema["properties"]["threshold"].is_object());
    }

    #[test]
    fn test_create_analyze_lint_hotspot_tool() {
        let tool = create_analyze_lint_hotspot_tool();
        assert_eq!(tool.name, "analyze_lint_hotspot");
        assert!(tool.input_schema["properties"]["max_density"].is_object());
    }

    #[test]
    fn test_create_analyze_entropy_tool() {
        let tool = create_analyze_entropy_tool();
        assert_eq!(tool.name, "analyze_entropy");
        assert!(tool.input_schema["properties"]["min_severity"].is_object());
    }

    #[test]
    fn test_create_quality_gate_tool() {
        let tool = create_quality_gate_tool();
        assert_eq!(tool.name, "quality_gate");
        assert!(tool.input_schema["properties"]["profile"].is_object());
    }

    #[test]
    fn test_create_refactor_auto_tool() {
        let tool = create_refactor_auto_tool();
        assert_eq!(tool.name, "refactor_auto");
        assert!(tool.input_schema["properties"]["target_complexity"].is_object());
    }

    #[test]
    fn test_create_scaffold_agent_tool() {
        let tool = create_scaffold_agent_tool();
        assert_eq!(tool.name, "scaffold_agent");
        assert!(tool.input_schema["properties"]["quality_level"].is_object());
    }

    #[test]
    fn test_create_scaffold_wasm_tool() {
        let tool = create_scaffold_wasm_tool();
        assert_eq!(tool.name, "scaffold_wasm");
        assert!(tool.input_schema["properties"]["framework"].is_object());
    }

    #[test]
    fn test_create_validate_roadmap_tool() {
        let tool = create_validate_roadmap_tool();
        assert_eq!(tool.name, "validate_roadmap");
        assert!(tool.input_schema["properties"]["roadmap_path"].is_object());
    }

    #[test]
    fn test_create_health_check_tool() {
        let tool = create_health_check_tool();
        assert_eq!(tool.name, "health_check");
        assert!(tool.input_schema["properties"]["quick"].is_object());
    }

    #[test]
    fn test_create_generate_tickets_tool() {
        let tool = create_generate_tickets_tool();
        assert_eq!(tool.name, "generate_tickets");
        assert!(tool.input_schema["properties"]["dry_run"].is_object());
    }

    #[test]
    fn test_mcp_operation_result_serialization() {
        let result = McpOperationResult::success(json!({"value": 42}));
        let json_str = serde_json::to_string(&result).unwrap();
        assert!(json_str.contains("\"success\":true"));
        assert!(json_str.contains("\"value\":42"));
    }

    #[test]
    fn test_mcp_operation_result_deserialization() {
        let json_str = r#"{"success":true,"data":{"value":42}}"#;
        let result: McpOperationResult = serde_json::from_str(json_str).unwrap();
        assert!(result.success);
        assert!(result.data.is_some());
    }

    #[test]
    fn test_tool_definitions_have_required_fields() {
        let tools = vec![
            create_analyze_complexity_tool(),
            create_analyze_satd_tool(),
            create_analyze_dead_code_tool(),
            create_analyze_tdg_tool(),
        ];

        for tool in tools {
            assert!(!tool.name.is_empty());
            assert!(!tool.description.is_empty());
            assert!(tool.input_schema.is_object());
        }
    }

    #[test]
    fn test_all_tool_schemas_have_properties() {
        let tools = vec![
            create_analyze_complexity_tool(),
            create_analyze_satd_tool(),
            create_analyze_dead_code_tool(),
            create_analyze_tdg_tool(),
            create_analyze_lint_hotspot_tool(),
            create_analyze_entropy_tool(),
            create_quality_gate_tool(),
            create_refactor_auto_tool(),
            create_scaffold_agent_tool(),
            create_scaffold_wasm_tool(),
            create_validate_roadmap_tool(),
            create_health_check_tool(),
            create_generate_tickets_tool(),
        ];

        for tool in tools {
            assert!(
                tool.input_schema.get("properties").is_some(),
                "Tool {} missing properties",
                tool.name
            );
        }
    }
}