Skip to main content

ADR-001: MCP Server Architecture using TypeScript SDK

Status

Accepted

Context

DocuMCP requires a robust server architecture that can integrate seamlessly with development environments like GitHub Copilot, Claude Desktop, and other MCP-enabled tools. The server needs to provide intelligent repository analysis, static site generator recommendations, and automated documentation deployment workflows.

Key requirements:

  • Standards-compliant MCP protocol implementation
  • Stateless operation for consistency and reliability
  • Modular design separating concerns
  • Integration with existing developer workflows
  • Scalable architecture supporting complex multi-step operations

Decision

We will implement the DocuMCP server using the TypeScript Model Context Protocol SDK, following a modular, stateless architecture pattern.

Core Architectural Components:

  1. MCP Server Foundation: TypeScript-based implementation using official MCP SDK
  2. Repository Analysis Engine: Multi-layered analysis of project characteristics
  3. Static Site Generator Recommendation Engine: Algorithmic decision framework
  4. File Generation and Template System: Template-based configuration generation
  5. GitHub Integration Layer: Automated deployment orchestration

Design Principles:

  • Stateless Operation: Each invocation analyzes current repository state
  • Modular Design: Clear separation between analysis, recommendation, generation, and deployment
  • Standards Compliance: Full adherence to MCP specification requirements
  • Session Context: Temporary context preservation within single sessions for complex workflows

Alternatives Considered

Python-based Implementation

  • Pros: Rich ecosystem for NLP and analysis, familiar to many developers
  • Cons: Less mature MCP SDK, deployment complexity, slower startup times
  • Decision: Rejected due to MCP ecosystem maturity in TypeScript

Go-based Implementation

  • Pros: High performance, excellent concurrency, small binary size
  • Cons: Limited MCP SDK support, smaller ecosystem for documentation tools
  • Decision: Rejected due to limited MCP tooling and development velocity concerns

Stateful Server with Database

  • Pros: Could cache analysis results, maintain user preferences
  • Cons: Deployment complexity, synchronization issues, potential staleness
  • Decision: Rejected to maintain simplicity and ensure consistency

Consequences

Positive

  • Developer Familiarity: TypeScript is widely known in the target developer community
  • MCP Ecosystem: Mature tooling and extensive documentation available
  • Rapid Development: Rich ecosystem accelerates feature development
  • Integration: Seamless integration with existing JavaScript/TypeScript tooling
  • Consistency: Stateless design eliminates synchronization issues
  • Reliability: Reduces complexity and potential failure modes

Negative

  • Runtime Overhead: Node.js runtime may have higher memory usage than compiled alternatives
  • Startup Time: Node.js startup may be slower than Go or Rust alternatives
  • Dependency Management: npm ecosystem can introduce supply chain complexity

Risks and Mitigations

  • Supply Chain Security: Use npm audit and dependency scanning in CI/CD
  • Performance: Implement intelligent caching and optimize hot paths
  • Memory Usage: Monitor and optimize memory allocation patterns

Implementation Details

Project Structure

src/
├── server/ # MCP server implementation
├── analysis/ # Repository analysis engine
├── recommendation/ # SSG recommendation logic
├── generation/ # File and template generation
├── deployment/ # GitHub integration
└── types/ # TypeScript type definitions

Key Dependencies

  • @modelcontextprotocol/typescript-sdk: MCP protocol implementation
  • typescript: Type safety and development experience
  • zod: Runtime type validation for MCP tools
  • yaml: Configuration file parsing and generation
  • mustache: Template rendering engine
  • simple-git: Git repository interaction

Error Handling Strategy

  • Comprehensive input validation using Zod schemas
  • Structured error responses with actionable guidance
  • Graceful degradation for partial analysis failures
  • Detailed logging for debugging and monitoring

Compliance and Standards

  • Full MCP specification compliance for protocol interactions
  • JSON-RPC message handling with proper error codes
  • Standardized tool parameter validation and responses
  • Security best practices for file system access and Git operations

Research Integration (2025-01-14)

Performance Validation

Research Findings Incorporated: Comprehensive analysis validates our architectural decisions:

  1. TypeScript MCP SDK Performance:

    • ✅ JSON-RPC 2.0 protocol provides minimal communication overhead
    • ✅ Native WebSocket/stdio transport layers optimize performance
    • ✅ Type safety adds compile-time benefits without runtime performance cost
  2. Node.js Memory Optimization (Critical for Repository Analysis):

    • Streaming Implementation: 10x memory reduction for files >100MB
    • Worker Thread Pool: 3-4x performance improvement for parallel processing
    • Memory-Mapped Files: 5x speed improvement for large directory traversal

Updated Implementation Strategy

Based on research validation, the architecture will implement:

// Enhanced streaming approach for large repositories
class RepositoryAnalyzer {
private workerPool: WorkerPool;
private streamThreshold = 10 * 1024 * 1024; // 10MB

async analyzeRepository(repoPath: string): Promise<AnalysisResult> {
try {
const files = await this.scanDirectory(repoPath);

// Parallel processing with worker threads
const chunks = this.chunkFiles(files, this.workerPool.size);
const results = await Promise.allSettled(
chunks.map(chunk => this.workerPool.execute('analyzeChunk', chunk))
);

// Handle partial failures gracefully
const successfulResults = results
.filter((result): result is PromiseFulfilledResult<any> => result.status === 'fulfilled')
.map(result => result.value);

if (successfulResults.length === 0) {
throw new Error('All analysis chunks failed');
}

return this.aggregateResults(successfulResults);
} catch (error) {
throw new Error(`Repository analysis failed: ${error.message}`);
}
}

private async analyzeFile(filePath: string): Promise<FileAnalysis> {
try {
const stats = await fs.stat(filePath);

// Use streaming for large files
if (stats.size > this.streamThreshold) {
return await this.analyzeFileStream(filePath);
}

return await this.analyzeFileStandard(filePath);
} catch (error) {
throw new Error(`File analysis failed for ${filePath}: ${error.message}`);
}
}
}

Performance Benchmarks

Research-validated performance targets:

  • Small Repositories (<100 files): <1 second analysis time
  • Medium Repositories (100-1000 files): <10 seconds analysis time
  • Large Repositories (1000+ files): <60 seconds analysis time
  • Memory Usage: Constant memory profile regardless of repository size

Future Considerations

  • Potential migration to WebAssembly for performance-critical components
  • Plugin architecture for extensible SSG support
  • Distributed analysis for large repository handling (validated by research)
  • Machine learning integration for improved recommendations

References