9. Architecture Decisions

This chapter records the most important architectural decisions.

ADR-001: File-System as Single Source of Truth

Status

Accepted

Date

2025-09-18

Decision Makers

Gemini Architect

Context

The PRD requires that the system integrates with existing Git workflows, that files remain human-readable, and that there are no database dependencies. We need a simple, robust way to store the documentation content that honors these constraints.

Decision

The file system will be treated as the single source of truth. The server will not have its own persistent state. All content and structure information is derived directly from the .adoc and .md files within the project directory.

Consequences

  • Pro: Simplifies the architecture immensely. No database schema migrations or data synchronization logic needed.

  • Pro: Inherently compatible with Git and other version control systems.

  • Pro: Developers can still use their favorite text editors.

  • Con: Queries that are not based on the document’s natural hierarchy may be inefficient to answer.

  • Con: The system’s performance is tied to file system performance.

Alternatives Considered

  • SQLite Database: Store content in a local SQLite file. Rejected because it violates the "human-readable files" and "no database" constraints.

  • Key-Value Store (e.g., RocksDB): Use an embedded database. Rejected for the same reasons as SQLite.

ADR-002: In-Memory Index for Performance

Status

Accepted

Date

2025-09-18

Decision Makers

Gemini Architect

Context

The quality goal PERF-1 requires API calls to respond in under 2 seconds. Reading and parsing text files from disk on every request would be too slow for large projects, as identified in the runtime analysis.

Decision

On startup, the server will perform a one-time scan of the entire project directory. It will parse all documentation files and build an "In-Memory Structure Index". This index will hold metadata about each document, including section names, hierarchical paths, and the start/end line numbers for each section in its source file. Read requests will consult this index to find the exact byte range to read from a file.

Consequences

  • Pro: Read operations (get_section) are extremely fast, as they become simple dictionary lookups followed by a targeted file read.

  • Pro: Enables efficient implementation of structure-aware APIs like get_structure.

  • Con: Increased memory consumption, proportional to the size of the documentation project.

  • Con: Slower server startup time due to the initial indexing phase.

  • Con: A mechanism to detect external file changes (file watching) is needed to keep the index from becoming stale.

Alternatives Considered

  • No Index: Parse the relevant files on every API request. Rejected due to poor performance that would violate quality goals.

  • Persistent Disk-Based Index: Cache the index to disk. Rejected as it adds complexity (cache invalidation) and violates the "stateless" principle from the solution strategy.

ADR-003: Technology Stack (Python/FastAPI)

Status

Accepted

Date

2025-09-18

Decision Makers

Gemini Architect

Context

A programming language and web framework are needed to build the MCP API Server. The choice must align with the need for rapid development, strong text-processing capabilities, and high performance for an I/O-bound application.

Decision

The backend will be implemented in Python. The FastAPI framework will be used to build the web server and API endpoints.

Consequences

  • Pro: Python has an exceptional ecosystem for text processing and data manipulation.

  • Pro: FastAPI provides high performance for I/O-bound tasks, data validation, and automatic OpenAPI/Swagger documentation, which helps achieve USAB-1 and USAB-2.

  • Pro: The large talent pool for Python simplifies maintenance.

  • Con: Python’s GIL can be a limitation for CPU-bound tasks, but this application is primarily I/O-bound (reading files, network requests).

Alternatives Considered

  • Node.js/Express: A strong contender, also asynchronous and fast. Python was chosen for its perceived stronger data science and text-processing ecosystem.

  • Go/Gin: Offers superior raw performance and concurrency. Rejected because development time is typically longer, and the performance gain was not deemed critical enough to justify the trade-off.

  • Java/Spring: Mature and robust, but generally more verbose and memory-intensive, which was deemed overkill for this service.

ADR-004: Atomic Writes via Temporary Files

Status

Accepted

Date

2025-09-18

Decision Makers

Gemini Architect

Context

The quality goal REL-1 (Atomic Writes) is critical to prevent file corruption during update operations. A failure (e.g., disk full, application crash) during a file write could leave a document in an unrecoverable, partially-written state.

Decision

The File System Handler component will implement atomic writes using a backup-and-replace strategy: 1. Create a backup of the original file (e.g., doc.adocdoc.adoc.bak). 2. Write all intended changes to a new temporary file (e.g., doc.adoc.tmp). 3. If the write is successful, atomically rename/move the temporary file to replace the original file. 4. Delete the backup file. 5. If any step fails, restore the original file from the backup and delete the temporary file.

