Skip to content

Prefer request origin for MCP OAuth resource metadata - #657

Merged
kentcdodds merged 2 commits into
mainfrom
fix/mcp-app-base-url-request-origin
Jul 7, 2026
Merged

kentcdodds merged 2 commits into
mainfrom
fix/mcp-app-base-url-request-origin

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 7, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Prefer the inbound request origin in getAppBaseUrl so MCP protected-resource metadata matches the host clients connect to; APP_BASE_URL / https://heykody.dev remain the fallback for background work.
  • Fix OAuth authorize SSR: renderAppPage now configures COOKIE_SECRET before reading session cookies so /oauth/authorize no longer 500s when the browser sends any Cookie header (this was blocking Cursor reconnect after the account move).
  • Ops already set GitHub APP_BASE_URL=https://heykody.dev and redeployed; leftover KCD cleanup tracked in Clean up leftover Kody resources on the old KCD Cloudflare account #656.

Test plan

  • Unit tests for getAppBaseUrl and MCP auth metadata
  • Unit test: renderAppPage succeeds with a Cookie header when session secret was not preconfigured
  • Preview verify: /oauth/authorize returns 200 with and without Cookie headers
  • Reconnect Kody MCP in Cursor after production deploy of this PR

Preview

https://kody-pr-657.kody-a99.workers.dev

System recap — extends existing primitives (medium risk)

Mode: recap · Base: main @ 158aac1d · Head: 2d0b6cf1

Classification: extends — changes public origin resolution for MCP OAuth and fixes authorize SSR cookie init; no new primitives.

Primitives touched

Primitive Group Impact
mcp-oauth auth extends — request-origin metadata + authorize page no longer 500s on Cookie headers
app-ui surfaces extends — renderAppPage initializes session secret for non-appHandler SSR entries
mcp-server surfaces composes — generated UI / MCP URL derivation follows getAppBaseUrl
workflows / email assistant composes — background base URL uses env/default without fake request hosts

System map

flowchart LR
  client[MCP client / Cursor] -->|GET /oauth/authorize + Cookie| render[renderAppPage]
  render --> secret[setAuthSessionSecret]
  secret --> session[loadSessionInfo]
  session --> spa[Authorize SPA]
  client2[MCP client] -->|connect /mcp| worker[Worker fetch]
  worker --> prm[protected resource metadata]
  prm --> gab[getAppBaseUrl]
  gab -->|request URL| reqOrigin[Request origin]
  gab -->|no request| appBase[APP_BASE_URL / heykody.dev]
Loading

Review focus

APP_BASE_URL remains the fallback for background work so email/workflows keep a stable public host after account moves without breaking clients that connect via heykody.dev.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 7, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates base URL resolution to prefer inbound request origins, adjusts callers and tests to use that behavior, initializes SSR auth session secrets before cookie reads, and revises documentation for APP_BASE_URL fallback semantics.

Changes

Request-origin-based base URL and SSR auth session initialization

Layer / File(s) Summary
getAppBaseUrl contract and fallback logic
packages/worker/src/app/app-base-url.ts, packages/worker/src/app/app-base-url.node.test.ts
getAppBaseUrl now accepts an optional requestUrl, resolves origin from it first with guarded parsing, falls back to trimmed/parsed APP_BASE_URL, then to https://heykody.dev; tests cover the fallback branches.
Call site updates to use request-derived origin
packages/worker/src/email/package-subscriptions.ts, packages/worker/src/execute-maintenance.ts, packages/worker/src/package-runtime/package-workflows.ts
Email dispatch, maintenance smoke checks, and package workflow callers now rely on getAppBaseUrl({ env }) instead of passing explicit request URLs or reading APP_BASE_URL directly.
SSR auth session initialization
packages/worker/src/app/auth-session.ts, packages/worker/src/app/ssr-render.tsx, packages/worker/src/app/ssr-render.node.test.ts
Adds a reset helper for auth session state and initializes the SSR session secret before loading cookies; the SSR test covers rendering with a stale session cookie.
MCP auth and widget test updates
packages/worker/src/mcp-auth.workers.test.ts, packages/worker/src/mcp/generated-ui-app-base-url.node.test.ts
Tests now assert protected-resource metadata, auth challenges, and generated widget URLs derive origin from the inbound request URL rather than a canonical APP_BASE_URL.
Documentation clarifications
docs/contributing/architecture/request-lifecycle.md, docs/contributing/setup-manifest.md
Documents APP_BASE_URL as a fallback public origin used only when no request URL is available, with request-scoped app/MCP/OAuth URLs using the inbound request origin.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • kentcdodds/kody#43: Both PRs center on getAppBaseUrl and MCP/auth-related origin selection.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: using the request origin for MCP OAuth resource metadata.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mcp-app-base-url-request-origin

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/worker/src/app/app-base-url.node.test.ts (1)

4-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for malformed-URL fallback branches and URL input.

The new try/catch fallback paths (invalid requestUrl string, invalid APP_BASE_URL string) and the URL-instance branch of the requestUrl type aren't exercised by any test here.

✅ Suggested additional cases
+test('getAppBaseUrl falls through on malformed requestUrl/APP_BASE_URL', () => {
+	expect(
+		getAppBaseUrl({
+			env: { APP_BASE_URL: 'https://configured.example' },
+			requestUrl: 'not-a-valid-url',
+		}),
+	).toBe('https://configured.example')
+
+	expect(
+		getAppBaseUrl({
+			env: { APP_BASE_URL: 'not-a-valid-url' },
+		}),
+	).toBe('https://heykody.dev')
+
+	expect(
+		getAppBaseUrl({
+			env: {},
+			requestUrl: new URL('https://kody-production.kody-a99.workers.dev/mcp'),
+		}),
+	).toBe('https://kody-production.kody-a99.workers.dev')
+})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/app-base-url.node.test.ts` around lines 4 - 39, Add
tests for the uncovered fallback branches in getAppBaseUrl: exercise an invalid
requestUrl string so the request-origin parsing path falls back cleanly, and an
invalid APP_BASE_URL string so the env fallback path returns the default
heykody.dev value. Also add a case where requestUrl is passed as a URL instance
to verify the URL-specific branch behaves the same as a string input. Use the
existing getAppBaseUrl test file and keep the assertions focused on the returned
base URL.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/worker/src/app/app-base-url.node.test.ts`:
- Around line 4-39: Add tests for the uncovered fallback branches in
getAppBaseUrl: exercise an invalid requestUrl string so the request-origin
parsing path falls back cleanly, and an invalid APP_BASE_URL string so the env
fallback path returns the default heykody.dev value. Also add a case where
requestUrl is passed as a URL instance to verify the URL-specific branch behaves
the same as a string input. Use the existing getAppBaseUrl test file and keep
the assertions focused on the returned base URL.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ac4ee88d-7dc6-4f0c-80f3-f5ad8e243304

📥 Commits

Reviewing files that changed from the base of the PR and between 158aac1 and 9e8124f.

📒 Files selected for processing (9)
  • docs/contributing/architecture/request-lifecycle.md
  • docs/contributing/setup-manifest.md
  • packages/worker/src/app/app-base-url.node.test.ts
  • packages/worker/src/app/app-base-url.ts
  • packages/worker/src/email/package-subscriptions.ts
  • packages/worker/src/execute-maintenance.ts
  • packages/worker/src/mcp-auth.workers.test.ts
  • packages/worker/src/mcp/generated-ui-app-base-url.node.test.ts
  • packages/worker/src/package-runtime/package-workflows.ts
💤 Files with no reviewable changes (2)
  • packages/worker/src/email/package-subscriptions.ts
  • packages/worker/src/package-runtime/package-workflows.ts

@github-actions

github-actions Bot commented Jul 7, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-657.kody-a99.workers.dev

Worker: kody-pr-657
D1: kody-pr-657-db
KV: kody-pr-657-oauth-kv

Mocks:

renderAppPage now configures COOKIE_SECRET before reading session cookies so /oauth/authorize no longer 500s for Cursor (and other MCP clients) that retain cookies from prior visits.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kentcdodds
kentcdodds merged commit fd1a667 into main Jul 7, 2026
5 checks passed
@kentcdodds
kentcdodds deleted the fix/mcp-app-base-url-request-origin branch July 7, 2026 21:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant