Skip to content
agentgateway has joined the Agentic AI FoundationLearn more

For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.

Page as Markdown

Set up MCP auth

Secure your Model Context Protocol (MCP) servers with OAuth 2.0 authentication by using agentgateway and an identity provider like Keycloak.

About this guide

In this guide, you configure the agentgateway proxy to protect a static MCP server with Keycloak. The MCP client uses dynamic client registration (DCR) with Keycloak and sends the user through the OAuth flow. DCR creates the client registration but does not grant access to the MCP server. Agentgateway validates the token audience and permits only members of the Keycloak users group.

MCP auth vs JWT auth

You can configure both MCP and JWT auth with an AgentgatewayPolicy. For most MCP cases, choose MCP auth.

  • MCP auth: Use MCP auth for MCP clients, such as MCP Inspector, VS Code, or Claude Code that need to dynamically discover the auth server and register with your IdP to get a client ID. The agentgateway proxy facilitates the discovery and client registration process between MCP clients and IdPs that do not implement the MCP OAuth spec. This way, your MCP clients successfully obtain a client ID to complete the OAuth flow.

  • JWT auth: Use basic JWT auth when you have static clients or service-to-service traffic. Clients already have a JWT from your IdP or a static token. You only need the gateway to validate the token and optionally enforce RBAC by claims. For example, you might want to grant access only to JWTs that contain the sub or team claim. No discovery or client registration is involved.

Review the following table for a quick comparison of MCP auth and JWT auth.

FeatureMCP AuthJWT Auth
GoalFull MCP OAuth flow (discovery, client registration, token validation)Validate tokens and optional claim-based RBAC
Policy sectionspec.traffic.jwtAuthentication, including the mcp fieldspec.traffic.jwtAuthentication
Target refGateway or HTTPRouteGateway or HTTPRoute
Client registrationDynamic registration with IdPNone (client has token)

MCP auth builds on JWT auth instead of replacing it, which is why both rows name the same policy section and target ref. Configure the shared providers, mode, and location fields the same way for either type of auth, then add the mcp field to turn on the MCP OAuth behavior. The mcp field contributes only the MCP-specific settings: provider, clientId, and resourceMetadata.

For more information, see the JWT auth docs.

Before you begin

  1. Set up an agentgateway proxy.
  2. Follow the steps to set up an MCP server with a fetch tool.
  3. Follow the steps to set up Keycloak.
  4. Install the experimental channel Gateway API.
    kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.0/experimental-install.yaml

Configure MCP auth

With Keycloak deployed and your MCP backend configured, you can now create an AgentgatewayPolicy that enforces authentication for the MCP backend.

  1. Create an AgentgatewayPolicy with MCP authentication and authorization configuration. The policy validates the resource audience and uses a Common Expression Language (CEL) rule to require the Keycloak users group.

    kubectl apply -f - <<EOF
    apiVersion: agentgateway.dev/v1alpha1
    kind: AgentgatewayPolicy
    metadata:
      name: mcp-echo-authn
    spec:
      # Target the HTTPRoute to apply authentication at the route level
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: HTTPRoute
        name: mcp
      # Configure MCP authentication at the traffic (route) level
      traffic:
        jwtAuthentication:
          # Require a valid JWT from one of the configured providers
          mode: Strict
          providers:
          - # Issuer URL - must match the 'iss' claim in JWT tokens
            issuer: "${KEYCLOAK_ISSUER}"
            # Expected audience in JWT tokens
            audiences:
            - "${MCP_RESOURCE}"
            # JWKS configuration for token validation
            jwks:
              remote:
                # Reference to the Keycloak service for fetching public keys
                backendRef:
                  name: keycloak
                  kind: Service
                  namespace: keycloak
                  port: 8080
                # Path to the JWKS endpoint on the issuer
                jwksPath: "${KEYCLOAK_JWKS_PATH}"
          # MCP-specific extensions for OAuth discovery
          mcp:
            # Identity provider type
            provider: Keycloak
            # MCP resource metadata for OAuth discovery
            resourceMetadata:
              # Resource identifier for this MCP server
              resource: "${MCP_RESOURCE}"
              # Scopes supported by this MCP server
              scopesSupported:
              - email
              # Methods for providing bearer tokens
              bearerMethodsSupported:
              - header
              - body
              - query
        # Allow only tokens from members of the Keycloak users group
        authorization:
          action: Allow
          policy:
            matchExpressions:
            - 'has(jwt.groups) && jwt.groups.exists(group, group == "users")'
    EOF
    SettingDescription
    traffic.jwtAuthentication.providers[].issuerThe OAuth 2.0 issuer URL from your identity provider. This must exactly match the iss claim in JWT tokens. Agentgateway validates this claim to ensure tokens come from the expected identity provider.
    traffic.jwtAuthentication.providers[].jwks.remote.backendRefThe Keycloak service for fetching JWKS public keys.
    traffic.jwtAuthentication.providers[].jwks.remote.jwksPathThe path to the JWKS endpoint to obtain public keys.
    traffic.jwtAuthentication.providers[].audiencesThe purpose of the JWT token. This value must match the aud claim in JWT tokens.
    traffic.jwtAuthentication.modeThe JWT validation mode. Strict mode requires a valid JWT from one of the configured providers.
    traffic.jwtAuthentication.mcp.providerThe identity provider that you use. In this example, Keycloak is used.
    traffic.jwtAuthentication.mcp.resourceMetadataMCP OAuth resource metadata for discovery. Includes the resource identifier, supported scopes, and bearer token methods.
    traffic.authorization.policy.matchExpressionsCEL rules that authorize the verified JWT claims. This example requires membership in the Keycloak users group.
  2. Verify that the policy was accepted.

    kubectl get AgentgatewayPolicy mcp-echo-authn -o yaml
  1. Update the HTTPRoute that routes incoming traffic to the MCP server to include the discovery paths for the MCP resource and authorization server. This way, the agentgateway proxy can retrieve the resource and authorization server metadata during the MCP auth flow.
    kubectl apply -f - <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: mcp
    spec:
      # Reference the Agentgateway
      parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: agentgateway-proxy
        namespace: agentgateway-system
      rules:
      - filters:
         # Enable CORS for browser-based MCP clients
          - type: CORS
            cors:
              allowCredentials: true
              allowHeaders:
                - Origin
                - Authorization
                - Content-Type
              allowMethods:
                - "*"
              allowOrigins:
                - "*"
              exposeHeaders:
                - Origin
                - X-HTTPRoute-Header
              maxAge: 86400
        # Route to the MCP backend
        backendRefs:
        - group: agentgateway.dev
          kind: AgentgatewayBackend
          name: mcp-backend
        # Match MCP and OAuth discovery paths
        matches:
        # Main MCP endpoint to connect to the MCP server
        - path:
            type: PathPrefix
            value: /mcp
        # Path to access resource server metadata
        - path:
            type: PathPrefix
            value: /.well-known/oauth-protected-resource/mcp
        # Path to access authorization server metadata
        - path:
            type: PathPrefix
            value: /.well-known/oauth-authorization-server/mcp
        # JWKS endpoint for token validation
        - path:
            type: PathPrefix
            value: /realms/master/protocol/openid-connect/certs
    EOF

