Files
mcphub/docs/development/architecture.mdx
2025-06-01 00:17:09 +08:00

725 lines
16 KiB
Plaintext

---
title: 'Architecture Overview'
description: "Understand MCPHub's system architecture and design principles"
---
## System Overview
MCPHub is designed as a scalable, modular platform for managing Model Context Protocol (MCP) servers. The architecture follows modern web application patterns with clear separation of concerns, microservices-ready design, and extensibility in mind.
## High-Level Architecture
```mermaid
graph TB
subgraph "Client Layer"
WEB[Web Dashboard]
API[External APIs]
CLI[CLI Tools]
end
subgraph "Application Layer"
LB[Load Balancer/Nginx]
APP[MCPHub Server]
WS[WebSocket Server]
end
subgraph "Service Layer"
MCP[MCP Service]
AUTH[Auth Service]
ROUTE[Smart Routing]
MON[Monitoring Service]
end
subgraph "Data Layer"
PG[(PostgreSQL)]
REDIS[(Redis)]
VECTOR[(Vector Store)]
end
subgraph "MCP Servers"
GITHUB[GitHub MCP]
FS[Filesystem MCP]
DB[Database MCP]
CUSTOM[Custom MCP]
end
WEB --> LB
API --> LB
CLI --> LB
LB --> APP
APP --> WS
APP --> MCP
APP --> AUTH
APP --> ROUTE
APP --> MON
MCP --> GITHUB
MCP --> FS
MCP --> DB
MCP --> CUSTOM
AUTH --> PG
AUTH --> REDIS
ROUTE --> VECTOR
MON --> PG
MON --> REDIS
```
## Core Components
### 1. Application Server
The main Node.js/Express application that handles all HTTP requests and coordinates between services.
```typescript
// src/server.ts - Main application entry point
class MCPHubServer {
private app: Express;
private httpServer: Server;
private wsServer: WebSocketServer;
async start(): Promise<void> {
await this.initializeDatabase();
await this.initializeServices();
await this.setupRoutes();
await this.startServer();
}
}
```
**Key Responsibilities:**
- HTTP request handling
- WebSocket connections for real-time features
- Service coordination
- Middleware chain management
- Error handling and logging
### 2. MCP Service Layer
Manages the lifecycle and communication with MCP servers.
```typescript
// src/services/mcpService.ts
class MCPService {
private servers: Map<string, MCPServerInstance> = new Map();
private processManager: ProcessManager;
async startServer(config: MCPServerConfig): Promise<void> {
const instance = await this.processManager.spawn(config);
this.servers.set(config.name, instance);
await this.waitForHealthy(instance);
}
async executeRequest(serverName: string, request: MCPRequest): Promise<MCPResponse> {
const server = this.servers.get(serverName);
return await server.sendRequest(request);
}
}
```
**Key Features:**
- Process lifecycle management
- Health monitoring
- Request routing
- Error recovery
- Resource management
### 3. Smart Routing Engine
Provides AI-powered tool discovery and routing using vector embeddings.
```typescript
// src/services/smartRouting.ts
class SmartRoutingService {
private vectorStore: VectorStore;
private embeddingService: EmbeddingService;
async findRelevantTools(query: string): Promise<ToolMatch[]> {
const queryEmbedding = await this.embeddingService.embed(query);
const matches = await this.vectorStore.similaritySearch(queryEmbedding);
return this.rankResults(matches, query);
}
async indexTool(tool: ToolDefinition): Promise<void> {
const embedding = await this.embeddingService.embed(tool.description);
await this.vectorStore.upsert(tool.id, embedding, tool);
}
}
```
**Components:**
- Vector embedding generation
- Similarity search
- Result ranking and filtering
- Tool metadata management
### 4. Authentication & Authorization
Handles user authentication, session management, and access control.
```typescript
// src/services/authService.ts
class AuthService {
async authenticate(credentials: Credentials): Promise<User> {
const user = await this.validateCredentials(credentials);
const token = await this.generateJWT(user);
await this.createSession(user, token);
return user;
}
async authorize(user: User, resource: string, action: string): Promise<boolean> {
const permissions = await this.getUserPermissions(user);
return this.checkPermission(permissions, resource, action);
}
}
```
**Features:**
- JWT-based authentication
- Role-based access control (RBAC)
- Session management
- API key authentication
- Group-based permissions
### 5. Monitoring & Logging
Provides comprehensive monitoring, metrics collection, and logging.
```typescript
// src/services/monitoringService.ts
class MonitoringService {
private metricsCollector: MetricsCollector;
private alertManager: AlertManager;
async collectMetrics(): Promise<void> {
const systemMetrics = await this.getSystemMetrics();
const serverMetrics = await this.getMCPServerMetrics();
await this.metricsCollector.record(systemMetrics, serverMetrics);
await this.checkAlerts(systemMetrics, serverMetrics);
}
}
```
**Capabilities:**
- Real-time metrics collection
- Performance monitoring
- Error tracking
- Alert management
- Audit logging
## Data Architecture
### Database Schema
```sql
-- Core entities
CREATE TABLE users (
id UUID PRIMARY KEY,
username VARCHAR UNIQUE NOT NULL,
email VARCHAR UNIQUE NOT NULL,
password_hash VARCHAR NOT NULL,
role VARCHAR NOT NULL DEFAULT 'user',
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE servers (
id UUID PRIMARY KEY,
name VARCHAR UNIQUE NOT NULL,
command VARCHAR NOT NULL,
args JSONB NOT NULL DEFAULT '[]',
env JSONB DEFAULT '{}',
group_name VARCHAR,
status VARCHAR DEFAULT 'stopped',
config JSONB DEFAULT '{}',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE groups (
id UUID PRIMARY KEY,
name VARCHAR UNIQUE NOT NULL,
description TEXT,
config JSONB DEFAULT '{}',
created_at TIMESTAMP DEFAULT NOW()
);
-- Vector search for smart routing
CREATE TABLE tool_embeddings (
id UUID PRIMARY KEY,
server_name VARCHAR NOT NULL,
tool_name VARCHAR NOT NULL,
description TEXT,
embedding vector(1536),
metadata JSONB DEFAULT '{}',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Monitoring and logging
CREATE TABLE request_logs (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
server_name VARCHAR NOT NULL,
tool_name VARCHAR,
request_data JSONB,
response_data JSONB,
status VARCHAR NOT NULL,
duration_ms INTEGER,
created_at TIMESTAMP DEFAULT NOW()
);
```
### Caching Strategy
```typescript
// src/services/cacheService.ts
class CacheService {
// Multi-layer caching strategy
private memoryCache: Map<string, CacheEntry> = new Map();
private redisCache: Redis;
async get<T>(key: string): Promise<T | null> {
// L1: Memory cache
const memoryEntry = this.memoryCache.get(key);
if (memoryEntry && !this.isExpired(memoryEntry)) {
return memoryEntry.value;
}
// L2: Redis cache
const redisValue = await this.redisCache.get(key);
if (redisValue) {
const value = JSON.parse(redisValue);
this.memoryCache.set(key, { value, expiry: Date.now() + 60000 });
return value;
}
return null;
}
}
```
**Cache Layers:**
- **L1 (Memory)**: Fast access for frequently used data
- **L2 (Redis)**: Shared cache across instances
- **L3 (Database)**: Persistent storage with query optimization
## Communication Patterns
### Request Flow
```mermaid
sequenceDiagram
participant Client
participant API
participant Auth
participant Router
participant MCP
participant Server
Client->>API: HTTP Request
API->>Auth: Validate Token
Auth-->>API: User Context
API->>Router: Route Request
Router->>Router: Find Target Server
Router->>MCP: Execute Request
MCP->>Server: MCP Protocol
Server-->>MCP: MCP Response
MCP-->>Router: Formatted Response
Router-->>API: Response Data
API-->>Client: HTTP Response
```
### WebSocket Communication
```typescript
// src/services/websocketService.ts
class WebSocketService {
private connections: Map<string, WebSocket> = new Map();
handleConnection(ws: WebSocket, userId: string): void {
this.connections.set(userId, ws);
ws.on('message', async (data) => {
const message = JSON.parse(data.toString());
await this.handleMessage(userId, message);
});
ws.on('close', () => {
this.connections.delete(userId);
});
}
broadcast(event: string, data: any): void {
this.connections.forEach((ws) => {
ws.send(JSON.stringify({ event, data }));
});
}
}
```
### Event-Driven Architecture
```typescript
// src/events/eventBus.ts
class EventBus {
private listeners: Map<string, EventListener[]> = new Map();
emit(event: string, data: any): void {
const handlers = this.listeners.get(event) || [];
handlers.forEach((handler) => handler(data));
}
on(event: string, handler: EventListener): void {
const handlers = this.listeners.get(event) || [];
handlers.push(handler);
this.listeners.set(event, handlers);
}
}
// Usage
eventBus.on('server.started', (data) => {
logger.info(`Server ${data.name} started`);
monitoringService.updateServerStatus(data.name, 'running');
});
```
## Security Architecture
### Authentication Flow
```mermaid
graph LR
A[Client] --> B[Login Request]
B --> C[Validate Credentials]
C --> D[Generate JWT]
D --> E[Create Session]
E --> F[Return Token]
F --> G[Store in Cookie/Header]
G --> H[Subsequent Requests]
H --> I[Validate Token]
I --> J[Check Permissions]
J --> K[Allow/Deny Access]
```
### Authorization Model
```typescript
// Role-Based Access Control (RBAC)
interface Permission {
resource: string; // e.g., 'servers', 'groups', 'users'
action: string; // e.g., 'create', 'read', 'update', 'delete'
scope?: string; // e.g., 'own', 'group', 'all'
}
interface Role {
name: string;
permissions: Permission[];
}
const roles: Role[] = [
{
name: 'admin',
permissions: [{ resource: '*', action: '*', scope: 'all' }],
},
{
name: 'manager',
permissions: [
{ resource: 'servers', action: '*', scope: 'group' },
{ resource: 'groups', action: 'read', scope: 'all' },
],
},
{
name: 'user',
permissions: [
{ resource: 'servers', action: 'read', scope: 'group' },
{ resource: 'tools', action: 'execute', scope: 'group' },
],
},
];
```
## Scalability Considerations
### Horizontal Scaling
```yaml
# Kubernetes deployment for scaling
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcphub
spec:
replicas: 3
selector:
matchLabels:
app: mcphub
template:
spec:
containers:
- name: mcphub
image: mcphub:latest
resources:
requests:
memory: '256Mi'
cpu: '200m'
limits:
memory: '512Mi'
cpu: '500m'
```
### Load Balancing Strategy
```typescript
// src/services/loadBalancer.ts
class LoadBalancer {
private servers: ServerInstance[] = [];
private algorithm: 'round-robin' | 'least-connections' | 'weighted';
selectServer(): ServerInstance {
switch (this.algorithm) {
case 'round-robin':
return this.roundRobin();
case 'least-connections':
return this.leastConnections();
case 'weighted':
return this.weighted();
}
}
}
```
### Database Scaling
```typescript
// Database connection management
class DatabaseManager {
private readPool: Pool; // Read replicas
private writePool: Pool; // Primary database
async query(sql: string, params: any[]): Promise<any> {
if (this.isReadOperation(sql)) {
return this.readPool.query(sql, params);
} else {
return this.writePool.query(sql, params);
}
}
}
```
## Performance Optimization
### Query Optimization
```sql
-- Optimized queries with proper indexing
CREATE INDEX CONCURRENTLY idx_servers_status_group
ON servers(status, group_name)
WHERE status IN ('running', 'starting');
CREATE INDEX CONCURRENTLY idx_tool_embeddings_similarity
ON tool_embeddings USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
CREATE INDEX CONCURRENTLY idx_request_logs_performance
ON request_logs(created_at, status, duration_ms)
WHERE created_at > NOW() - INTERVAL '30 days';
```
### Caching Strategy
```typescript
// Multi-level caching
class CacheManager {
// Cache server configurations
@Cache({ ttl: 300, key: 'server-config' })
async getServerConfig(name: string): Promise<ServerConfig> {
return this.database.getServerConfig(name);
}
// Cache tool metadata for smart routing
@Cache({ ttl: 3600, key: 'tool-metadata' })
async getToolMetadata(): Promise<ToolMetadata[]> {
return this.database.getToolMetadata();
}
// Cache user permissions
@Cache({ ttl: 600, key: 'user-permissions' })
async getUserPermissions(userId: string): Promise<Permission[]> {
return this.authService.getUserPermissions(userId);
}
}
```
## Monitoring & Observability
### Metrics Collection
```typescript
// src/services/metricsService.ts
class MetricsService {
private prometheus: PrometheusRegistry;
constructor() {
this.initializeMetrics();
}
private initializeMetrics(): void {
// Request metrics
this.requestCount = new Counter({
name: 'mcphub_requests_total',
help: 'Total number of requests',
labelNames: ['method', 'route', 'status'],
});
// Server metrics
this.serverStatus = new Gauge({
name: 'mcphub_server_status',
help: 'Status of MCP servers',
labelNames: ['server_name', 'status'],
});
// Performance metrics
this.responseTime = new Histogram({
name: 'mcphub_response_time_seconds',
help: 'Response time in seconds',
labelNames: ['route'],
});
}
}
```
### Distributed Tracing
```typescript
// OpenTelemetry integration
import { trace } from '@opentelemetry/api';
class MCPService {
async executeRequest(serverName: string, request: MCPRequest): Promise<MCPResponse> {
const span = trace.getActiveSpan();
span?.setAttributes({
'mcp.server': serverName,
'mcp.tool': request.tool,
'mcp.request_id': request.id,
});
try {
const response = await this.sendRequest(serverName, request);
span?.setStatus({ code: SpanStatusCode.OK });
return response;
} catch (error) {
span?.setStatus({
code: SpanStatusCode.ERROR,
message: error.message,
});
throw error;
}
}
}
```
## Extension Points
### Plugin Architecture
```typescript
// Plugin interface
interface MCPHubPlugin {
name: string;
version: string;
init(context: PluginContext): Promise<void>;
destroy(): Promise<void>;
}
// Plugin manager
class PluginManager {
private plugins: Map<string, MCPHubPlugin> = new Map();
async loadPlugin(plugin: MCPHubPlugin): Promise<void> {
await plugin.init(this.createContext());
this.plugins.set(plugin.name, plugin);
}
private createContext(): PluginContext {
return {
eventBus: this.eventBus,
logger: this.logger,
database: this.database,
// ... other services
};
}
}
```
### Custom Middleware
```typescript
// Custom middleware registration
class MiddlewareManager {
register(middleware: Middleware): void {
this.app.use(middleware);
}
registerRoute(path: string, middleware: Middleware): void {
this.app.use(path, middleware);
}
}
// Example custom middleware
const customAuthMiddleware: Middleware = (req, res, next) => {
// Custom authentication logic
next();
};
```
## Deployment Architecture
### Container Strategy
```dockerfile
# Multi-stage build for optimized images
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:18-alpine AS runtime
RUN addgroup -g 1001 -S nodejs
RUN adduser -S mcphub -u 1001
WORKDIR /app
COPY --from=builder --chown=mcphub:nodejs /app .
USER mcphub
EXPOSE 3000
CMD ["node", "dist/server.js"]
```
### Infrastructure as Code
```terraform
# Terraform configuration for AWS deployment
resource "aws_ecs_cluster" "mcphub" {
name = "mcphub-cluster"
}
resource "aws_ecs_service" "mcphub" {
name = "mcphub"
cluster = aws_ecs_cluster.mcphub.id
task_definition = aws_ecs_task_definition.mcphub.arn
desired_count = 3
load_balancer {
target_group_arn = aws_lb_target_group.mcphub.arn
container_name = "mcphub"
container_port = 3000
}
}
```
This architecture provides a solid foundation for building a scalable, maintainable, and extensible MCP server management platform while following modern software development best practices.