Semantic linting MCP server that detects codebase redundancy created by AI coding agents
Echo Guard exposes 4 tools for duplicate detection and codebase health analysis. Tool naming follows verb_noun convention (check_for_duplicates, resolve_finding, get_codebase_health, list_findings), good. Descriptions are present and moderately detailed (100-300 chars), explaining WHEN to call tools and severity models. However, input schemas are not visible in the provided source code, only parameter names and descriptions are shown in the tool docstrings. Without explicit JSON Schema definitions, schema quality cannot be verified. Parameter descriptions exist but lack formal type constraints (enums, ranges, patterns). Error handling guidance is minimal. The tool set is well-composed (each does one thing) and addresses a coherent domain (code redundancy detection).
Check code for duplicates against the existing codebase. WHEN TO CALL THIS: - Before writing a utility/helper function that might already exist - After completing a task, pass all new code to check in one batch - When you're about to create something that "feels" like it could exist You do NOT need to call this for every function you write. Use your judgment — call it when there's a reasonable chance of duplication. SEVERITY MODEL (action-based): - extract: 3+ copies exist — extract to shared module immediately - review: 2 copies — worth noting, import existing or defer per Rule of Three Each finding includes a finding_id. After reviewing, call resolve_finding to record your decision (resolved, intentional, or dismissed). Previously resolved findings are automatically excluded.
Get a health score for the codebase based on redundancy metrics. Returns: - health_score: 0-100 integer (100 = no redundancy, 0 = severe redundancy) - total_functions: Number of functions indexed - total_redundancies: Number of duplicate clusters found - extract_severity: Count of 3+ copy clusters (highest priority) - review_severity: Count of 2-copy clusters (medium priority) - details: Breakdown by language and severity
List all unresolved duplicate findings in the codebase. Returns a paginated list of findings sorted by severity (extract > review). Each finding includes: - finding_id: Stable identifier for resolve_finding() - severity: 'extract' (3+ copies) or 'review' (2 copies) - source: The proposed/new function - existing: The existing function it matches - similarity_score: 0-1 confidence - clone_type: 'type1', 'type2', 'type3', 'type4', or 'cross_lang'
Record your decision on a duplicate finding after review. Use this to mark findings as: - resolved: You've addressed the duplication (extracted, refactored, etc.) - intentional: The duplication is intentional and should be kept - dismissed: False positive or not actionable Once recorded, the finding will not appear in future check_for_duplicates calls.
Input schemas not visible in source code. Parameter definitions show names and descriptions but no explicit JSON Schema with type constraints, enums, or ranges. Cannot verify schema completeness or validation rules.
Missing enum constraints on string parameters. 'language' in check_for_duplicates lists valid values in description ('python, javascript, ...') but should be declared as an enum in schema. 'verdict' in resolve_finding should be an enum ('resolved', 'intentional', 'dismissed'). 'severity' in list_findings should be an enum ('extract', 'review').
Output schemas not documented. Tools return structured data (health_score, findings, etc.) but the response schema is not formally specified. LLMs cannot reliably extract fields without documented return types.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 52 | <=2025-11-25 | v2 |
Minimal error handling guidance. Tool descriptions do not explain what errors can occur, how to recover, or what the LLM should do if a call fails. No recovery hints (e.g., 'If repo_root is invalid, try auto-detection').
Numeric parameters lack range constraints. 'limit' and 'offset' in list_findings have no documented min/max values. Unbounded integers invite LLMs to pass absurd values (limit=999999, offset=-1).