Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/v2-forward-passthrough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@executor-js/cloud": patch
---

Executor Cloud forwards MCP requests that use `mode=passthrough` for a workspace that has moved to Executor v2, instead of refusing them. v2 serves its own tools for them.
15 changes: 6 additions & 9 deletions apps/cloud/src/mcp/v2-forward.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
// ---------------------------------------------------------------------------

import { jsonRpcErrorBody, UNAVAILABLE_RETRY_AFTER_SECONDS } from "@executor-js/host-mcp";
import { readElicitationMode, readToolMode } from "@executor-js/cloudflare/mcp/do-headers";
import { readElicitationMode } from "@executor-js/cloudflare/mcp/do-headers";
import { EXECUTOR_ORG_SELECTOR_HEADER } from "@executor-js/sdk/shared";

import type { MovedToV2 } from "./moved-to-v2";
Expand Down Expand Up @@ -105,7 +105,11 @@ export const toolkitConnectionId = async (
return `v1-${hex(digest).slice(0, 40)}`;
};

/** v2's MCP endpoint for a request: only the elicitation mode and toolkit connection carry over. */
/**
* v2's MCP endpoint for a request: only the elicitation mode and toolkit
* connection carry over. v1's tool mode (`mode=passthrough`) does not: v2
* serves its own tools for every request.
*/
export const buildV2Url = (origin: string, request: Request, connection?: string): URL => {
const url = new URL("/mcp", origin);
const mode = readElicitationMode(request);
Expand Down Expand Up @@ -169,9 +173,6 @@ export const relayV2Response = (
});
};

export const PASSTHROUGH_MOVED_MESSAGE =
"This workspace has moved to Executor v2, which has no passthrough mode. Remove mode=passthrough from the MCP URL.";

export const TOOLKIT_NOT_FOUND_MESSAGE = "Toolkit not found";

/** The bindings forwarding needs; absent in workers that do not forward. */
Expand Down Expand Up @@ -217,10 +218,6 @@ export const forwardToV2 = async (
): Promise<Response> => {
const log = deps.log ?? defaultLog;

if (readToolMode(request) === "passthrough") {
return jsonRpcErrorBody(400, -32600, PASSTHROUGH_MOVED_MESSAGE);
}

const { V2_MCP: binding, V2_MCP_ORIGIN: origin, V2_MCP_FORWARD_SECRET: secret } = env;
if (!binding || !origin || !secret) {
log({ event: "mcp_v2_forward_unconfigured", hasBinding: !!binding, hasOrigin: !!origin });
Expand Down
Loading