Mirrored from
ARCHITECTURE.mdat build time.
Architecture - Tech Debt MCP
This document describes the architecture, design patterns, and data flow of the Tech Debt MCP server.
Table of Contents
- Overview
- Project Structure
- Design Patterns
- Data Flow
- Core Components
- Extending the System
- Dependency Graph
- Performance Considerations
- Future Enhancements
Overview
Tech Debt MCP is a Model Context Protocol server that analyzes technical debt across multiple programming languages. It follows a modular, plugin-based architecture that makes it easy to add new language analyzers and analysis capabilities.
Key Principles
- Single Responsibility — Each module has one clear purpose
- Factory Pattern — Create analyzers and parsers dynamically based on language/file type
- Base Class Inheritance — Share common logic through abstract base classes
- Configuration-Driven — Centralize rules and thresholds in configuration files
- Types First — Single source of truth for all TypeScript interfaces
- Offline-First — No external API calls by default; online features are opt-in
Project Structure
TechDebtMCP/
├── src/
│ ├── index.ts # Entry point — creates server, attaches handlers, runs
│ ├── server/
│ │ ├── setup.ts # McpServer instantiation and transport wiring
│ │ ├── handlers.ts # Core MCP tool request handlers & dispatch
│ │ ├── tools.ts # Centralized TOOL_DEFINITIONS array
│ │ ├── inputParser.ts # Tool argument validation (requireString, optionalString, optionalAbsolutePath, etc.)
│ │ ├── argValidation.ts # Argument coercion and constraint checks
│ │ ├── formatters.ts # Output formatting helpers
│ │ ├── configValidator.ts # .techdebtrc.json validation handler
│ │ ├── dependencyHandlers.ts # Dependency analysis & vulnerability report handlers
│ │ ├── customRulesHandlers.ts # Custom rules management handlers (add, remove, list, execute, validate)
│ │ └── resourceHandlers.ts # ✅ MCP resource templates (Phase 6 - COMPLETE)
│ ├── types/
│ │ └── index.ts # All TypeScript interfaces (single source of truth)
│ ├── config/
│ │ └── languages.ts # Language definitions and configurations
│ ├── core/
│ │ ├── analysisEngine.ts # Main orchestrator for analysis
│ │ ├── sqaleEngine.ts # ✅ SQALE metrics calculations (Phase 1 - COMPLETE)
│ │ └── customRulesEngine.ts # ✅ Custom rules engine (Phase 5 - COMPLETE)
│ ├── analyzers/
│ │ ├── baseAnalyzer.ts # Abstract base class for all language analyzers
│ │ ├── index.ts # Analyzer factory (createAnalyzer)
│ │ ├── [language]Analyzer.ts # 14 language-specific analyzers
│ │ ├── swiftUiChecks.ts # SwiftUI Phase 1 checks (companion to swiftAnalyzer)
│ │ ├── swiftUiChecksPhase2.ts # SwiftUI Phase 2 checks (advanced patterns)
│ │ └── dependencies/ # ✅ Dependency parsers (Phase 2 - COMPLETE)
│ │ ├── baseParser.ts # Abstract base parser
│ │ ├── index.ts # Parser factory (createDependencyParser)
│ │ └── [ecosystem]Parser.ts # 10 ecosystem parsers
│ └── utils/
│ ├── fileUtils.ts # File system utilities
│ └── regexUtils.ts # escapeRegExp() — safe RegExp interpolation helper
├── dist/ # Compiled output
├── .claude/
│ ├── hooks/ # PreToolUse hooks (block-npm-publish.sh, check-tools-manifest-sync.sh)
│ ├── rules/ # Markdown rule files loaded by Claude Code (code-quality, docs-maintenance, etc.)
│ ├── skills/ # Project-specific skills (add-config-block, refresh-self-scan)
│ └── settings.json # Claude Code project settings (hook registrations, permissions)
├── .claude-plugin/
│ ├── plugin.json # Claude Code plugin manifest (mcpServers → npx -y tech-debt-mcp@latest)
│ ├── marketplace.json # Marketplace entry so this repo doubles as its own marketplace
│ ├── README.md # User-facing plugin README shown in the Claude Code marketplace
│ ├── commands/ # Slash commands (/techdebt-scan, /techdebt-file, /techdebt-summary)
│ └── skills/ # Skills (proactive-analysis — context-triggered analysis)
├── mcpb/
│ ├── manifest.json # MCPB v0.3 manifest for Claude Desktop one-click bundle
│ └── icon.png # 512×512 bundle icon
├── docs/site/
│ ├── .vitepress/ # VitePress config + custom slate theme
│ ├── public/ # Static assets (icon.png + inverted icon-light.png)
│ ├── .showcase.json # Pinned-SHA manifest consumed by scripts/scan-showcase.mjs
│ ├── index.md # Landing hero
│ └── install.md, languages.md, custom-rules.md, security.md, privacy.md
├── scripts/
│ ├── build-mcpb.mjs # Stages + packs the .mcpb (npm run mcpb:pack)
│ ├── gen-docs-tools.mjs # Generates docs/site/tools/*.md from TOOL_DEFINITIONS
│ └── scan-showcase.mjs # Clones repos in docs/site/.showcase.json at pinned SHAs, calls AnalysisEngine.analyzeProject() directly (not the MCP tool handler), emits docs/site/examples/*.md chat-style pages
├── package.json
├── tsconfig.json
├── .github/copilot-instructions.md
├── CONTRIBUTING.md
└── ARCHITECTURE.md # This fileDesign Patterns
1. Factory Pattern
Used to create appropriate analyzer or parser instances based on language or file type.
Client
↓
createAnalyzer(language) → Switch statement
├→ 'typescript' → new TypeScriptAnalyzer()
├→ 'python' → new PythonAnalyzer()
└→ 'java' → new JavaAnalyzer()Files involved:
src/analyzers/index.ts—createAnalyzer()factorysrc/analyzers/dependencies/index.ts—createDependencyParser()factory (10 ecosystems)
2. Abstract Base Class with Inheritance
All language analyzers extend BaseAnalyzer to share common logic while allowing language-specific implementations.
BaseAnalyzer (abstract)
├─ performLanguageSpecificChecks() [abstract, must override]
├─ checkTodoComments() [shared]
├─ checkFileTooLong() [shared]
├─ checkPattern() [helper]
├─ applyRuleExclusions() [filter by config globs]
└─ calculateMetrics() [shared]
↓
TypeScriptAnalyzer
PythonAnalyzer
JavaAnalyzer
... (11 more)Files involved:
src/analyzers/baseAnalyzer.ts— Base classsrc/analyzers/[language]Analyzer.ts— Language-specific implementations
3. Configuration-Driven Design
Rules, thresholds, and language definitions are centralized in configuration files, not hardcoded.
src/config/languages.ts
└─ LANGUAGE_CONFIGS: Record<SupportedLanguage, LanguageConfig>
├─ language name
├─ file extensions
├─ package files
├─ comment patterns
├─ TODO patterns
└─ specific checks
.techdebtrc.json (user-provided)
├─ ignore patterns
├─ rule thresholds
├─ rule exclusions (per-rule file glob suppression)
├─ custom patterns
└─ language overridesData Flow
High-Level Analysis Flow
graph TD
A[MCP Client] -->|analyze_project| B[MCP Server]
B -->|analyzeProject| C[AnalysisEngine]
C -->|loadConfig| D[File System]
D -->|read .techdebtrc.json| C
C -->|getProjectFiles| D
D -->|files to analyze| C
C -->|for each file| E[Factory]
E -->|createAnalyzer| F[Language Analyzer]
F -->|performLanguageSpecificChecks| G[Issues Found]
F -->|calculateMetrics| H[File Metrics]
C -->|aggregate| I[TechDebtReport]
I -->|format| J[MCP Response]
J -->|return| AAnalyzer Processing Flow
graph TD
A[analyzeFile] -->|readFile| B[File Content]
B -->|detectLanguage| C[SupportedLanguage]
C -->|createAnalyzer| D[BaseAnalyzer]
D -->|analyze| E[FileAnalysisResult]
E --> F{Check Type}
F -->|Common| G[checkTodoComments]
F -->|Common| H[checkFileTooLong]
F -->|Common| I[checkLongLines]
F -->|Language-Specific| J[performLanguageSpecificChecks]
G --> K[TechDebtIssue]
H --> K
I --> K
J --> K
K -->|aggregate| L[Issues Array]
L -->|applyRuleExclusions| N[Filtered Issues]
D -->|calculateMetrics| M[FileMetrics]
N -->|combine| E
M -->|add to| EReport Generation Flow
graph TD
A[allIssues] -->|calculateSummary| B[DebtSummary]
B -->|bySeverity| C{Count by Level}
B -->|byCategory| D{Count by Type}
B -->|byLanguage| E{Count by Lang}
B -->|debtScore| F[0-100 calculation]
C --> G[TechDebtReport]
D --> G
E --> G
F --> G
A -->|generateRecommendations| H[Recommendation Array]
H --> GCore Components
1. AnalysisEngine (src/core/analysisEngine.ts)
Responsibility: Orchestrates the entire analysis workflow.
Key Methods:
analyzeProject(options)— Main entry point; appliesmergedConfig.includeallowlist filter aftergetProjectFiles()(TEC-57)calculateSummary(issues)— Aggregate statisticsgenerateRecommendations(issues, summary)— Create actionable suggestionsdetectPackageManagers(packageFiles)— Identify dependency managers
Dependencies:
BaseAnalyzer(through factory)fileUtilslanguagesconfig
2. BaseAnalyzer (src/analyzers/baseAnalyzer.ts)
Responsibility: Shared analysis logic for all languages.
Supported Languages (14 total):
- JavaScript, TypeScript, Python, Java, Swift, Kotlin
- Objective-C, C++, C, C#, Go, Rust, Ruby, PHP
Each language has a dedicated analyzer extending BaseAnalyzer.
Key Methods:
analyze(filePath, content)— Main entry pointperformLanguageSpecificChecks(filePath, content)— [Abstract] Override in subclassescheckTodoComments()— Find TODO/FIXME/HACK commentscheckFileTooLong()— Flag files exceeding line limitscheckPattern(filePath, content, regex, issue)— Helper to match patterns (respects inline suppression)isLineSuppressed(lines, lineIndex, rule, blockMap?)— Check inline suppression directivesapplyRuleExclusions(filePath, issues)— Filter issues viaruleExclusionsconfig globs (usesminimatch)calculateMetrics(content)— Compute file statistics
Inheritance Chain:
BaseAnalyzer (abstract)
↓
TypeScriptAnalyzer, PythonAnalyzer, JavaAnalyzer, ... (11 more)3. MCP Server (src/server/)
Responsibility: Expose analysis capabilities as MCP tools and resources.
The server is split into focused modules under src/server/:
setup.ts— McpServer instantiation and stdio transport wiringtools.ts—TOOL_DEFINITIONSarray (16 tool schemas/descriptions)handlers.ts—CallToolRequestSchemaswitch dispatching to handler functionsformatters.ts— Output formatting helpersconfigValidator.ts—.techdebtrc.jsonvalidation handlerdependencyHandlers.ts—check_dependenciesandget_vulnerability_reporthandlersresourceHandlers.ts— MCP resource templates (debt://summary,debt://issues)
Entry point: src/index.ts (18 lines) creates server, attaches handlers + resources, runs.
Path sanitization convention (Issue #129): All handler output that includes file or project paths must use basename() (from node:path) or getRelativePath() (from fileUtils.ts) — never embed raw absolute paths in MCP error messages or report fields. This applies to dependencyHandlers.ts (McpError messages, project-name fields) and configValidator.ts (all user-facing messages). Raw filesystem error messages (e.g., from stat() or readFile()) must also be sanitized before being surfaced to clients — either strip the absolute path from err.message or rethrow as a new McpError with a safe, basename-only message.
16 MCP Tools:
- Core:
analyze_project,analyze_file,get_debt_summary,list_supported_languages,get_recommendations,get_issues_by_severity,get_issues_by_category,get_sqale_metrics - Custom Rules (Phase 5):
add_custom_rule,remove_custom_rule,list_custom_rules,execute_custom_rules,validate_custom_pattern - Dependencies (Phase 2):
check_dependencies,validate_config,get_vulnerability_report
2 MCP Resources (Phase 6):
debt://summary/{+projectPath}— Health score, SQALE metrics, issue counts (projectPathmust be an absolute filesystem path)debt://issues/{+projectPath}— Filterable issues list (severity, category, limit) (projectPathmust be an absolute filesystem path)
Future Tools:
save_baseline,compare_with_baseline,get_trend,list_snapshots,delete_snapshot(Phase 3)get_complexity_report(Phase 4)
4. Types (src/types/index.ts)
Responsibility: Single source of truth for all TypeScript interfaces.
Key Interfaces:
SupportedLanguage— Union type of 14 languagesTechDebtIssue— Individual issue foundFileAnalysisResult— Result from analyzing one fileTechDebtReport— Complete analysis reportDebtSummary— Aggregated statisticsRecommendation— Actionable suggestionsLanguageConfig— Language definitionTechDebtConfig— User configuration- ✅
SQALEMetrics— SQALE technical debt metrics (Phase 1) - ✅
SQALERating— A-E rating scale (Phase 1) - ✅
EffortTimeMapping— Effort-to-time configuration (Phase 1) - ✅
CustomPattern— Custom rule definition (Phase 5)
5. SQALEEngine (src/core/sqaleEngine.ts) ✅ COMPLETE
Responsibility: Calculate SQALE (Software Quality Assessment based on Lifecycle Expectations) metrics for quantifying technical debt.
Key Methods:
calculateMetrics(issues, developmentTime)— Compute complete SQALE metricsgetRemediationTime(effort)— Convert effort level to minutesgetRating(debtRatio)— Calculate A-E rating from debt ratioformatTime(minutes)— Human-readable time formatting- Private helpers for category/severity breakdowns
SQALE Rating Scale:
- A: ≤5% debt ratio (Excellent)
- B: 6-10% debt ratio (Good)
- C: 11-20% debt ratio (Fair)
- D: 21-50% debt ratio (Poor)
- E: >50% debt ratio (Critical)
Metrics Provided:
- Total remediation time (minutes)
- Formatted time (e.g., "2h 30m", "1d 4h")
- Debt ratio (percentage)
- SQALE rating (A-E)
- Breakdown by category
- Breakdown by severity
6. CustomRulesEngine (src/core/customRulesEngine.ts) ✅ COMPLETE
Responsibility: Allow users to define and execute custom pattern-based tech debt checks using regex.
Key Methods:
addRule(pattern)— Add a custom ruleremoveRule(ruleId)— Remove a rule by IDgetRule(ruleId)/getAllRules()— Retrieve rulesexecuteRules(filePath, content, language)— Run all rules against codegetRuleStats()— Get statistics by severity/categorystatic validatePattern(pattern)— Validate rule before addingstatic createSimplePattern()— Helper to create patterns
Features:
- Regex pattern matching with configurable flags (allowlist:
dgimsuvy— includes thevunicodeSets flag;uandvare mutually exclusive; patterns capped at 1,000 characters; inlinecodecapped at 500,000 characters;pathinputs capped at 500,000 bytes before reading). Node.js >=20.19.0 required as of v2.0.2 (project minimum, including tooling such as ESLint). - Language-specific rule filtering
- Inline suppression (
techdebt-ignore-next-line [rule]/techdebt-ignore-start/end [rule]) — consistent withBaseAnalyzer; block map built once per file, checked per matched line - Multiple matches per line support
- Cross-platform line ending support (\r\n and \n)
- Column information for precise issue location
- Error callback for better testability
- Category and severity validation
Pattern Execution Flow:
CustomPattern
↓
validatePattern() [static]
↓
addRule()
↓
executeRules(filePath, content, language)
├─ Filter by language (if specified)
├─ Split content by lines (/\r?\n/)
├─ buildBlockSuppressionMap(lines) [once per file]
├─ For each pattern:
│ └─ executePattern(filePath, lines, blockMap, pattern)
│ ├─ Apply regex with exec loop per line
│ ├─ isLineSuppressed(lines, index, rule, blockMap) ← skip suppressed lines
│ ├─ Capture match index & column
│ └─ Create TechDebtIssue
└─ Return issues arrayExtending the System
Adding a New Language Analyzer
Create the analyzer file:
typescript// src/analyzers/rustAnalyzer.ts export class RustAnalyzer extends BaseAnalyzer { constructor(config: TechDebtConfig = {}) { super('rust', config); } protected async performLanguageSpecificChecks( filePath: string, content: string ): Promise<TechDebtIssue[]> { const issues: TechDebtIssue[] = []; // Add Rust-specific checks issues.push(...this.checkPattern(filePath, content, /\.unwrap\(\)/g, { category: 'code-quality', severity: 'medium', title: 'unwrap() usage', description: 'Using unwrap() can panic at runtime', suggestion: 'Use error handling or Option::map instead', effort: 'small', rule: 'unwrap-usage', tags: ['error-handling'], })); return issues; } }Register in factory (
src/analyzers/index.ts):typescriptcase 'rust': return new RustAnalyzer(config);Ensure language config exists (
src/config/languages.ts):typescriptrust: { name: 'Rust', extensions: ['.rs'], packageFiles: ['Cargo.toml'], commentPatterns: { /* ... */ }, todoPatterns: [ /* ... */ ], specificChecks: [ /* ... */ ], }Add type (
src/types/index.ts):typescriptexport type SupportedLanguage = | 'javascript' | 'typescript' | 'python' | /* ... */ | 'rust'; // Add hereWrite tests (
src/analyzers/__tests__/rustAnalyzer.test.ts)
Adding a New MCP Tool
Add tool schema (
src/server/tools.ts):typescript{ name: 'my_new_tool', description: 'What it does', inputSchema: { /* ... */ }, }Add handler case (
src/server/handlers.ts):typescriptcase 'my_new_tool': return await handleMyNewTool(args);Implement handler — in
handlers.tsfor core tools, or in a dedicated file (e.g.,configValidator.ts,dependencyHandlers.ts) for domain-specific tools. Keephandlers.tsunder 500 lines.
Adding a New Core Engine
For major new functionality (like SQALE, dependency checking, trend tracking):
- Create engine file:
src/core/[feature]Engine.ts - Export types: Add to
src/types/index.ts - Integrate with AnalysisEngine: Call from
analyzeProject() - Add MCP tool: Schema in
src/server/tools.ts, handler insrc/server/handlers.ts(or dedicated file) - Write tests:
src/core/__tests__/[feature]Engine.test.ts
Dependency Graph
index.ts (Entry point)
├─ server/setup.ts (McpServer + transport)
├─ server/handlers.ts (tool dispatch)
│ ├─ AnalysisEngine
│ │ ├─ Analyzer (via factory)
│ │ │ └─ BaseAnalyzer → src/config/languages.ts
│ │ ├─ fileUtils
│ │ └─ regexUtils (escapeRegExp)
│ ├─ ✅ SQALEEngine (Phase 1)
│ ├─ ✅ CustomRulesEngine (Phase 5)
│ ├─ ✅ configValidator.ts (Phase 2)
│ └─ ✅ dependencyHandlers.ts (Phase 2)
│ └─ DependencyParsers (10 ecosystems, via factory)
└─ server/resourceHandlers.ts (Phase 6)
└─ AnalysisEngine (passive data access)
Future additions:
├─ SnapshotManager (Phase 3)
└─ ComplexityAnalyzer (Phase 4)Performance Considerations
- File Processing: Analyzed in sequential order; can be parallelized in future
- Regex Patterns: Compiled once in config;
.lastIndexreset per line - Memory: Issues stored in memory; large projects may need pagination
- Configuration: Loaded once per analysis; consider caching
SwiftUI Analysis Architecture
Version Added: v1.1.0
Module: SwiftAnalyzer (extends BaseAnalyzer)
Implementation: Issue #58
Overview
The SwiftUI analyzer provides 14 specialized checks for SwiftUI applications across 2 phases:
- Phase 1: Core SwiftUI checks (9 patterns)
- Phase 2: Advanced SwiftUI patterns (5 patterns)
Implementation Pattern
All SwiftUI checks follow a consistent architecture:
private checkSwiftUIPattern(filePath: string, lines: string[]): TechDebtIssue[] {
const issues: TechDebtIssue[] = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Pattern detection logic
if (/* pattern detected */) {
issues.push({
id: `pattern-name-${filePath}-${i + 1}`, // Globally unique ID
category: 'code-quality',
severity: 'medium',
file: filePath,
line: i + 1,
title: 'Issue title',
description: 'What the issue is',
suggestion: 'How to fix it',
effort: 'small',
language: 'swift',
rule: 'swiftui-pattern-name',
tags: ['swiftui', 'specific-tag'],
});
}
}
return issues;
}Performance Optimization
Content Splitting: Pre-split once in performLanguageSpecificChecks:
const lines = content.split('\n');
issues.push(...this.checkExcessiveStateVariables(filePath, lines));
issues.push(...this.checkStateObjectMisuse(filePath, lines));
// ... all other checks receive pre-split linesThis reduces overhead from O(N × checks) to O(1) for content splitting.
Phase 1: Core SwiftUI Checks (9 Patterns)
| Check | Rule | Severity | Detection Method |
|---|---|---|---|
| Excessive @State | swiftui-excessive-state | Medium | Per-view @State counting with struct scope tracking |
| @ObservedObject Misuse | swiftui-state-object-misuse | High | Pattern: @ObservedObject + = on same line |
| Environment Validation | swiftui-env-validation | High | Force unwrap detection at @Environment usage sites |
| Combine Circular Refs | swiftui-combine-circular-ref | High | .sink without [weak self] in context |
| Missing Timer Cleanup | swiftui-timer-cleanup | Medium | Timer.scheduledTimer without onDisappear |
| Missing Task Cancel | swiftui-task-cancellation | Medium | Task { without tracking or .task modifier |
| Main Thread Safety | swiftui-main-thread-safety | High | Task { + self. without DispatchQueue.main |
| Missing .id() | swiftui-missing-id | Medium | ForEach + dynamic data without .id() |
| Expensive Calculations | swiftui-expensive-calculation | Medium | reduce/sort/filter in view body |
Phase 2: Advanced Patterns (5 Patterns)
| Check | Rule | Severity | Detection Method |
|---|---|---|---|
| AnyView Misuse | swiftui-anyview-misuse | Medium | AnyView( detection (type erasure) |
| NavigationLink Issues | swiftui-navigationlink-deprecated | Medium | Deprecated NavigationLink patterns |
| GeometryReader Root | swiftui-geometryreader-root | Medium | GeometryReader at var body: level |
| Retain Cycles | swiftui-retain-cycle-closure | High | .onChange/.onReceive without [weak self] |
| Deep Nesting | swiftui-deep-nesting | Medium | Brace depth >6 in view body |
Test Coverage
Total Repository Tests: 597 (576 passing + 21 todo across 29 suites)
SwiftUI Analyzer Tests:
- Phase 1 Tests: 21 implemented test cases
- Phase 2 Tests: 20 implemented test cases
- Phase 3 Tests: 13 todo tests for future enhancements
Test Pattern:
it('should detect SwiftUI pattern', async () => {
const code = `/* sample Swift code */`;
const result = await analyzer.analyze('test.swift', code);
const issues = result.issues.filter(i => i.rule === 'swiftui-pattern-name');
expect(issues.length).toBeGreaterThan(0);
expect(issues[0].severity).toBe('medium');
});Heuristic Limitations
The SwiftUI analyzer uses line-based pattern matching with the following known limitations:
- Multi-line Constructs: Complex multi-line SwiftUI code may not be detected
- Comment Filtering: Inline comments are stripped but may affect detection
- Scope Tracking: Brace-depth counting for view scope has edge cases
- False Positives: Demo/example code may trigger warnings
Recommended Improvements (Phase 3):
- Full Swift AST parsing for accurate scope detection
- Context-aware pattern matching
- Enhanced comment/string literal filtering
- User-configurable thresholds
Design Decisions
- Issue ID Format:
${rule}-${filePath}-${lineNumber}for global uniqueness - Pre-split Lines: Pass
string[]instead ofcontent: stringfor performance - Per-View Counting: Track @State count per struct, not file-wide
- Severity Levels: Align with Apple's best practices (High = potential crash)
Dependencies
import { TechDebtIssue } from '../types/index.js';
import { BaseAnalyzer } from './baseAnalyzer.js';No External Dependencies: Uses only Node.js built-ins (string/array manipulation)
Code Quality Standards
Project Health Metrics (Self-Scan)
Current Status (v2.0.2, April 2026):
- SQALE Rating: A ⭐⭐⭐⭐⭐ (Excellent)
- Debt Score: 5/100 (Target: ≤5/100)
- Health Score: 95/100
- Total Issues: 13 (0 critical, 0 high, 6 medium, 7 low)
- Remediation Time: 14 hours
Note: Down from 118 issues / 42.4 health in the v2.0.1 baseline after v2.0.2 security hardening, ruleExclusions config, nesting refactors (PRs #113, #118, #131, #146), and custom-rules handler extraction (#145). Remaining debt is 5 nesting hotspots (4 in server / core modules + 1 in eslint.config.mjs), 7 type-assertion usages at system boundaries, and 1 non-null assertion.
See TECH_DEBT_SCAN.md for complete analysis including before/after comparison.
File Size & Complexity Limits
| Metric | Limit | Current Max | Status |
|---|---|---|---|
| File length | 500 lines | 346 (src/server/handlers.ts) | ✅ Good (further reduced in v2.0.2 after custom-rules handler extraction) |
| Nesting depth | 4 levels | 6 (5 hotspots) | ⚠️ Known — 5 remaining hotspots (max depth 6 in customRulesEngine.ts); tracked in TECH_DEBT_SCAN.md |
| Function length | 50 lines | Compliant | ✅ Good |
| Cyclomatic complexity | 10 | Compliant | ✅ Good |
Note: File count grew from 25 → 43 → 49 across Feb 2026 → March 2026 → April 2026 scans as more analyzers, dependency parsers, server modules, and the ESLint flat config were added across v2.0.0, v2.0.1, and v2.0.2.
Known Technical Debt Items
High Priority (Address when touching these files)
✅ DONE (v2.0.0) — now 18 lines, split intosrc/index.ts(883 lines) - Split into modulessrc/server/modules✅ DONE (PR #113) — refactored to ≤4 levels via helper methods and early returnssrc/analyzers/csharpAnalyzer.ts:267- Deep nesting (14 levels)False positives in analyzers (13 high-severity false positives)✅ DONE (v2.0.1+) — Two complementary mechanisms: (a)ruleExclusionsconfig in.techdebtrc.jsonfor file-level glob suppression; (b) inline suppression comments (// techdebt-ignore-next-line [rule]and// techdebt-ignore-start/end [rule]) for line- and block-level suppression directly in source code. Analyzer pattern definitions use block suppression to avoid self-detection. Seesrc/analyzers/baseAnalyzer.tsisLineSuppressed()andbuildBlockSuppressionMap().
Medium Priority (Gradual improvement)
Deep nesting in multiple files:✅ DONE (PR #118) — refactored to ≤4 levels via helper methodssrc/core/customRulesEngine.ts:129- 7 levels✅ DONE (#146) — extractedsrc/core/customRulesEngine.ts:validatePattern- 6 levelsvalidatePatternRegexprivate helper✅ DONE (PR #118) — refactored to ≤4 levels via early returnssrc/core/analysisEngine.ts:93- 5 levels✅ DONE (#131) — extractedsrc/analyzers/dependencies/cppParser.ts- 5 levels inparseVcpkgJsonmakeVcpkgDep()helper and early-return guard
Remaining (v2.0.2): 5 active nesting hotspots —
customRulesEngine.ts:156(depth 6),handlers.ts:273,dependencyHandlers.ts:228,analysisEngine.ts:257,eslint.config.mjs:25(all depth 5). See TECH_DEBT_SCAN.md.Test file organization - Previously had 9-level deep nesting
- Now excluded from production analysis via
.techdebtrc.json - Can still be improved for test maintainability
- Now excluded from production analysis via
Code Quality Enforcement
These rules are enforced via .techdebtrc.json and CI checks:
❌ Forbidden in production code:
debuggerstatements@ts-ignorecomments (use@ts-expect-errorwith explanation)console.logstatements (use proper logging or remove)
✅ Required patterns:
- JSDoc on all public APIs
- Early returns to reduce nesting
- Optional chaining for nullable access
- Helper functions for complex logic
Self-Scan Strategy
Prevent False Positives:
- Test files are ignored (contain test patterns, not production issues)
- Analyzer files may reference keywords (e.g., "debugger" in pattern definitions)
- Configuration in
.techdebtrc.jsonexcludes test directories
Configuration Impact (Measured, v2.0.2 April 2026):
# v2.0.2 (April 2026, post security hardening + nesting refactors):
- 13 issues, 14 hours remediation
- 49 files analyzed (TypeScript + JavaScript, including the eslint flat config)
- 0 high-severity issues
# v2.0.1 baseline (March 2026, wider scan scope):
- 118 issues, ~96 hours remediation
- 43 files analyzed
- 12 high-severity issues
# Original baseline (Feb 2026, pre-.techdebtrc.json):
- 101 issues, 70 hours remediation
- 33 files analyzed (including tests)
- 17 high-severity issues (includes test false positives)Regular Health Checks:
# Run self-scan before major releases
npx tech-debt-mcp analyze_project --path=/path/to/TechDebtMCP
# Target metrics:
# - SQALE Rating: A (≤5% debt ratio)
# - Critical issues: 0
# - High issues: <10 (excluding analyzer patterns)
# - File length violations: 0See TECH_DEBT_SCAN.md for complete before/after analysis and detailed findings.
Future Enhancements
- Parallel file processing — Analyze multiple files concurrently
- Incremental analysis — Skip unchanged files
- Plugin system — Load analyzers dynamically
- Custom severity weights — User-configurable issue scoring
- Integration with CI/CD — GitHub Actions, GitLab CI, etc.
Phase 2: Dependency Analysis (Added)
Phase 2 introduces a modular dependency parsing subsystem and a new MCP tool, check_dependencies.
Key points:
- Parsers are implemented under
src/analyzers/dependencies/following the same factory + base class pattern as language analyzers. - Each parser focuses on one ecosystem and exposes a common async
parse(filePath, content)interface that returnsPromise<ParsedDependency[]>. - A
check_dependenciesMCP tool scans the repository for recognized package files, invokes these async parsers, and returns a human-readable markdown report with production vs development dependencies and any failed parse entries. - The design is offline-first and describes extension points for future vulnerability scanning services (e.g., a dedicated vulnerability scanning module in a later phase) without adding an immediate implementation path.
Files added in Phase 2:
src/analyzers/dependencies/
├── baseParser.ts
├── index.ts (factory)
├── npmParser.ts
├── pipParser.ts
├── cargoParser.ts
├── goModParser.ts
├── gradleParser.ts
├── composerParser.ts
├── bundlerParser.ts
├── nugetParser.ts
├── cppParser.ts
└── swiftPackageParser.tsThese modules follow the existing analyzer conventions and are covered by unit tests in src/analyzers/dependencies/__tests__/.