(betterAuth: BetterAuthHandle)
| 48 | // aside from scrubbing any client-supplied value of that header so it can't be |
| 49 | // spoofed into an unrewritten request. |
| 50 | const selfHostHttpMiddleware = (betterAuth: BetterAuthHandle) => |
| 51 | HttpMiddleware.make((httpApp) => |
| 52 | Effect.gen(function* () { |
| 53 | const request = yield* HttpServerRequest.HttpServerRequest; |
| 54 | const url = new URL(request.url, "http://host.internal"); |
| 55 | if ( |
| 56 | url.pathname === OAUTH_CALLBACK_PATH && |
| 57 | (request.method === "GET" || request.method === "HEAD") |
| 58 | ) { |
| 59 | const headers = new Headers(request.headers as Record<string, string>); |
| 60 | const webRequest = new Request(url, { method: request.method, headers }); |
| 61 | const location = yield* Effect.promise(() => |
| 62 | oauthCallbackSignInRedirectLocation(webRequest, betterAuth.auth), |
| 63 | ); |
| 64 | if (location) return HttpServerResponse.redirect(location, { status: 302 }); |
| 65 | } |
| 66 | |
| 67 | const rewritten = stripMcpOrgSegment(url.pathname); |
| 68 | if (rewritten === null) { |
| 69 | // Never let a client dictate the org-scoped echo below by smuggling |
| 70 | // this header in directly — it's only ever trustworthy when WE set it |
| 71 | // a few lines down, for a request we ourselves just rewrote. |
| 72 | if (!EffectHeaders.has(request.headers, MCP_ORIGINAL_PATH_HEADER)) return yield* httpApp; |
| 73 | return yield* httpApp.pipe( |
| 74 | Effect.provideService( |
| 75 | HttpServerRequest.HttpServerRequest, |
| 76 | request.modify({ |
| 77 | headers: EffectHeaders.remove(request.headers, MCP_ORIGINAL_PATH_HEADER), |
| 78 | }), |
| 79 | ), |
| 80 | ); |
| 81 | } |
| 82 | return yield* httpApp.pipe( |
| 83 | Effect.provideService( |
| 84 | HttpServerRequest.HttpServerRequest, |
| 85 | request.modify({ |
| 86 | url: `${rewritten}${url.search}`, |
| 87 | headers: EffectHeaders.set(request.headers, MCP_ORIGINAL_PATH_HEADER, url.pathname), |
| 88 | }), |
| 89 | ), |
| 90 | ); |
| 91 | }), |
| 92 | ); |
| 93 | |
| 94 | export const startServer = async (): Promise<void> => { |
| 95 | const config = loadConfig(); |
no test coverage detected