# pyscn MCP Server Model Context Protocol (MCP) integration for pyscn - Python Code Quality Analyzer. ## Overview pyscn MCP Server exposes pyscn's code analysis capabilities as MCP tools, allowing AI assistants like Claude, Cursor, and ChatGPT to directly analyze Python code quality. ## Features ### Available Tools | Tool | Description | Key Metrics | |------|-------------|-------------| | `analyze_code` | Comprehensive code analysis | All metrics combined | | `check_complexity` | Cyclomatic complexity analysis | McCabe complexity, nesting depth | | `detect_clones` | Code clone detection | APTED + LSH, Type 1-4 clones | | `check_coupling` | Class coupling analysis | CBO (Coupling Between Objects) | | `find_dead_code` | Dead code detection | CFG-based unreachable code | | `get_health_score` | Overall code health | Score (0-100), Grade (A-F) | ## Quick Start ### Claude Code: Plugin Install (Recommended) For Claude Code, install the plugin. It registers the MCP server and also adds Agent Skills that teach Claude when to use each analysis: ```bash claude plugin marketplace add ludo-technologies/pyscn claude plugin install pyscn-mcp@pyscn-marketplace ``` For other MCP clients, or to set up only the MCP server, use one of the options below. ### Option 1: Using uvx (Recommended) The simplest way to use pyscn-mcp is with `uvx`, which automatically handles installation and execution: ```json { "mcpServers": { "pyscn-mcp": { "command": "uvx", "args": ["pyscn-mcp"], "env": { "PYSCN_CONFIG": "/path/to/.pyscn.toml" } } } } ``` **Benefits**: - ✅ No manual installation needed - ✅ Always uses the latest version - ✅ Works across all platforms - ✅ Supports environment variables **Environment Variables**: - `PYSCN_CONFIG`: Path to custom configuration file (optional) ### Option 2: Using uv tool install If you prefer to install pyscn once and use the binary path: #### 1. Install pyscn via uv tool ```bash # Install pyscn as a uv tool uv tool install pyscn ``` This installs pyscn and includes the compiled `pyscn-mcp` binary. #### 2. Locate the Binary Path The MCP server binary is included in the uv tool installation. To find its path: ```bash # Get the tool directory uv tool dir # Example output: C:\Users\YourName\AppData\Local\uv\tools\pyscn ``` The binary location depends on your platform: - **Windows**: `\pyscn\bin\pyscn-mcp.exe` - **Linux**: `/pyscn/bin/pyscn-mcp` - **macOS**: `/pyscn/bin/pyscn-mcp` #### 3. Configure Cursor Add to Cursor settings (Settings → Features → Model Context Protocol): **Windows Example:** ```json { "mcpServers": { "pyscn-mcp": { "command": "C:\\Users\\YourName\\AppData\\Local\\uv\\tools\\pyscn\\bin\\pyscn-mcp.exe", "args": [], "env": { "PYSCN_CONFIG": "/path/to/.pyscn.toml" } } } } ``` **Linux Example:** ```json { "mcpServers": { "pyscn-mcp": { "command": "/home/username/.local/share/uv/tools/pyscn/bin/pyscn-mcp", "args": [], "env": { "PYSCN_CONFIG": "/path/to/.pyscn.toml" } } } } ``` **macOS Example:** ```json { "mcpServers": { "pyscn-mcp": { "command": "/Users/username/Library/Application Support/uv/tools/pyscn/bin/pyscn-mcp", "args": [], "env": { "PYSCN_CONFIG": "/path/to/.pyscn.toml" } } } } ``` **Note**: Replace the path with your actual `uv tool dir` output path. ## Configuration ### Configuration File Priority pyscn-mcp uses the TOML-only configuration loader. YAML, JSON, XDG, and home-directory-specific configuration locations are not searched. 1. **`PYSCN_CONFIG`** - When set, this explicit file path is loaded at server startup. A load failure is logged and the server registers its tools with a built-in-default configuration snapshot; it does not continue searching other locations. The explicit path is still retained, however, so tools that load configuration while handling a request (including `analyze_code`) report that configuration error instead of silently analyzing with defaults. Fix or unset an invalid `PYSCN_CONFIG` value. 2. **Server working directory** - When `PYSCN_CONFIG` is unset, the server searches upward from its current working directory. A `.pyscn.toml` file takes priority over `pyproject.toml` with a `[tool.pyscn]` section. 3. **Per-tool loading** - Configuration is not consumed uniformly by every tool. `analyze_code` resolves project analysis settings from the target path upward when no explicit path is set. `check_complexity`, `detect_clones`, `check_cohesion`, and `find_dead_code` pass the configured path to their use-case loaders and may reload it for each request. `check_coupling` uses selected values from the startup snapshot together with domain defaults; it does not construct a CBO configuration loader. 4. **Built-in defaults** - Used when no supported configuration is found. **Best Practice**: Set `PYSCN_CONFIG` when the MCP server may start outside the project directory. Otherwise, place `.pyscn.toml` in the project root. ## Testing ### Restart Cursor Restart Cursor to load the MCP server. ### Test It Out Try asking your AI assistant: - "Analyze the code quality of /path/to/my/project" - "Check the complexity of functions in main.py" - "Find duplicate code in my project" - "What's the health score of my codebase?" ## Tool Usage ### analyze_code **Description**: Comprehensive Python code quality analysis **Parameters**: - `path` (required): Path to Python code (file or directory) - `analyses` (optional): Array of analyses to run - Options: `["complexity", "dead_code", "clone", "cbo", "lcom", "deps", "communities"]` - Default: all analyses, including `communities` - `recursive` (optional): Recursively analyze directories (default: `true`) - `output_mode` (optional): `"summary"` (default) returns the health score and high-level metrics; `"full"` returns the complete report, including `community_analysis` and its `community_context_map` when community detection runs **Example**: ``` Analyze the code at /home/user/project with all metrics ``` **Output**: JSON with comprehensive analysis results ```json { "complexity": { ... }, "dead_code": { ... }, "clone": { ... }, "cbo": { ... }, "summary": { "health_score": 85, "grade": "A", "total_files": 42, "average_complexity": 5.2, "dead_code_count": 2, "clone_pairs": 5 } } ``` #### Module communities (context map for AI agents) Community detection groups modules into clusters by their import structure so an agent knows which files to inspect together. It runs by default; when `analyses` is provided, include `"communities"` in that list and set `output_mode: "full"` to retrieve the full context map. **Example**: ``` Map the module architecture of /home/user/project and tell me which files to review together ``` The full response embeds a compact, deterministic `community_context_map` under `community_analysis`: ```json { "community_analysis": { "total_communities": 2, "community_risk_score": 65, "community_context_map": { "version": 1, "bundles": [ { "community_id": "community_1", "modules": ["app.orders.service", "app.orders.repository"], "module_count": 2, "packages": ["app.orders"], "risk_level": "low", "bridge_modules": [], "suggested_review_scope": "app/orders/", "summary": "2 modules; 1 package; risk low; 0 cross-community edges." } ], "bridge_modules": [ { "module": "app.core.hub", "connects": ["community_1", "community_3"], "reason": "3 cross-community import edges" } ] } } } ``` Field notes: - `bundles[]` are clusters to review together. `modules` is capped for large clusters with a `... +N more` marker; `module_count` always holds the true total. `suggested_review_scope` (a path prefix) is omitted when members share no common package. - `bridge_modules[]` couple two or more communities. Pull them into the review scope before changing cluster boundaries. ### check_complexity **Description**: Analyze cyclomatic complexity of Python execution scopes **Parameters**: - `path` (required): Path to Python code - `min_complexity` (optional): Minimum complexity to report (default: `1`) - `max_complexity` (optional): Maximum allowed complexity; `0` uses the default of `10` (default: `0`) - `show_details` (optional): Include detailed metrics (default: `true`) - `output_mode` (optional): `"summary"`, `"detailed"`, or `"full"` (default: `"summary"`) - `max_results` (optional): Maximum findings in summary or detailed output; `0` means unlimited (default: `0`) **Example**: ``` Check complexity of functions with complexity > 10 in src/ ``` **Output**: Complexity analysis with risk levels Summary and detailed findings use the same `min_complexity` and `report_unchanged` filtered scope population returned by full mode. Their aggregate `max_scope_complexity` and `average_scope_complexity` fields still describe the complete analyzed population; `max_complexity` remains the function-population maximum. ```json { "functions": [ { "name": "complex_function", "file_path": "src/main.py", "start_line": 42, "metrics": { "complexity": 15, "nesting_depth": 4 }, "risk_level": "high" } ], "summary": { "average_complexity": 8.5, "high_risk_functions": 3 } } ``` ### detect_clones **Description**: Detect code clones using APTED tree edit distance and LSH **Parameters**: - `path` (required): Path to Python code - `similarity_threshold` (optional): Minimum similarity 0.0-1.0 (default: `0.8`) - `min_lines` (optional): Minimum lines to consider (default: `5`) - `group_clones` (optional): Group related clones (default: `true`) - `output_mode` (optional): `"summary"`, `"detailed"`, or `"full"` (default: `"summary"`) - `max_results` (optional): Maximum findings in summary or detailed output; `0` means unlimited (default: `0`) **Example**: ``` Find duplicate code with similarity > 0.85 in my project ``` **Output**: Clone pairs and groups ```json { "clone_pairs": [ { "clone1": { "file_path": "src/a.py", "start_line": 10, "end_line": 25 }, "clone2": { "file_path": "src/b.py", "start_line": 42, "end_line": 57 }, "similarity": 0.92, "type": "Type-2" } ], "statistics": { "total_clone_pairs": 5, "average_similarity": 0.87 } } ``` ### check_coupling **Description**: Analyze class coupling (CBO - Coupling Between Objects) **Parameters**: - `path` (required): Path to Python code - `min_cbo` (optional): Minimum CBO for high-coupling findings (default: `10`) - `output_mode` (optional): `"summary"`, `"detailed"`, or `"full"` (default: `"summary"`) - `max_results` (optional): Maximum findings in summary or detailed output; `0` means unlimited (default: `0`) **Example**: ``` Check the coupling of classes in src/ ``` **Output**: CBO metrics per class ```json { "classes": [ { "name": "MyClass", "file_path": "src/service.py", "cbo": 8, "risk_level": "high", "coupled_classes": ["ClassA", "ClassB", ...] } ], "summary": { "average_coupling": 4.2, "high_coupling_classes": 3 } } ``` ### check_cohesion **Description**: Analyze class cohesion using LCOM4 **Parameters**: - `path` (required): Path to Python code - `output_mode` (optional): `"summary"`, `"detailed"`, or `"full"` (default: `"summary"`) - `max_results` (optional): Maximum findings in summary or detailed output; `0` means unlimited (default: `0`) ### find_dead_code **Description**: Find unreachable code using CFG analysis **Parameters**: - `path` (required): Path to Python code - `min_severity` (optional): Minimum severity: `info`, `warning`, `error` (default: `warning`) - `output_mode` (optional): `"summary"`, `"detailed"`, or `"full"` (default: `"summary"`) - `max_results` (optional): Maximum findings in summary or detailed output; `0` means unlimited (default: `0`) **Example**: ``` Find dead code with severity >= warning in my project ``` **Output**: Detailed mode returns structured issues from functions and executable class suites. `function` keeps the raw scope name for compatibility; `scope_kind` identifies its owner and `scope_label` is the canonical display label. ```json { "issues": [ { "file": "src/util.py", "function": "process_data", "line": 42, "column": 5, "scope_kind": "function", "scope_label": "process_data", "severity": "warning", "reason": "unreachable_branch" } ], "summary": { "total_issues": 5, "critical_issues": 2, "warning_issues": 3, "info_issues": 0, "files_analyzed": 4 } } ``` Full mode returns `DeadCodeResponse`; its existing `functions`, `total_functions`, and `affected_functions` fields remain function-only. Class suites are reported additively in `class_scopes`, `total_class_scopes`, and `affected_class_scopes`. Aggregate finding, block, health, and module metrics include both populations. ### get_health_score **Description**: Get overall code health score (0-100) with grade **Parameters**: - `path` (required): Path to Python code **Example**: ``` What's the health score of my codebase? ``` **Output**: Health score and breakdown ```json { "health_score": 85, "grade": "A", "is_healthy": true, "partial": false, "diagnostics": [], "failures": [], "category_scores": { "complexity_score": 90, "dead_code_score": 95, "duplication_score": 80, "coupling_score": 85, "cohesion_score": 92, "dependency_score": 88, "architecture_score": 82 }, "summary": { "total_files": 42, "analyzed_files": 42, "skipped_files": 0, "average_complexity": 5.2, "high_complexity_count": 1, "dead_code_count": 2, "clone_pairs": 5, "high_coupling_classes": 3, "high_lcom_classes": 1 } } ``` ## Use Cases ### 1. AI Code Review **Scenario**: Get AI-powered code review with actual metrics **Example Prompts**: - "Review this function for complexity and suggest improvements" - "What are the quality issues in this module?" - "Is this code maintainable?" **Benefits**: - Objective metrics instead of subjective opinions - Specific refactoring suggestions - Quantifiable improvement targets ### 2. Refactoring Assistant **Scenario**: Find refactoring opportunities **Example Prompts**: - "Find duplicate code that can be refactored" - "Which functions are too complex?" - "What classes have high coupling?" **Benefits**: - Data-driven refactoring decisions - Prioritized by impact - Clear before/after metrics ### 3. Quality Gate **Scenario**: Check if code is ready for review/deployment **Example Prompts**: - "Is this code ready for production?" - "Check if the code meets our quality standards" - "What's the overall quality of this PR?" **Benefits**: - Automated quality checks - Consistent standards - Fast feedback loop ### 4. Code Understanding **Scenario**: Understand unfamiliar code **Example Prompts**: - "Explain this complex function" - "What are the dependencies in this module?" - "Which parts of this code are tightly coupled?" **Benefits**: - Context-aware explanations - Visual dependency maps - Complexity hotspots ## Development ### Building ```bash # Build for current platform make build-mcp # Build for all platforms make build-mcp-all # Install globally make install-mcp ``` ### Testing #### Manual Testing ```bash # Run the server directly ./pyscn-mcp ``` Then interact with it via stdin/stdout (JSON-RPC format). #### MCP Inspector Use the official MCP Inspector: ```bash npx @modelcontextprotocol/inspector pyscn-mcp ``` This provides a web UI for: - Viewing available tools - Testing tool calls - Inspecting request/response payloads - Debugging issues ### Adding New Tools 1. **Define the tool** in `mcp/tools.go`: ```go s.AddTool(mcp.NewTool("my_new_tool", mcp.WithDescription("Tool description"), mcp.WithString("path", mcp.Required(), mcp.Description("Path parameter")), ), HandleMyNewTool) ``` 2. **Implement the handler** in `mcp/handlers.go`: ```go func HandleMyNewTool(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Parse arguments // Call existing use cases // Return JSON result } ``` 3. **Rebuild**: ```bash make build-mcp ``` ## Troubleshooting ### Server Not Found **Issue**: `command not found: pyscn-mcp` **Solutions**: 1. Build the binary: `make build-mcp` 2. Add to PATH or use absolute path in config 3. Verify with: `which pyscn-mcp` (Unix) or `where pyscn-mcp` (Windows) ### Permission Denied **Issue**: Permission denied when running `pyscn-mcp` **Solution** (Unix): ```bash chmod +x pyscn-mcp ``` ### Tool Not Appearing **Issue**: Tool doesn't show up in AI assistant **Solutions**: 1. Restart the AI assistant completely 2. Check server logs: `./pyscn-mcp 2> mcp.log` 3. Verify config file syntax 4. Test with MCP Inspector ### Analysis Fails **Issue**: Tool returns error or times out **Solutions**: 1. Check path exists and is accessible 2. Verify Python code is valid 3. Increase timeout in config 4. Check logs for specific errors ### Slow Performance **Issue**: Analysis takes too long **Solutions**: 1. Analyze specific files instead of entire project 2. Disable heavy analyses (clone detection) 3. Increase timeout 4. Use filters (min_complexity, similarity_threshold) ## Architecture ``` AI Assistant (Claude/Cursor) ↓ JSON-RPC via stdio pyscn MCP Server ↓ Function calls Tool Handlers (mcp/handlers.go) ↓ Domain requests Use Cases (app/) ↓ Business logic Analyzers (internal/analyzer/) ↓ Tree-sitter parsing Python Code ``` ## Performance - **Complexity analysis**: ~100,000+ lines/sec - **Clone detection**: Depends on code size - LSH acceleration for large codebases - ~1000 fragments/sec without LSH - ~10,000+ fragments/sec with LSH - **CBO analysis**: ~50,000+ lines/sec - **Dead code**: ~80,000+ lines/sec ## Security - **Path validation**: Prevents directory traversal - **Resource limits**: Timeout and memory constraints - **Sandboxing**: Analysis runs in isolated context - **No code execution**: Static analysis only ## Contributing See [CONTRIBUTING.md](../CONTRIBUTING.md) for development guidelines. ## License MIT License - see [LICENSE](../LICENSE) ## Support - **Issues**: https://github.com/ludo-technologies/pyscn/issues - **Discussions**: https://github.com/ludo-technologies/pyscn/discussions - **Documentation**: https://github.com/ludo-technologies/pyscn/tree/main/docs