/*
 * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
 */
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import express from "express";
import { createConsoleLogger, } from "../../console-logger.js";
import { createMCPServer } from "../../server.js";
import { buildAnnotationFilter } from "../../tools.js";
import { landingPageExpress } from "../../../landing-page.js";
export async function main(flags) {
    flags.env?.forEach(([key, value]) => {
        process.env[key] = value;
    });
    switch (flags.transport) {
        case "stdio":
            await startStdio(flags);
            break;
        case "sse":
            await startSSE(flags);
            break;
        default:
            throw new Error(`Invalid transport: ${flags.transport}`);
    }
}
async function startStdio(flags) {
    const logger = createConsoleLogger(flags["log-level"]);
    const transport = new StdioServerTransport();
    const { server } = createMCPServer({
        logger,
        allowedTools: flags.tool,
        dynamic: flags.mode === "dynamic",
        annotationFilter: buildAnnotationFilter(flags["tool-annotations"]),
        scopes: flags.scope,
        security: {
            cloudinaryAuth: flags["api-key"] != null && flags["api-secret"] != null
                ? {
                    api_key: flags["api-key"] ?? "",
                    api_secret: flags["api-secret"] ?? "",
                }
                : void 0,
            oauth2: flags.oauth2 ?? "",
        },
        cloud_name: flags["cloud-name"],
        serverURL: flags["server-url"],
        serverIdx: flags["server-index"],
        region: flags.region,
        host: flags["api-host"],
    });
    await server.connect(transport);
    const abort = async () => {
        await server.close();
        process.exit(0);
    };
    process.on("SIGTERM", abort);
    process.on("SIGINT", abort);
}
async function startSSE(cliFlags) {
    const logger = createConsoleLogger(cliFlags["log-level"]);
    const app = express();
    const sessions = new Map();
    const controller = new AbortController();
    app.get("/sse", async (req, res) => {
        const sessionId = crypto.randomUUID();
        logger.info("SSE connection initiated", {
            sessionId,
            userAgent: req.headers["user-agent"],
        });
        // Track early disconnection
        let connectionClosed = false;
        res.on("close", () => {
            if (!connectionClosed) {
                logger.info("Connection closed early", { sessionId });
            }
            connectionClosed = true;
        });
        // Merge CLI flags with header overrides for security credentials
        const flags = {
            ...cliFlags,
            // Security fields can be overridden via headers
            "api-key": req.headers["api_key"] ?? cliFlags["api-key"],
            "api-secret": req.headers["api_secret"]
                ?? cliFlags["api-secret"],
            "oauth2": req.headers["oauth2"] ?? cliFlags["oauth2"],
        };
        // Create a new MCP server for this connection with its auth
        const { server: mcpServer } = createMCPServer({
            logger,
            allowedTools: flags.tool,
            dynamic: flags.mode === "dynamic",
            annotationFilter: buildAnnotationFilter(flags["tool-annotations"]),
            scopes: flags.scope,
            security: {
                cloudinaryAuth: flags["api-key"] != null && flags["api-secret"] != null
                    ? {
                        api_key: flags["api-key"] ?? "",
                        api_secret: flags["api-secret"] ?? "",
                    }
                    : void 0,
                oauth2: flags.oauth2 ?? "",
            },
            cloud_name: flags["cloud-name"],
            serverURL: flags["server-url"],
            serverIdx: flags["server-index"],
            region: flags.region,
            host: flags["api-host"],
        });
        // Message path includes session ID for routing
        const transport = new SSEServerTransport(`/message/${sessionId}`, res);
        const cleanup = async () => {
            await mcpServer.close();
        };
        sessions.set(sessionId, { mcpServer, transport, cleanup });
        logger.info("Session created", { sessionId, totalSessions: sessions.size });
        controller.signal.addEventListener("abort", cleanup);
        // Log server-side errors for debugging (e.g. tools/list handler failures)
        mcpServer.server.onerror = (error) => {
            logger.error("MCP protocol error", {
                sessionId,
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            });
        };
        // Wrap transport.send to log error responses for debugging
        const originalSend = transport.send.bind(transport);
        transport.send = async (message) => {
            if ("error" in message && message.error) {
                logger.error("MCP sending error response", {
                    sessionId,
                    id: message.id,
                    errorCode: message.error.code,
                    errorMessage: message.error.message,
                });
            }
            return originalSend(message);
        };
        await mcpServer.connect(transport);
        mcpServer.server.onclose = async () => {
            connectionClosed = true;
            controller.signal.removeEventListener("abort", cleanup);
            sessions.delete(sessionId);
            logger.info("Session closed", {
                sessionId,
                totalSessions: sessions.size,
            });
            res.end();
        };
    });
    app.post("/message/:sessionId", async (req, res) => {
        const session = sessions.get(req.params.sessionId);
        if (!session) {
            res.status(404).send("Session not found");
            return;
        }
        await session.transport.handlePostMessage(req, res);
    });
    app.get("/", landingPageExpress);
    const httpServer = app.listen(cliFlags.port, "0.0.0.0", () => {
        const ha = httpServer.address();
        const host = typeof ha === "string" ? ha : `${ha?.address}:${ha?.port}`;
        logger.info("MCP HTTP server started", { host });
    });
    let closing = false;
    controller.signal.addEventListener("abort", async () => {
        if (closing) {
            logger.info("Received second signal. Forcing shutdown.");
            process.exit(1);
        }
        closing = true;
        logger.info("Shutting down HTTP server");
        const timer = setTimeout(() => {
            logger.info("Forcing shutdown");
            process.exit(1);
        }, 5000);
        httpServer.close(() => {
            clearTimeout(timer);
            logger.info("Graceful shutdown complete");
            process.exit(0);
        });
    });
    const abort = () => controller.abort();
    process.on("SIGTERM", abort);
    process.on("SIGINT", abort);
}
//# sourceMappingURL=impl.js.map