AuthdogVerifier from the authdog_mcp package verifies the bearer token an MCP client presents to your Python MCP server. It calls GET {base_url}/v1/userinfo with the token and returns an AuthInfo dataclass. Source is `python/` in authdog/mcp-sdk. It depends on requests>=2.28.0; setup.py declares python_requires>=3.8.
Availability
This package is source-available in github.com/authdog/mcp-sdk and may not resolve from registries yet. At the time of writing authdog-mcp returns 404 on PyPI, and the repository has no release tags. Version is 0.1.0. Install from source until a release is published.
Install
From source:
pip install "git+https://github.com/authdog/mcp-sdk.git#subdirectory=python"Or from a local clone:
git clone https://github.com/authdog/mcp-sdk.git
pip install ./mcp-sdk/pythonOnce a release is published, the README gives:
pip install authdog-mcpConfigure
from authdog_mcp import AuthdogVerifier
verifier = AuthdogVerifier(base_url="https://api.authdog.com", timeout=10.0)| Argument | Type | Default | Behavior |
|---|---|---|---|
base_url |
str |
required | Authdog API base URL. Trailing slashes are stripped. Not validated for emptiness. |
timeout |
float |
10.0 |
Request timeout in seconds, passed to requests.get. |
Each request sends Authorization: Bearer <token> and User-Agent: authdog-mcp-python-sdk/0.1.0.
Verify a token
from authdog_mcp import AuthdogVerifier, AuthenticationError, APIError
verifier = AuthdogVerifier(base_url="https://api.authdog.com")
try:
info = verifier.verify_token("incoming-access-token")
print(f"Subject: {info.subject}")
print(f"Username: {info.username}")
print(f"Email: {info.email}")
print(f"Expires: {info.expires_at}")
except AuthenticationError as e:
print(f"Authentication failed: {e}")
except APIError as e:
print(f"API error: {e}")verify_token(access_token: str) -> AuthInfo is synchronous and blocking (it uses requests). It does not pre-check for an empty token; an empty string is sent and the server decides.
AuthInfo is a dataclass:
| Field | Type | Value |
|---|---|---|
token |
str |
The token you passed in |
subject |
str |
user.id |
username |
str |
user.userName |
email |
Optional[str] |
First non-empty emails[].value, or None |
scopes |
List[str] |
Always [] |
expires_at |
Optional[datetime] |
UTC time, now plus session.remainingSeconds; None only when that key is absent or null |
user |
dict |
Raw user object from the response |
scopes is empty because the userinfo endpoint does not return scopes; the SDK hard-codes []. Do not use it for scope-based authorization. Authentication identifies the caller; apply authorization separately.
If a 2xx response has no user, the SDK does not raise: subject and username are None. Check info.subject before trusting the result if you need that guarantee.
Wire into an MCP server
The MCP Python SDK authenticates requests through a TokenVerifier. Adapt AuthdogVerifier to it:
from mcp.server.auth.provider import AccessToken, TokenVerifier
from authdog_mcp import AuthdogVerifier, AuthdogError
authdog = AuthdogVerifier(base_url="https://api.authdog.com")
class AuthdogTokenVerifier(TokenVerifier):
async def verify_token(self, token: str) -> AccessToken | None:
try:
info = authdog.verify_token(token)
except AuthdogError:
return None # invalid token or upstream failure -> unauthenticated
return AccessToken(
token=info.token,
client_id=info.subject,
scopes=info.scopes,
expires_at=(
int(info.expires_at.timestamp()) if info.expires_at else None
),
)
# Pass the verifier to your FastMCP / MCP server's auth configuration.Two notes on this example. The AccessToken | None annotation needs Python 3.10 or newer (or from __future__ import annotations), even though the SDK itself declares 3.8. And authdog.verify_token blocks the event loop inside an async def; for high concurrency, run it with asyncio.to_thread.
Errors
Exported from authdog_mcp, all extending Exception:
| Class | Raised when |
|---|---|
AuthdogError |
Base class for the others |
AuthenticationError |
HTTP 401 (Unauthorized - invalid or expired token) |
APIError |
requests failure or timeout (Request failed: ...), other non-2xx (HTTP error <status>: <body>), or a non-JSON body (Invalid JSON response: ...) |
Related
- MCP SDK: language overview
- MCP authentication: how MCP clients obtain tokens
- Node.js and Go verifiers