Skip to main content
Agentgateway supports fine-grained authorization policies for both MCP and HTTP traffic. Authorization rules use Common Expression Language (CEL) — a compact, safe expression language designed for policy evaluation.

MCP authorization

The mcpAuthorization policy on an MCP route defines which users can access which tools and resources. Rules are evaluated against the authenticated JWT subject and claims. Tools and resources that a user is not permitted to access are automatically filtered out of the tools/list and resources/list responses. If a user attempts to call a denied tool directly, the call is also rejected.

Configuration

Here is the full authorization example config from examples/authorization/config.yaml:
config.yaml
# yaml-language-server: $schema=https://agentgateway.dev/schema/config
binds:
- port: 3000
  listeners:
  - routes:
    - policies:
        cors:
          allowOrigins:
          - "*"
          allowHeaders:
          - "*"
          exposeHeaders:
          - "Mcp-Session-Id"
        backendAuth:
          passthrough: {}
        jwtAuth:
          issuer: agentgateway.dev
          audiences: [test.agentgateway.dev]
          jwks:
            # Relative to the folder the binary runs from, not the config file
            file: ./manifests/jwt/pub-key
        mcpAuthorization:
          rules:
          # Allow anyone to call 'echo'
          - 'mcp.tool.name == "echo"'
          # Only the test-user can call 'add'
          - 'jwt.sub == "test-user" && mcp.tool.name == "add"'
          # Any authenticated user with the claim `nested.key == value` can access 'printEnv'
          - 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"'
      backends:
      - mcp:
          targets:
          - name: mcp2
            mcp:
              host: http://localhost:3001/mcp
jwtAuth handles authentication (token validation), while mcpAuthorization handles authorization (what a validated user may do). Both are required for JWT-claim-based rules.

CEL rule syntax

Each rule in mcpAuthorization.rules is a CEL expression that evaluates to a boolean. A request is permitted if any rule evaluates to true.
rules:
- 'mcp.tool.name == "echo"'
Any authenticated user may call the echo tool. No JWT claim check is required.
rules:
- 'jwt.sub == "test-user" && mcp.tool.name == "add"'
Only the user whose JWT sub claim is test-user can call add. All other users see this tool filtered from their tool list.
rules:
- 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"'
Any authenticated user whose token contains the nested claim nested.key == "value" may call printEnv. Nested JWT claims are accessed with dot notation: jwt.<field>.<subfield>.
rules:
- 'mcp.tool.name == "echo"'
- 'mcp.tool.name == "add"'
- 'mcp.tool.name == "time"'
Add one rule per tool to allow access to a specific set of tools for all users.

Available CEL fields

FieldTypeDescription
mcp.tool.namestringName of the MCP tool being called
jwt.substringSubject claim from the JWT
jwt.<claim>anyAny top-level JWT claim
jwt.<claim>.<field>anyNested JWT claim accessed with dot notation

Rule evaluation

Rules are evaluated in order. A request is permitted as soon as any rule evaluates to true. If no rule matches, the request is denied.
When mcpAuthorization is configured, tools are filtered proactively. Clients see only the tools they are permitted to access in tools/list responses — they cannot discover tools they do not have access to.

Testing authorization rules

1

Start the gateway

cargo run -- -f examples/authorization/config.yaml
2

Connect with a restricted token

Use the example token manifests/jwt/pub-key/example2.key. This token has sub: test-user and no extra claims.Paste the token into MCP Inspector under Authentication > Bearer Token and run List Tools.You should see only echo and add — the two tools accessible to test-user without additional claims.
3

Connect with a token that has custom claims

Use manifests/jwt/pub-key/example1.key. This token has sub: test-user and the following claims:
{
  "field1": "value1",
  "nested": {
    "key": "value"
  },
  "list": ["apple", "banana"]
}
Run List Tools again. You should now also see printEnv, because the third rule (jwt.nested.key == "value") now matches.
MCP Inspector caches the tools list. Re-run List Tools explicitly after switching tokens to see the updated results.

HTTP authorization

For plain HTTP routes, use the authorization policy instead of mcpAuthorization. The syntax is the same — a list of CEL rules — but the available fields reflect HTTP request context.
policies:
  authorization:
    rules:
    - 'jwt.sub == "admin"'
HTTP authorization rules apply to all traffic on the route, not just MCP protocol calls. Use mcpAuthorization specifically when the backend is an MCP server.

Combining authentication and authorization

Authentication (jwtAuth or mcpAuthentication) must be configured alongside authorization to make JWT claims available in rules. The typical pattern is:
policies:
  # 1. Validate the token and extract claims
  jwtAuth:
    issuer: agentgateway.dev
    audiences: [test.agentgateway.dev]
    jwks:
      file: ./manifests/jwt/pub-key
  # 2. Enforce access rules using those claims
  mcpAuthorization:
    rules:
    - 'mcp.tool.name == "echo"'
    - 'jwt.sub == "test-user" && mcp.tool.name == "add"'
See the Authentication guide for details on configuring JWT validation.