Skip to content

feat: add auth0-ai-mcp package - #171

Open
kishore7snehil wants to merge 7 commits into
mainfrom
feat/auth0-ai-mcp-package
Open

kishore7snehil wants to merge 7 commits into
mainfrom
feat/auth0-ai-mcp-package

Conversation

@kishore7snehil

@kishore7snehil kishore7snehil commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

📋 Changes

Adds auth0-ai-mcp, a library that secures Model Context Protocol (MCP) servers with Auth0. It is built on auth0-api-python and ships no MCP framework of its own, so each framework gets a thin adapter around it. Guides and a runnable example follow in separate PRs.

✨ Features

  • Verifies the bearer token on each request and builds the verified caller as a Principal.
  • Auth0AsgiMiddleware wraps any ASGI app. It answers 401 for a missing, malformed or invalid token and 503 when Auth0 cannot be reached, before the MCP handler runs. A bearer value with whitespace inside is rejected without calling Auth0. The 401 challenge carries scope when scopes_supported is set, and 401 and 503 responses send Cache-Control: no-store. It also serves protected resource metadata.
  • scopes_supported must be a list of single-value strings, otherwise ConfigurationError is raised at startup.
  • Request context accessors give tool code the verified caller and a request-scoped client that never exposes the raw token.
  • require_scopes and with_required_scopes gate tools on the caller's scopes.
  • Token exchange for downstream calls with On-Behalf-Of, client credentials and Token Vault, including downscope and expiry checks (a token with no usable expiry and one that is already expired raise separate messages), with an optional token_store for caching through the core SDK.
  • Organization policy options on create_mcp_client.
  • test.yml runs the tests and ruff on Python 3.10 to 3.14, and dependabot.yml gets a pip entry for the package.

🔧 API Changes

New public API exported from auth0_ai_mcp, with Auth0AsgiMiddleware imported from auth0_ai_mcp.middleware. Nothing existing changes.

📖 Documentation

Adds a short README.md and CONTRIBUTING.md. The guides and examples are added in follow-up PRs.

🧪 Testing

The package has 273 unit tests that stub the core client, so they need no Auth0 tenant. pytest, ruff check . and poetry build pass locally.

auth0-api-python is pinned to a commit SHA until the release that includes the token caching, malformed-token and client_info changes is published. This PR stays a draft until the pin is replaced with a released version.

  • This change adds unit test coverage
  • This change adds integration test coverage
  • This change has been tested on the latest version of the platform/language or why not

Contributor Checklist

@kishore7snehil
kishore7snehil marked this pull request as ready for review October 30, 2026 08:17
@kishore7snehil
kishore7snehil requested a review from a team as a code owner October 30, 2026 08:17
Comment thread packages/auth0-ai-mcp/README.md Resolved
Comment thread packages/auth0-ai-mcp/README.md Resolved
Comment thread .github/workflows/test.yml Resolved
nandan-bhat
nandan-bhat previously approved these changes Nov 3, 2026
Comment thread packages/auth0-ai-mcp/pyproject.toml Resolved
VerifyAccessTokenError: If the token is invalid, or is bound to a DPoP key or a client certificate (it has a `cnf` claim) and so cannot be used as a Bearer token.
AuthServerUnavailableError: If the OIDC discovery document or JWKS cannot be reached.
"""
claims = await self._api.verify_access_token(access_token=access_token)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This call doesn't pass request_url or request_headers, so a domains resolver on a prebuilt multi-domain api_client receives None for both. Separately, if the resolver fails, the middleware answers 503 with Retry-After rather than 401.

Is that intentional? In particular:

  • Is a request-aware resolver meant to be supported in this release?
  • Is 503 the expected response when the resolver fails, including for an unrecognized issuer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A request-aware domains resolver isn't supported in this release. A static multi-domain list works, create_mcp_client has no resolver option, and a resolver on a prebuilt api_client receives None for the URL and headers. The 503 only happens when the resolver itself fails (it raises or returns an invalid list). A token from an unrecognized issuer is a 401, because core raises VerifyAccessTokenError for it. We can add request context later if a real use case comes up.

- A bearer value with whitespace inside gets a 401 invalid_token without calling Auth0.
- 401 and 503 responses carry Cache-Control: no-store.
- An exchanged token with no usable expiry and one already expired now raise separate messages.
- scopes_supported must be a list of single-value strings, otherwise ConfigurationError is raised at startup.
- The mcp import fallback only applies when mcp is not installed, so a renamed class fails loudly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants