# Task ID: 3 **Title:** Implement mcpd Core Server Framework **Status:** pending **Dependencies:** 1, 2 **Priority:** high **Description:** Build the mcpd daemon server with Express/Fastify, including middleware for authentication, logging, and error handling. Design for horizontal scalability. **Details:** Create mcpd server in `src/mcpd/src/`: ```typescript // server.ts import Fastify from 'fastify'; import { PrismaClient } from '@prisma/client'; const app = Fastify({ logger: true }); const prisma = new PrismaClient(); // Middleware app.register(require('@fastify/cors')); app.register(require('@fastify/helmet')); app.register(require('@fastify/rate-limit'), { max: 100, timeWindow: '1 minute' }); // Health check for load balancers app.get('/health', async () => ({ status: 'ok', timestamp: new Date().toISOString() })); // Auth middleware app.addHook('preHandler', async (request, reply) => { if (request.url === '/health') return; const token = request.headers.authorization?.replace('Bearer ', ''); if (!token) return reply.status(401).send({ error: 'Unauthorized' }); // Validate token against session table }); // Audit logging middleware app.addHook('onResponse', async (request, reply) => { await prisma.auditLog.create({ data: { action: request.method, resource: request.url, details: { statusCode: reply.statusCode }, userId: request.user?.id } }); }); ``` Design principles: - Stateless: All state in PostgreSQL, no in-memory session storage - Scalable: Can run multiple instances behind load balancer - Configurable via environment variables - Graceful shutdown handling **Test Strategy:** Unit test middleware functions. Integration test health endpoint. Load test with multiple concurrent requests. Verify statelessness by running two instances and alternating requests. ## Subtasks ### 3.1. Set up mcpd package structure with clean architecture layers and TDD infrastructure **Status:** pending **Dependencies:** None Create the src/mcpd directory structure following clean architecture principles with separate layers for routes, controllers, services, and repositories, along with Vitest test configuration. **Details:** Create src/mcpd/src/ directory structure with the following layers: - routes/ - HTTP route definitions (thin layer, delegates to controllers) - controllers/ - Request/response handling, input validation - services/ - Business logic, orchestrates repositories - repositories/ - Data access layer, Prisma abstraction - middleware/ - Auth, logging, error handling, rate limiting - config/ - Environment configuration with Zod validation - types/ - TypeScript interfaces for dependency injection - utils/ - Utility functions (graceful shutdown, health checks) Create src/mcpd/tests/ with matching structure: - unit/ (routes, controllers, services, repositories, middleware) - integration/ (API endpoint tests) - fixtures/ (mock data, Prisma mock setup) Set up vitest.config.ts extending root config with mcpd-specific settings. Create test-utils.ts with Prisma mock factory and Fastify test helpers. Install dependencies: fastify, @fastify/cors, @fastify/helmet, @fastify/rate-limit, zod, pino. DevDependencies: vitest, @vitest/coverage-v8, supertest. ### 3.2. Implement Fastify server core with health endpoint and database connectivity verification **Status:** pending **Dependencies:** 3.1 Create the core Fastify server with health check endpoint that verifies PostgreSQL database connectivity, environment configuration validation, and server lifecycle management. **Details:** Create src/mcpd/src/server.ts with Fastify instance factory function createServer(config: ServerConfig) for testability via dependency injection. Implement: - config/env.ts: Zod schema for environment variables (DATABASE_URL, PORT, NODE_ENV, LOG_LEVEL) - config/index.ts: loadConfig() function that validates env with Zod - utils/health.ts: checkDatabaseConnectivity(prisma) function - routes/health.ts: GET /health endpoint returning { status: 'ok' | 'degraded', timestamp: ISO8601, db: 'connected' | 'disconnected' } Server requirements: - Fastify with pino logger enabled (configurable log level) - Health endpoint bypasses auth middleware - Health endpoint checks actual DB connectivity via prisma.$queryRaw - Server does NOT start if DATABASE_URL is missing (fail fast) - Export createServer() and startServer() separately for testing Write TDD tests FIRST in tests/unit/routes/health.test.ts and tests/unit/config/env.test.ts before implementing. ### 3.3. Implement authentication middleware with JWT validation and session management **Status:** pending **Dependencies:** 3.2 Create authentication preHandler hook that validates Bearer tokens against the Session table in PostgreSQL, with proper error responses and request decoration for downstream handlers. **Details:** Create src/mcpd/src/middleware/auth.ts with: - authMiddleware(prisma: PrismaClient) factory function (dependency injection) - Fastify preHandler hook implementation - Extract Bearer token from Authorization header - Validate token exists and format is correct - Query Session table: find by token, check expiresAt > now() - Query User by session.userId for request decoration - Decorate request with user: { id, email, name } via fastify.decorateRequest - Return 401 Unauthorized with { error: 'Unauthorized', code: 'TOKEN_REQUIRED' } for missing token - Return 401 with { error: 'Unauthorized', code: 'TOKEN_EXPIRED' } for expired session - Return 401 with { error: 'Unauthorized', code: 'TOKEN_INVALID' } for invalid token Create types/fastify.d.ts with FastifyRequest augmentation for user property. Write unit tests in tests/unit/middleware/auth.test.ts with mocked Prisma client before implementation. ### 3.4. Implement security middleware stack with CORS, Helmet, rate limiting, and input sanitization **Status:** pending **Dependencies:** 3.2 Configure and register security middleware including CORS policy, Helmet security headers, rate limiting, and create input sanitization utilities to prevent injection attacks. **Details:** Create src/mcpd/src/middleware/security.ts with: - registerSecurityPlugins(app: FastifyInstance, config: SecurityConfig) function - CORS configuration: configurable origins (default: same-origin for production, * for development), credentials support, allowed methods/headers - Helmet configuration: contentSecurityPolicy, hsts (enabled in production), noSniff, frameguard - Rate limiting: 100 requests per minute default, configurable via env, different limits for auth endpoints (stricter) Create src/mcpd/src/utils/sanitize.ts: - sanitizeInput(input: unknown): sanitized value - stripHtmlTags(), escapeHtml() for XSS prevention - Validate JSON input doesn't exceed size limits Create src/mcpd/src/middleware/validate.ts: - createValidationMiddleware(schema: ZodSchema) factory - Validates request.body against Zod schema - Returns 400 Bad Request with Zod errors formatted Document security decisions in src/mcpd/SECURITY.md with rationale for each configuration choice. ### 3.5. Implement error handling, audit logging middleware, and graceful shutdown with comprehensive tests **Status:** pending **Dependencies:** 3.2, 3.3, 3.4 Create global error handler, audit logging onResponse hook that records all operations to database, and graceful shutdown handling with connection draining and proper signal handling. **Details:** Create src/mcpd/src/middleware/error-handler.ts: - Global Fastify error handler via setErrorHandler - Handle Zod validation errors -> 400 Bad Request - Handle Prisma errors (P2002 unique, P2025 not found) -> appropriate HTTP codes - Handle custom application errors with error codes - Log errors with pino, include stack trace in development only - Never expose internal errors to clients in production Create src/mcpd/src/middleware/audit.ts: - auditMiddleware(prisma: PrismaClient, auditLogger: AuditLogger) factory - Fastify onResponse hook - Create AuditLog record with: userId (from request.user), action (HTTP method), resource (URL), details ({ statusCode, responseTime, ip }) - Skip audit logging for /health endpoint - Async write - don't block response - Handle audit write failures gracefully (log warning, don't fail request) Create src/mcpd/src/utils/shutdown.ts: - setupGracefulShutdown(app: FastifyInstance, prisma: PrismaClient) function - Handle SIGTERM, SIGINT signals - Stop accepting new connections - Wait for in-flight requests (configurable timeout, default 30s) - Disconnect Prisma client - Exit with appropriate code Create services/audit-logger.ts interface that Task 14 will implement.