import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const DEFAULT_MCP_TIMEOUT_MS = 30_000;
export class McpClientService {
    async listTools(server) {
        return await this.withClient(server, async (client) => {
            const tools = await client.listTools({}, { timeout: DEFAULT_MCP_TIMEOUT_MS });
            const serverVersion = client.getServerVersion();
            return {
                serverName: serverVersion?.name,
                serverVersion: serverVersion?.version,
                instructions: client.getInstructions(),
                tools: tools.tools.map(toToolDescriptor),
            };
        });
    }
    async callTool(server, toolName, args) {
        try {
            return await this.withClient(server, async (client) => {
                const result = await client.callTool({
                    name: toolName,
                    arguments: args,
                }, undefined, { timeout: DEFAULT_MCP_TIMEOUT_MS });
                return {
                    ok: true,
                    output: normalizeToolResult(result),
                };
            });
        }
        catch (error) {
            return {
                ok: false,
                error: error instanceof Error ? error.message : String(error),
            };
        }
    }
    async withClient(server, callback) {
        const client = new Client({
            name: 'heddle',
            version: '0.0.0',
        });
        const transport = createTransport(server);
        try {
            await client.connect(transport, { timeout: DEFAULT_MCP_TIMEOUT_MS });
            return await callback(client);
        }
        finally {
            await client.close().catch(() => undefined);
            await transport.close().catch(() => undefined);
        }
    }
}
function createTransport(server) {
    if (server.transport === 'stdio') {
        return new StdioClientTransport({
            command: server.command,
            args: server.args,
            cwd: server.cwd,
            env: resolveEnv(server.env),
            stderr: 'pipe',
        });
    }
    if (server.transport === 'sse') {
        return new SSEClientTransport(new URL(server.url), {
            requestInit: {
                headers: resolveEnv(server.headers),
            },
        });
    }
    return new StreamableHTTPClientTransport(new URL(server.url), {
        requestInit: {
            headers: resolveEnv(server.headers),
        },
    });
}
function resolveEnv(values) {
    return Object.fromEntries(Object.entries(values).map(([key, value]) => [key, value.replace(/\$\{env:([A-Za-z_][A-Za-z0-9_]*)\}/g, (_match, envKey) => (process.env[envKey] ?? ''))]));
}
function toToolDescriptor(tool) {
    return {
        name: tool.name,
        title: tool.title,
        description: tool.description,
        inputSchema: tool.inputSchema,
        outputSchema: tool.outputSchema,
        annotations: tool.annotations,
    };
}
function normalizeToolResult(result) {
    if (!result || typeof result !== 'object') {
        return result;
    }
    const value = result;
    if (value.toolResult !== undefined) {
        return value.toolResult;
    }
    return {
        isError: value.isError ?? false,
        structuredContent: value.structuredContent,
        content: value.content,
    };
}
//# sourceMappingURL=client-service.js.map