Lead · Core path · 7 chapters
Multi-tenant servers
Per-user credential isolation, no shared ambient authority, per-request identity
A shared credential or leaked request identity turns one MCP bug into cross-tenant data access, so isolation must be enforced and tested at every request boundary.
Read these first
What you will know
Isolate credentials per user in a multi-tenant server
A process-wide token or reusable privileged client lets one compromised request act on behalf of every tenant.
Trace a request path and identify where ambient authority could enter
Hidden service credentials, filesystem access, or an overprivileged tool can bypass the caller's permissions even when the API looks tenant-aware.
Show that user A cannot reach user B's data through the server
Use forged identifiers, altered tool arguments, and alternate lookup paths rather than relying on a code review or happy-path test.
Carry identity per request rather than per connection
Connection reuse and asynchronous work can associate a later operation with the wrong caller unless identity is propagated explicitly.
Test the isolation adversarially
Include retries, caching, logs, background jobs, and error responses, where tenant boundaries often leak outside the primary handler.
Chapters
- 1
Per-request identity
A multi-tenant server that binds the caller to the HTTP session answers the question 'who is this?' once and reads the answer for hours. A gateway multiplexing clients, a pooling proxy, or a reconnect landing on a live session id puts a second caller on that session, and the handler cannot tell. Resolve identity from each request's own credentials and pass it down as an argument — which costs 0.05 to 0.2 percent of a 180 ms tool call, so the objection is not really about latency.
- 2
Ambient authority
A credential is ambient when code can use it without anyone handing it over, so nothing at the call site records that authority was exercised. That is how a server deriving the tenant from a validated token, with every query filtered, still gives one tenant a document title belonging to another: a privileged client built once at startup resolves a name or warms a cache. The exercise that finds them is listing the outbound calls that are not queries, and on one 30,000-line server a single tool call made 23 of them.
- 3
Credentials as arguments
A process-wide token or a reusable privileged client lets one compromised request act for every tenant, so credentials become arguments a caller supplies rather than state the process reaches for. They also need a home: a store that accepts an identity rather than a tenant id, since a store any path may ask for any tenant's token is a startup client with a lookup in front of it. The awkward case is asynchronous — a worker picking up a job 200 ms or four hours later has no request, so tenant and acting user are recorded into the payload and the worker re-checks that identity before acting.
- 4
Integration tests for tenant isolation
A suite of 340 integration tests in which each tenant successfully reads its own records is evidence about the happy path and nothing about the boundary, because every one of them also passes on a server with no tenant filtering at all. The tests that count run as A and reach for B: B's ids in every argument, B's names in free-text lookups, a forged tenant claim, a retry of a call that failed for B. Six categories, an assertion that names no identifier of B anywhere, and the two categories that go green for the wrong reason.
- 5
Tenant leaks outside the handler
An error message naming another tenant's file is not a formatting bug: something resolved a name outside the caller's scope before failing on it, so the boundary had already been crossed when the string was written. Sanitising deletes the evidence rather than the defect. A complete tool-call matrix covers the surface and misses exactly these paths — retries, shared caches, logs and traces, background jobs and error text — because they are properties of a path rather than of an endpoint.
- 6
Stored credentials under process compromise
Per-tenant KMS keys, row-level security, per-request identity and an adversarial suite in CI are all worth having, and not one of them changes what a single remote code execution yields. A server that must decrypt any tenant's refresh token on demand in order to do its job can decrypt every tenant's token once it is running attacker code — eighty of them in about two seconds. This is the limit no control in the previous chapters moves, and the one control that does move the outcome is detection rather than prevention.
- 7
Alternatives to a credential store
An objection is only useful if you can name what you would build instead. Three shapes answer a process that holds every tenant's long-lived credentials: a cell per tenant, so attacker code inside it reaches one tenant's grants; credentials the user presents at request time; and a broker that mints short-lived tenant-scoped tokens against a validated identity, leaving the tool process holding nothing reusable. Each costs something real — 40 deployments, re-authentication, or one more service on the critical path — which is what the argument about scaling is actually about.
External resources
- Enforcing tenant isolation — AWS Prescriptive Guidance for multitenant agentic AIdocs.aws.amazon.com
Reference patterns for scoping every request to a tenant identity.
- How to Architect a Multi-Tenant MCP Server for Enterprise B2B SaaStruto.one
Concrete design for per-tenant credential lookup on each request.
- MCP Security for Multi-Tenant AI Agents: Isolation Patternsprefactor.tech
Where shared caches and sessions leak across tenants.
- The Developer's Guide to MCP Gatewaysdescope.com
How a gateway keeps raw tokens away from the model and client.
- Tenant Isolation & Data Partitioningyoutube.com
Specific multi-tenant isolation mechanics