import { type LoaderFunctionArgs } from "@remix-run/node"; import { getIntegrationDefinitionWithId } from "~/services/integrationDefinition.server"; import { runIntegrationTrigger } from "~/services/integration.server"; import { IntegrationEventType } from "@core/types"; import { createMCPAuthClient } from "@core/mcp-proxy"; import { logger } from "~/services/logger.service"; import { env } from "~/env.server"; import { getIntegrationDefinitionForState } from "~/services/oauth/oauth.server"; import { getIntegrationAccount, getIntegrationAccountForId, } from "~/services/integrationAccount.server"; const CALLBACK_URL = `${env.APP_ORIGIN}/api/v1/oauth/callback`; const MCP_CALLBACK_URL = `${CALLBACK_URL}/mcp`; export async function loader({ request }: LoaderFunctionArgs) { const url = new URL(request.url); const authorizationCode = url.searchParams.get("code"); const state = url.searchParams.get("state"); if (!authorizationCode || !state) { return new Response(null, { status: 302, headers: { Location: `${env.APP_ORIGIN}/integrations?success=false&error=${encodeURIComponent( "Missing authorization code or state", )}`, }, }); } const { integrationDefinitionId, redirectURL, userId, workspaceId, integrationAccountId, } = await getIntegrationDefinitionForState(state); try { // For now, we'll assume Linear integration - in the future this should be derived from state const integrationDefinition = await getIntegrationDefinitionWithId( integrationDefinitionId, ); const integrationAccount = await getIntegrationAccountForId(integrationAccountId); if (!integrationDefinition) { throw new Error("Integration definition not found"); } const spec = integrationDefinition.spec as any; if (!spec.mcp) { throw new Error("MCP auth configuration not found for this integration"); } const { transportStrategy, url } = spec.mcp; const authClient = createMCPAuthClient({ serverUrl: url, transportStrategy: transportStrategy || "sse-first", redirectUrl: MCP_CALLBACK_URL, }); const result = await authClient.completeOAuthFlow({ authorizationCode, state, scope: "read write", }); // Run integration trigger with MCP OAuth response await runIntegrationTrigger( integrationDefinition, { event: IntegrationEventType.SETUP, eventBody: { oauthResponse: result, oauthParams: { code: authorizationCode, state, redirect_uri: MCP_CALLBACK_URL, }, mcp: true, }, }, // We need to get userId from somewhere - for now using undefined userId, workspaceId, integrationAccount ?? undefined, ); return new Response(null, { status: 302, headers: { Location: `${redirectURL}?success=true&integrationName=${encodeURIComponent( integrationDefinition.name, )}`, }, }); } catch (error: any) { logger.error("MCP OAuth callback error:", error); return new Response(null, { status: 302, headers: { Location: `${redirectURL}?success=false&error=${encodeURIComponent( error.message || "OAuth callback failed", )}`, }, }); } }