import { db } from '@sim/db' import { workflowMcpServer, workflowMcpTool } from '@sim/db/schema' import { createLogger } from '@sim/logger' import { toError } from '@sim/utils/errors' import { and, eq, isNull } from 'drizzle-orm' import type { NextRequest } from 'next/server' import { updateWorkflowMcpServerBodySchema, workflowMcpServerParamsSchema, } from '@/lib/api/contracts/workflow-mcp-servers' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' import { mcpBodyReadErrorResponse, readMcpJsonBodyWithLimit, withMcpAuth, } from '@/lib/mcp/middleware' import { performDeleteWorkflowMcpServer, performUpdateWorkflowMcpServer, } from '@/lib/mcp/orchestration' import { createMcpErrorResponse, createMcpSuccessResponse, mcpOrchestrationStatus, } from '@/lib/mcp/utils' const logger = createLogger('WorkflowMcpServerAPI') export const dynamic = 'force-dynamic' interface RouteParams { id: string } /** * GET - Get a specific workflow MCP server with its tools */ export const GET = withRouteHandler( withMcpAuth('read')( async (request: NextRequest, { userId, workspaceId, requestId }, { params }) => { try { const { id: serverId } = workflowMcpServerParamsSchema.parse(await params) logger.info(`[${requestId}] Getting workflow MCP server: ${serverId}`) const [server] = await db .select({ id: workflowMcpServer.id, workspaceId: workflowMcpServer.workspaceId, createdBy: workflowMcpServer.createdBy, name: workflowMcpServer.name, description: workflowMcpServer.description, isPublic: workflowMcpServer.isPublic, createdAt: workflowMcpServer.createdAt, updatedAt: workflowMcpServer.updatedAt, }) .from(workflowMcpServer) .where( and( eq(workflowMcpServer.id, serverId), eq(workflowMcpServer.workspaceId, workspaceId), isNull(workflowMcpServer.deletedAt) ) ) .limit(1) if (!server) { return createMcpErrorResponse(new Error('Server not found'), 'Server not found', 404) } const tools = await db .select() .from(workflowMcpTool) .where(and(eq(workflowMcpTool.serverId, serverId), isNull(workflowMcpTool.archivedAt))) logger.info( `[${requestId}] Found workflow MCP server: ${server.name} with ${tools.length} tools` ) return createMcpSuccessResponse({ server, tools }) } catch (error) { logger.error(`[${requestId}] Error getting workflow MCP server:`, error) return createMcpErrorResponse(toError(error), 'Failed to get workflow MCP server', 500) } } ) ) /** * PATCH - Update a workflow MCP server */ export const PATCH = withRouteHandler( withMcpAuth('write')( async ( request: NextRequest, { userId, userName, userEmail, workspaceId, requestId }, { params } ) => { try { const { id: serverId } = workflowMcpServerParamsSchema.parse(await params) const rawBody = await readMcpJsonBodyWithLimit(request) const parsedBody = updateWorkflowMcpServerBodySchema.safeParse(rawBody) if (!parsedBody.success) { return createMcpErrorResponse(parsedBody.error, 'Invalid request format', 400) } const body = parsedBody.data logger.info(`[${requestId}] Updating workflow MCP server: ${serverId}`) const result = await performUpdateWorkflowMcpServer({ serverId, workspaceId, userId, actorName: userName, actorEmail: userEmail, name: body.name, description: body.description, isPublic: body.isPublic, }) if (!result.success || !result.server) { const status = mcpOrchestrationStatus(result.errorCode) return createMcpErrorResponse( new Error(result.error || 'Failed to update workflow MCP server'), result.error || 'Failed to update workflow MCP server', status ) } const updatedServer = result.server logger.info(`[${requestId}] Successfully updated workflow MCP server: ${serverId}`) return createMcpSuccessResponse({ server: updatedServer }) } catch (error) { const bodyErrorResponse = mcpBodyReadErrorResponse(error, request) if (bodyErrorResponse) return bodyErrorResponse logger.error(`[${requestId}] Error updating workflow MCP server:`, error) return createMcpErrorResponse(toError(error), 'Failed to update workflow MCP server', 500) } } ) ) /** * DELETE - Delete a workflow MCP server and all its tools */ export const DELETE = withRouteHandler( withMcpAuth('write')( async ( request: NextRequest, { userId, userName, userEmail, workspaceId, requestId }, { params } ) => { try { const { id: serverId } = workflowMcpServerParamsSchema.parse(await params) logger.info(`[${requestId}] Deleting workflow MCP server: ${serverId}`) const result = await performDeleteWorkflowMcpServer({ serverId, workspaceId, userId, actorName: userName, actorEmail: userEmail, }) if (!result.success || !result.server) { return createMcpErrorResponse( new Error(result.error || 'Server not found'), result.error || 'Server not found', mcpOrchestrationStatus(result.errorCode) ) } const deletedServer = result.server logger.info(`[${requestId}] Successfully deleted workflow MCP server: ${serverId}`) return createMcpSuccessResponse({ message: `Server ${serverId} deleted successfully` }) } catch (error) { logger.error(`[${requestId}] Error deleting workflow MCP server:`, error) return createMcpErrorResponse(toError(error), 'Failed to delete workflow MCP server', 500) } } ) )