← Back to list

MCP dynamic client registration with Auth0 on Amazon Bedrock AgentCore Runtime

MCP servers expose tools that AI agents consume. In development, running them without authentication works fine. In production, every MCP…

Tola Ore-Aruwaji · 2026-05-16 23:45 · 400 claps · 3.8 min read paywalled
#amazon-bedrock #mcp-server #auth0 #python #ai
Open on Medium ↗
Wiki topics: AGT · AI Agents AI · AI · General 🏃 · Running & Endurance

MCP dynamic client registration with Auth0 on Amazon Bedrock AgentCore Runtime

MCP dynamic client registration with Auth0

MCP dynamic client registration with Auth0

MCP servers expose tools that AI agents consume. In development, running them without authentication works fine. In production, every MCP server endpoint needs access control — only authorized clients invoke your tools.

Dynamic Client Registration (DCR) is the OAuth 2.0 mechanism that lets MCP clients register themselves with an authorization server automatically. Combined with Auth0 as the identity provider and AgentCore Runtime as the hosting platform, this creates a fully authenticated MCP deployment: clients discover the server, register dynamically, authenticate via browser-based OAuth, and invoke tools with JWT tokens.

In this tutorial, deploy an MCP server to AgentCore Runtime with Auth0 JWT authorization, then build an OAuth client that handles the full DCR flow automatically.

The full source code is available in the amazon-bedrock-agentcore-samples repository.

What you build

  • An MCP server with three tools deployed to AgentCore Runtime with JWT authorization
  • Auth0 tenant configuration with an API and application supporting DCR
  • An OAuth client that handles dynamic registration, browser-based authorization, token management, and MCP tool invocation

How DCR works with AgentCore Runtime

The authentication flow has four steps:

  1. Discovery: The MCP client fetches the OpenID Connect discovery document from Auth0 to learn the authorization, token, and registration endpoints
  2. Registration: The client registers itself with Auth0 using the DCR endpoint, receiving a client ID and secret
  3. Authorization: The user authenticates in the browser. Auth0 redirects back with an authorization code.
  4. Token exchange: The client exchanges the authorization code for a JWT access token. All subsequent MCP requests include this token in the Authorization header.

AgentCore Runtime validates the JWT using the customJWTAuthorizer configuration — checking the audience, issuer, and signature against Auth0's JWKS endpoint.

. . .

Prerequisites

  • An Auth0 account (free tier works)
  • An active AWS account with credentials configured
  • Python 3.10 or later installed
  • Docker running locally
  • IAM permissions: BedrockAgentCoreFullAccess

Set up Auth0

Step 1: Create an API

In the Auth0 dashboard, create a new API:

  • Name: AgentCore Runtime API (or any descriptive name)
  • Identifier: ac-runtime-api (this becomes the audience parameter)
  • Signing algorithm: RS256

Step 2: Create an application

Create a new application in Auth0:

  • Type: Regular Web Application
  • Allowed callback URLs: [http://localhost:3030/callback](http://localhost:3030/callback)
  • Grant types: Authorization Code, Refresh Token

Step 3: Note the discovery URL

DISCOVERY_URL="https://<your-auth0-tenant>.us.auth0.com/.well-known/openid-configuration"
AUDIENCE="ac-runtime-api"

Create the MCP server

Step 4: Define the server

Create server.py — the same FastMCP server from the MCP hosting tutorial:

from mcp.server.fastmcp import FastMCP
mcp = FastMCP(host="0.0.0.0", stateless_http=True)
@mcp.tool()
def add_numbers(a: int, b: int) -> int:
    """Add two numbers together"""
    return a + b
@mcp.tool()
def multiply_numbers(a: int, b: int) -> int:
    """Multiply two numbers together"""
    return a * b
@mcp.tool()
def greet_user(name: str) -> str:
    """Greet a user by name"""
    return f"Hello, {name}! Nice to meet you."
if __name__ == "__main__":
    mcp.run(transport="streamable-http")

The server code stays identical. Authentication is handled by AgentCore Runtime, not the server itself.

Deploy with JWT authorization

Step 5: Configure and launch with Auth0 authorizer

from bedrock_agentcore_starter_toolkit import Runtime
from boto3.session import Session
boto_session = Session()
region = boto_session.region_name
agentcore_runtime = Runtime()
# Configure JWT authorization with Auth0
auth_config = {
    "customJWTAuthorizer": {
        "allowedAudience": [AUDIENCE],
        "discoveryUrl": DISCOVERY_URL,
    }
}
response = agentcore_runtime.configure(
    entrypoint="server.py",
    auto_create_execution_role=True,
    requirements_file="requirements.txt",
    region=region,
    agent_name="mcp_dcr_sample",
    authorizer_configuration=auth_config,
    protocol="MCP",
    memory_mode="NO_MEMORY",
    deployment_type="direct_code_deploy",
    runtime_type="PYTHON_3_13",
)
launch_result = agentcore_runtime.launch()

Key details:

  • customJWTAuthorizer tells AgentCore Runtime to validate incoming JWT tokens
  • allowedAudience matches the Auth0 API identifier
  • discoveryUrl points to Auth0's OIDC discovery document for JWKS key resolution
  • protocol="MCP" configures the endpoint for MCP RPC messages
  • deployment_type="direct_code_deploy" deploys source code directly without Docker

. . .

Build the OAuth client

Step 6: Create the authenticated MCP client

The client uses the MCP SDK’s OAuthClientProvider to handle the full OAuth flow:

from mcp.client.auth import OAuthClientProvider, TokenStorage
from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamablehttp_client
from mcp.shared.auth import OAuthClientMetadata, OAuthToken
class InMemoryTokenStorage(TokenStorage):
    """Simple in-memory token storage."""
    def __init__(self):
        self._tokens = None
        self._client_info = None
    async def get_tokens(self): return self._tokens
    async def set_tokens(self, tokens): self._tokens = tokens
    async def get_client_info(self): return self._client_info
    async def set_client_info(self, client_info): self._client_info = client_info
async def connect_with_auth(server_url, auth0_audience):
    """Connect to an authenticated MCP server."""
    client_metadata = OAuthClientMetadata.model_validate({
        "client_name": "MCP Auth0 Client",
        "redirect_uris": ["http://localhost:3030/callback"],
        "grant_types": ["authorization_code", "refresh_token"],
        "response_types": ["code"],
    })
    oauth_auth = OAuthClientProvider(
        server_url=server_url,
        client_metadata=client_metadata,
        storage=InMemoryTokenStorage(),
        redirect_handler=lambda url: webbrowser.open(url),
        callback_handler=wait_for_browser_callback,
    )
    async with streamablehttp_client(
        url=server_url,
        auth=oauth_auth,
        timeout=timedelta(seconds=60),
    ) as (read_stream, write_stream, get_session_id):
        async with ClientSession(read_stream, write_stream) as session:
            await session.initialize()
            # List available tools
            tools = await session.list_tools()
            for tool in tools.tools:
                print(f"  - {tool.name}: {tool.description}")
            # Invoke a tool
            result = await session.call_tool(
                "add_numbers", {"a": 2, "b": 2}
            )
            print(f"Result: {result.content[0].text}")

The OAuth flow happens automatically:

  1. The MCP SDK discovers Auth0’s endpoints from the discovery URL
  2. The client registers itself using DCR
  3. A browser window opens for user authentication
  4. The callback server captures the authorization code
  5. The SDK exchanges the code for a JWT access token
  6. All MCP requests include the JWT in the Authorization header

Test the authenticated MCP server

Step 7: Run the client

import mcp_auth0_client as mcp_client
agent_arn = launch_result.agent_arn
base_endpoint = f"https://bedrock-agentcore.{region}.amazonaws.com"
await mcp_client.main(agent_arn, base_endpoint, AUDIENCE)

The client connects, authenticates via browser, and invokes all three tools on the deployed server.

Step 8: Clean up

agentcore_runtime.destroy()

. . .

Reference

What’s next

  • Full MCP server end-to-end — Complete MCP server deployment with all production patterns
  • AgentCore Gateway — Route requests across multiple agents with the Gateway service
  • AgentCore Memory — Add short-term and long-term memory to your agents
  • AgentCore Observability — Monitor and trace agent executions in production

메타데이터
post_id
b7bb68ca4ac6
slug
mcp-dynamic-client-registration-with-auth0-on-amazon-bedrock-agentcore-runtime-b7bb68ca4ac6
url
https://medium.com/@thecraftman/mcp-dynamic-client-registration-with-auth0-on-amazon-bedrock-agentcore-runtime-b7bb68ca4ac6
canonical_url
https://medium.com/@thecraftman/mcp-dynamic-client-registration-with-auth0-on-amazon-bedrock-agentcore-runtime-b7bb68ca4ac6
author_url
https://medium.com/@thecraftman
status
ok
fetched_at
2026-06-09 15:37:30