#!/usr/bin/env node
import { Command } from "commander";
import { resolve } from "node:path";
import { loadConfig } from "./config/loader.js";
import { ServerManager } from "./client/manager.js";
import { createApp } from "./http/app.js";
import { closeAllSessions } from "./http/router.js";
import { setupGracefulShutdown } from "./utils/shutdown.js";
import logger from "./utils/logger.js";
const program = new Command();
program
.name("mcp-server-hub")
.description("MCP Server Hub - Aggregate and proxy multiple MCP servers")
.version("0.1.0")
.option("-c, --config <path>", "Path to config file", "config.json")
.option("-p, --port <number>", "Port to listen on (overrides config)")
.action(async (options) => {
try {
const configPath = resolve(options.config);
const config = await loadConfig(configPath);
// CLI port override
const port = options.port ? parseInt(options.port, 10) : config.hub.port;
logger.info("Starting MCP Server Hub", {
servers: Object.keys(config.servers).length,
groups: Object.keys(config.groups).length,
port,
});
// Initialize server manager
const manager = new ServerManager(
config.servers,
config.groups,
config.hub.reconnect,
config.hub.idleTimeoutMs
);
logger.info("Servers will connect on demand when first accessed");
// Create Express app
const app = createApp(manager, config.hub.auth);
// Start HTTP server
const httpServer = app.listen(port, () => {
logger.info(`MCP Server Hub listening on port ${port}`);
logger.info("Endpoints:");
logger.info(` POST/GET/DELETE http://localhost:${port}/mcp (all servers)`);
for (const id of manager.getServerIds()) {
logger.info(` POST/GET/DELETE http://localhost:${port}/mcp/server/${id}`);
}
for (const id of manager.getGroupIds()) {
logger.info(` POST/GET/DELETE http://localhost:${port}/mcp/group/${id}`);
}
logger.info(` GET http://localhost:${port}/health`);
});
// Setup graceful shutdown
setupGracefulShutdown(httpServer, manager, closeAllSessions);
} catch (err) {
logger.error("Failed to start MCP Server Hub", { error: (err as Error).message });
process.exit(1);
}
});
program.parse();