// Cloud: the raw /mcp wire protocol — CORS preflight, OAuth discovery// metadata, bearer-auth failures, org-scoped routing, and session lifecycle// errors — asserted with hand-rolled JSON-RPC over fetch, exactly the bytes an// MCP transport sends. Every hop is the production topology: real workerd,// real McpSessionDO, and real bearers minted from the authorization server the// product itself advertises (discovery → DCR → authorize → token).//// Ported from apps/cloud/src/mcp-flow.test.ts (workerd-pool SELF.fetch with// test-seam bearers). DO-internal coverage from that file (forced runtime// eviction, idle-alarm firing, alarm scheduling, storage seeding) is clock /// internals dependent and intentionally NOT carried — only black-box// guarantees live here.import { randomBytes, randomUUID } from "node:crypto"; import { expect } from "@effect/vitest";import { Effect } from "effect"; import { scenario } from "../src/scenario";import { Mcp, Target } from "../src/services";import type { Identity } from "../src/target"; const JSON_AND_SSE = "application/json, text/event-stream";const PROTOCOL_VERSION = "2025-03-26";const INITIALIZE_REQUEST = { jsonrpc: "2.0" as const, id: 1, method: "initialize", params: { protocolVersion: PROTOCOL_VERSION, capabilities: {}, clientInfo: { name: "executor-e2e-mcp-protocol", version: "0.0.1" }, },}; const TOOLS_LIST_REQUEST = { jsonrpc: "2.0" as const, id: 2, method: "tools/list", params: {},}; const INITIALIZED_NOTIFICATION = { jsonrpc: "2.0" as const, method: "notifications/initialized",}; type JsonRpcError = { readonly jsonrpc: string; readonly error: { readonly code: number; readonly message: string };}; const emailOf = (identity: Identity): string => identity.credentials?.email ?? identity.label; /** The org the bearer is scoped to, read from the JWT's public claims. */const orgIdOf = (bearer: string): string => { const claims = JSON.parse(Buffer.from(bearer.split(".")[1] ?? "", "base64url").toString()) as { readonly org_id?: string; }; if (!claims.org_id) throw new Error("orgIdOf: bearer carries no org_id claim"); return claims.org_id;}; const mcpPost = ( url: string | URL, init: { readonly bearer?: string; readonly sessionId?: string; readonly body: unknown },): Promise<Response> => fetch(url, { method: "POST", headers: { accept: JSON_AND_SSE, "content-type": "application/json", ...(init.bearer ? { authorization: `Bearer ${init.bearer}` } : {}), ...(init.sessionId ? { "mcp-session-id": init.sessionId } : {}), }, body: JSON.stringify(init.body), }); /** initialize → session id (asserted present) → notifications/initialized. */const openSession = async (mcpUrl: string, bearer: string): Promise<string> => { const initialize = await mcpPost(mcpUrl, { bearer, body: INITIALIZE_REQUEST }); const sessionId = initialize.headers.get("mcp-session-id"); await initialize.text(); if (initialize.status !== 200 || !sessionId) { throw new Error(`openSession: initialize failed (${initialize.status})`); } const initialized = await mcpPost(mcpUrl, { bearer, sessionId, body: INITIALIZED_NOTIFICATION, }); await initialized.text(); if (initialized.status !== 202) { throw new Error(`openSession: notifications/initialized failed (${initialized.status})`); } return sessionId;}; scenario( "MCP protocol · /mcp answers a CORS preflight allowing the headers an MCP client sends", {}, Effect.gen(function* () { const target = yield* Target; const response = yield* Effect.promise(() => fetch(new URL("/mcp", target.baseUrl), { method: "OPTIONS", headers: { origin: "https://claude.ai", "access-control-request-method": "POST", "access-control-request-headers": "authorization, content-type, mcp-session-id", }, }), ); expect(response.status, "the preflight succeeds").toBe(204); const allowedMethods = (response.headers.get("access-control-allow-methods") ?? "") .split(",") .map((method) => method.trim()); expect(allowedMethods, "POST (requests) is allowed").toContain("POST"); expect(allowedMethods, "GET (standalone SSE) is allowed").toContain("GET"); expect(allowedMethods, "DELETE (session termination) is allowed").toContain("DELETE"); const allowedHeaders = response.headers.get("access-control-allow-headers") ?? ""; expect(allowedHeaders, "the bearer header is allowed").toContain("authorization"); expect(allowedHeaders, "the JSON body header is allowed").toContain("content-type"); expect(allowedHeaders, "the session header is allowed").toContain("mcp-session-id"); }),); scenario( "MCP protocol · protected-resource metadata advertises a discoverable authorization server", {}, Effect.gen(function* () { const target = yield* Target; const response = yield* Effect.promise(() => fetch(new URL("/.well-known/oauth-protected-resource/mcp", target.baseUrl), { headers: { origin: "https://claude.ai" }, }), ); expect(response.status, "the discovery document is public").toBe(200); expect( response.headers.get("access-control-allow-origin"), "discovery is readable cross-origin", ).toBe("*"); const body = (yield* Effect.promise(() => response.json())) as { readonly resource: string; readonly authorization_servers: ReadonlyArray<string>; readonly bearer_methods_supported: ReadonlyArray<string>; readonly scopes_supported: ReadonlyArray<string>; }; expect(body, "the metadata names the MCP resource and its auth server").toEqual({ resource: new URL("/mcp", target.baseUrl).toString(), authorization_servers: [expect.any(String)], bearer_methods_supported: ["header"], // offline_access MUST stay advertised: spec-faithful clients request // exactly this list, and it is what earns them a refresh token (the // OpenCode daily re-auth bug). scopes_supported: ["openid", "profile", "email", "offline_access"], }); // The advertised server must itself be discoverable — that is what lets // an MCP client complete OAuth from nothing but the resource URL. const issuer = body.authorization_servers[0] ?? ""; const authServer = (yield* Effect.promise(async () => (await fetch(new URL("/.well-known/oauth-authorization-server", issuer))).json(), )) as Record<string, unknown>; expect( authServer["authorization_endpoint"], "the auth server publishes its authorize endpoint", ).toEqual(expect.any(String)); expect(authServer["token_endpoint"], "the auth server publishes its token endpoint").toEqual( expect.any(String), ); expect(authServer["registration_endpoint"], "dynamic client registration is available").toEqual( expect.any(String), ); }),); scenario( "MCP protocol · org-scoped discovery metadata points at the org-scoped resource", {}, Effect.gen(function* () { const target = yield* Target; const orgId = `org_e2e_${randomBytes(4).toString("hex")}`; const [bare, scoped] = yield* Effect.promise(() => Promise.all([ fetch(new URL("/.well-known/oauth-protected-resource/mcp", target.baseUrl)).then( (r) => r.json() as Promise<{ authorization_servers: ReadonlyArray<string> }>, ), fetch(new URL(`/.well-known/oauth-protected-resource/${orgId}/mcp`, target.baseUrl)), ]), ); expect(scoped.status, "the org-scoped discovery path is served").toBe(200); const body = (yield* Effect.promise(() => scoped.json())) as Record<string, unknown>; expect(body["resource"], "the resource is the org-scoped MCP URL").toBe( new URL(`/${orgId}/mcp`, target.baseUrl).toString(), ); expect( body["authorization_servers"], "the org-scoped variant points at the same auth server", ).toEqual(bare.authorization_servers); }),); scenario( "MCP protocol · a request without a bearer is challenged with the resource metadata", {}, Effect.gen(function* () { const target = yield* Target; const response = yield* Effect.promise(() => mcpPost(target.mcpUrl, { body: INITIALIZE_REQUEST }), ); expect(response.status, "anonymous requests are rejected").toBe(401); const wwwAuth = response.headers.get("www-authenticate") ?? ""; expect(wwwAuth, "the challenge is a Bearer challenge").toContain('Bearer resource_metadata="'); expect(wwwAuth, "the challenge points at the discovery document").toContain( new URL("/.well-known/oauth-protected-resource/mcp", target.baseUrl).toString(), ); expect(wwwAuth, "a missing token carries no error code (per RFC 6750)").not.toContain("error="); expect( response.headers.get("access-control-expose-headers") ?? "", "browsers can read the challenge", ).toContain("WWW-Authenticate"); expect(yield* Effect.promise(() => response.json()), "the body is a JSON-RPC error").toEqual({ jsonrpc: "2.0", error: { code: -32001, message: "Unauthorized" }, id: null, }); }),); scenario( "MCP protocol · a garbage bearer is rejected as an invalid token", {}, Effect.gen(function* () { const target = yield* Target; const response = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer: "bogus.bogus.bogus", body: INITIALIZE_REQUEST }), ); expect(response.status, "an unverifiable token is rejected").toBe(401); const wwwAuth = response.headers.get("www-authenticate") ?? ""; expect(wwwAuth, "the challenge names the invalid_token error").toContain( 'error="invalid_token"', ); expect(wwwAuth, "the challenge still points at the discovery document").toContain( new URL("/.well-known/oauth-protected-resource/mcp", target.baseUrl).toString(), ); expect(yield* Effect.promise(() => response.json()), "the body is a JSON-RPC error").toEqual({ jsonrpc: "2.0", error: { code: -32001, message: "Unauthorized" }, id: null, }); }),); scenario( "MCP protocol · a valid bearer whose user has no organization cannot open a session", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; // A brand-new user straight through OAuth — never visited the web app, // never created or joined an org. const bearer = yield* mcp.mintBearer(`no-org-${randomUUID().slice(0, 8)}@e2e.test`); const response = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer, body: INITIALIZE_REQUEST }), ); expect(response.status, "the org gate fires before any session is created").toBe(403); const body = (yield* Effect.promise(() => response.json())) as JsonRpcError; expect(body.error.code, "the error is the MCP auth error code").toBe(-32001); expect(body.error.message, "the error tells the user what is missing").toMatch( /no organization/i, ); }),); scenario( "MCP protocol · the URL can pin the active org, but membership is enforced", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const identity = yield* target.newIdentity(); const bearer = yield* mcp.mintBearer(emailOf(identity)); const ownOrg = orgIdOf(bearer); const member = yield* Effect.promise(() => mcpPost(new URL(`/${ownOrg}/mcp`, target.baseUrl), { bearer, body: INITIALIZE_REQUEST, }), ); expect(member.status, "the member's own org-scoped URL opens a session").toBe(200); expect( member.headers.get("mcp-session-id"), "the org-scoped session is a real session", ).toBeTruthy(); yield* Effect.promise(() => member.text()); // The slug form — what the install card prints (`/acme/mcp`) — selects // the same org. The slug comes from the account surface. const me = yield* Effect.promise(() => fetch(new URL("/api/account/me", target.baseUrl), { headers: identity.headers }).then( (r) => r.json() as Promise<{ organization: { slug: string } | null }>, ), ); const ownSlug = me.organization?.slug; expect(ownSlug, "the account surface advertises the org's URL slug").toBeTruthy(); const slugged = yield* Effect.promise(() => mcpPost(new URL(`/${ownSlug}/mcp`, target.baseUrl), { bearer, body: INITIALIZE_REQUEST, }), ); expect(slugged.status, "the member's slug-pinned URL opens a session").toBe(200); expect( slugged.headers.get("mcp-session-id"), "the slug-pinned session is a real session", ).toBeTruthy(); yield* Effect.promise(() => slugged.text()); // An unknown slug selects nothing — same rejection as a foreign org id. const unknownSlug = yield* Effect.promise(() => mcpPost(new URL(`/zz-no-such-org-${randomBytes(3).toString("hex")}/mcp`, target.baseUrl), { bearer, body: INITIALIZE_REQUEST, }), ); expect(unknownSlug.status, "an unknown slug authorizes nothing").toBe(403); const foreignOrg = `org_e2e_${randomBytes(4).toString("hex")}`; const foreign = yield* Effect.promise(() => mcpPost(new URL(`/${foreignOrg}/mcp`, target.baseUrl), { bearer, body: INITIALIZE_REQUEST, }), ); expect(foreign.status, "an org the user is no member of is rejected").toBe(403); const body = (yield* Effect.promise(() => foreign.json())) as JsonRpcError; expect(body.error.code, "the rejection is the MCP auth error code").toBe(-32001); expect(body.error.message, "the URL is a selector, not a trust boundary").toMatch( /no organization/i, ); }),); scenario( "MCP protocol · a non-org path segment is not claimed by the MCP route", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const identity = yield* target.newIdentity(); const bearer = yield* mcp.mintBearer(emailOf(identity)); // `/settings/mcp` must fall through to app routing rather than being // swallowed by the MCP filter — only `org_…`-shaped segments are claimed. const response = yield* Effect.promise(() => mcpPost(new URL("/settings/mcp", target.baseUrl), { bearer, body: INITIALIZE_REQUEST, }), ); expect( response.headers.get("mcp-session-id"), "no MCP session is opened on an app route", ).toBeNull(); const body = (yield* Effect.promise(() => response.text())) as string; expect(body, "the response is not a JSON-RPC envelope").not.toContain('"jsonrpc"'); }),); scenario( "MCP protocol · verbs outside the MCP transport are rejected with a JSON-RPC 405", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const identity = yield* target.newIdentity(); const bearer = yield* mcp.mintBearer(emailOf(identity)); const statuses: Array<{ method: string; status: number; body: JsonRpcError }> = []; for (const method of ["PUT", "PATCH"]) { const response = yield* Effect.promise(() => fetch(target.mcpUrl, { method, headers: { accept: JSON_AND_SSE, "content-type": "application/json", authorization: `Bearer ${bearer}`, }, body: JSON.stringify(TOOLS_LIST_REQUEST), }), ); statuses.push({ method, status: response.status, body: (yield* Effect.promise(() => response.json())) as JsonRpcError, }); } expect( statuses.map(({ method, status }) => `${method}:${status}`), "PUT and PATCH never reach the session engine", ).toEqual(["PUT:405", "PATCH:405"]); for (const { body } of statuses) { expect(body.error.code, "the rejection is a JSON-RPC error").toBe(-32001); expect(body.error.message, "the rejection names the problem").toMatch(/method not allowed/i); } }),); scenario( "MCP protocol · initialize opens a session and notifications are accepted with 202", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const identity = yield* target.newIdentity(); const bearer = yield* mcp.mintBearer(emailOf(identity)); const initialize = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer, body: INITIALIZE_REQUEST }), ); expect(initialize.status, "initialize succeeds").toBe(200); const sessionId = initialize.headers.get("mcp-session-id"); expect(sessionId, "the server assigns a session id").toBeTruthy(); expect( initialize.headers.get("access-control-expose-headers") ?? "", "browser clients can read the session id", ).toContain("mcp-session-id"); yield* Effect.promise(() => initialize.text()); const notification = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer, sessionId: sessionId ?? "", body: INITIALIZED_NOTIFICATION, }), ); expect(notification.status, "notifications are accepted, not answered").toBe(202); expect(yield* Effect.promise(() => notification.text()), "the body is empty").toBe(""); }),); scenario( "MCP protocol · a terminated session's id is rejected with a reconnect error", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const identity = yield* target.newIdentity(); const bearer = yield* mcp.mintBearer(emailOf(identity)); const sessionId = yield* Effect.promise(() => openSession(target.mcpUrl, bearer)); const terminate = yield* Effect.promise(() => fetch(target.mcpUrl, { method: "DELETE", headers: { authorization: `Bearer ${bearer}`, "mcp-session-id": sessionId }, }), ); expect(terminate.status, "the client can terminate its session").toBe(200); yield* Effect.promise(() => terminate.text()); const reuse = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer, sessionId, body: TOOLS_LIST_REQUEST }), ); expect(reuse.status, "the dead session id no longer works").toBe(404); const body = (yield* Effect.promise(() => reuse.json())) as JsonRpcError; expect(body.error.code, "the rejection is a JSON-RPC error").toBe(-32001); expect(body.error.message, "the client is told to reconnect").toMatch(/timed out|reconnect/i); }),); scenario( "MCP protocol · a session cannot be ridden by a different account's bearer", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const victim = yield* target.newIdentity(); const attacker = yield* target.newIdentity(); const victimBearer = yield* mcp.mintBearer(emailOf(victim)); const attackerBearer = yield* mcp.mintBearer(emailOf(attacker)); const sessionId = yield* Effect.promise(() => openSession(target.mcpUrl, victimBearer)); // The attacker authenticates fine — but with a leaked session id of a // session that is not theirs. const hijack = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer: attackerBearer, sessionId, body: TOOLS_LIST_REQUEST, }), ); expect(hijack.status, "the leaked session id is useless to another account").toBe(403); const body = (yield* Effect.promise(() => hijack.json())) as JsonRpcError; expect(body.error.code, "the rejection is the session-ownership error").toBe(-32003); expect(body.error.message, "the error names the ownership violation").toMatch( /does not belong/i, ); // The owner is unaffected. const owner = yield* Effect.promise(() =>Lines 1–500 of 612. Load more
// Cloud: the raw /mcp wire protocol — CORS preflight, OAuth discovery // metadata, bearer-auth failures, org-scoped routing, and session lifecycle // errors — asserted with hand-rolled JSON-RPC over fetch, exactly the bytes an // MCP transport sends. Every hop is the production topology: real workerd, // real McpSessionDO, and real bearers minted from the authorization server the // product itself advertises (discovery → DCR → authorize → token). // // Ported from apps/cloud/src/mcp-flow.test.ts (workerd-pool SELF.fetch with // test-seam bearers). DO-internal coverage from that file (forced runtime // eviction, idle-alarm firing, alarm scheduling, storage seeding) is clock / // internals dependent and intentionally NOT carried — only black-box // guarantees live here. import { randomBytes, randomUUID } from "node:crypto"; import { expect } from "@effect/vitest"; import { Effect } from "effect"; import { scenario } from "../src/scenario"; import { Mcp, Target } from "../src/services"; import type { Identity } from "../src/target"; const JSON_AND_SSE = "application/json, text/event-stream"; const PROTOCOL_VERSION = "2025-03-26"; const INITIALIZE_REQUEST = { jsonrpc: "2.0" as const, id: 1, method: "initialize", params: { protocolVersion: PROTOCOL_VERSION, capabilities: {}, clientInfo: { name: "executor-e2e-mcp-protocol", version: "0.0.1" }, }, }; const TOOLS_LIST_REQUEST = { jsonrpc: "2.0" as const, id: 2, method: "tools/list", params: {}, }; const INITIALIZED_NOTIFICATION = { jsonrpc: "2.0" as const, method: "notifications/initialized", }; type JsonRpcError = { readonly jsonrpc: string; readonly error: { readonly code: number; readonly message: string }; }; const emailOf = (identity: Identity): string => identity.credentials?.email ?? identity.label; /** The org the bearer is scoped to, read from the JWT's public claims. */ const orgIdOf = (bearer: string): string => { const claims = JSON.parse(Buffer.from(bearer.split(".")[1] ?? "", "base64url").toString()) as { readonly org_id?: string; }; if (!claims.org_id) throw new Error("orgIdOf: bearer carries no org_id claim"); return claims.org_id; }; const mcpPost = ( url: string | URL, init: { readonly bearer?: string; readonly sessionId?: string; readonly body: unknown }, ): Promise<Response> => fetch(url, { method: "POST", headers: { accept: JSON_AND_SSE, "content-type": "application/json", ...(init.bearer ? { authorization: `Bearer ${init.bearer}` } : {}), ...(init.sessionId ? { "mcp-session-id": init.sessionId } : {}), }, body: JSON.stringify(init.body), }); /** initialize → session id (asserted present) → notifications/initialized. */ const openSession = async (mcpUrl: string, bearer: string): Promise<string> => { const initialize = await mcpPost(mcpUrl, { bearer, body: INITIALIZE_REQUEST }); const sessionId = initialize.headers.get("mcp-session-id"); await initialize.text(); if (initialize.status !== 200 || !sessionId) { throw new Error(`openSession: initialize failed (${initialize.status})`); } const initialized = await mcpPost(mcpUrl, { bearer, sessionId, body: INITIALIZED_NOTIFICATION, }); await initialized.text(); if (initialized.status !== 202) { throw new Error(`openSession: notifications/initialized failed (${initialized.status})`); } return sessionId; }; scenario( "MCP protocol · /mcp answers a CORS preflight allowing the headers an MCP client sends", {}, Effect.gen(function* () { const target = yield* Target; const response = yield* Effect.promise(() => fetch(new URL("/mcp", target.baseUrl), { method: "OPTIONS", headers: { origin: "https://claude.ai", "access-control-request-method": "POST", "access-control-request-headers": "authorization, content-type, mcp-session-id", }, }), ); expect(response.status, "the preflight succeeds").toBe(204); const allowedMethods = (response.headers.get("access-control-allow-methods") ?? "") .split(",") .map((method) => method.trim()); expect(allowedMethods, "POST (requests) is allowed").toContain("POST"); expect(allowedMethods, "GET (standalone SSE) is allowed").toContain("GET"); expect(allowedMethods, "DELETE (session termination) is allowed").toContain("DELETE"); const allowedHeaders = response.headers.get("access-control-allow-headers") ?? ""; expect(allowedHeaders, "the bearer header is allowed").toContain("authorization"); expect(allowedHeaders, "the JSON body header is allowed").toContain("content-type"); expect(allowedHeaders, "the session header is allowed").toContain("mcp-session-id"); }), ); scenario( "MCP protocol · protected-resource metadata advertises a discoverable authorization server", {}, Effect.gen(function* () { const target = yield* Target; const response = yield* Effect.promise(() => fetch(new URL("/.well-known/oauth-protected-resource/mcp", target.baseUrl), { headers: { origin: "https://claude.ai" }, }), ); expect(response.status, "the discovery document is public").toBe(200); expect( response.headers.get("access-control-allow-origin"), "discovery is readable cross-origin", ).toBe("*"); const body = (yield* Effect.promise(() => response.json())) as { readonly resource: string; readonly authorization_servers: ReadonlyArray<string>; readonly bearer_methods_supported: ReadonlyArray<string>; readonly scopes_supported: ReadonlyArray<string>; }; expect(body, "the metadata names the MCP resource and its auth server").toEqual({ resource: new URL("/mcp", target.baseUrl).toString(), authorization_servers: [expect.any(String)], bearer_methods_supported: ["header"], // offline_access MUST stay advertised: spec-faithful clients request // exactly this list, and it is what earns them a refresh token (the // OpenCode daily re-auth bug). scopes_supported: ["openid", "profile", "email", "offline_access"], }); // The advertised server must itself be discoverable — that is what lets // an MCP client complete OAuth from nothing but the resource URL. const issuer = body.authorization_servers[0] ?? ""; const authServer = (yield* Effect.promise(async () => (await fetch(new URL("/.well-known/oauth-authorization-server", issuer))).json(), )) as Record<string, unknown>; expect( authServer["authorization_endpoint"], "the auth server publishes its authorize endpoint", ).toEqual(expect.any(String)); expect(authServer["token_endpoint"], "the auth server publishes its token endpoint").toEqual( expect.any(String), ); expect(authServer["registration_endpoint"], "dynamic client registration is available").toEqual( expect.any(String), ); }), ); scenario( "MCP protocol · org-scoped discovery metadata points at the org-scoped resource", {}, Effect.gen(function* () { const target = yield* Target; const orgId = `org_e2e_${randomBytes(4).toString("hex")}`; const [bare, scoped] = yield* Effect.promise(() => Promise.all([ fetch(new URL("/.well-known/oauth-protected-resource/mcp", target.baseUrl)).then( (r) => r.json() as Promise<{ authorization_servers: ReadonlyArray<string> }>, ), fetch(new URL(`/.well-known/oauth-protected-resource/${orgId}/mcp`, target.baseUrl)), ]), ); expect(scoped.status, "the org-scoped discovery path is served").toBe(200); const body = (yield* Effect.promise(() => scoped.json())) as Record<string, unknown>; expect(body["resource"], "the resource is the org-scoped MCP URL").toBe( new URL(`/${orgId}/mcp`, target.baseUrl).toString(), ); expect( body["authorization_servers"], "the org-scoped variant points at the same auth server", ).toEqual(bare.authorization_servers); }), ); scenario( "MCP protocol · a request without a bearer is challenged with the resource metadata", {}, Effect.gen(function* () { const target = yield* Target; const response = yield* Effect.promise(() => mcpPost(target.mcpUrl, { body: INITIALIZE_REQUEST }), ); expect(response.status, "anonymous requests are rejected").toBe(401); const wwwAuth = response.headers.get("www-authenticate") ?? ""; expect(wwwAuth, "the challenge is a Bearer challenge").toContain('Bearer resource_metadata="'); expect(wwwAuth, "the challenge points at the discovery document").toContain( new URL("/.well-known/oauth-protected-resource/mcp", target.baseUrl).toString(), ); expect(wwwAuth, "a missing token carries no error code (per RFC 6750)").not.toContain("error="); expect( response.headers.get("access-control-expose-headers") ?? "", "browsers can read the challenge", ).toContain("WWW-Authenticate"); expect(yield* Effect.promise(() => response.json()), "the body is a JSON-RPC error").toEqual({ jsonrpc: "2.0", error: { code: -32001, message: "Unauthorized" }, id: null, }); }), ); scenario( "MCP protocol · a garbage bearer is rejected as an invalid token", {}, Effect.gen(function* () { const target = yield* Target; const response = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer: "bogus.bogus.bogus", body: INITIALIZE_REQUEST }), ); expect(response.status, "an unverifiable token is rejected").toBe(401); const wwwAuth = response.headers.get("www-authenticate") ?? ""; expect(wwwAuth, "the challenge names the invalid_token error").toContain( 'error="invalid_token"', ); expect(wwwAuth, "the challenge still points at the discovery document").toContain( new URL("/.well-known/oauth-protected-resource/mcp", target.baseUrl).toString(), ); expect(yield* Effect.promise(() => response.json()), "the body is a JSON-RPC error").toEqual({ jsonrpc: "2.0", error: { code: -32001, message: "Unauthorized" }, id: null, }); }), ); scenario( "MCP protocol · a valid bearer whose user has no organization cannot open a session", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; // A brand-new user straight through OAuth — never visited the web app, // never created or joined an org. const bearer = yield* mcp.mintBearer(`no-org-${randomUUID().slice(0, 8)}@e2e.test`); const response = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer, body: INITIALIZE_REQUEST }), ); expect(response.status, "the org gate fires before any session is created").toBe(403); const body = (yield* Effect.promise(() => response.json())) as JsonRpcError; expect(body.error.code, "the error is the MCP auth error code").toBe(-32001); expect(body.error.message, "the error tells the user what is missing").toMatch( /no organization/i, ); }), ); scenario( "MCP protocol · the URL can pin the active org, but membership is enforced", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const identity = yield* target.newIdentity(); const bearer = yield* mcp.mintBearer(emailOf(identity)); const ownOrg = orgIdOf(bearer); const member = yield* Effect.promise(() => mcpPost(new URL(`/${ownOrg}/mcp`, target.baseUrl), { bearer, body: INITIALIZE_REQUEST, }), ); expect(member.status, "the member's own org-scoped URL opens a session").toBe(200); expect( member.headers.get("mcp-session-id"), "the org-scoped session is a real session", ).toBeTruthy(); yield* Effect.promise(() => member.text()); // The slug form — what the install card prints (`/acme/mcp`) — selects // the same org. The slug comes from the account surface. const me = yield* Effect.promise(() => fetch(new URL("/api/account/me", target.baseUrl), { headers: identity.headers }).then( (r) => r.json() as Promise<{ organization: { slug: string } | null }>, ), ); const ownSlug = me.organization?.slug; expect(ownSlug, "the account surface advertises the org's URL slug").toBeTruthy(); const slugged = yield* Effect.promise(() => mcpPost(new URL(`/${ownSlug}/mcp`, target.baseUrl), { bearer, body: INITIALIZE_REQUEST, }), ); expect(slugged.status, "the member's slug-pinned URL opens a session").toBe(200); expect( slugged.headers.get("mcp-session-id"), "the slug-pinned session is a real session", ).toBeTruthy(); yield* Effect.promise(() => slugged.text()); // An unknown slug selects nothing — same rejection as a foreign org id. const unknownSlug = yield* Effect.promise(() => mcpPost(new URL(`/zz-no-such-org-${randomBytes(3).toString("hex")}/mcp`, target.baseUrl), { bearer, body: INITIALIZE_REQUEST, }), ); expect(unknownSlug.status, "an unknown slug authorizes nothing").toBe(403); const foreignOrg = `org_e2e_${randomBytes(4).toString("hex")}`; const foreign = yield* Effect.promise(() => mcpPost(new URL(`/${foreignOrg}/mcp`, target.baseUrl), { bearer, body: INITIALIZE_REQUEST, }), ); expect(foreign.status, "an org the user is no member of is rejected").toBe(403); const body = (yield* Effect.promise(() => foreign.json())) as JsonRpcError; expect(body.error.code, "the rejection is the MCP auth error code").toBe(-32001); expect(body.error.message, "the URL is a selector, not a trust boundary").toMatch( /no organization/i, ); }), ); scenario( "MCP protocol · a non-org path segment is not claimed by the MCP route", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const identity = yield* target.newIdentity(); const bearer = yield* mcp.mintBearer(emailOf(identity)); // `/settings/mcp` must fall through to app routing rather than being // swallowed by the MCP filter — only `org_…`-shaped segments are claimed. const response = yield* Effect.promise(() => mcpPost(new URL("/settings/mcp", target.baseUrl), { bearer, body: INITIALIZE_REQUEST, }), ); expect( response.headers.get("mcp-session-id"), "no MCP session is opened on an app route", ).toBeNull(); const body = (yield* Effect.promise(() => response.text())) as string; expect(body, "the response is not a JSON-RPC envelope").not.toContain('"jsonrpc"'); }), ); scenario( "MCP protocol · verbs outside the MCP transport are rejected with a JSON-RPC 405", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const identity = yield* target.newIdentity(); const bearer = yield* mcp.mintBearer(emailOf(identity)); const statuses: Array<{ method: string; status: number; body: JsonRpcError }> = []; for (const method of ["PUT", "PATCH"]) { const response = yield* Effect.promise(() => fetch(target.mcpUrl, { method, headers: { accept: JSON_AND_SSE, "content-type": "application/json", authorization: `Bearer ${bearer}`, }, body: JSON.stringify(TOOLS_LIST_REQUEST), }), ); statuses.push({ method, status: response.status, body: (yield* Effect.promise(() => response.json())) as JsonRpcError, }); } expect( statuses.map(({ method, status }) => `${method}:${status}`), "PUT and PATCH never reach the session engine", ).toEqual(["PUT:405", "PATCH:405"]); for (const { body } of statuses) { expect(body.error.code, "the rejection is a JSON-RPC error").toBe(-32001); expect(body.error.message, "the rejection names the problem").toMatch(/method not allowed/i); } }), ); scenario( "MCP protocol · initialize opens a session and notifications are accepted with 202", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const identity = yield* target.newIdentity(); const bearer = yield* mcp.mintBearer(emailOf(identity)); const initialize = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer, body: INITIALIZE_REQUEST }), ); expect(initialize.status, "initialize succeeds").toBe(200); const sessionId = initialize.headers.get("mcp-session-id"); expect(sessionId, "the server assigns a session id").toBeTruthy(); expect( initialize.headers.get("access-control-expose-headers") ?? "", "browser clients can read the session id", ).toContain("mcp-session-id"); yield* Effect.promise(() => initialize.text()); const notification = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer, sessionId: sessionId ?? "", body: INITIALIZED_NOTIFICATION, }), ); expect(notification.status, "notifications are accepted, not answered").toBe(202); expect(yield* Effect.promise(() => notification.text()), "the body is empty").toBe(""); }), ); scenario( "MCP protocol · a terminated session's id is rejected with a reconnect error", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const identity = yield* target.newIdentity(); const bearer = yield* mcp.mintBearer(emailOf(identity)); const sessionId = yield* Effect.promise(() => openSession(target.mcpUrl, bearer)); const terminate = yield* Effect.promise(() => fetch(target.mcpUrl, { method: "DELETE", headers: { authorization: `Bearer ${bearer}`, "mcp-session-id": sessionId }, }), ); expect(terminate.status, "the client can terminate its session").toBe(200); yield* Effect.promise(() => terminate.text()); const reuse = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer, sessionId, body: TOOLS_LIST_REQUEST }), ); expect(reuse.status, "the dead session id no longer works").toBe(404); const body = (yield* Effect.promise(() => reuse.json())) as JsonRpcError; expect(body.error.code, "the rejection is a JSON-RPC error").toBe(-32001); expect(body.error.message, "the client is told to reconnect").toMatch(/timed out|reconnect/i); }), ); scenario( "MCP protocol · a session cannot be ridden by a different account's bearer", {}, Effect.gen(function* () { const target = yield* Target; const mcp = yield* Mcp; const victim = yield* target.newIdentity(); const attacker = yield* target.newIdentity(); const victimBearer = yield* mcp.mintBearer(emailOf(victim)); const attackerBearer = yield* mcp.mintBearer(emailOf(attacker)); const sessionId = yield* Effect.promise(() => openSession(target.mcpUrl, victimBearer)); // The attacker authenticates fine — but with a leaked session id of a // session that is not theirs. const hijack = yield* Effect.promise(() => mcpPost(target.mcpUrl, { bearer: attackerBearer, sessionId, body: TOOLS_LIST_REQUEST, }), ); expect(hijack.status, "the leaked session id is useless to another account").toBe(403); const body = (yield* Effect.promise(() => hijack.json())) as JsonRpcError; expect(body.error.code, "the rejection is the session-ownership error").toBe(-32003); expect(body.error.message, "the error names the ownership violation").toMatch( /does not belong/i, ); // The owner is unaffected. const owner = yield* Effect.promise(() =>