#!/usr/bin/env node
/**
 * index.ts
 *
 * Run MCP stdio servers over SSE, convert between stdio, SSE, WS.
 *
 * Usage:
 *   # stdio→SSE
 *   npx -y supergateway --stdio "npx -y @modelcontextprotocol/server-filesystem /" \
 *                       --port 8000 --baseUrl http://localhost:8000 --ssePath /sse --messagePath /message
 *
 *   # SSE→stdio
 *   npx -y supergateway --sse "https://mcp-server-ab71a6b2-cd55-49d0-adba-562bc85956e3.supermachine.app"
 *
 *   # stdio→WS
 *   npx -y supergateway --stdio "npx -y @modelcontextprotocol/server-filesystem /" --outputTransport ws
 *
 *   # Streamable HTTP→stdio
 *   npx -y supergateway --streamableHttp "https://mcp-server.example.com/mcp"
 */
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { stdioToSse } from './gateways/stdioToSse.js';
import { sseToStdio } from './gateways/sseToStdio.js';
import { stdioToWs } from './gateways/stdioToWs.js';
import { streamableHttpToStdio } from './gateways/streamableHttpToStdio.js';
import { headers } from './lib/headers.js';
import { corsOrigin } from './lib/corsOrigin.js';
import { getLogger } from './lib/getLogger.js';
async function main() {
    const argv = yargs(hideBin(process.argv))
        .option('stdio', {
        type: 'string',
        description: 'Command to run an MCP server over Stdio',
    })
        .option('sse', {
        type: 'string',
        description: 'SSE URL to connect to',
    })
        .option('streamableHttp', {
        type: 'string',
        description: 'Streamable HTTP URL to connect to',
    })
        .option('outputTransport', {
        type: 'string',
        choices: ['stdio', 'sse', 'ws'],
        default: () => {
            const args = hideBin(process.argv);
            if (args.includes('--stdio'))
                return 'sse';
            if (args.includes('--sse'))
                return 'stdio';
            if (args.includes('--streamableHttp'))
                return 'stdio';
            return undefined;
        },
        description: 'Transport for output. Default is "sse" when using --stdio and "stdio" when using --sse or --streamableHttp.',
    })
        .option('port', {
        type: 'number',
        default: 8000,
        description: '(stdio→SSE, stdio→WS) Port for output MCP server',
    })
        .option('baseUrl', {
        type: 'string',
        default: '',
        description: '(stdio→SSE) Base URL for output MCP server',
    })
        .option('ssePath', {
        type: 'string',
        default: '/sse',
        description: '(stdio→SSE) Path for SSE subscriptions',
    })
        .option('messagePath', {
        type: 'string',
        default: '/message',
        description: '(stdio→SSE, stdio→WS) Path for messages',
    })
        .option('logLevel', {
        choices: ['debug', 'info', 'none'],
        default: 'info',
        description: 'Logging level',
    })
        .option('cors', {
        type: 'array',
        description: 'Enable CORS. Use --cors with no values to allow all origins, or supply one or more allowed origins (e.g. --cors "http://example.com" or --cors "/example\\.com$/" for regex matching).',
    })
        .option('healthEndpoint', {
        type: 'array',
        default: [],
        description: 'One or more endpoints returning "ok", e.g. --healthEndpoint /healthz --healthEndpoint /readyz',
    })
        .option('header', {
        type: 'array',
        default: [],
        description: 'Headers to be added to the request headers, e.g. --header "x-user-id: 123"',
    })
        .option('oauth2Bearer', {
        type: 'string',
        description: 'Authorization header to be added, e.g. --oauth2Bearer "some-access-token" adds "Authorization: Bearer some-access-token"',
    })
        .help()
        .parseSync();
    const hasStdio = Boolean(argv.stdio);
    const hasSse = Boolean(argv.sse);
    const hasStreamableHttp = Boolean(argv.streamableHttp);
    const activeCount = [hasStdio, hasSse, hasStreamableHttp].filter(Boolean).length;
    const logger = getLogger({
        logLevel: argv.logLevel,
        outputTransport: argv.outputTransport,
    });
    if (activeCount === 0) {
        logger.error('Error: You must specify one of --stdio, --sse, or --streamableHttp');
        process.exit(1);
    }
    else if (activeCount > 1) {
        logger.error('Error: Specify only one of --stdio, --sse, or --streamableHttp, not multiple');
        process.exit(1);
    }
    logger.info('Starting...');
    logger.info('Supergateway is supported by Supermachine (hosted MCPs) - https://supermachine.ai');
    logger.info(`  - outputTransport: ${argv.outputTransport}`);
    try {
        if (hasStdio) {
            if (argv.outputTransport === 'sse') {
                await stdioToSse({
                    stdioCmd: argv.stdio,
                    port: argv.port,
                    baseUrl: argv.baseUrl,
                    ssePath: argv.ssePath,
                    messagePath: argv.messagePath,
                    logger,
                    corsOrigin: corsOrigin({ argv }),
                    healthEndpoints: argv.healthEndpoint,
                    headers: headers({
                        argv,
                        logger,
                    }),
                });
            }
            else if (argv.outputTransport === 'ws') {
                await stdioToWs({
                    stdioCmd: argv.stdio,
                    port: argv.port,
                    messagePath: argv.messagePath,
                    logger,
                    corsOrigin: corsOrigin({ argv }),
                    healthEndpoints: argv.healthEndpoint,
                });
            }
            else {
                logger.error(`Error: stdio→${argv.outputTransport} not supported`);
                process.exit(1);
            }
        }
        else if (hasSse) {
            if (argv.outputTransport === 'stdio') {
                await sseToStdio({
                    sseUrl: argv.sse,
                    logger,
                    headers: headers({
                        argv,
                        logger,
                    }),
                });
            }
            else {
                logger.error(`Error: sse→${argv.outputTransport} not supported`);
                process.exit(1);
            }
        }
        else if (hasStreamableHttp) {
            if (argv.outputTransport === 'stdio') {
                await streamableHttpToStdio({
                    streamableHttpUrl: argv.streamableHttp,
                    logger,
                    headers: headers({
                        argv,
                        logger,
                    }),
                });
            }
            else {
                logger.error(`Error: streamableHttp→${argv.outputTransport} not supported`);
                process.exit(1);
            }
        }
        else {
            logger.error('Error: Invalid input transport');
            process.exit(1);
        }
    }
    catch (err) {
        logger.error('Fatal error:', err);
        process.exit(1);
    }
}
main();
