MCPG's tenancy model is three levels: organizations contain workspaces, which contain environments. RBAC binds users to roles at any level. License entitlements gate which plugins each org can use.
When you need this
- A SaaS company giving each customer their own MCPG slice
- A platform team running MCPG for multiple internal teams
- A consultant or MSP managing several client deployments
If you're a single team running one gateway, you don't need any of this — Tier-0 ships with a single org / workspace / environment by default.
The hierarchy
Organization (e.g. "acme-corp")
└── Workspace (e.g. "platform-team")
└── Environment (e.g. "prod" / "staging" / "dev")
└── Gateway instances (e.g. "gw-prod-1", "gw-prod-2")
Each level scopes:
| Scope | What's tenant-isolated |
|---|---|
| Organization | License, audit chain, billing, SSO domain |
| Workspace | Plugin sets, policies, identity chains, secrets |
| Environment | Gateway instances, runtime config, observability data |
Postgres deployments use row-level security (RLS) — every query is scoped to the
caller's org via a mcpg.org_id session variable. SQLite deployments enforce this in
the application layer.
Setting it up
# Create the org
mcpg-ctl org create acme-corp --display-name "Acme, Inc."
# Create a workspace
mcpg-ctl workspace create acme-corp/platform-team
# Create environments
mcpg-ctl env create acme-corp/platform-team/prod
mcpg-ctl env create acme-corp/platform-team/staging
mcpg-ctl env create acme-corp/platform-team/dev
The CP UI does the same thing graphically.
Plugin sets per workspace
Each workspace can have its own plugin set:
# Workspace platform-team uses an enterprise policy bundle
apiVersion: mcpg.dev/v1
kind: MCPGPluginSet
metadata:
name: platform-team-prod
namespace: mcpg-acme
spec:
workspace: acme-corp/platform-team
plugins:
- id: identity.oidc
- id: policy.cedar
config:
bundle: oci://policies.acme.com/platform-team:1.0
- id: reliability.rate-limit
- id: observability.audit
Workspaces in different teams (e.g. acme-corp/finance-team) can use entirely
different plugin sets without touching each other.
RBAC
Three role tiers:
| Role | Scope | Permissions |
|---|---|---|
admin | Org | Everything: workspaces, billing, identity, licenses |
operator | Workspace | Plugin sets, gateway lifecycle, secrets |
viewer | Environment | Read-only — instances, audit, metrics |
Bind users:
mcpg-ctl rbac grant alice@acme.com admin --on org/acme-corp
mcpg-ctl rbac grant bob@acme.com operator --on workspace/acme-corp/platform-team
mcpg-ctl rbac grant carol@acme.com viewer --on env/acme-corp/platform-team/prod
workspace.rbac requires Team tier; environment.rbac requires Enterprise.
Subdomain routing (optional)
For SaaS deployments, route by subdomain:
# acme.mcpg.dev → org acme-corp
tenancy:
subdomain_routing:
enabled: true
suffix: mcpg.dev
Now acme.mcpg.dev/v1/... automatically scopes the request to acme-corp without
the operator-side tenant header. Useful for white-label deployments.
Tenant isolation enforcement
The CP enforces isolation at three layers:
- HTTP middleware — every request resolves to a tenant before any handler runs; handlers receive a tenant-scoped pool, not a global pool.
- Postgres RLS —
mcpg.org_idsession var is set per-request;org_id-keyed tables have RLS policies that filter automatically. - Audit chain — each org's audit ledger is a separate chain; cross-tenant access is detectable by chain mismatch.
For air-gap / sovereign deployments, you can also run separate gateways per tenant — many small instances rather than one big multi-tenant deployment. The CP manages both topologies.
Cloud federation (Tier 1+)
Self-hosted Tier-1+ deployments can federate to auth.mcpg.dev for license
issuance. The federation:
- Issues 24h JWTs with embedded tier + entitlements
- Refreshes every 8h
- Has a 7-day grace window for outages
- Issues offline (1-year expiry) licenses for sovereign deployments via
mcpg-license issue
Federation is opt-in. Tier-0 never federates. Enterprise BYOC can run their own federation.