Verify MCP auth

  1. Open the MCP inspector.

    npx @modelcontextprotocol/inspector@0.21.2
  2. From the MCP Inspector menu, connect to your agentgateway address as follows:

    • Transport Type: Select Streamable HTTP.
    • URL: Enter the agentgateway address, port, and the /mcp path. If your agentgateway proxy is exposed with a LoadBalancer server, use http://${INGRESS_GW_ADDRESS}/mcp. In local test setups where you port-forwarded the agentgateway proxy on your local machine, use http://localhost:8080/mcp.
    • Click Connect.

    Verify that the connection fails, because authentication is required to access the MCP server.

  3. Click Open Auth Settings to run through the MCP Auth flow that you configured with the agentgateway proxy.

  4. Run through the auth flow. You can decide to manually run through the auth flow or select Quick OAuth Flow to automatically run through all the auth steps automatically. This guide assumes that you run through the auth flow manually.

    1. In the OAuth Flow Progress card, click Continue to start the Metadata Discovery phase. Verify that the step succeeds and that you see the authorization server metadata. The metadata include information about the location of the authorization server, supported scopes, and ways to provide the bearer token.

    2. Click Continue to start the Client registration phase. Verify that the MCP inspector tool successfully registered as a client in Keycloak and is assigned a client ID.

    3. Click Continue to start the Preparing Authorization phase. Verify that you get back a URL to log in to Keycloak with your credentials. Open the link in your browser and log in with the user user1 and password password.

      After you log in to Keycloak, an authorization code is displayed. Copy the authorization code and continue with the next step.

    4. Copy the authorization code into the Authorization Code field in the MCP inspector. Then, click Continue to start the Request Authorization and acquire authorization code phase.

    5. Click Continue to start the Token Request phase. Verify that the Authentication Complete phase returns a token from Keycloak. The access token includes the MCP resource in aud and the users group in groups.

    6. Connect to your MCP server.

      1. Copy the access_token value from the Authentication Complete phase.
      2. Open the Authentication section in the MCP inspector.
      3. In the Custom Headers card, click Add.
      4. Add the following values:
        • header name: Authorization
        • header value: Bearer <value of access_token>
      5. Click Connect to connect to your MCP server.
  5. Verify that tool calls work without re-authentication. Because the client authenticates at connect time, tool calls succeed immediately without any additional login prompts.

    1. From the menu bar, click the Tools tab.

    2. Click List Tools and select the fetch tool.

    3. In the url field, enter a website URL, such as https://example.com/.

    4. Click Run Tool.

    5. Verify that the tool call succeeds and returns the fetched content. No additional authentication is required because the token from the initial connection is reused for all tool calls within the session.

Clean up

You can remove the resources that you created in this guide.
kubectl delete AgentgatewayPolicy mcp-echo-authn
kubectl delete httproute mcp
Was this page helpful?
Agentgateway assistant

Ask me anything about agentgateway configuration, features, or usage.

Note: AI-generated content might contain errors; please verify and test all returned information.

Tip: one topic per conversation gives the best results. Use the + button in the chat header to start a new conversation.

Switching topics? Starting a new conversation improves accuracy.
↑↓ navigate select esc dismiss

What could be improved?

Your feedback helps us improve assistant answers and identify docs gaps we should fix.

Need more help? Join us on Discord: https://discord.gg/y9efgEmppm

Want to use your own agent? Add the Solo MCP server to query our docs directly. Get started here: https://search.solo.io/.