Authdog

MCP SDK: Python

Last updated Oct 13, 2026
View as Markdown

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/python

Once a release is published, the README gives:

pip install authdog-mcp

Configure

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: ...)