Consequences

  • Pro: Guarantees that the primary file is never in a corrupted state.

  • Pro: Relatively simple to implement and understand.

  • Con: Slightly higher I/O overhead for each write operation (copy, write, move). This is an acceptable trade-off for the gain in reliability.

Alternatives Considered

  • Journaling: Implement a file-based journal to log changes before applying them. Rejected as this is significantly more complex to implement correctly.

  • In-place updates with locking: Lock the file and update it directly. Rejected because it does not protect against application crashes or system power loss during the write.

ADR-005: Custom Parser for Include Resolution

Status

Accepted

Date

2025-09-18

Decision Makers

Gemini Architect

Context

A core feature is the ability to map a hierarchical path (e.g., chapter-1.section-2) to a precise location in a source file. This is complicated by AsciiDoc’s include::[] directive, as content from multiple files is logically part of one document. Existing parsers often flatten the document, losing this critical source-map information.

Decision

A custom document parser will be developed. This parser will be responsible for: 1. Parsing the AsciiDoc/Markdown syntax. 2. Recognizing and recursively resolving include::[] directives. 3. Building an Abstract Syntax Tree (AST) that retains the original file path and line numbers for every single element of the document.

Consequences

  • Pro: Provides full control over the parsing process, ensuring the crucial source-map information is preserved.

  • Pro: Allows for tailored error handling of malformed documents or circular includes.

  • Con: Significant development and maintenance effort compared to using an off-the-shelf library. This is the most complex component of the system.

Alternatives Considered

  • Use an existing library (e.g., asciidoctor.py): This was investigated, but most libraries are designed to render documents (e.g., to HTML), not to provide a detailed source map across included files. Adapting them was deemed more complex than building a focused, custom solution.

ADR-006: Modular MCP Server Architecture

Status

Accepted

Date

2025-10-02

Decision Makers

Development Team

Related Issues

GitHub Issue #12

Context

The initial implementation of mcp_server.py grew to 916 lines, violating the project’s CLAUDE.md best practice of keeping files under 500 lines. The file contained three distinct responsibilities:

  1. MCP Protocol Handling: JSON-RPC request/response processing

  2. Document API Operations: Implementation of all MCP tools (get_structure, get_section, search, etc.)

  3. Server Orchestration: Initialization, file watching, webserver management

This monolithic structure made the codebase difficult to navigate, test, and maintain. Each component had different testing requirements and change frequencies.

Decision

Split mcp_server.py into four focused modules using the Extract-and-Delegate pattern:

  1. src/mcp/document_api.py (~435 lines): All document operation methods

    • Structure queries: get_structure(), get_main_chapters(), get_root_files_structure()

    • Section access: get_section(), get_sections(), get_sections_by_level()

    • Search and metadata: search_content(), get_metadata(), get_dependencies()

    • Content modification: update_section_content(), insert_section()

  2. src/mcp/protocol_handler.py (~279 lines): MCP protocol implementation

    • JSON-RPC request processing

    • MCP initialize, tools/list, tools/call handlers

    • Tool routing and parameter validation

    • Error response formatting

  3. src/mcp/webserver_manager.py (~121 lines): Web server lifecycle

    • Port discovery and management

    • Background thread handling

    • Server status tracking

    • Browser auto-launch

  4. src/mcp_server.py (~202 lines): Thin orchestrator

    • Component initialization with dependency injection

    • File watcher coordination

    • Delegation methods for backward compatibility

    • Main entry point and signal handling

The main server class receives instances of all modules and delegates calls to them, maintaining a clean separation of concerns.

Consequences

  • Pro: All files now comply with <500 line constraint, improving code maintainability

  • Pro: Clear separation of concerns - each module has a single, well-defined responsibility

  • Pro: Easier to test - modules can be tested independently with focused test suites

  • Pro: Better code navigation - developers can quickly find relevant code

  • Pro: Reduced merge conflicts - changes to different concerns modify different files

  • Pro: Improved test coverage achieved (69% → 82% through focused module testing)

  • Con: Slightly more files to navigate (1 file → 4 files)

  • Con: Delegation pattern adds minor indirection for method calls

  • Neutral: Backward compatibility maintained through delegation methods in main server class

Implementation Details

Dependency Injection Pattern:

