Adding a Language¶
Every language in MCP Zen of Languages follows the same structure. You'll define zen principles, implement an analyzer, create detectors, and wire everything together. The architecture does the rest.
Mental model¶
Think of each language module as answering three questions:
- What does "good code" mean? →
rules.py(zen principles) - How do we parse the code? →
analyzer.py(Template Method hooks) - What patterns do we flag? →
detectors.py(Strategy implementations)
Directory structure¶
Create src/mcp_zen_of_languages/languages/<language>/ with:
<language>/
├── __init__.py # Module exports
├── rules.py # Zen principles (ZenPrinciple models)
├── analyzer.py # Subclass of BaseAnalyzer
├── detectors.py # ViolationDetector implementations
└── mapping.py # Rule ID → Detector class bindings
Step-by-step¶
1. Define zen principles¶
In rules.py, define principles as ZenPrinciple Pydantic models. Each principle needs a unique rule ID, name, category, and severity:
# languages/kotlin/rules.py
KOTLIN_ZEN_RULES = [
ZenPrinciple(
rule_id="kt-001",
name="Null safety is non-negotiable",
category="SAFETY",
severity=7,
description="Use Kotlin's type system to eliminate null pointer exceptions.",
),
# ... more principles
]
2. Implement the analyzer¶
Subclass BaseAnalyzer and implement the two abstract methods:
# languages/kotlin/analyzer.py
from mcp_zen_of_languages.analyzers.base import BaseAnalyzer
class KotlinAnalyzer(BaseAnalyzer):
def parse_code(self, code: str):
return None # Use None for regex-based detection
def compute_metrics(self, code: str, ast_tree):
return None, None, len(code.splitlines())
Most languages use regex-based detection (no AST parsing required). Only Python currently has full AST support.
2.1 Declare analyzer capabilities¶
Every analyzer can optionally override capabilities() to declare support for AST parsing, dependency analysis, and richer metrics.
from mcp_zen_of_languages.analyzers.base import AnalyzerCapabilities
class KotlinAnalyzer(BaseAnalyzer):
def capabilities(self) -> AnalyzerCapabilities:
return AnalyzerCapabilities(supports_ast=False)
Guidance:
- Keep hook signatures (
parse_code,compute_metrics,_build_dependency_analysis) intact even when implementations are placeholders. - Returning
Nonefromparse_codeis valid for text-only analyzers;BaseAnalyzerrecords this viaAnalysisContext.ast_status. - Override
capabilities()when you add a real parser or dependency graph so detectors can branch on explicit support.
3. Create detectors¶
Each detector implements ViolationDetector with a detect() method:
# languages/kotlin/detectors.py
from mcp_zen_of_languages.analyzers.detectors.base import ViolationDetector
class NullAssertionDetector(ViolationDetector):
def detect(self, context, config):
violations = []
for i, line in enumerate(context.code.splitlines(), 1):
if "!!" in line:
violations.append(self._build_violation(
rule_id="kt-001",
message=f"Non-null assertion (!!) at line {i}",
severity=7,
line=i,
))
return violations
4. Register mappings¶
In mapping.py, connect rule IDs to detector classes:
# languages/kotlin/mapping.py
from .detectors import NullAssertionDetector
RULE_DETECTOR_MAP = {
"kt-001": NullAssertionDetector,
}
5. Add detector configs (if needed)¶
If your detectors need configurable thresholds, add config models in languages/configs.py.
6. Register in the factory¶
Add your analyzer to analyzers/analyzer_factory.py so the factory can create it.
7. Add tests¶
At minimum, write tests for each detector in tests/. Test both positive cases (violation expected) and negative cases (clean code).
Verification¶
See Also¶
- Architecture — How the patterns connect
- Adding a Detector — Focused guide for single detectors
- Languages — Existing language implementations for reference