RBAC Configuration
Role-based access control (RBAC) defines which actions users or teams can perform in MCP Gateway. This document covers the security model, token scoping semantics, and best practices for access control.
Overview
MCP Gateway implements a multi-layered access control system:
- Authentication: Verify user identity via JWT, SSO, or API tokens
- Team Membership: Group users for collective access policies
- Token Scoping: Restrict token capabilities to specific resources
- Visibility Filtering: Control which resources users can discover
┌─────────────────────────────────────────────────────────────────────────────┐
│ Access Control Layers │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Request → Authentication → Team Resolution → Token Scoping → Visibility │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ JWT │ │ User │ │ Token │ │ Resource │ │ Filtered │ │
│ │ Token │──▶│ Identity │──▶│ Teams │──▶│ Access │──▶│ Results │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Core Concepts
Subjects
Users authenticated via:
- JWT tokens (session or API)
- SSO providers (OAuth 2.0/OIDC)
- Basic authentication (development only)
Teams
Logical groups that:
- Organize users for access boundaries
- Own resources (tools, prompts, resources)
- Map from external identity providers (SSO groups)
Roles
Current role types:
- Admin: Full management access, can bypass team restrictions
- Maintainer: Manage servers, tools, prompts, configurations
- Viewer: Read-only access and metrics
Resources
Protected entities:
- Servers (MCP gateways and virtual servers)
- Tools, Prompts, Resources (MCP primitives)
- System configuration and audit logs
Token Scoping Model
Token scoping controls what resources a token can access based on the teams claim in the JWT payload. This provides fine-grained access control for automation tokens, service accounts, and restricted user sessions.
Teams Claim Semantics
The teams claim in JWT tokens determines resource visibility:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Token Teams Claim Handling │
├─────────────────────────────────────────────────────────────────────────────┤
│ JWT Claim State │ Admin User │ Non-Admin User │
├───────────────────────────┼───────────────────────┼─────────────────────────┤
│ No "teams" key │ UNRESTRICTED │ PUBLIC-ONLY (secure) │
│ teams: null │ UNRESTRICTED │ PUBLIC-ONLY (secure) │
│ teams: [] │ PUBLIC-ONLY │ PUBLIC-ONLY │
│ teams: ["team-id"] │ Team + Public │ Team + Public │
│ teams: ["t1", "t2"] │ Both Teams + Public │ Both Teams + Public │
└───────────────────────────┴───────────────────────┴─────────────────────────┘
Security Design Principles
Principle of Least Privilege
- Non-admin tokens without explicit team scope default to public-only access
- This prevents accidental exposure of team resources
Scoped Automation Tokens
- Admin tokens with
teams: []are intentionally restricted to public resources - Use case: CI/CD pipelines, monitoring systems, public API clients
- Admin tokens with
Backward Compatible Admin Access
- Admin session tokens (from UI login) omit the teams claim entirely
- This grants unrestricted access for administrative operations
Tool Name Separator
The gateway uses a separator to combine the gateway name and tool name (e.g., gateway-tool).
- Default:
-(dash) - Configurable: Yes, via
GATEWAY_TOOL_NAME_SEPARATORenv var - Supported values:
-,--,_,.
# Example: Use double underscore (legacy behavior)
GATEWAY_TOOL_NAME_SEPARATOR=__
┌──────────────────┐
│ JWT Token │
│ Received │
└────────┬─────────┘
│
▼
┌───────────────────────┐
│ Extract "teams" │
│ claim from JWT │
└───────────┬───────────┘
│
┌───────────────┴───────────────┐
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ "teams" key exists │ │ "teams" key missing │
│ with non-null value │ │ OR teams: null │
└──────────┬──────────┘ └──────────┬──────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ Use explicit scope │ │ Check is_admin flag │
│ teams = [...] or [] │ └──────────┬──────────┘
└──────────┬──────────┘ │
│ ┌───────────┴───────────┐
│ │ │
│ ▼ ▼
│ ┌──────────────────┐ ┌──────────────────┐
│ │ Admin: teams = │ │ Non-Admin: │
│ │ None (bypass) │ │ teams = [] │
│ │ UNRESTRICTED │ │ PUBLIC-ONLY │
│ └────────┬─────────┘ └────────┬─────────┘
│ │ │
└───────────────┴──────────────────────┘
│
▼
┌───────────────────────┐
│ Apply visibility │
│ filter to query │
└───────────────────────┘
Visibility Levels
Resources in MCP Gateway have three visibility levels:
| Visibility | Description | Who Can See |
|---|---|---|
public |
Accessible to all authenticated users | Everyone with valid token |
team |
Accessible to team members only | Team members + admins (unrestricted) |
private |
Accessible to owner only | Resource owner + admins (unrestricted) |
Enforcement Points
Token scoping is enforced consistently across all access paths:
| Layer | Location | Description |
|---|---|---|
| Middleware | token_scoping.py |
Request-level access control |
| REST API | main.py |
/tools, /resources, /prompts endpoints |
| RPC Handler | main.py |
tools/list, resources/list, prompts/list |
| MCP Transport | streamablehttp_transport.py |
Streamable HTTP protocol filtering |
| Service Layer | *_service.py |
Database query filtering |
Token Types and Use Cases
Session Tokens (UI Login)
Generated when users log in via the Admin UI:
{
"sub": "user@example.com",
"is_admin": true,
"iss": "mcpgateway",
"aud": "mcpgateway-api",
"exp": 1234567890
// Note: No "teams" key for admin users = unrestricted access
}
Behavior: Admin session tokens omit the teams claim, granting unrestricted access to all resources.
API Tokens (Programmatic Access)
Generated via the Admin UI or API for automation:
{
"sub": "service-account@example.com",
"is_admin": false,
"teams": ["team-uuid-1", "team-uuid-2"],
"iss": "mcpgateway",
"aud": "mcpgateway-api",
"exp": 1234567890
}
Behavior: Access restricted to public resources plus resources owned by specified teams.
Scoped Automation Tokens
For CI/CD, monitoring, or public API access:
{
"sub": "ci-pipeline@example.com",
"is_admin": true,
"teams": [], // Explicitly empty = public-only
"iss": "mcpgateway",
"aud": "mcpgateway-api",
"exp": 1234567890
}
Behavior: Even admin tokens with teams: [] are restricted to public resources only. This enables creating limited-scope tokens for automation that shouldn't access team-internal resources.
Generating Scoped Tokens
Using the CLI Tool
# Unrestricted admin token (no teams key)
python3 -m mcpgateway.utils.create_jwt_token \
--username admin@example.com \
--exp 60 \
--secret $JWT_SECRET_KEY
# Team-scoped token
python3 -m mcpgateway.utils.create_jwt_token \
--username user@example.com \
--exp 60 \
--secret $JWT_SECRET_KEY \
--teams '["team-uuid-1"]'
# Public-only scoped token (for automation)
python3 -m mcpgateway.utils.create_jwt_token \
--username ci@example.com \
--exp 60 \
--secret $JWT_SECRET_KEY \
--teams '[]'
Using the Admin UI
Navigate to Admin UI → Tokens
Click Create Token
Select team scope:
- No team selected: Public resources only (secure default)
- Specific team(s): Team + public resources
Configure additional restrictions (IP, permissions, expiry)
!!! warning "Token Scope Warning" Tokens created without selecting a team will have access to public resources only. This is the secure default to prevent accidental exposure of team resources.
Best Practices
Token Lifecycle
- Use short expiration times for interactive sessions (hours)
- Use longer expiration for service accounts with IP restrictions
- Rotate tokens regularly (recommended: 90 days for long-lived tokens)
- Revoke tokens immediately when access should be removed
Team Organization
Create purpose-specific teams:
platform-admins- Full administrative accessdevelopers- Development and testing resourcesci-automation- CI/CD pipeline accessmonitoring- Read-only observability access
Map SSO groups to teams for automatic membership management
Use personal teams for individual resource ownership
Scoping Strategy
| Use Case | Recommended Token Scope |
|---|---|
| Admin UI access | Session token (no teams key) |
| CI/CD pipeline | teams: [] (public-only) |
| Service integration | Specific team(s) |
| Developer access | Personal team + project teams |
| Monitoring/alerting | teams: [] with read permissions |
Troubleshooting
Token Not Seeing Expected Resources
Check token claims: Decode the JWT to verify
teamsclaim# Decode JWT payload (middle section) echo "$TOKEN" | cut -d. -f2 | base64 -d | jq .Verify resource visibility: Check the resource's
visibilityandteam_idcurl -H "Authorization: Bearer $ADMIN_TOKEN" /tools/{id} | jq '{visibility, teamId}'Check user admin status: Non-admin users without teams get public-only access
Admin Token Being Restricted
If an admin token is unexpectedly restricted:
- Check for explicit
teamsclaim:teams: []restricts even admins - Verify
is_adminflag: Must betruein JWT or database user - Check middleware logs: Look for "token_teams" in debug output
Inconsistent Results Between Endpoints
If REST and RPC endpoints return different results:
- Check for caching: REST list endpoints may have cached data
- Wait for cache TTL: Default is 60 seconds for registry cache
- Use direct GET:
/tools/{id}bypasses list cache
Bootstrap Custom Roles
MCP Gateway allows you to define custom roles that are automatically created during database bootstrap. This is useful for organizations that need to pre-configure roles before deployment.
Configuration
Enable custom role bootstrapping with these environment variables:
| Variable | Default | Description |
|---|---|---|
MCPGATEWAY_BOOTSTRAP_ROLES_IN_DB_ENABLED |
false |
Enable loading additional roles from file |
MCPGATEWAY_BOOTSTRAP_ROLES_IN_DB_FILE |
additional_roles_in_db.json |
Path to the JSON file containing role definitions |
Role Definition Format
Create a JSON file containing an array of role definitions:
[
{
"name": "data_analyst",
"description": "Read-only access for data analysis",
"scope": "team",
"permissions": ["tools.read", "resources.read", "prompts.read"],
"is_system_role": true
},
{
"name": "auditor",
"description": "Compliance audit access",
"scope": "global",
"permissions": ["tools.read", "resources.read", "prompts.read", "servers.read", "gateways.read"],
"is_system_role": true
}
]
Required fields:
name- Unique role namescope- Eitherteam(team-level access) orglobal(system-wide access)permissions- Array of permission strings (e.g.,tools.read,resources.create)
Optional fields:
description- Human-readable descriptionis_system_role- Set totrueto prevent users from modifying/deleting the role
Available Permissions
| Resource | Permissions |
|---|---|
| Tools | tools.create, tools.read, tools.update, tools.delete, tools.execute |
| Resources | resources.create, resources.read, resources.update, resources.delete |
| Prompts | prompts.create, prompts.read, prompts.update, prompts.delete |
| Servers | servers.create, servers.read, servers.update, servers.delete |
| Gateways | gateways.create, gateways.read, gateways.update, gateways.delete |
| Teams | teams.create, teams.read, teams.update, teams.delete, teams.join |
Docker Compose Example
services:
gateway:
environment:
- MCPGATEWAY_BOOTSTRAP_ROLES_IN_DB_ENABLED=true
- MCPGATEWAY_BOOTSTRAP_ROLES_IN_DB_FILE=/app/custom_roles.json
volumes:
- ./custom_roles.json:/app/custom_roles.json:ro
Kubernetes/Helm Example
# values.yaml
mcpContextForge:
env:
MCPGATEWAY_BOOTSTRAP_ROLES_IN_DB_ENABLED: "true"
MCPGATEWAY_BOOTSTRAP_ROLES_IN_DB_FILE: "/config/custom_roles.json"
# Mount ConfigMap with role definitions
extraVolumes:
- name: custom-roles
configMap:
name: mcp-gateway-roles
extraVolumeMounts:
- name: custom-roles
mountPath: /config
Error Handling
- File not found: Bootstrap continues with default roles only; warning logged
- Invalid JSON: Bootstrap continues with default roles only; error logged
- Malformed entries: Invalid role entries are skipped with warnings; valid entries are processed
!!! tip "Idempotent Bootstrap" Bootstrap is idempotent - running it multiple times won't duplicate roles. Existing roles are detected and skipped.
Related Documentation
- Team Management - Setting up teams and SSO mapping
- Security Features - Comprehensive security configuration
- Configuration Reference - Environment variables
- API Usage - Token usage in API calls