Skip to content

Add architecture documentation explaining design patterns #32

@sgaunet

Description

@sgaunet

Problem

The codebase lacks comprehensive architecture documentation explaining key design patterns and structures, making it harder for new contributors to understand the system design.

Missing Documentation

1. Tool Registration Pattern

No documentation explaining:

  • How setupXxxTool() functions work
  • Why tools are registered separately instead of inline
  • How parameter definitions map to handler arguments
  • The role of mcp.NewTool() and registerAllTools()

Example to document:

// Each tool follows this pattern:
// 1. Create tool with mcp.NewTool(name, description, inputSchema)
// 2. Define handler function with parameter validation
// 3. Call business logic via appInstance methods
// 4. Format response as JSON and return CallToolResult

2. TableToolConfig Pattern

The TableToolConfig struct in main.go is used to reduce duplication, but this pattern isn't explained:

type TableToolConfig struct {
    name        string
    description string
    methodName  string
    needsTable  bool
}

Questions unanswered:

  • Why was this abstraction created?
  • When to use it vs custom tool setup?
  • How does needsTable affect behavior?

3. Interface Hierarchy

interfaces.go defines key interfaces, but their relationships aren't documented:

PostgreSQLClient (interface)
    └── PostgreSQLClientImpl (concrete implementation)
    
App (struct)
    └── Uses: PostgreSQLClient interface

Missing explanations:

  • Why the interface exists (testing? multiple implementations?)
  • What's the contract between App and PostgreSQLClient?
  • When to use the interface vs concrete type?

4. Layered Architecture

The codebase follows a layered pattern, but it's not explicitly documented:

main.go (MCP Server Layer)
    ├── Tool registration and HTTP/stdio handling
    └── Calls ↓
    
internal/app/app.go (Application Layer)
    ├── Business logic and high-level operations
    └── Calls ↓
    
internal/app/client.go (Data Layer)
    └── Low-level PostgreSQL operations

5. Error Handling Strategy

No documentation on:

  • When to return mcp.NewToolResultError() vs mcp.NewToolResultText()
  • Error wrapping conventions
  • How errors propagate through layers
  • What error information is exposed to users

6. Testing Architecture

While CLAUDE.md mentions testing, it doesn't explain:

  • Why testcontainers is used
  • How mocks interact with the interface design
  • The separation between unit and integration tests
  • The SKIP_INTEGRATION_TESTS pattern

Proposed Solution

Create docs/ARCHITECTURE.md:

# Architecture Documentation

## Overview

The PostgreSQL MCP server follows a **three-layer architecture**:

1. **MCP Server Layer** (`main.go`): Protocol handling and tool registration
2. **Application Layer** (`internal/app/app.go`): Business logic
3. **Data Layer** (`internal/app/client.go`): Database operations

## Design Patterns

### 1. Tool Registration Pattern

Each MCP tool is registered using a consistent pattern...

[Detailed explanation with code examples]

### 2. Interface-Based Design

The `PostgreSQLClient` interface abstracts database operations...

[Explain dependency injection, testing, flexibility]

### 3. Error Handling Strategy

Errors are handled differently at each layer...

[Explain error types, wrapping, user-facing messages]

### 4. Configuration Management

Connection parameters and settings...

[Explain environment variables, defaults, validation]

## Component Interaction

┌─────────────────┐
│ MCP Client │ (Claude Code)
└────────┬────────┘
│ stdio/http
┌────────▼────────┐
│ MCP Server │ (main.go)
│ Tool Registry │
└────────┬────────┘
│ Go function calls
┌────────▼────────┐
│ App Layer │ (app.go)
│ Business Logic │
└────────┬────────┘
│ Interface calls
┌────────▼────────┐
│ Client Layer │ (client.go)
│ PostgreSQL Ops │
└────────┬────────┘
│ lib/pq
┌────────▼────────┐
│ PostgreSQL DB │
└─────────────────┘


## Design Decisions

### Why Interface-Based?

The `PostgreSQLClient` interface exists to:
- Enable testing with mocks
- Allow future multi-database support
- Decouple business logic from database implementation

### Why Separate Tool Setup Functions?

Tools are set up in separate `setupXxxTool()` functions because:
- Reduces complexity in main()
- Makes it easy to add/remove tools
- Improves testability
- Follows single responsibility principle

### Why TableToolConfig?

The `TableToolConfig` pattern reduces duplication for similar tools...

## Testing Strategy

### Unit Tests
- Mock the `PostgreSQLClient` interface
- Test business logic in isolation
- Fast, no external dependencies

### Integration Tests
- Use testcontainers for real PostgreSQL
- Test end-to-end database operations
- Slow, requires Docker

[More details on testing patterns]

## Adding New Tools

To add a new MCP tool:

1. Define the tool in `main.go`:
```go
func setupNewToolTool(appInstance *app.App) *mcp.Tool {
    // ...
}
  1. Add business logic to app.go:
func (a *App) NewToolOperation() (ResultType, error) {
    // ...
}
  1. Implement database operations in client.go if needed
  2. Register in registerAllTools()
  3. Add tests

[Detailed example]

Security Model

[Explain read-only validation, identifier escaping, etc.]

Performance Considerations

[Explain connection pooling, query limits, etc.]


## Additional Documentation

Also create:
- `docs/CONTRIBUTING.md`: How to contribute, coding standards
- `docs/TESTING.md`: Detailed testing guide
- `docs/DEPLOYMENT.md`: How to deploy the MCP server

## Impact

- **Severity**: LOW
- **Type**: Documentation
- **Benefits**: Easier onboarding, better maintainability, clearer design

## Checklist

- [ ] Create docs/ARCHITECTURE.md with comprehensive design documentation
- [ ] Document the three-layer architecture pattern
- [ ] Explain tool registration pattern with examples
- [ ] Document interface hierarchy and relationships
- [ ] Explain TableToolConfig and when to use it
- [ ] Add component interaction diagrams
- [ ] Document design decisions and their rationale
- [ ] Add "Adding New Tools" guide with step-by-step instructions
- [ ] Document error handling strategy across layers
- [ ] Document testing architecture and patterns
- [ ] Link to architecture docs from main README
- [ ] Create CONTRIBUTING.md with coding standards

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions