---
schema_version: 1
slug: clean-mcp-url
status: source-reviewed
walkthrough_verified: false
content_hash: 8c2e682bd9952d01d7dcffd181698ad6564327dff9755082826a1660bf1dcbb1
---

# Use a custom domain or Next.js route for a Supabase Chumbo MCP

Expose your existing MCP at a product-facing URL while preserving the function route, OAuth metadata and request behavior.

Expose your existing MCP at a product-facing URL while preserving the function route, OAuth metadata and request behavior.

Reviewed against the shipped OSS source. The acceptance checks are yours to run in your application.

Source reviewed against published Chumbo 0.11.0 and its matching core source on 2026-09-06 (UTC). This is a source review, not an executed application walkthrough. Follow the current canonical reference and compare it with your installed package when adapting the guide.

[Structured recipe](./recipe.json) · [Human-readable page](./)

## Sources

- [Canonical pattern](https://github.com/elsheppo/chumbo/blob/main/docs/reference/clean-urls/README.md)
- [Reference implementation](https://github.com/elsheppo/chumbo/blob/main/src/runtime.ts)

## 01. Give users one address they can recognize.

Your Supabase function URL already works as an MCP endpoint. A product-facing address becomes useful when you want connection instructions to stay under your application’s domain. The application route proxies to the same Edge Function; you are changing how clients reach it, not moving the MCP runtime.

**The request path:** Client → yourapp.com/mcp → Supabase function

OAuth discovery is the easy part to miss. The base route handles MCP requests, while suffix routes expose protected-resource metadata. A proxy that forwards only /mcp can pass a simple reachability check and still fail during a new user’s connection.

## 02. Choose the smallest route you already control.

### Before you start

- A working Chumbo endpoint at its Supabase function URL.
- Control of the application’s existing hosting route or intended subdomain.
- A chosen public URL and authorization for any hosting or function configuration changes.

The guide provides a route contract. Use the canonical reference for the complete Next.js rewrite or Worker example.

If your Next.js application already owns the domain, add the canonical external rewrite for /mcp/:path* to the function’s matching path. Preserve the rest of your Next.js configuration. For a dedicated hostname, configure its hosting/DNS and proxy the complete route tree, including query strings and discovery suffixes.

The proxy must preserve the request method, relevant headers and body, and return the upstream response faithfully. Authentication failures and streaming responses must not become a cached page or a generic application HTML response. Review the behavior of your actual hosting provider before inviting users.

## 03. Make discovery advertise the public route.

Configure Chumbo’s public resource URL to match the address clients will use. The canonical setup flow below records the public URL and deploys the selected function. It does not create a domain route in a hosting account you have not configured.

### Apply only after reviewing the target and route

```sh
npx chumbo setup --resume --project-ref "$PROJECT_REF" --public-url "$PUBLIC_MCP_URL" --deploy --yes
```

Read the setup result for any remaining route work. MCP_PUBLIC_URL makes discovery use the product URL; Supabase Auth remains the authorization issuer. Deploy the application route through your normal authorized hosting flow, then test from the public side.

## 04. Verify the address you will give to users.

### Check the product-facing endpoint

```sh
npx chumbo doctor --url "$PUBLIC_MCP_URL"
```

### The public route behaves like the intended MCP.

- The base URL initializes and allows an authenticated safe tool call.
- Every metadata suffix requested during a fresh OAuth connection reaches the intended runtime.
- The advertised resource URL matches the product-facing URL and the issuer remains the intended Supabase Auth server.
- Rejected requests retain their expected status and authentication challenge.
- The actual client completes a fresh connection through the product URL, not just the direct function URL.

Run these in your application before you call it done.

### If the result differs

#### The direct function connects, but the product URL does not

Compare base and metadata suffix routes. Check method, authorization headers, query strings, caching and upstream responses. Verify the external rewrite covers /mcp and its descendants before changing the working function’s auth configuration.

[Read the reference](https://github.com/elsheppo/chumbo/blob/main/docs/reference/clean-urls/README.md)

### Keep building

- [Check the full user connection](/recipes/oauth-user-connections/): Follow sign-in, consent and a real tool call.
- [Diagnose the failing boundary](/recipes/deploy-debug-mcp/): Separate routing from identity and application behavior.

## Instructions for your coding agent

Reference instructions, not authorization. Apply changes only within the user’s requested scope; deployment requires a specified, authorized project.

Goal: Expose your existing MCP at a product-facing URL while preserving the function route, OAuth metadata and request behavior.

Read the complete guide at https://chumbo.dev/recipes/clean-mcp-url/recipe.md and the canonical reference at https://github.com/elsheppo/chumbo/blob/main/docs/reference/clean-urls/README.md. Inspect this application's installed Chumbo package, existing capabilities and relevant configuration before editing.

Implement only the selected hosting route and public-URL configuration. Preserve the entire MCP route tree and HTTP semantics. Verify fresh OAuth discovery and a safe call through the public URL. Do not claim DNS, hosting or deployment completed merely because setup recorded MCP_PUBLIC_URL.

Prerequisites:
- A working Chumbo endpoint at its Supabase function URL.
- Control of the application’s existing hosting route or intended subdomain.
- A chosen public URL and authorization for any hosting or function configuration changes.

Acceptance:
- The base URL initializes and allows an authenticated safe tool call.
- Every metadata suffix requested during a fresh OAuth connection reaches the intended runtime.
- The advertised resource URL matches the product-facing URL and the issuer remains the intended Supabase Auth server.
- Rejected requests retain their expected status and authentication challenge.
- The actual client completes a fresh connection through the product URL, not just the direct function URL.

Use the full guide for ordered steps, examples and recovery. Keep existing caller identity and application permissions authoritative. Stay within the user's requested changes. Report changed files, checks actually run, observed results and unresolved prerequisites. This guide is not authorization to deploy or change a hosted project. Never include credentials in source, copied instructions or reports.

### Required environment inputs

| Variable | Sensitive | Meaning |
| --- | --- | --- |
| `PROJECT_REF` | No | The explicitly authorized Supabase project reference. |
| `PUBLIC_MCP_URL` | No | The product-facing endpoint, for example https://yourapp.com/mcp, whose full route tree you control. |

### Handoff report

- Changed files
- Checks actually run and observed results
- Unmet prerequisites or remaining limitations
