(request: Request, token: VerifiedToken)
| 133 | * and 403s carry the client fingerprint. |
| 134 | */ |
| 135 | const finishAuthorized = (request: Request, token: VerifiedToken): Effect.Effect<AuthOutcome> => |
| 136 | Effect.gen(function* () { |
| 137 | // OLD `mcpApp` annotated with parseBody = (POST && isAuthorized) BEFORE |
| 138 | // org-authz, so a verified-but-no/revoked-org POST still captured |
| 139 | // mcp.rpc.method/id. The body is read via `request.clone().text()` |
| 140 | // (annotateMcpRequest -> readJsonRpcEnvelope), so it never consumes the |
| 141 | // original stream a downstream dispatch reads — safe on every path, |
| 142 | // including the Forbidden short-circuit. Keep parseBody keyed on POST, |
| 143 | // not on the org outcome, to preserve that telemetry. |
| 144 | const parseBody = request.method === "POST"; |
| 145 | |
| 146 | // URL is the source of truth for the active org when pinned — the org's |
| 147 | // slug (`/acme/mcp`, what the install card prints) or a legacy org id |
| 148 | // (`/org_xxx/mcp`), carried in the header by `prepareMcpOrgScope`; the |
| 149 | // bare `/mcp` falls back to the token's `org_id`. Either way |
| 150 | // `orgAuth.authorize` resolves the selector and re-checks live WorkOS |
| 151 | // membership below, so the URL is a selector, not a trust boundary. |
| 152 | const organizationSelector = mcpOrganizationFromRequest(request) ?? token.organizationId; |
| 153 | if (!organizationSelector) { |
| 154 | yield* annotateMcpRequest(request, { token, parseBody }); |
| 155 | return forbidden(NO_ORGANIZATION_MESSAGE, -32001); |
| 156 | } |
| 157 | |
| 158 | const organizationId = yield* orgAuth.authorize(token.accountId, organizationSelector).pipe( |
| 159 | Effect.catchCause((error) => |
| 160 | Effect.gen(function* () { |
| 161 | yield* Effect.annotateCurrentSpan({ |
| 162 | "mcp.auth.organization_authorize_error": Cause.pretty(error), |
| 163 | }); |
| 164 | return null; |
| 165 | }), |
| 166 | ), |
| 167 | Effect.withSpan("mcp.auth.authorize_organization", { |
| 168 | attributes: { "mcp.auth.organization_selector": organizationSelector }, |
| 169 | }), |
| 170 | ); |
| 171 | |
| 172 | yield* annotateMcpRequest(request, { token, parseBody }); |
| 173 | |
| 174 | if (!organizationId) return forbidden(NO_ORGANIZATION_MESSAGE, -32001); |
| 175 | return authenticated(principalFromToken(token, organizationId)); |
| 176 | }); |
| 177 | |
| 178 | const toOutcome = (request: Request, result: McpAuthResult): Effect.Effect<AuthOutcome> => { |
| 179 | if (Predicate.isTagged(result, "Authorized")) { |
no test coverage detected