MCP Authorization the Easy Way

Christian Posta, Rinor Maloku

Aug 12, 2025

In June 2025, the MCP community updated the specification to alleviate some of the concerns from the previous version regarding MCP Authorization. However, this update introduces new concerns, especially around enterprise usage. Nevertheless, many public facing MCP clients (Claude, VS Code, etc) do implement the MCP Authorization spec, and many public facing MCP services are expecting this.

In agentgateway, we are trying to make this easier for those building MCP servers. In recent builds, we’ve introduced a way to configure mcpAuthentication which leverages an external OAuth provider, specifically implementing the MCP server side of the MCP Authorization spec for you via configuration.

The MCP specification says the following about the MCP Server’s responsibilities in the authorization spec:

MCP servers MUST use the HTTP header WWW-Authenticate when returning a 401 Unauthorized to indicate the location of the resource server metadata URL as described in RFC9728 Section 5.1 “WWW-Authenticate Response”.

And also…

MCP servers MUST implement the OAuth 2.0 Protected Resource Metadata (RFC9728) specification to indicate the locations of authorization servers. The Protected Resource Metadata document returned by the MCP server MUST include the authorization_servers field containing at least one authorization server.

For example, if you’ve built an MCP server (npx, python, remote, whatever), and you want to handle these spec requirements consistently for your MCP server (and potentially exposing many others), you can use agentgateway to do this.

For example, if this is how you route to your MCP Server:

binds:
- listeners:
  - routes:
    - backends:
      - mcp:
          targets:
          - name: hello-world
            stdio:
              args:
              - 'run' 
              - 'src/main.py'
              cmd: 'uv'
      matches:
      - path:
          exact: /hello/mcp
      policies:
        cors:
          allowHeaders:
          - mcp-protocol-version
          - content-type
          allowOrigins:
          - '*'
  port: 3000

Then you can add the new mcpAuthentication configuration to implement this behavior:

        mcpAuthentication:
          issuer: http://localhost:7080/realms/mcp
          jwksUrl: http://localhost:7080/realms/mcp/protocol/openid-connect/certs
          audience: mcp_proxy
          provider:
            keycloak: {}
          resourceMetadata:
            resource: http://localhost:3000/hello/mcp
            scopesSupported:
            - profile
            - offline_access
            - openid
            bearerMethodsSupported:
            - header
            - body
            - query
            resourceDocumentation: http://localhost:3000/hello/docs
            resourcePolicyUri: http://localhost:3000/hello/policies

There are a couple important points to make here. When we use this configuration, we automatically get a spec-compliant implementation for MCP Auth. But, depending on the OAuth provider we use, it may need some massaging. For example, Keycloak has some challenges with Dynamic Client Registration (ie, registration endpoint, CORS, etc). agentgateway can automatically wrap this and expose it in a way that’s spec compliant. That’s the point of the provider: keycloak {} configuration.

Out of the box provider: auth0 {} is also supported. If your provider correctly supports all of the OAuth RFC / specs, then you can ommit provider: completely.

Take a look at this demo video to see how it all works: