185 lines · 6.0 KB · TypeScript
RawDownload
import { HttpApiBuilder } from "effect/unstable/httpapi";import { Context, Effect } from "effect"; import { addGroup, capture } from "@executor-js/api";import type { McpPluginExtension, McpProbeEndpointInput, McpServerInput } from "../sdk/plugin";import { parseMcpIntegrationConfig } from "../sdk/types";import { McpGroup } from "./group"; // ---------------------------------------------------------------------------// Service tag — holds the raw extension shape the executor produces. Handlers// wrap their generator bodies with `capture(...)` from `@executor-js/api`,// which translates `StorageError` to `InternalError` at the edge.// --------------------------------------------------------------------------- export class McpExtensionService extends Context.Service<McpExtensionService, McpPluginExtension>()(  "McpExtensionService",) {} // ---------------------------------------------------------------------------// Composed API// --------------------------------------------------------------------------- const ExecutorApiWithMcp = addGroup(McpGroup); // ---------------------------------------------------------------------------// Convert API payload → McpServerInput// --------------------------------------------------------------------------- const toServerInput = (  payload: { transport?: "remote" | "stdio" } & Record<string, unknown>,): McpServerInput => {  if (payload.transport === "stdio") {    const p = payload as {      transport: "stdio";      name: string;      family?: string;      description?: string;      command: string;      args?: readonly string[];      envVars?: readonly string[];      env?: Record<string, string>;      cwd?: string;      versionNegotiation?: "legacy" | "auto";      appServer?: { server: string; surface?: "sky" | "browser"; modulePath?: string };      slug?: string;    };    return {      transport: "stdio",      name: p.name,      family: p.family,      description: p.description,      command: p.command,      args: p.args ? [...p.args] : undefined,      envVars: p.envVars ? [...p.envVars] : undefined,      env: p.env,      cwd: p.cwd,      versionNegotiation: p.versionNegotiation,      appServer: p.appServer,      slug: p.slug,    };  }   const p = payload as {    transport?: "remote";    name: string;    family?: string;    description?: string;    endpoint: string;    remoteTransport?: "streamable-http" | "sse" | "auto";    queryParams?: Record<string, string>;    headers?: Record<string, string>;    slug?: string;    authenticationTemplate?: McpServerInput extends { authenticationTemplate?: infer T }      ? T      : never;    auth?: McpServerInput extends { auth?: infer A } ? A : never;  };   return {    transport: "remote",    name: p.name,    family: p.family,    description: p.description,    endpoint: p.endpoint,    remoteTransport: p.remoteTransport,    queryParams: p.queryParams,    headers: p.headers,    slug: p.slug,    authenticationTemplate: p.authenticationTemplate,    auth: p.auth,  };}; // ---------------------------------------------------------------------------// Handlers// --------------------------------------------------------------------------- export const McpHandlers = HttpApiBuilder.group(ExecutorApiWithMcp, "mcp", (handlers) =>  handlers    .handle("probeEndpoint", ({ payload }) =>      capture(        Effect.gen(function* () {          const ext = yield* McpExtensionService;          return yield* ext.probeEndpoint(payload as McpProbeEndpointInput);        }),      ),    )    .handle("addServer", ({ payload }) =>      capture(        Effect.gen(function* () {          const ext = yield* McpExtensionService;          return yield* ext.addServer(            toServerInput(payload as Parameters<typeof toServerInput>[0]),          );        }),      ),    )    .handle("removeServer", ({ params: path }) =>      capture(        Effect.gen(function* () {          const ext = yield* McpExtensionService;          yield* ext.removeServer(path.slug);          return { removed: true };        }),      ),    )    .handle("getServer", ({ params: path }) =>      capture(        Effect.gen(function* () {          const ext = yield* McpExtensionService;          const integration = yield* ext.getServer(path.slug);          if (integration === null) return null;          const config = parseMcpIntegrationConfig(integration.config);          if (config === null) return null;          return {            slug: integration.slug,            description: integration.description,            kind: integration.kind,            canRemove: integration.canRemove,            canRefresh: integration.canRefresh,            config,          };        }),      ),    )    .handle("configureServer", ({ params: path, payload }) =>      capture(        Effect.gen(function* () {          const ext = yield* McpExtensionService;          yield* ext.configureServer(path.slug, payload.config);          return { config: payload.config };        }),      ),    )    .handle("configureAuth", ({ params: path, payload }) =>      capture(        Effect.gen(function* () {          const ext = yield* McpExtensionService;          const authenticationTemplate = yield* ext.configureAuth(path.slug, {            authenticationTemplate: payload.authenticationTemplate,            mode: payload.mode ?? "merge",          });          return { authenticationTemplate: [...authenticationTemplate] };        }),      ),    )    .handle("listCodexPlugins", () =>      capture(        Effect.gen(function* () {          const ext = yield* McpExtensionService;          const plugins = yield* ext.listCodexPlugins();          return { plugins: [...plugins] };        }),      ),    )    .handle("getCodexPluginIcon", ({ params }) =>      capture(        Effect.gen(function* () {          const ext = yield* McpExtensionService;          const plugins = yield* ext.listCodexPlugins();          return { icon: plugins.find((plugin) => plugin.id === params.id)?.icon ?? null };        }),      ),    ),);