import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
import path from 'node:path';
import fs from 'node:fs';
import { parse as parseYaml } from 'yaml';
const EXPX_SERVER_URL = process.env.EXPX_SERVER_URL ?? 'http://127.0.0.1:3001';
const EXPX_API_KEY = process.env.EXPX_API_KEY ?? '';
async function fetchJson(url, body) {
    const opts = {
        headers: {
            'Content-Type': 'application/json',
            ...(EXPX_API_KEY ? { Authorization: `Bearer ${EXPX_API_KEY}` } : {}),
        },
    };
    if (body) {
        opts.method = 'POST';
        opts.body = JSON.stringify(body);
    }
    const res = await fetch(url, opts);
    if (!res.ok) {
        const text = await res.text();
        throw new Error(`ExpxAgents API error ${res.status}: ${text}`);
    }
    return res.json();
}
function listSquads() {
    const squadsDir = path.resolve(process.cwd(), 'squads');
    if (!fs.existsSync(squadsDir))
        return [];
    const results = [];
    const entries = fs.readdirSync(squadsDir, { withFileTypes: true });
    for (const entry of entries) {
        if (!entry.isDirectory() || entry.name.startsWith('.') || entry.name.startsWith('_'))
            continue;
        const yamlPath = path.join(squadsDir, entry.name, 'squad.yaml');
        if (!fs.existsSync(yamlPath))
            continue;
        try {
            const raw = fs.readFileSync(yamlPath, 'utf-8');
            const parsed = parseYaml(raw);
            const s = parsed?.squad;
            if (!s)
                continue;
            const agents = Array.isArray(s.agents)
                ? s.agents.map((a) => {
                    if (typeof a === 'string')
                        return a;
                    if (typeof a === 'object' && a !== null)
                        return String(a.id ?? a.name ?? '');
                    return String(a);
                })
                : [];
            results.push({
                name: String(s.name ?? entry.name),
                code: String(s.code ?? entry.name),
                description: String(s.description ?? ''),
                agents,
                directory: path.join(squadsDir, entry.name),
            });
        }
        catch {
            // skip malformed yaml
        }
    }
    return results;
}
const server = new McpServer({
    name: 'expxagents',
    version: '1.0.0',
});
server.registerTool('list_squads', {
    title: 'List Squads',
    description: 'List all available agent squads. Returns name, description, and agents for each squad.',
    inputSchema: {},
}, async () => {
    const squads = listSquads();
    return {
        content: [{ type: 'text', text: JSON.stringify(squads, null, 2) }],
    };
});
server.registerTool('get_squad_info', {
    title: 'Get Squad Info',
    description: 'Get detailed information about a specific squad including its agents and configuration.',
    inputSchema: z.object({
        name: z.string().describe('The squad name'),
    }),
}, async ({ name }) => {
    const squads = listSquads();
    const squad = squads.find((s) => s.code === name || s.name === name);
    if (!squad) {
        return {
            content: [{ type: 'text', text: `Squad "${name}" not found` }],
            isError: true,
        };
    }
    return {
        content: [{ type: 'text', text: JSON.stringify(squad, null, 2) }],
    };
});
server.registerTool('list_squad_agents', {
    title: 'List Squad Agents',
    description: 'List all agents available in a specific squad.',
    inputSchema: z.object({
        name: z.string().describe('The squad name'),
    }),
}, async ({ name }) => {
    const squads = listSquads();
    const squad = squads.find((s) => s.code === name || s.name === name);
    if (!squad) {
        return {
            content: [{ type: 'text', text: `Squad "${name}" not found` }],
            isError: true,
        };
    }
    return {
        content: [{ type: 'text', text: JSON.stringify(squad.agents, null, 2) }],
    };
});
server.registerTool('run_squad', {
    title: 'Run Squad',
    description: 'Execute a squad pipeline. The squad will process the prompt and return results.',
    inputSchema: z.object({
        name: z.string().describe('The squad name (directory name, e.g. "marketing-squad")'),
        prompt: z.string().describe('The task description or prompt for the squad to execute'),
    }),
}, async ({ name, prompt }) => {
    const squads = listSquads();
    const squad = squads.find((s) => s.code === name || s.name === name);
    if (!squad) {
        return {
            content: [{ type: 'text', text: `Squad "${name}" not found` }],
            isError: true,
        };
    }
    try {
        const result = await fetchJson(`${EXPX_SERVER_URL}/api/chat/send`, { squadName: name, message: prompt });
        if (!result.success) {
            return {
                content: [{ type: 'text', text: result.error ?? 'Failed to start squad' }],
                isError: true,
            };
        }
        return {
            content: [
                {
                    type: 'text',
                    text: JSON.stringify({
                        status: 'started',
                        squad: name,
                        activityId: result.activityId,
                        message: `Squad "${name}" started successfully. Pipeline execution is underway.`,
                    }, null, 2),
                },
            ],
        };
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        return {
            content: [{ type: 'text', text: `Error: ${message}` }],
            isError: true,
        };
    }
});
server.registerTool('stop_squad', {
    title: 'Stop Squad',
    description: 'Stop a running squad pipeline.',
    inputSchema: z.object({
        name: z.string().describe('The squad name to stop'),
    }),
}, async ({ name }) => {
    try {
        await fetchJson(`${EXPX_SERVER_URL}/api/chat/stop`, {
            squadName: name,
        });
        return {
            content: [{ type: 'text', text: JSON.stringify({ status: 'stopped', squad: name }, null, 2) }],
        };
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        return {
            content: [{ type: 'text', text: `Error: ${message}` }],
            isError: true,
        };
    }
});
server.registerTool('query_knowledge', {
    title: 'Query Knowledge',
    description: 'Search the project knowledge base. Finds documents, learnings, decisions, and entity relationships across all squads.',
    inputSchema: z.object({
        query: z.string().describe('Search query in natural language'),
        mode: z.enum(['search', 'graph', 'auto']).optional().default('auto').describe('Query mode'),
        squad: z.string().optional().describe('Filter by squad code'),
        source_type: z
            .enum(['external', 'agent_output', 'squad_memory', 'activity_log'])
            .optional()
            .describe('Filter by source type'),
        limit: z.number().optional().default(10).describe('Max results to return'),
    }),
}, async ({ query, mode, squad, source_type, limit }) => {
    try {
        const params = new URLSearchParams({ q: query, mode: mode ?? 'auto', limit: String(limit ?? 10) });
        if (squad)
            params.set('squad', squad);
        if (source_type)
            params.set('source_type', source_type);
        const response = await fetch(`${EXPX_SERVER_URL}/api/knowledge/query?${params}`, {
            headers: { Authorization: `Bearer ${EXPX_API_KEY}` },
        });
        if (!response.ok) {
            return { content: [{ type: 'text', text: `Error: ${response.status} ${response.statusText}` }], isError: true };
        }
        const result = await response.json();
        return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
    }
    catch (err) {
        return { content: [{ type: 'text', text: `Knowledge query failed: ${err.message}` }], isError: true };
    }
});
async function main() {
    const transport = new StdioServerTransport();
    await server.connect(transport);
}
main().catch((err) => {
    console.error('[expxagents-mcp] Fatal error:', err);
    process.exit(1);
});
//# sourceMappingURL=expxagents-mcp.js.map