import fs from "fs";
import yaml from "js-yaml";
import { z } from "zod";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { bridgeHttp } from "./bridgeHttp.js";
import { bridgeStdio } from "./bridgeStdio.js";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
// Get the directory of this module file
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Resolve the bridge config path relative to the source directory
const bridgeConfigPath = join(__dirname, "..", "bridges", "hub.yaml");
const Config = z.object({
servers: z.array(
z.discriminatedUnion("type", [
z.object({
type: z.literal("http"),
prefix: z.string(),
url: z.string().url(),
apiKeyEnv: z.string().optional(),
omit: z.array(z.string()).optional(),
}),
z.object({
type: z.literal("stdio"),
prefix: z.string(),
cmd: z.string(),
args: z.array(z.string()).optional(),
omit: z.array(z.string()).optional(),
env: z.record(z.string()).optional(),
}),
])
),
});
export function main(hub: McpServer): Promise<void>[] {
let raw;
try {
console.error(`Loading bridge config from: ${bridgeConfigPath}`);
raw = yaml.load(fs.readFileSync(bridgeConfigPath, "utf8"));
} catch (error) {
console.error("Failed to load bridge config:", error);
console.error("Expected config file at:", bridgeConfigPath);
return []; // Return empty array if no config found
}
const { servers } = Config.parse(raw);
const tasks: Promise<void>[] = [];
for (const s of servers) {
if (s.type === "http") {
tasks.push(bridgeHttp(hub, s.url, s.prefix, process.env[s.apiKeyEnv!], s.omit));
} else {
tasks.push(bridgeStdio(hub, s.cmd, s.args||[], s.prefix, s.omit));
}
}
return tasks;
}