/**
 * MCP Streamable HTTP endpoint
 *
 * Exposes Studiograph's MCP tools over HTTP at /mcp so external clients
 * (Claude Code, Cursor, etc.) can connect to a remote Studiograph server.
 *
 * Uses stateless mode — each request creates a fresh MCP server instance
 * bound to the caller's identity. The Bearer header MUST resolve to a
 * real user (JWT or per-user API token). There is no workspace-wide
 * shared key anywhere in the system — every MCP call carries a user.
 */
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { registerTools, MCP_SERVER_INFO, MCP_INSTRUCTIONS } from '../../mcp/tools.js';
export async function registerMcpRoutes(fastify, workspaceManager, authService, wsHub, commentService) {
    // POST /mcp — handle MCP JSON-RPC requests (tool calls, initialization, etc.)
    fastify.post('/mcp', async (req, reply) => {
        const user = req.user;
        if (!user) {
            return reply.status(401).send({
                error: 'MCP requires a user-scoped Bearer token. Generate one at POST /api/auth/tokens.',
            });
        }
        // The auth hook stashes the api_tokens.name on req when the request was
        // bearer-authenticated against a named token (the typical MCP path).
        // We thread it through so mutation broadcasts are labeled with the
        // integration name (e.g. "Christian's Cursor" rather than just the user).
        const apiTokenName = req.apiTokenName;
        const server = new McpServer(MCP_SERVER_INFO, { instructions: MCP_INSTRUCTIONS });
        // Passing wsHub in the context lets create_entity / update_entity
        // broadcast entity_change events so connected web clients refresh
        // their views live when an MCP agent mutates a folder.
        registerTools(server, workspaceManager, authService, { user, wsHub, apiTokenName, commentService });
        const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
        await server.connect(transport);
        // Hijack the response so Fastify doesn't interfere with the MCP transport's writes
        reply.hijack();
        await transport.handleRequest(req.raw, reply.raw, req.body);
        await transport.close();
        await server.close();
    });
    // GET /mcp — SSE endpoint for server-initiated notifications (stateless: returns 405)
    fastify.get('/mcp', async (_req, reply) => {
        return reply.status(405).send({ error: 'SSE not available in stateless mode. Use POST.' });
    });
    // DELETE /mcp — session cleanup (stateless: returns 405)
    fastify.delete('/mcp', async (_req, reply) => {
        return reply.status(405).send({ error: 'No sessions in stateless mode.' });
    });
}
//# sourceMappingURL=mcp.js.map