| @@ -1,7 +1,6 @@ |
| 1 | import type { | 1 | import type { |
| 2 | ExecutionEnvelope, | 2 | ExecutionEnvelope, |
| 3 | ExecutionInteraction, | 3 | ControlPlaneRuntime, |
| 4 | SqlControlPlaneRuntime, | | |
| 5 | } from "@executor/control-plane"; | 4 | } from "@executor/control-plane"; |
| 6 | import { | 5 | import { |
| 7 | EXECUTOR_SOURCES_ADD_HELP_LINES, | 6 | EXECUTOR_SOURCES_ADD_HELP_LINES, |
| @@ -18,6 +17,11 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; · 10 unmodified lines |
| 18 | import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js"; | 17 | import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js"; |
| 19 | import { z } from "zod/v4"; | 18 | import { z } from "zod/v4"; |
| 20 | | 19 | |
| | 20 | import { |
| | 21 | buildPausedResultText, |
| | 22 | parseInteractionPayload, |
| | 23 | } from "./paused-result"; |
| | 24 | |
| 21 | const pollingIntervalMs = 200; | 25 | const pollingIntervalMs = 200; |
| 22 | | 26 | |
| 23 | const executeInputSchema = { | 27 | const executeInputSchema = { |
| @@ -34,14 +38,6 @@ const resumeInputSchema = { · 10 unmodified lines |
| 34 | }).optional(), | 38 | }).optional(), |
| 35 | }; | 39 | }; |
| 36 | | 40 | |
| 37 | type ParsedInteractionPayload = { | | |
| 38 | mode: "form" | "url"; | | |
| 39 | message: string; | | |
| 40 | url?: string; | | |
| 41 | requestedSchema?: Record<string, unknown>; | | |
| 42 | elicitationId?: string; | | |
| 43 | }; | | |
| 44 | | | |
| 45 | type ResumePayload = { | 41 | type ResumePayload = { |
| 46 | executionId: string; | 42 | executionId: string; |
| 47 | }; | 43 | }; |
| @@ -62,9 +58,6 @@ export type ExecutorMcpRequestHandler = { · 14 unmodified lines |
| 62 | close: () => Promise<void>; | 58 | close: () => Promise<void>; |
| 63 | }; | 59 | }; |
| 64 | | 60 | |
| 65 | const isRecord = (value: unknown): value is Record<string, unknown> => | | |
| 66 | typeof value === "object" && value !== null && !Array.isArray(value); | | |
| 67 | | | |
| 68 | const parseJsonValue = (value: string | null): unknown => { | 61 | const parseJsonValue = (value: string | null): unknown => { |
| 69 | if (value === null) { | 62 | if (value === null) { |
| 70 | return null; | 63 | return null; |
| @@ -93,48 +86,8 @@ const formatResultPreview = (resultJson: string): string => { · 22 unmodified lines |
| 93 | return truncateText(resultJson, maxResultPreviewChars); | 86 | return truncateText(resultJson, maxResultPreviewChars); |
| 94 | } | 87 | } |
| 95 | }; | 88 | }; |
| 96 | | | |
| 97 | | | |
| 98 | const parseInteractionPayload = ( | | |
| 99 | interaction: ExecutionInteraction, | | |
| 100 | ): ParsedInteractionPayload | null => { | | |
| 101 | try { | | |
| 102 | const parsed = JSON.parse(interaction.payloadJson) as { | | |
| 103 | elicitation?: { | | |
| 104 | mode?: "form" | "url"; | | |
| 105 | message?: string; | | |
| 106 | url?: string; | | |
| 107 | requestedSchema?: Record<string, unknown>; | | |
| 108 | elicitationId?: string; | | |
| 109 | id?: string; | | |
| 110 | }; | | |
| 111 | }; | | |
| 112 | | | |
| 113 | if (!parsed.elicitation || typeof parsed.elicitation.message !== "string") { | | |
| 114 | return null; | | |
| 115 | } | | |
| 116 | | | |
| 117 | return { | | |
| 118 | mode: parsed.elicitation.mode === "url" ? "url" : "form", | | |
| 119 | message: parsed.elicitation.message, | | |
| 120 | url: parsed.elicitation.url, | | |
| 121 | requestedSchema: isRecord(parsed.elicitation.requestedSchema) | | |
| 122 | ? parsed.elicitation.requestedSchema | | |
| 123 | : undefined, | | |
| 124 | elicitationId: | | |
| 125 | typeof parsed.elicitation.elicitationId === "string" | | |
| 126 | ? parsed.elicitation.elicitationId | | |
| 127 | : typeof parsed.elicitation.id === "string" | | |
| 128 | ? parsed.elicitation.id | | |
| 129 | : undefined, | | |
| 130 | }; | | |
| 131 | } catch { | | |
| 132 | return null; | | |
| 133 | } | | |
| 134 | }; | | |
| 135 | | | |
| 136 | const runControlPlane = async <A, E, R>( | 89 | const runControlPlane = async <A, E, R>( |
| 137 | runtime: SqlControlPlaneRuntime, | 90 | runtime: ControlPlaneRuntime, |
| 138 | effect: Effect.Effect<A, E, R>, | 91 | effect: Effect.Effect<A, E, R>, |
| 139 | ): Promise<A> => { | 92 | ): Promise<A> => { |
| 140 | const exit = await Effect.runPromiseExit( | 93 | const exit = await Effect.runPromiseExit( |
| @@ -192,7 +145,7 @@ const buildExecuteWorkflowText = (namespaces: readonly string[] = []): string => · 51 unmodified lines |
| 192 | | 145 | |
| 193 | const defaultExecuteDescription = buildExecuteWorkflowText(); | 146 | const defaultExecuteDescription = buildExecuteWorkflowText(); |
| 194 | | 147 | |
| 195 | const loadExecuteDescription = (runtime: SqlControlPlaneRuntime): Promise<string> => | 148 | const loadExecuteDescription = (runtime: ControlPlaneRuntime): Promise<string> => |
| 196 | runControlPlane( | 149 | runControlPlane( |
| 197 | runtime, | 150 | runtime, |
| 198 | Effect.gen(function* () { | 151 | Effect.gen(function* () { |
| @@ -265,9 +218,7 @@ const buildPausedResult = (envelope: ExecutionEnvelope): ExecutorMcpToolResult = · 66 unmodified lines |
| 265 | return { | 218 | return { |
| 266 | content: [{ | 219 | content: [{ |
| 267 | type: "text", | 220 | type: "text", |
| 268 | text: interaction | 221 | text: buildPausedResultText(envelope), |
| 269 | ? `Execution ${envelope.execution.id} paused: ${parsed?.message ?? "Interaction required."}` | | |
| 270 | : `Execution ${envelope.execution.id} is waiting for interaction.`, | | |
| 271 | }], | 222 | }], |
| 272 | structuredContent: { | 223 | structuredContent: { |
| 273 | executionId: envelope.execution.id, | 224 | executionId: envelope.execution.id, |
| @@ -305,7 +256,7 @@ const buildToolResult = (envelope: ExecutionEnvelope): ExecutorMcpToolResult => · 31 unmodified lines |
| 305 | }; | 256 | }; |
| 306 | | 257 | |
| 307 | const waitForInteractionProgress = async (input: { | 258 | const waitForInteractionProgress = async (input: { |
| 308 | runtime: SqlControlPlaneRuntime; | 259 | runtime: ControlPlaneRuntime; |
| 309 | workspaceId: string; | 260 | workspaceId: string; |
| 310 | executionId: string; | 261 | executionId: string; |
| 311 | pendingInteractionId: string; | 262 | pendingInteractionId: string; |
| @@ -331,7 +282,7 @@ const waitForInteractionProgress = async (input: { · 19 unmodified lines |
| 331 | }; | 282 | }; |
| 332 | | 283 | |
| 333 | const driveExecutionWithElicitation = async (input: { | 284 | const driveExecutionWithElicitation = async (input: { |
| 334 | runtime: SqlControlPlaneRuntime; | 285 | runtime: ControlPlaneRuntime; |
| 335 | workspaceId: string; | 286 | workspaceId: string; |
| 336 | accountId: string; | 287 | accountId: string; |
| 337 | server: McpServer; | 288 | server: McpServer; |
| @@ -408,7 +359,7 @@ const driveExecutionWithElicitation = async (input: { · 70 unmodified lines |
| 408 | }; | 359 | }; |
| 409 | | 360 | |
| 410 | const driveExecutionWithoutElicitation = async (input: { | 361 | const driveExecutionWithoutElicitation = async (input: { |
| 411 | runtime: SqlControlPlaneRuntime; | 362 | runtime: ControlPlaneRuntime; |
| 412 | workspaceId: string; | 363 | workspaceId: string; |
| 413 | accountId: string; | 364 | accountId: string; |
| 414 | executionId: string; | 365 | executionId: string; |
| @@ -447,7 +398,7 @@ const driveExecutionWithoutElicitation = async (input: { · 32 unmodified lines |
| 447 | }; | 398 | }; |
| 448 | | 399 | |
| 449 | const createExecutorMcpServer = async (config: { | 400 | const createExecutorMcpServer = async (config: { |
| 450 | runtime: SqlControlPlaneRuntime; | 401 | runtime: ControlPlaneRuntime; |
| 451 | }): Promise<McpServer> => { | 402 | }): Promise<McpServer> => { |
| 452 | const executeDescription = await loadExecuteDescription(config.runtime); | 403 | const executeDescription = await loadExecuteDescription(config.runtime); |
| 453 | const server = new McpServer( | 404 | const server = new McpServer( |
| @@ -552,7 +503,7 @@ const jsonErrorResponse = (status: number, code: number, message: string) => · 98 unmodified lines |
| 552 | }); | 503 | }); |
| 553 | | 504 | |
| 554 | export const createExecutorMcpRequestHandler = ( | 505 | export const createExecutorMcpRequestHandler = ( |
| 555 | runtime: SqlControlPlaneRuntime, | 506 | runtime: ControlPlaneRuntime, |
| 556 | ): ExecutorMcpRequestHandler => { | 507 | ): ExecutorMcpRequestHandler => { |
| 557 | const transports = new Map<string, WebStandardStreamableHTTPServerTransport>(); | 508 | const transports = new Map<string, WebStandardStreamableHTTPServerTransport>(); |
| 558 | const servers = new Map<string, McpServer>(); | 509 | const servers = new Map<string, McpServer>(); |