/**
 * MCP server connection and tool discovery.
 *
 * Handles connecting to an MCP server via streamable-http or stdio transport,
 * discovering available tools, and resolving {{env.VAR}} templates in config.
 */
/**
 * Connect to an MCP server and return a client for tool discovery and execution.
 *
 * Supports two transport types:
 * - `url` → streamable-http (remote MCP servers like mcp.sanity.io)
 * - `command` → stdio (local MCP server processes)
 */
export async function connectMCP(serverConfig) {
    const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
    const client = new Client({
        name: "ailf-mcp-eval",
        version: "1.0.0",
    });
    const resolvedConfig = resolveEnvTemplates(serverConfig);
    let closeTransport;
    if (resolvedConfig.command) {
        const { StdioClientTransport } = await import("@modelcontextprotocol/sdk/client/stdio.js");
        const parts = String(resolvedConfig.command).split(/\s+/);
        const transport = new StdioClientTransport({
            command: parts[0],
            args: parts.slice(1),
            env: process.env,
        });
        await client.connect(transport);
        closeTransport = () => transport.close();
    }
    else if (resolvedConfig.url) {
        const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
        const headers = {};
        // Auth-derived headers (structured auth config)
        const auth = resolvedConfig.auth;
        if (auth?.type === "bearer" && auth.token) {
            headers["Authorization"] = `Bearer ${auth.token}`;
        }
        // Explicit headers override auth-derived ones
        const customHeaders = resolvedConfig.headers;
        if (customHeaders) {
            Object.assign(headers, customHeaders);
        }
        const transport = new StreamableHTTPClientTransport(new URL(String(resolvedConfig.url)), { requestInit: { headers } });
        await client.connect(transport);
        closeTransport = () => transport.close();
    }
    else {
        throw new Error("MCP server config must have either 'command' (stdio) or 'url' (http)");
    }
    // Discover tools
    const { tools: toolsList } = await client.listTools();
    const allTools = toolsList.map((t) => ({
        name: t.name,
        description: t.description,
        inputSchema: t.inputSchema,
    }));
    return {
        getAllTools: () => allTools,
        callTool: async (name, args) => {
            const result = await client.callTool({ name, arguments: args });
            let content = "";
            if (result?.content) {
                if (Array.isArray(result.content)) {
                    content = result.content
                        .map((c) => c.text || JSON.stringify(c))
                        .join("\n");
                }
                else {
                    content = String(result.content);
                }
            }
            return { content, error: result.isError ? content : undefined };
        },
        cleanup: async () => {
            await closeTransport().catch(() => { });
        },
    };
}
/**
 * Resolve `{{env.VAR}}` templates in config values, recursively.
 */
export function resolveEnvTemplates(config) {
    const resolved = {};
    for (const [key, value] of Object.entries(config)) {
        if (typeof value === "string") {
            resolved[key] = value.replace(/\{\{env\.(\w+)\}\}/g, (_, varName) => {
                return process.env[varName] || "";
            });
        }
        else if (value && typeof value === "object" && !Array.isArray(value)) {
            resolved[key] = resolveEnvTemplates(value);
        }
        else {
            resolved[key] = value;
        }
    }
    return resolved;
}
