Skip to content

Mirrored from ARCHITECTURE.md at 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

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

  1. Single Responsibility — Each module has one clear purpose
  2. Factory Pattern — Create analyzers and parsers dynamically based on language/file type
  3. Base Class Inheritance — Share common logic through abstract base classes
  4. Configuration-Driven — Centralize rules and thresholds in configuration files
  5. Types First — Single source of truth for all TypeScript interfaces
  6. 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 file

Design 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.tscreateAnalyzer() factory
  • src/analyzers/dependencies/index.tscreateDependencyParser() 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 class
  • src/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 overrides

Data Flow

High-Level Analysis Flow

mermaid
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| A

Analyzer Processing Flow

mermaid
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| E

Report Generation Flow

mermaid
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 --> G

Core Components

1. AnalysisEngine (src/core/analysisEngine.ts)

Responsibility: Orchestrates the entire analysis workflow.

Key Methods:

  • analyzeProject(options) — Main entry point; applies mergedConfig.include allowlist filter after getProjectFiles() (TEC-57)
  • calculateSummary(issues) — Aggregate statistics
  • generateRecommendations(issues, summary) — Create actionable suggestions
  • detectPackageManagers(packageFiles) — Identify dependency managers

Dependencies:

  • BaseAnalyzer (through factory)
  • fileUtils
  • languages config

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 point
  • performLanguageSpecificChecks(filePath, content) — [Abstract] Override in subclasses
  • checkTodoComments() — Find TODO/FIXME/HACK comments
  • checkFileTooLong() — Flag files exceeding line limits
  • checkPattern(filePath, content, regex, issue) — Helper to match patterns (respects inline suppression)
  • isLineSuppressed(lines, lineIndex, rule, blockMap?) — Check inline suppression directives
  • applyRuleExclusions(filePath, issues) — Filter issues via ruleExclusions config globs (uses minimatch)
  • 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 wiring
  • tools.tsTOOL_DEFINITIONS array (16 tool schemas/descriptions)
  • handlers.tsCallToolRequestSchema switch dispatching to handler functions
  • formatters.ts — Output formatting helpers
  • configValidator.ts.techdebtrc.json validation handler
  • dependencyHandlers.tscheck_dependencies and get_vulnerability_report handlers
  • resourceHandlers.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 (projectPath must be an absolute filesystem path)
  • debt://issues/{+projectPath} — Filterable issues list (severity, category, limit) (projectPath must 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 languages
  • TechDebtIssue — Individual issue found
  • FileAnalysisResult — Result from analyzing one file
  • TechDebtReport — Complete analysis report
  • DebtSummary — Aggregated statistics
  • Recommendation — Actionable suggestions
  • LanguageConfig — Language definition
  • TechDebtConfig — 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 metrics
  • getRemediationTime(effort) — Convert effort level to minutes
  • getRating(debtRatio) — Calculate A-E rating from debt ratio
  • formatTime(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 rule
  • removeRule(ruleId) — Remove a rule by ID
  • getRule(ruleId) / getAllRules() — Retrieve rules
  • executeRules(filePath, content, language) — Run all rules against code
  • getRuleStats() — Get statistics by severity/category
  • static validatePattern(pattern) — Validate rule before adding
  • static createSimplePattern() — Helper to create patterns

Features:

  • Regex pattern matching with configurable flags (allowlist: dgimsuvy — includes the v unicodeSets flag; u and v are mutually exclusive; patterns capped at 1,000 characters; inline code capped at 500,000 characters; path inputs 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 with BaseAnalyzer; 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 array

Extending the System

Adding a New Language Analyzer

  1. 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;
      }
    }
  2. Register in factory (src/analyzers/index.ts):

    typescript
    case 'rust':
      return new RustAnalyzer(config);
  3. Ensure language config exists (src/config/languages.ts):

    typescript
    rust: {
      name: 'Rust',
      extensions: ['.rs'],
      packageFiles: ['Cargo.toml'],
      commentPatterns: { /* ... */ },
      todoPatterns: [ /* ... */ ],
      specificChecks: [ /* ... */ ],
    }
  4. Add type (src/types/index.ts):

    typescript
    export type SupportedLanguage = 
      | 'javascript' | 'typescript' | 'python' | /* ... */
      | 'rust'; // Add here
  5. Write tests (src/analyzers/__tests__/rustAnalyzer.test.ts)

Adding a New MCP Tool

  1. Add tool schema (src/server/tools.ts):

    typescript
    {
      name: 'my_new_tool',
      description: 'What it does',
      inputSchema: { /* ... */ },
    }
  2. Add handler case (src/server/handlers.ts):

    typescript
    case 'my_new_tool':
      return await handleMyNewTool(args);
  3. Implement handler — in handlers.ts for core tools, or in a dedicated file (e.g., configValidator.ts, dependencyHandlers.ts) for domain-specific tools. Keep handlers.ts under 500 lines.

Adding a New Core Engine

