mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-18 12:18:27 +00:00
143 lines
3.9 KiB
TypeScript
143 lines
3.9 KiB
TypeScript
import { createActionApiRoute } from "~/services/routeBuilders/apiBuilder.server";
|
|
|
|
import { getIntegrationDefinitionWithSlug } from "~/services/integrationDefinition.server";
|
|
import { proxyRequest } from "~/utils/proxy.server";
|
|
import { z } from "zod";
|
|
import { getIntegrationAccount } from "~/services/integrationAccount.server";
|
|
import { createMCPStdioProxy } from "@core/mcp-proxy";
|
|
import { randomUUID } from "node:crypto";
|
|
import { configureStdioMCPEnvironment } from "~/trigger/utils/mcp";
|
|
|
|
export const integrationSlugSchema = z.object({
|
|
slug: z.string(),
|
|
});
|
|
|
|
const { action, loader } = createActionApiRoute(
|
|
{
|
|
params: integrationSlugSchema,
|
|
allowJWT: true,
|
|
authorization: {
|
|
action: "mcp",
|
|
},
|
|
corsStrategy: "all",
|
|
},
|
|
async ({ authentication, request, params }) => {
|
|
try {
|
|
const slug = params.slug;
|
|
|
|
if (!slug) {
|
|
return new Response(
|
|
JSON.stringify({ error: "Integration slug is required" }),
|
|
{
|
|
status: 400,
|
|
headers: { "Content-Type": "application/json" },
|
|
},
|
|
);
|
|
}
|
|
|
|
// Fetch integration definition by slug
|
|
const integrationDefinition =
|
|
await getIntegrationDefinitionWithSlug(slug);
|
|
|
|
if (!integrationDefinition) {
|
|
return new Response(
|
|
JSON.stringify({ error: "Integration not found" }),
|
|
{
|
|
status: 404,
|
|
headers: { "Content-Type": "application/json" },
|
|
},
|
|
);
|
|
}
|
|
|
|
const spec = integrationDefinition.spec as any;
|
|
|
|
if (!spec.mcp) {
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: "MCP auth configuration not found for this integration",
|
|
}),
|
|
{
|
|
status: 400,
|
|
headers: { "Content-Type": "application/json" },
|
|
},
|
|
);
|
|
}
|
|
|
|
const { url, type } = spec.mcp;
|
|
|
|
// Find the integration account for this user and integration
|
|
const integrationAccount = await getIntegrationAccount(
|
|
integrationDefinition.id,
|
|
authentication.userId,
|
|
);
|
|
|
|
if (type === "http") {
|
|
const integrationConfig =
|
|
integrationAccount?.integrationConfiguration as any;
|
|
|
|
if (
|
|
!integrationAccount ||
|
|
!integrationConfig ||
|
|
!integrationConfig.mcp
|
|
) {
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: "No integration account with mcp config",
|
|
}),
|
|
{
|
|
status: 400,
|
|
headers: { "Content-Type": "application/json" },
|
|
},
|
|
);
|
|
}
|
|
|
|
// Proxy the request to the serverUrl
|
|
return await proxyRequest(
|
|
request,
|
|
url,
|
|
integrationConfig.mcp.tokens.access_token,
|
|
);
|
|
} else {
|
|
if (!integrationAccount) {
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: "No integration account found",
|
|
}),
|
|
{
|
|
status: 400,
|
|
headers: { "Content-Type": "application/json" },
|
|
},
|
|
);
|
|
}
|
|
|
|
// Configure environment variables using the utility function
|
|
const { env, args } = configureStdioMCPEnvironment(
|
|
spec,
|
|
integrationAccount,
|
|
);
|
|
|
|
// Get session_id from headers (case-insensitive), or generate a new uuid if not present
|
|
const sessionId =
|
|
request.headers.get("mcp-session-id") ||
|
|
request.headers.get("Mcp-Session-Id") ||
|
|
randomUUID();
|
|
|
|
// Use the saved local file instead of command
|
|
const executablePath = `./integrations/${slug}/main`;
|
|
|
|
return createMCPStdioProxy(request, executablePath, args, {
|
|
env,
|
|
sessionId,
|
|
});
|
|
}
|
|
} catch (error: any) {
|
|
return new Response(JSON.stringify({ error: error.message }), {
|
|
status: 500,
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
}
|
|
},
|
|
);
|
|
|
|
export { action, loader };
|