feat: add Docker bootstrap for mcpd with auto-migration and seeding
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:
@@ -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
104
src/mcpd/src/main.ts
Normal 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);
|
||||
});
|
||||
17
src/mcpd/src/seed-runner.ts
Normal file
17
src/mcpd/src/seed-runner.ts
Normal 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);
|
||||
});
|
||||
Reference in New Issue
Block a user