class MCPDocumentationServer:
    def __init__(self, project_root: Path, enable_webserver: bool = True):
        # Core components
        self.parser = DocumentParser()
        self.editor = ContentEditor(project_root)

        # Modular components (dependency injection)
        self.doc_api = DocumentAPI(self)
        self.webserver = WebserverManager(self)

    # Delegation methods for backward compatibility
    def get_structure(self, max_depth: int = 3):
        return self.doc_api.get_structure(max_depth)

Each module receives the server instance, allowing access to shared state (sections, parser, editor) without circular dependencies.

Alternatives Considered

  • Keep monolithic structure: Rejected due to violation of coding standards and poor maintainability

  • Split into more modules (e.g., separate each tool): Rejected as too granular - would create excessive fragmentation

  • Use plugins/extensions pattern: Rejected as over-engineered for current scope

ADR-007: Separate HTML Template Files

Status

Accepted

Date

2025-10-02

Decision Makers

Development Team

Related Issues

GitHub Issue #11

Context

The web_server.py file contained a large embedded HTML template string (~300 lines) for the web interface. This resulted in:

  • File size approaching the 500-line limit

  • Poor editor support (no HTML syntax highlighting in Python string)

  • Difficult template maintenance (escaping, formatting issues)

  • Mixed concerns (server logic + presentation)

Decision

Extract the HTML template to a separate file: src/templates/web_interface.html

The template is loaded at runtime using Python’s standard library:

from pathlib import Path

template_path = Path(__file__).parent / "templates" / "web_interface.html"
HTML_TEMPLATE = template_path.read_text(encoding='utf-8')

Consequences

  • Pro: web_server.py reduced in size, complying with coding standards

  • Pro: Proper HTML syntax highlighting and validation in editors

  • Pro: Easier template maintenance and modification

  • Pro: Clear separation between server logic and presentation

  • Pro: Template can be edited by frontend developers without touching Python code

  • Con: Template file must be distributed with the package (handled by package manifest)

  • Con: Template path resolution adds minor complexity

Alternatives Considered

  • Keep template embedded: Rejected due to maintainability and file size issues

  • Use template engine (Jinja2, Mako): Rejected as overkill - template is static with no dynamic server-side rendering

  • Serve static HTML file directly: Rejected because template needs runtime parameter substitution

ADR-008: Test Infrastructure with pytest

Status

Accepted

Date

2025-10-02

Decision Makers

Development Team

Related Issues

GitHub Issue #13

Context