For major new functionality (like SQALE, dependency checking, trend tracking):

  1. Create engine file: src/core/[feature]Engine.ts
  2. Export types: Add to src/types/index.ts
  3. Integrate with AnalysisEngine: Call from analyzeProject()
  4. Add MCP tool: Schema in src/server/tools.ts, handler in src/server/handlers.ts (or dedicated file)
  5. 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

  1. File Processing: Analyzed in sequential order; can be parallelized in future
  2. Regex Patterns: Compiled once in config; .lastIndex reset per line
  3. Memory: Issues stored in memory; large projects may need pagination
  4. 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:

typescript
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:

typescript
const lines = content.split('\n');
issues.push(...this.checkExcessiveStateVariables(filePath, lines));
issues.push(...this.checkStateObjectMisuse(filePath, lines));
// ... all other checks receive pre-split lines

This reduces overhead from O(N × checks) to O(1) for content splitting.

Phase 1: Core SwiftUI Checks (9 Patterns)

CheckRuleSeverityDetection Method
Excessive @Stateswiftui-excessive-stateMediumPer-view @State counting with struct scope tracking
@ObservedObject Misuseswiftui-state-object-misuseHighPattern: @ObservedObject + = on same line
Environment Validationswiftui-env-validationHighForce unwrap detection at @Environment usage sites
Combine Circular Refsswiftui-combine-circular-refHigh.sink without [weak self] in context
Missing Timer Cleanupswiftui-timer-cleanupMediumTimer.scheduledTimer without onDisappear
Missing Task Cancelswiftui-task-cancellationMediumTask { without tracking or .task modifier
Main Thread Safetyswiftui-main-thread-safetyHighTask { + self. without DispatchQueue.main
Missing .id()swiftui-missing-idMediumForEach + dynamic data without .id()
Expensive Calculationsswiftui-expensive-calculationMediumreduce/sort/filter in view body

Phase 2: Advanced Patterns (5 Patterns)

CheckRuleSeverityDetection Method
AnyView Misuseswiftui-anyview-misuseMediumAnyView( detection (type erasure)
NavigationLink Issuesswiftui-navigationlink-deprecatedMediumDeprecated NavigationLink patterns
GeometryReader Rootswiftui-geometryreader-rootMediumGeometryReader at var body: level
Retain Cyclesswiftui-retain-cycle-closureHigh.onChange/.onReceive without [weak self]
Deep Nestingswiftui-deep-nestingMediumBrace 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:

typescript
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:

  1. Multi-line Constructs: Complex multi-line SwiftUI code may not be detected
  2. Comment Filtering: Inline comments are stripped but may affect detection
  3. Scope Tracking: Brace-depth counting for view scope has edge cases
  4. 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

  1. Issue ID Format: ${rule}-${filePath}-${lineNumber} for global uniqueness
  2. Pre-split Lines: Pass string[] instead of content: string for performance
  3. Per-View Counting: Track @State count per struct, not file-wide
  4. Severity Levels: Align with Apple's best practices (High = potential crash)

Dependencies

typescript
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

MetricLimitCurrent MaxStatus
File length500 lines346 (src/server/handlers.ts)✅ Good (further reduced in v2.0.2 after custom-rules handler extraction)
Nesting depth4 levels6 (5 hotspots)⚠️ Known — 5 remaining hotspots (max depth 6 in customRulesEngine.ts); tracked in TECH_DEBT_SCAN.md
Function length50 linesCompliant✅ Good
Cyclomatic complexity10Compliant✅ 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)

  1. src/index.ts (883 lines) - Split into modulesDONE (v2.0.0) — now 18 lines, split into src/server/ modules

  2. src/analyzers/csharpAnalyzer.ts:267 - Deep nesting (14 levels)DONE (PR #113) — refactored to ≤4 levels via helper methods and early returns

  3. False positives in analyzers (13 high-severity false positives)DONE (v2.0.1+) — Two complementary mechanisms: (a) ruleExclusions config in .techdebtrc.json for 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. See src/analyzers/baseAnalyzer.ts isLineSuppressed() and buildBlockSuppressionMap().

Medium Priority (Gradual improvement)

  1. Deep nesting in multiple files:

    • src/core/customRulesEngine.ts:129 - 7 levelsDONE (PR #118) — refactored to ≤4 levels via helper methods
    • src/core/customRulesEngine.ts:validatePattern - 6 levelsDONE (#146) — extracted validatePatternRegex private helper
    • src/core/analysisEngine.ts:93 - 5 levelsDONE (PR #118) — refactored to ≤4 levels via early returns
    • src/analyzers/dependencies/cppParser.ts - 5 levels in parseVcpkgJsonDONE (#131) — extracted makeVcpkgDep() 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.

  2. Test file organization - Previously had 9-level deep nesting

    • Now excluded from production analysis via .techdebtrc.json
    • Can still be improved for test maintainability

Code Quality Enforcement

These rules are enforced via .techdebtrc.json and CI checks:

  • Forbidden in production code:

    • debugger statements
    • @ts-ignore comments (use @ts-expect-error with explanation)
    • console.log statements (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.json excludes test directories

Configuration Impact (Measured, v2.0.2 April 2026):

bash
# 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:

bash
# 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: 0

See 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 returns Promise<ParsedDependency[]>.
  • A check_dependencies MCP 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.ts

These modules follow the existing analyzer conventions and are covered by unit tests in src/analyzers/dependencies/__tests__/.