A multi-tenant MCP server serves many customers from one deployment. The appeal is obvious: one thing to deploy, upgrade and monitor, rather than one per customer. The difficulty is that a single mistake becomes a cross-customer data leak rather than a bug.
Routing is the easy half
Getting a request to the right tenant is straightforward: a URL prefix, a subdomain, or a header resolves to a tenant before anything else happens. Almost every implementation gets this right.
Isolation is the hard half
The failure mode is not routing to the wrong tenant. It is a query somewhere in the codebase that forgets to filter by tenant, and therefore returns everything. This is a single missing clause in a single query, written by someone who was thinking about something else, and no test will catch it unless the test was written to look for it.
The durable fix is to make isolation a property of the database connection rather than of each query. Postgres row-level security lets you set a tenant context on the transaction and have policies scope every query to it. A query that forgets to filter then returns nothing rather than everything. The failure is loud and safe instead of quiet and catastrophic.
What else has to be per-tenant
- Credentials. Each customer's upstream secrets encrypted separately, decrypted in memory at call time.
- Signing keys. A session token minted for one tenant must not verify against another.
- Tool catalogs. A tool published by one customer should be invisible to every other, so nobody can enumerate what others expose.
- Audit records. One customer's log must never be readable by another.
- Rate limits and quotas, or one noisy customer degrades everyone.
The connection-level question
One tenant usually has more than one API. Treating each as an independent connection, with its own endpoint, base URL, credentials and tools, keeps blast radius small and lets a customer onboard a second system without touching the first.
How to evaluate one
Ask where isolation is enforced. If the answer is "every query filters by tenant", that is a convention, and conventions are broken by new joiners under deadline. If the answer names a database-level mechanism, the property survives the team changing.