The project initially lacked a comprehensive test infrastructure. As the codebase grew to ~750 lines across multiple modules, the risk of regressions increased significantly. A robust testing framework was needed to:

  • Ensure code quality and correctness

  • Enable safe refactoring (e.g., the Issue #12 modularization)

  • Measure and improve test coverage

  • Support CI/CD integration

Decision

Adopt pytest as the testing framework with the following tools:

Core Framework: - pytest: Modern Python testing framework with fixture support - pytest-cov: Code coverage measurement and reporting - pytest-html: HTML test report generation

Testing Approach: - Unit tests for individual modules (test_document_parser.py, test_document_api.py, etc.) - Integration tests for component interaction - Fixture-based test setup for reusable test environments - Coverage target: >80% for core modules

Directory Structure:

tests/
├── conftest.py              # Shared fixtures
├── test_document_parser.py  # Parser unit tests
├── test_document_api.py     # DocumentAPI unit tests
├── test_protocol_handler.py # Protocol handler tests
├── test_mcp_server.py       # Server orchestration tests
└── test_webserver_manager.py # Webserver tests

Consequences

  • Pro: Modern, expressive test syntax with minimal boilerplate

  • Pro: Excellent fixture system for test setup/teardown

  • Pro: Rich plugin ecosystem (coverage, HTML reports, parallel execution)

  • Pro: Detailed assertion introspection (automatic error messages)

  • Pro: Easy CI/CD integration (JUnit XML output, exit codes)

  • Pro: Coverage improved from 0% to 82% through systematic testing

  • Pro: Enabled safe refactoring with regression detection

  • Con: Additional dependencies (pytest, pytest-cov, pytest-html)

  • Con: Learning curve for developers unfamiliar with pytest fixtures

Test Coverage Achieved

After implementing comprehensive test suites:

  • Overall coverage: 82% (618/750 lines)

  • document_parser.py: 100%

  • protocol_handler.py: 95%

  • document_api.py: 93%

  • file_watcher.py: 92%

  • content_editor.py: 91%

Test Statistics: - 123 tests total - 121 passing (98.4% success rate) - ~1,400 lines of test code

Alternatives Considered

  • unittest (Python standard library): Rejected due to verbose syntax and lack of advanced features

  • nose2: Rejected as pytest has better ecosystem and active development

  • No testing framework: Rejected as unacceptable for production code quality

ADR-009: Migration to FastMCP SDK

Status

Accepted

Date

2025-10-05

Decision Makers

Development Team (Claude Code)

Related Issues

GitHub Issue #51

Context

The project initially implemented the MCP (Model Context Protocol) manually using custom JSON-RPC 2.0 message handling in src/mcp/protocol_handler.py. This 282-line module contained:

  • Manual initialize, tools/list, and tools/call handlers

  • Hand-written JSON schema definitions for 10 MCP tools

  • Custom request routing with if/elif dispatch logic

  • Manual error response formatting

This approach created several problems:

  1. Maintenance Overhead: Every protocol change required manual updates to request/response handling

  2. Protocol Drift Risk: No guarantee of compliance with MCP specification updates

  3. Boilerplate Code: Repetitive schema definitions and routing logic

  4. Testing Complexity: Manual protocol implementation difficult to test comprehensively

The project’s architecture principle states: "Nutze für MCP-Server immer fastMCP" (Always use fastMCP for MCP servers), recognizing that mature libraries reduce risk compared to custom implementations.

Decision

Migrate to the official MCP SDK (mcp[cli]>=1.0.0) which includes FastMCP 1.0 as from mcp.server.fastmcp import FastMCP.

Implementation approach: - Replace manual stdin/stdout JSON-RPC loop with mcp.run() - Convert 10 tool handlers to @mcp.tool() decorators - Delete src/mcp/protocol_handler.py entirely (282 lines) - Use type hints for automatic schema generation - Keep DocumentAPI business logic unchanged (out of scope)

Consequences

Pro: * Protocol Compliance Guaranteed: Official SDK maintained by Anthropic ensures MCP specification adherence * Automatic Schema Generation: Type hints (e.g., def get_section(path: str) → dict) auto-generate JSON schemas * Less Boilerplate: Reduced from 282 lines (protocol_handler.py) + manual schemas to ~80 lines of decorator-based tools * Better Maintainability: Protocol updates handled by SDK dependency updates, not manual code changes * Improved Developer Experience: Decorator syntax (@mcp.tool()) more Pythonic than manual routing

Con: * External Dependency: Added mcp>=1.0.0 dependency (16 transitive dependencies) * SDK Learning Curve: Team must learn FastMCP patterns (mitigated by similarity to FastAPI) * Less Control: Some edge cases may require SDK updates rather than immediate fixes

Neutral: * Testing Changes: Removed 2 test files (test_protocol_handler.py, test_webserver_startup.py) testing deleted code * Coverage Impact: 70% coverage (down from 82%) due to tool wrapper functions not directly testable via unit tests

Implementation Results

Code Reduction: - Deleted: 282 lines (protocol_handler.py) + 445 lines (tests) = 727 lines - Added: 89 lines (tool decorators in mcp_server.py) - Net reduction: -638 lines (88% reduction in MCP-related code)

Migration: - 10 MCP tools successfully migrated: * Read tools: get_section, get_metadata, get_sections, get_dependencies, validate_structure, refresh_index, get_structure, search_content * Write tools: update_section, insert_section - Webserver start hook moved from initialize handler to MCPDocumentationServer.init() - All delegation methods retained for backward compatibility

Testing: - 81 core tests passing (document_parser: 100%, document_api: 86%, mcp_server: 67%) - No regressions in business logic (DocumentAPI unchanged)

Commits: - b8a644e: feat: Migrate from manual MCP protocol to FastMCP SDK - 515e6f1: test: Remove obsolete protocol_handler tests and update imports

Alternatives Considered

1. Status Quo (Keep Manual Implementation) - Rejected: Technical debt would compound as MCP evolves - Risk: Protocol drift, maintenance burden increases over time

2. FastMCP 2.0 (Separate Framework) - Description: pip install fastmcp - enterprise features (auth, deployment, OpenAPI) - Rejected: Too complex for project needs, unnecessary features - Comparison: Official SDK provides sufficient functionality without enterprise overhead

3. Other MCP SDKs (Node.js, Go) - Rejected: Would require rewriting entire Python codebase - Not evaluated: Python ecosystem alignment more important than alternative language features

  • ADR-006: Modular MCP Server Architecture - Enabled clean migration by separating protocol handling from business logic

  • ADR-003: Technology Stack (Python/FastAPI) - Python ecosystem makes official MCP SDK the natural choice

ADR-010: Pure Docstring BDD Testing Approach

Status

Accepted

Date

2025-10-07

Decision Makers

Development Team (Collaborative Decision)

Related Issues

GitHub Issue #61

Context

The project needed to decide whether to adopt Behavior-Driven Development (BDD) testing practices for the existing pytest-based test suite (19 files, 4,287 lines of test code). The evaluation included:

  • Current test structure using pytest with unittest.TestCase classes

  • BDD framework options (pytest-bdd, behave)

  • Stakeholder readability vs. maintenance overhead considerations

  • Team size (single developer) and project type (technical MCP server tool)

Key constraint identified during collaborative decision process: Requirement for inline BDD approach where Gherkin syntax and test implementation exist in the same file, avoiding separate .feature files.

Decision

Adopt Pure Docstring BDD approach for new tests and gradual conversion of existing tests. This approach combines:

  1. Gherkin-style docstrings with business context (Feature/Scenario/Given/When/Then)

  2. Structured comments in test code matching docstring steps

  3. No separate .feature files or additional framework dependencies

  4. Full pytest compatibility with existing infrastructure

Example Implementation:

def test_parser_initialization(self):
    """
    Feature: Document Parser Initialization
    As a documentation maintainer
    I want to create a DocumentParser with sensible defaults
    So that I can process documentation with predictable behavior

    Scenario: Initialize parser with default configuration
        Given I need to parse AsciiDoc documents
        When I create a new DocumentParser instance
        Then it should have max_include_depth of 4
        And it should have an empty processed files set
    """
    # Given: I need to parse AsciiDoc documents
    # When: I create a new DocumentParser instance
    parser = DocumentParser()
    # Then: it should have max_include_depth of 4
    assert parser.max_include_depth == 4
    # And: it should have an empty processed files set
    assert isinstance(parser.processed_files, set)
    assert len(parser.processed_files) == 0

Consequences

Pro: * Stakeholder-readable: Business context clear in test docstrings * Zero Dependencies: Works with existing pytest infrastructure * Single File Approach: Meets user requirement for inline BDD * Gradual Adoption: Can convert tests incrementally during refactoring * Better Documentation: Tests become self-documenting specifications * Improved Onboarding: New contributors understand business context faster

Con: * Longer Files: More verbose docstrings increase file length * Discipline Required: Team must maintain consistent BDD formatting * Learning Curve: Developers need to understand Gherkin syntax

Neutral: * Same Number of Files: No additional .feature files to maintain * Pytest Compatibility: All existing tooling (coverage, markers, fixtures) continues to work

Implementation Strategy

Gradual Adoption: 1. New Tests: Write in Pure Docstring BDD format immediately 2. Refactoring Priority: Convert existing tests when making changes 3. Focus Areas: Integration tests benefit most from business context 4. Style Guide: Create consistent formatting standards

Quality Measures: - BDD docstring style guide for consistency - Examples and templates for common test patterns - Integration with existing pytest markers (unit, integration, web, parser)

Alternatives Considered

1. Traditional BDD with pytest-bdd - Description: Separate .feature files with step definitions - Rejected: User requirement for single-file approach not met - Concerns: 2.5x more code, maintenance overhead, separate file synchronization

2. Behave Framework - Description: Standalone BDD runner with pure Gherkin philosophy - Rejected: Would abandon existing pytest infrastructure - Concerns: Complete test suite migration required, learning curve

3. Status Quo (No BDD) - Description: Continue with current pytest/unittest approach - Rejected: User preference for BDD approach with business context - Concerns: Tests remain technically focused, lacking stakeholder readability

4. Comments-Only BDD - Description: Add Given/When/Then comments without docstring context - Rejected: Lacks feature/scenario business context in docstrings - Missing: User story mapping and acceptance criteria clarity

  • ADR-008: Test Infrastructure with pytest - Provides foundation for BDD enhancement

  • Coding Standards: Files <500 lines principle supports focused, well-documented test files