#AI Agent#MCP#DevOps

MCP Multi-Tenant Isolation: Preventing Cross-Tenant Leaks from Request Context to Cache Keys

The most dangerous failure in a multi-tenant MCP Server is not an error, but silently returning Team A’s data to Team B. This article presents a complete isolation design spanning identity context, query constraints, caching, tool parameters, and testing strategy.

Key Points

  • Topic Focus: AI Agent、MCP、DevOps
  • Suitable for: indie hackers, full-stack engineers, AI application developers
  • Core value: quickly understand background, practical paths, common pitfalls, and engineering advice
Author @admin·Published July 26, 2026·Updated July 26, 2026

The risks of a multi-tenant MCP Server extend beyond database queries. Even if every SQL statement includes tenant_id, omitting tenant context just once from a cache key, background job, file download link, or log query can silently expose one team’s data to another. Instead of relying on every developer to “remember to add the filter,” make isolation a default property of the execution path.

Tenant Context Must Come Only from a Trusted Identity Layer

A tenantId in tool parameters must be treated as user input, not as a basis for authorization. After authenticating the client and user, the Server derives tenant context from a signed session or internal authorization service and encapsulates it in a request context that cannot be modified arbitrarily. The tool executor receives only this context, rather than allowing the model to specify any team through parameters.

When administrators need cross-tenant support access, do not simply bypass filtering. Give support personnel a dedicated scope and require them to explicitly select the target tenant, record a reason, and generate an audit event. Cross-tenant access is a special capability, not the default mode for ordinary queries.

Enforce Filtering in the Data Access Layer

Business queries should pass through a unified data access entry point that automatically injects tenant constraints. The following pseudocode illustrates the boundary rather than the syntax of any specific ORM:

ts
const projects = projectRepository.forTenant(context.tenantId).findMany({ status: "active" });

Do not manually write where: { tenantId } in every tool, because it is easy to omit from a new query. For highly sensitive tables, add row-level security policies or restricted views at the database layer so that an application-layer mistake still cannot return an entire table across tenant boundaries. The exact mechanism depends on the database and operational capabilities, but “at least two layers of enforcement” is a goal worth maintaining.

Caches, Queues, and Object Storage Are the Easiest Places to Miss

Cache keys must include the tenant and every authorization factor that affects the result. A key such as report:latest works in single-tenant tests but will immediately mix data in production. A safer form is tenant:{id}:report:{queryHash}:role:{roleVersion}. If project membership also affects the result, include the role version or permission version in the key and proactively invalidate it after permissions change.

Asynchronous jobs must likewise persist tenantId and reload authorization constraints when a worker consumes them. File exports must not generate permanent public URLs. A download token should be bound to the tenant, resource, expiration time, and user, and the download service must check the context again instead of trusting an ID in the filename.

Design Tools to Prevent Unauthorized Composition

Individual tools may appear safe while becoming unauthorized when composed. For example, list_projects might return guessable global IDs while get_project_metrics queries only by ID, allowing the two tools together to enumerate other tenants. Every read tool must authorize access independently rather than relying on the assumption that “the caller could not theoretically obtain this ID.”

For search, pagination, and aggregation, confirm that filtering occurs before sorting, counting, and cursor generation. Otherwise, even if list items are filtered, totalCount, error messages, or cursor behavior may still leak information about the size and activity of other tenants.

Propagate Tenant Context Across Every Boundary

A single tool call often passes through an HTTP handler, authorization service, cache layer, message queue, worker, and object storage. If any layer drops the context, downstream code will attempt to use a default tenant or an empty constraint. Define an explicit structure for request context, and include an immutable tenantId, principal ID, traceId, and authorization snapshot version in asynchronous messages. A worker must not infer the tenant again from arbitrary message fields; it must verify that the job belongs to the context before executing it.

Database connection pools also deserve separate scrutiny. If session-level variables, row-level security, or temporary tables are used, their state must be cleared before returning a connection to the pool. Otherwise, the next tenant may inherit the previous session’s permission settings. Background work such as cache invalidation, full-text indexing, and data exports also requires tenant isolation tests because these paths often bypass normal HTTP middleware.

Prove Isolation with Negative Tests

Tests should verify not only that Team A can read Team A’s data, but also that Team B still fails when it obtains Team A’s resource ID, cache key, job ID, or download link. Establish a fixed regression suite of cross-tenant attacks: modify the tenantId in tool parameters, replay an expired job, reuse a cursor after switching accounts, hit the same cache entry, and attempt to download from an old link.

After deployment, monitor rejected cross-tenant requests, calls without tenant context, and malformed cache-key formats. Isolation defects are often not a single major incident, but a quiet bypass introduced by a new tool, performance optimization, or migration. Only by continuously including these paths in regression testing and auditing can MCP safely serve as the capability layer of a multi-tenant product.

Further Reading

Related

Related Content