Unified · Split
| @@ -88,22 +88,36 @@ export class McpAuth extends Context.Tag("@executor/cloud/McpAuth")< · 87 unmodified lines | |||
| 88 | 88 | ||
| 89 | export const McpAuthLive = Layer.succeed(McpAuth, { | 89 | export const McpAuthLive = Layer.succeed(McpAuth, { |
| 90 | verifyBearer: (request) => | 90 | verifyBearer: (request) => |
| 91 | Effect.promise(async () => { | 91 | Effect.gen(function* () { |
| 92 | const authHeader = request.headers.get("authorization"); | 92 | const authHeader = request.headers.get("authorization"); |
| 93 | if (!authHeader?.startsWith(BEARER_PREFIX)) return null; | 93 | if (!authHeader?.startsWith(BEARER_PREFIX)) { |
| 94 | yield* Effect.annotateCurrentSpan({ "mcp.auth.outcome": "missing_bearer" }); | ||
| 95 | return null; | ||
| 96 | } | ||
| 94 | try { | 97 | try { |
| 95 | const { payload } = await jwtVerify(authHeader.slice(BEARER_PREFIX.length), jwks, { | 98 | const { payload } = yield* Effect.promise(() => |
| 96 | issuer: AUTHKIT_DOMAIN, | 99 | jwtVerify(authHeader.slice(BEARER_PREFIX.length), jwks, { |
| 97 | }); | 100 | issuer: AUTHKIT_DOMAIN, |
| 98 | if (!payload.sub) return null; | 101 | }), |
| 99 | return { | 102 | ).pipe(Effect.withSpan("mcp.auth.jwt_verify")); |
| 103 | if (!payload.sub) { | ||
| 104 | yield* Effect.annotateCurrentSpan({ "mcp.auth.outcome": "missing_subject" }); | ||
| 105 | return null; | ||
| 106 | } | ||
| 107 | const token = { | ||
| 100 | accountId: payload.sub, | 108 | accountId: payload.sub, |
| 101 | organizationId: (payload.org_id as string | undefined) ?? null, | 109 | organizationId: (payload.org_id as string | undefined) ?? null, |
| 102 | }; | 110 | }; |
| 111 | yield* Effect.annotateCurrentSpan({ | ||
| 112 | "mcp.auth.outcome": "verified", | ||
| 113 | "mcp.auth.has_organization": !!token.organizationId, | ||
| 114 | }); | ||
| 115 | return token; | ||
| 103 | } catch { | 116 | } catch { |
| 117 | yield* Effect.annotateCurrentSpan({ "mcp.auth.outcome": "invalid" }); | ||
| 104 | return null; | 118 | return null; |
| 105 | } | 119 | } |
| 106 | }), | 120 | }).pipe(Effect.withSpan("mcp.auth.verify_bearer")), |
| 107 | }); | 121 | }); |
| 108 | 122 | ||
| 109 | // --------------------------------------------------------------------------- | 123 | // --------------------------------------------------------------------------- |
| @@ -216,7 +230,7 @@ const readJsonRpcEnvelope = (request: Request): Effect.Effect<Option.Option<Json · 106 unmodified lines | |||
| 216 | } catch { | 230 | } catch { |
| 217 | return Option.none(); | 231 | return Option.none(); |
| 218 | } | 232 | } |
| 219 | }); | 233 | }).pipe(Effect.withSpan("mcp.request.read_json_rpc")); |
| 220 | 234 | ||
| 221 | const methodAttrs = (envelope: JsonRpcEnvelope): Record<string, unknown> => { | 235 | const methodAttrs = (envelope: JsonRpcEnvelope): Record<string, unknown> => { |
| 222 | const params = envelope.params ?? {}; | 236 | const params = envelope.params ?? {}; |
| @@ -305,7 +319,14 @@ const annotateMcpRequest = ( · 82 unmodified lines | |||
| 305 | ...baseAttrs, | 319 | ...baseAttrs, |
| 306 | ...rpcAttrs(envelope), | 320 | ...rpcAttrs(envelope), |
| 307 | }); | 321 | }); |
| 308 | }); | 322 | }).pipe( |
| 323 | Effect.withSpan("mcp.request.annotate", { | ||
| 324 | attributes: { | ||
| 325 | "mcp.request.method": request.method, | ||
| 326 | "mcp.request.parse_body": opts.parseBody, | ||
| 327 | }, | ||
| 328 | }), | ||
| 329 | ); | ||
| 309 | 330 | ||
| 310 | // --------------------------------------------------------------------------- | 331 | // --------------------------------------------------------------------------- |
| 311 | // OAuth metadata endpoints | 332 | // OAuth metadata endpoints |
| @@ -507,6 +528,13 @@ const forwardToExistingSession = (request: Request, sessionId: string, peek: boo · 195 unmodified lines | |||
| 507 | const propagated = withPropagationHeaders(request, propagation); | 528 | const propagated = withPropagationHeaders(request, propagation); |
| 508 | const raw = yield* Effect.promise( | 529 | const raw = yield* Effect.promise( |
| 509 | () => stub.handleRequest(propagated) as Promise<Response>, | 530 | () => stub.handleRequest(propagated) as Promise<Response>, |
| 531 | ).pipe( | ||
| 532 | Effect.withSpan("mcp.do.handle_request", { | ||
| 533 | attributes: { | ||
| 534 | "mcp.request.method": request.method, | ||
| 535 | "mcp.request.session_id_present": true, | ||
| 536 | }, | ||
| 537 | }), | ||
| 510 | ); | 538 | ); |
| 511 | const annotated = peek ? yield* peekAndAnnotate(raw) : raw; | 539 | const annotated = peek ? yield* peekAndAnnotate(raw) : raw; |
| 512 | return HttpServerResponse.raw(annotated); | 540 | return HttpServerResponse.raw(annotated); |
| @@ -527,10 +555,21 @@ const dispatchPost = (request: Request, token: VerifiedToken) => · 14 unmodified lines | |||
| 527 | const propagation = yield* currentPropagationHeaders(request); | 555 | const propagation = yield* currentPropagationHeaders(request); |
| 528 | yield* Effect.promise(() => | 556 | yield* Effect.promise(() => |
| 529 | stub.init({ organizationId, userId: token.accountId }, propagation), | 557 | stub.init({ organizationId, userId: token.accountId }, propagation), |
| 558 | ).pipe( | ||
| 559 | Effect.withSpan("mcp.do.init", { | ||
| 560 | attributes: { "mcp.request.session_id_present": false }, | ||
| 561 | }), | ||
| 530 | ); | 562 | ); |
| 531 | const propagated = withPropagationHeaders(request, propagation); | 563 | const propagated = withPropagationHeaders(request, propagation); |
| 532 | const raw = yield* Effect.promise( | 564 | const raw = yield* Effect.promise( |
| 533 | () => stub.handleRequest(propagated) as Promise<Response>, | 565 | () => stub.handleRequest(propagated) as Promise<Response>, |
| 566 | ).pipe( | ||
| 567 | Effect.withSpan("mcp.do.handle_request", { | ||
| 568 | attributes: { | ||
| 569 | "mcp.request.method": request.method, | ||
| 570 | "mcp.request.session_id_present": false, | ||
| 571 | }, | ||
| 572 | }), | ||
| 534 | ); | 573 | ); |
| 535 | const annotated = yield* peekAndAnnotate(raw); | 574 | const annotated = yield* peekAndAnnotate(raw); |
| 536 | return HttpServerResponse.raw(annotated); | 575 | return HttpServerResponse.raw(annotated); |