(executionStack: McpExecutionStackLayer, hostOptions?: McpBuildHostOptions)
| 42 | */ |
| 43 | export const makeMcpBuildServer = |
| 44 | (executionStack: McpExecutionStackLayer, hostOptions?: McpBuildHostOptions): McpBuildServer => |
| 45 | (principal: Principal, options?: McpBuildServerOptions) => |
| 46 | Effect.gen(function* () { |
| 47 | const { engine, executor } = yield* makeExecutionStack( |
| 48 | principal.accountId, |
| 49 | principal.organizationId, |
| 50 | principal.organizationName, |
| 51 | { mcpResource: options?.resource }, |
| 52 | ).pipe(Effect.withSpan("mcp.execution_stack.build")); |
| 53 | // Read inside the provided boundary: `webBaseUrl` is a host seam, and |
| 54 | // hosts that can't know their public URL at boot leave it unset — in |
| 55 | // which case artifacts still persist but carry no deep link. |
| 56 | const hostConfig = yield* HostConfig; |
| 57 | return { engine, executor, webBaseUrl: hostConfig.webBaseUrl }; |
| 58 | }).pipe( |
| 59 | // Pin browser-handoff URLs to the principal's org slug when present; |
| 60 | // absent slug leaves the service unprovided and the URL stays bare. |
| 61 | principal.organizationSlug !== undefined |
| 62 | ? Effect.provideService(RequestOrgSlug, { slug: principal.organizationSlug }) |
| 63 | : (effect) => effect, |
| 64 | Effect.provide(executionStack), |
| 65 | Effect.mapError((cause) => new McpEngineBuildError({ cause })), |
| 66 | Effect.flatMap(({ engine, executor, webBaseUrl }) => |
| 67 | createExecutorMcpServer({ |
| 68 | engine, |
| 69 | artifacts: executor.artifacts, |
| 70 | connections: executor.connections, |
| 71 | ...(hostOptions?.loadAppShellHtml |
| 72 | ? { loadAppShellHtml: hostOptions.loadAppShellHtml } |
| 73 | : {}), |
| 74 | ...(hostOptions?.smokeRenderArtifact |
| 75 | ? { smokeRenderArtifact: hostOptions.smokeRenderArtifact } |
| 76 | : {}), |
| 77 | ...(hostOptions?.onArtifactUsage ? { onArtifactUsage: hostOptions.onArtifactUsage } : {}), |
| 78 | // Same org pinning as `RequestOrgSlug` above: self-host serves its |
| 79 | // console under `/<org-slug>` (`default` when unconfigured), so the |
| 80 | // deep link carries the principal's slug rather than relying on the |
| 81 | // browser's active org to canonicalize a bare path after landing. |
| 82 | ...(webBaseUrl |
| 83 | ? { artifactUrl: artifactUrlFor(webBaseUrl, principal.organizationSlug) } |
| 84 | : {}), |
| 85 | ...(options ?? {}), |
| 86 | }).pipe( |
| 87 | Effect.withSpan("mcp.server.create"), |
| 88 | Effect.map((mcpServer) => ({ mcpServer, engine })), |
| 89 | ), |
| 90 | ), |
| 91 | ); |
| 92 | |
| 93 | /** Per-host (not per-session) MCP wiring. Kept separate from |
| 94 | * `McpBuildServerOptions`, which the session store fills in per request. */ |
no test coverage detected