Architecture¶
Technical architecture and design decisions for the EARLY MCP Server.
Overview¶
The EARLY MCP Server is designed as a bridge between the Model Context Protocol (MCP) specification and the EARLY app API, providing AI assistants with structured access to time tracking functionality.
High-Level Architecture¶
graph TB
subgraph "MCP Client (Claude Desktop, Custom)"
A[MCP Client]
end
subgraph "EARLY MCP Server"
B[MCP Protocol Handler]
C[Tool Handlers]
D[Resource Handlers]
E[API Client]
F[Error Handling]
end
subgraph "EARLY API"
G[EARLY API v4]
end
A <-- stdio/JSON-RPC --> B
B --> C
B --> D
C --> E
D --> E
E <-- HTTPS/REST --> G
C --> F
D --> F Core Components¶
MCP Protocol Layer¶
File: src/index.ts
The main server class that implements the MCP protocol specification.
Key Responsibilities¶
- Protocol Compliance: Implements MCP 2024-11-05 specification
- Transport Handling: Manages stdio communication with MCP clients
- Request Routing: Routes tool calls and resource reads to appropriate handlers
- Error Management: Provides consistent error responses
Architecture Decisions¶
Transport: stdio - Why: MCP specification requirement for local integrations - Benefits: Simple, secure, no network configuration required - Tradeoffs: Limited to local connections only
JSON-RPC 2.0 - Why: MCP protocol standard - Benefits: Well-established protocol, good tooling support - Implementation: Each message is a single JSON line
Tool Handler Architecture¶
Files: src/handlers/*.ts
Modular architecture separating different types of operations.
handlers/
├── time-entry-handlers.ts # CRUD operations for time entries
├── tracking-handlers.ts # Timer start/stop operations
├── activity-handlers.ts # Activity management
└── resource-handlers.ts # MCP resource providers
Design Principles¶
Single Responsibility - Each handler focuses on one type of operation - Clear separation between time entries, timers, and activities - Resource handlers separate from tool handlers
Consistent Interface
Error Handling Pattern
try {
checkApiCredentials();
const result = await apiClient.operation(args);
return formatSuccessResponse(result);
} catch (error) {
return createToolErrorResponse(error, context);
}
API Client Layer¶
File: src/early-api-client.ts
Abstraction layer over the EARLY API with comprehensive functionality.
Architecture Features¶
Authentication Management
class EarlyApiClient {
private accessToken: string | null = null;
async authenticate(): Promise<void> {
// API Key + Secret → Bearer Token
}
private async ensureAuthenticated(): Promise<void> {
if (!this.accessToken) {
await this.authenticate();
}
}
}
HTTP Client Configuration - Base URL: Configurable via environment variables - Timeout: 30 seconds default, configurable - Interceptors: Request/response logging and error transformation - Headers: Automatic authentication, content-type management
Error Transformation
// Axios errors → Structured API errors
interface ApiError {
code: string;
message: string;
details?: any;
}
API Endpoints Coverage¶
Time Entries (Full CRUD) - POST /api/v4/time-entries - Create - GET /api/v4/time-entries/{id} - Read - PATCH /api/v4/time-entries/{id} - Update - DELETE /api/v4/time-entries/{id} - Delete - GET /api/v4/time-entries/{start}/{end} - Range query
Timer Operations - POST /api/v4/tracking/{activityId}/start - Start timer - POST /api/v4/tracking/stop - Stop timer - GET /api/v4/tracking - Get current timer
Activities - GET /api/v4/activities - List all activities
Type System¶
Files: src/types.ts, src/tool-types.ts
Comprehensive TypeScript definitions ensuring type safety throughout the application.
Core Types¶
Configuration
API Entities
interface TimeEntry {
id: string;
activity?: Activity;
duration: {
startedAt: string;
stoppedAt?: string;
};
note?: { text: string };
}
interface Activity {
id: string;
name: string;
}
Tool Arguments
interface CreateTimeEntryArgs {
projectId: string; // Required
description: string; // Required
startTime?: string; // Optional
endTime?: string; // Optional
duration?: number; // Optional
}
Type Safety Benefits¶
- Compile-time Validation: Catches parameter mismatches
- IDE Support: Autocomplete and inline documentation
- Refactoring Safety: Changes propagate through type system
- Documentation: Types serve as living documentation
Error Handling System¶
File: src/error-utils.ts
Centralized error handling providing consistent user experience.
Error Categories¶
Authentication Errors
// API credentials invalid or missing
return {
content: [{
type: 'text',
text: 'Operation failed: Authentication failed\n\nDebug info:\n- API Key: Present\n- API Secret: Missing'
}]
};
Validation Errors
API Errors
// EARLY API returns error
if (apiError.response?.status === 404) {
return {
content: [{
type: 'text',
text: 'Resource not found. The requested item may have been deleted.'
}]
};
}
Error Context¶
Benefits: - Debugging Information: Always includes environment status - User-Friendly Messages: Clear explanations over technical errors - Consistent Format: Same error structure across all tools - Security: No credential exposure in error messages
Design Decisions¶
MCP Protocol Version¶
Choice: MCP 2024-11-05 - Reasoning: Latest stable version with comprehensive tool support - Benefits: Future compatibility, full feature set - Alternatives Considered: Earlier versions lacked tool call features
Authentication Strategy¶
Choice: EARLY API Key + Secret → Bearer Token - Reasoning: EARLY API v4 requirement - Implementation: Automatic token refresh, session management - Security: Tokens stored in memory only, never logged
Tool vs Resource Design¶
Tools: Interactive operations that modify state - create_time_entry, start_timer, stop_timer - Require parameters, return operation results - Can have side effects
Resources: Read-only data access - early://time-entries/today, early://activities - No parameters, return structured data - Cacheable, no side effects
Error Response Format¶
Choice: Structured text responses with debug information - Reasoning: Human-readable for Claude Desktop users - Benefits: Clear troubleshooting guidance - Format: Emoji indicators + explanation + debug context
Modular Handler Architecture¶
Choice: Separate handler files by functionality - Benefits: - Easy to test individual components - Clear code organization - Simplified maintenance - Parallel development possible
Alternative Considered: Single large handler file - Rejected: Would become unwieldy as functionality grows
Performance Considerations¶
API Rate Limiting¶
Strategy: Respectful API usage - Implementation: No aggressive caching (respects real-time data) - Consideration: EARLY API rate limits unknown, designed for conservative usage - Future: Could add intelligent caching for activity lists
Memory Management¶
Token Storage: In-memory only - Benefits: No persistent token storage security risks - Tradeoff: Re-authentication required on server restart
Request Caching: Minimal - Choice: Fresh data prioritized over performance - Reasoning: Time tracking requires real-time accuracy
Startup Time¶
Optimization: Lazy authentication - Implementation: Authentication occurs on first API call - Benefit: Faster server startup, better error handling - User Experience: Immediate MCP availability
Security Architecture¶
Credential Management¶
Storage: Environment variables only - Benefits: Not stored in code, not committed to version control - Access: Only the server process can access credentials - Rotation: Simple environment variable updates
Network Security¶
HTTPS Only: All EARLY API communication encrypted Local Communication: MCP uses local stdio (no network exposure) No Logging: Credentials never appear in logs
Input Validation¶
Parameter Validation: All tool inputs validated Type Safety: TypeScript prevents many injection scenarios Error Handling: No credential exposure in error messages
Access Control¶
Principle: Server inherits user permissions - EARLY API: Respects account-level permissions - Local System: Runs with user's file system permissions - Network: Only accesses specified EARLY API endpoints
Testing Strategy¶
Unit Tests¶
Coverage: Individual handler functions Mocking: API client mocked for isolated testing Assertions: Response format, error handling, parameter validation
describe('handleCreateTimeEntry', () => {
it('should create time entry with valid parameters', async () => {
const mockClient = createMockApiClient();
const result = await handleCreateTimeEntry(mockClient, validArgs);
expect(result.content[0].text).toContain('Time entry created');
});
});
Integration Tests¶
Coverage: Full MCP protocol flow Real API: Uses test credentials for end-to-end validation Scenarios: Complete user workflows
Test Suite¶
Purpose: Automated testing and integration validation Implementation: Comprehensive Jest test suite covering all functionality Usage: npm test
Deployment Architecture¶
Local Development¶
User Machine
├── Node.js 18+
├── EARLY MCP Server
│ ├── Built JavaScript (dist/)
│ ├── Environment config (.env)
│ └── Test client
└── MCP Client (Claude Desktop)
└── Configuration file
Production Considerations¶
Environment Variables: Secure credential storage Process Management: Could use PM2 or similar for reliability Logging: Structured logging for operational monitoring Monitoring: Health check endpoints for system monitoring
Future Architecture Considerations¶
Scalability¶
Current: Single-user, single-instance design Future: Could support multi-user scenarios with user-scoped configurations
Caching Layer¶
Current: No caching for data freshness Future: Intelligent caching for activities list, configurable TTL
Protocol Extensions¶
Current: Basic MCP tool and resource support
Future: Could leverage advanced MCP features as they become available
High Availability¶
Current: Single point of failure Future: Could implement health checks, automatic restart capabilities
This architecture supports the current requirements while maintaining flexibility for future enhancements. The modular design allows for independent evolution of different components.