// MCP surface: the vendored mcporter fork as a programmatic MCP client, with // headless OAuth via the target's consent strategy. Session methods are // Effects; mcporter itself is promise-native underneath. Assertions are // vitest's job. import { createHash, randomBytes, randomUUID } from "node:crypto"; import { mkdtempSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Effect } from "effect"; import { createRuntime, type Runtime } from "@executor-js/mcporter"; import type { Identity, Target } from "../target"; export interface McpCallResult { readonly raw: unknown; readonly text: string; readonly ok: boolean; } export interface McpSession { readonly listTools: () => Effect.Effect>; readonly call: (name: string, args?: Record) => Effect.Effect; /** Find the paused executionId in `text` and resume it with approval. */ readonly approvePaused: ( text: string, content?: Record, ) => Effect.Effect; } export interface McpSurface { readonly session: (identity: Identity) => McpSession; /** * Mint a real MCP bearer headlessly: protected-resource discovery → * authorization-server discovery → dynamic client registration → authorize * with PKCE (consent via the target's strategy) → code exchange. Plumbing * for raw-wire scenarios that drive /mcp without an MCP client library — * client *behavior* (scope choices, refresh, token storage) is never * modeled here; that's what driving the real client binaries is for. */ readonly mintBearer: (email: string) => Effect.Effect; } const textOf = (result: unknown): string => { const content = (result as { content?: Array<{ type: string; text?: string }> })?.content; if (Array.isArray(content)) { return content .filter((part) => part.type === "text") .map((part) => part.text) .join("\n"); } return typeof result === "string" ? result : JSON.stringify(result); }; interface TokenResponse { readonly access_token?: string; } const mintBearerFlow = async (target: Target, email: string): Promise => { const consent = target.mcpConsent?.({ label: email, credentials: { email, password: "" }, }); if (!consent) throw new Error(`target ${target.name} has no mcpConsent strategy`); const mcpPath = new URL(target.mcpUrl).pathname; const resource = (await ( await fetch(new URL(`/.well-known/oauth-protected-resource${mcpPath}`, target.baseUrl)) ).json()) as { authorization_servers?: ReadonlyArray }; const issuer = resource.authorization_servers?.[0]; if (!issuer) throw new Error("mintBearer: no authorization server advertised"); const metadata = (await ( await fetch(new URL("/.well-known/oauth-authorization-server", issuer)) ).json()) as { readonly authorization_endpoint: string; readonly token_endpoint: string; readonly registration_endpoint: string; }; const redirectUri = "http://127.0.0.1:9/callback"; const registered = (await ( await fetch(metadata.registration_endpoint, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ client_name: "executor-e2e", redirect_uris: [redirectUri], grant_types: ["authorization_code", "refresh_token"], response_types: ["code"], token_endpoint_auth_method: "none", }), }) ).json()) as { readonly client_id: string }; const verifier = randomBytes(32).toString("base64url"); const authorizeUrl = new URL(metadata.authorization_endpoint); authorizeUrl.searchParams.set("client_id", registered.client_id); authorizeUrl.searchParams.set("redirect_uri", redirectUri); authorizeUrl.searchParams.set("response_type", "code"); authorizeUrl.searchParams.set("state", randomUUID()); authorizeUrl.searchParams.set( "code_challenge", createHash("sha256").update(verifier).digest("base64url"), ); authorizeUrl.searchParams.set("code_challenge_method", "S256"); const { code } = await consent({ authorizationUrl: authorizeUrl.toString() }); const token = (await ( await fetch(metadata.token_endpoint, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "authorization_code", code, redirect_uri: redirectUri, client_id: registered.client_id, code_verifier: verifier, }), }) ).json()) as TokenResponse; if (!token.access_token) throw new Error("mintBearer: token exchange returned no token"); return token.access_token; }; export const makeMcpSurface = (target: Target): McpSurface => ({ mintBearer: (email) => Effect.promise(() => mintBearerFlow(target, email)), session: (identity) => { const serverName = target.name; let runtimePromise: Promise | undefined; let connected = false; const consent = target.mcpConsent?.(identity); const callOptions = { autoAuthorize: true, oauthSessionOptions: consent ? { consentStrategy: consent } : {}, }; const runtime = () => { if (!runtimePromise) { const dir = mkdtempSync(join(tmpdir(), "executor-e2e-mcp-")); writeFileSync( join(dir, "mcporter.json"), JSON.stringify({ mcpServers: { [serverName]: { url: target.mcpUrl } }, }), ); runtimePromise = createRuntime({ configPath: join(dir, "mcporter.json"), }); } return runtimePromise; }; const listTools = () => Effect.promise(async () => { const defs = await (await runtime()).listTools(serverName, callOptions); connected = true; return defs.map((tool: { name: string }) => tool.name); }); const call = (name: string, args: Record = {}) => Effect.promise(async (): Promise => { if (!connected) { await (await runtime()).listTools(serverName, callOptions); connected = true; } const raw = await (await runtime()).callTool(serverName, name, { args, ...callOptions }); const isError = Boolean((raw as { isError?: boolean })?.isError); return { raw, text: textOf(raw), ok: !isError }; }); return { listTools, call, approvePaused: (text, content = {}) => Effect.suspend(() => { const match = /\bexecutionId:\s*(\S+)/.exec(text); if (!match) return Effect.die(new Error("approvePaused: executionId not found in text")); return call("resume", { executionId: match[1], action: "accept", content: JSON.stringify(content), }); }), }; }, });