MULTIPLE MCPS

Serve several MCPs. Deploy one Edge Function.

Resolve a named MCP from the request path, give each surface its own instructions and capabilities, and keep one deployable Supabase Edge Function.

Build this with Chumbo
ChumboSupabaseMultiple MCPs
ONE DEPLOYMENT. DISTINCT MCP SURFACES.
  1. 01One Edge Function
  2. 02Resolve the path slug
  3. 03Register one MCP
  4. 04Serve that surface
The URL chooses the server. The chosen server still authenticates every request.

THE RECIPE Resolve a named MCP from the request path, give each surface its own instructions and capabilities, and keep one deployable Supabase Edge Function.

View source pattern ↗
SOURCE REVIEW

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

Version and verification details

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.

01

Give each product surface a stable address.

Before you start
  • Name the surfaces by user purpose, such as directory and invoices, rather than by a temporary database table.
  • Decide whether the server definition is public configuration or protected application data before choosing how the function reads it.
  • Keep the ordinary one-MCP setup unless separate server identities or capability catalogs solve a real user-facing problem.

This pattern changes routing and registration. It does not create a new identity system or grant access to a downstream data plane.

A single Supabase Edge Function can expose /many-mcps/directory and /many-mcps/invoices as separate MCP servers. For each request, the function extracts one slug, loads that server's definition, creates the Chumbo app with the exact surface URL, and registers only that surface's tools. The canonical pattern shows the complete boundary.

Request reaches one Edge FunctionPath yields one bounded slugApplication loads one known definitionChumbo serves only that MCP surface
02

Keep definitions declarative and behavior authored.

The living reference stores server instructions, tool metadata, and fixed demonstration responses in Supabase. A production app can store similarly bounded definitions, but arbitrary rows should never become executable code. Keep handlers in reviewed source and use rows only to select known behavior or validated content. Read the reference implementation before adapting it.

The reference's public, rate-limited data fits its demonstration. For protected data, choose an auth mode for each resolved app and make downstream queries through the authority your design requires. A shared service credential does not establish end-user RLS isolation.

Choose what the path is allowed to changeIllustrative data

Rows configure reviewed handlers

Starting point
Slug selects a known server definition
  • Validated data supplies names and instructions
  • Tool names map to application-owned handlers
  • Authorization stays in source
What to do
Register only the selected handlers

This keeps deploy frequency low without making stored data executable.

Rows provide fixed structured responses

Starting point
Slug selects demonstration tool rows
  • Useful for public fixtures
  • Responses are validated
  • No user data plane is implied
What to do
Return the validated configured response

Do not generalize this fixture into arbitrary query or code execution.

Both cases use one function. They differ in how much application behavior comes from data.

03

Make routing failures useful and contained.

Parse the URL, decode exactly one slug after the function name, and reject a missing or unknown value before MCP handling. Build resourceUrl from the public base URL plus that same slug. OAuth metadata and discovery depend on the server knowing its real client-facing address.

Return a useful 404 without listing private surface names.

04

Compare discovery before you test execution.

Run each path as a fresh MCP endpoint. Compare initialize and tools/list, then call one allowed tool on each surface. For protected surfaces, exercise separate authorized and denied identities.

Run the routed function locally
Terminal
npx chumbo dev --function many-mcps
Open a protocol client in another terminal
Terminal
npx @modelcontextprotocol/inspector
YOUR ACCEPTANCE CHECK

Distinct catalogs. One controlled boundary.

  • 01Each known path initializes with the intended server name and instructions.
  • 02Directory discovery contains only directory tools; invoice discovery contains only invoice tools.
  • 03A successful call returns the result contract defined for that surface.
  • 04A missing or unknown slug returns a useful 404 and does not expose the catalog of valid private slugs.
  • 05Malformed or disabled slugs cannot select another definition or arbitrary application resource.
  • 06An unauthenticated or under-scoped caller cannot discover or invoke protected capabilities.
  • 07Two concurrent requests for different slugs do not exchange server instructions, tools, identity, or results.

The Chumbo reference suite exercises two row-defined public surfaces and an unknown path. Run the authentication and data-access cases against your application's own boundary.

05

Diagnose the boundary that disagrees.

If a surface is wrong

Both URLs advertise the same tools

Check that definition loading and app creation happen for the current request, and that registration closes over only the resolved definition. Do not cache a caller-specific Chumbo app globally. Read the reference ↗

OAuth metadata points at the base function

Confirm that resourceUrl includes the selected slug and matches the public URL the client used. Recheck any proxy or clean-URL mapping at the same time. Read the reference ↗

A row update changes more behavior than intended

Narrow stored definitions to validated configuration and map them to reviewed handlers. Remove any generic query, import, or credential field that makes database content executable. Read the reference ↗

Built from the real thing.

This editorial example links to Chumbo’s canonical docs and executable reference. Check the installed package when adapting the snippets.

Reference implementation ↗
Read the agent instructions

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

Goal: Resolve a named MCP from the request path, give each surface its own instructions and capabilities, and keep one deployable Supabase Edge Function.

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

Adapt the canonical path resolver and per-request registration to the application's known MCP surfaces. Keep executable handlers in reviewed source, validate every stored definition, and test discovery before calls. Do not turn row-defined configuration into arbitrary code, SQL, imports, or downstream credential brokerage.

Prerequisites:
- An existing Supabase project and a Chumbo Edge Function you can run locally.
- Two genuinely distinct MCP surfaces, each with a stable slug and an intentionally different capability list.
- An application-owned source of server definitions, plus an explicit authorization decision for reading it.

Acceptance:
- Each known path initializes with the intended server name and instructions.
- Directory discovery contains only directory tools; invoice discovery contains only invoice tools.
- A successful call returns the result contract defined for that surface.
- A missing or unknown slug returns a useful 404 and does not expose the catalog of valid private slugs.
- Malformed or disabled slugs cannot select another definition or arbitrary application resource.
- An unauthenticated or under-scoped caller cannot discover or invoke protected capabilities.
- Two concurrent requests for different slugs do not exchange server instructions, tools, identity, or results.

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.
BUILD WITH YOUR CODING AGENT

Give your agent a good start.

Copy this brief into your coding agent in the app’s repository. It includes the source, boundaries, and verification steps.

Download Markdown ↓