feat: add Docker bootstrap for mcpd with auto-migration and seeding
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions

Adds Dockerfile, entrypoint, and server bootstrap so that
`docker compose up` starts postgres, pushes the schema,
seeds default MCP servers, and starts mcpd with all routes wired up.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Michal
2026-02-21 13:34:18 +00:00
parent 6da4ae495c
commit 89b2b1b13d
7 changed files with 216 additions and 5 deletions

View File

@@ -9,7 +9,7 @@
"build": "tsc --build",
"clean": "rimraf dist",
"dev": "tsx watch src/index.ts",
"start": "node dist/index.js",
"start": "node dist/main.js",
"test": "vitest",
"test:run": "vitest run"
},

104
src/mcpd/src/main.ts Normal file
View File

@@ -0,0 +1,104 @@
import { PrismaClient } from '@prisma/client';
import { seedMcpServers } from '@mcpctl/db';
import { loadConfigFromEnv } from './config/index.js';
import { createServer } from './server.js';
import { setupGracefulShutdown } from './utils/index.js';
import {
McpServerRepository,
McpProfileRepository,
McpInstanceRepository,
ProjectRepository,
AuditLogRepository,
} from './repositories/index.js';
import {
McpServerService,
McpProfileService,
InstanceService,
ProjectService,
AuditLogService,
DockerContainerManager,
MetricsCollector,
HealthAggregator,
BackupService,
RestoreService,
} from './services/index.js';
import {
registerMcpServerRoutes,
registerMcpProfileRoutes,
registerInstanceRoutes,
registerProjectRoutes,
registerAuditLogRoutes,
registerHealthMonitoringRoutes,
registerBackupRoutes,
} from './routes/index.js';
async function main(): Promise<void> {
const config = loadConfigFromEnv();
// Database
const prisma = new PrismaClient({
datasources: { db: { url: config.databaseUrl } },
});
await prisma.$connect();
// Seed default servers (upsert, safe to repeat)
await seedMcpServers(prisma);
// Repositories
const serverRepo = new McpServerRepository(prisma);
const profileRepo = new McpProfileRepository(prisma);
const instanceRepo = new McpInstanceRepository(prisma);
const projectRepo = new ProjectRepository(prisma);
const auditLogRepo = new AuditLogRepository(prisma);
// Orchestrator
const orchestrator = new DockerContainerManager();
// Services
const serverService = new McpServerService(serverRepo);
const profileService = new McpProfileService(profileRepo, serverRepo);
const instanceService = new InstanceService(instanceRepo, serverRepo, orchestrator);
const projectService = new ProjectService(projectRepo, profileRepo, serverRepo);
const auditLogService = new AuditLogService(auditLogRepo);
const metricsCollector = new MetricsCollector();
const healthAggregator = new HealthAggregator(metricsCollector, orchestrator);
const backupService = new BackupService(serverRepo, profileRepo, projectRepo);
const restoreService = new RestoreService(serverRepo, profileRepo, projectRepo);
// Server
const app = await createServer(config, {
health: {
checkDb: async () => {
try {
await prisma.$queryRaw`SELECT 1`;
return true;
} catch {
return false;
}
},
},
});
// Routes
registerMcpServerRoutes(app, serverService);
registerMcpProfileRoutes(app, profileService);
registerInstanceRoutes(app, instanceService);
registerProjectRoutes(app, projectService);
registerAuditLogRoutes(app, auditLogService);
registerHealthMonitoringRoutes(app, { healthAggregator, metricsCollector });
registerBackupRoutes(app, { backupService, restoreService });
// Start
await app.listen({ port: config.port, host: config.host });
app.log.info(`mcpd listening on ${config.host}:${config.port}`);
// Graceful shutdown
setupGracefulShutdown(app, {
disconnectDb: () => prisma.$disconnect(),
});
}
main().catch((err) => {
console.error('Failed to start mcpd:', err);
process.exit(1);
});

View File

@@ -0,0 +1,17 @@
import { PrismaClient } from '@prisma/client';
import { seedMcpServers } from '@mcpctl/db';
async function run(): Promise<void> {
const prisma = new PrismaClient();
try {
const count = await seedMcpServers(prisma);
console.log(`Seeded ${count} MCP servers`);
} finally {
await prisma.$disconnect();
}
}
run().catch((err) => {
console.error('Seed failed:', err);
process.exit(1);
});