keycardai-fastmcp
FastMCP integration for Keycard OAuth: protect FastMCP servers with Keycard authentication and run delegated OAuth 2.0 token exchange (RFC 8693) for downstream APIs.
This is the canonical home for the integration. The old name,
keycardai-mcp-fastmcp, is retired; its final release (0.21.0) remains on
PyPI so existing pins keep resolving.
Installation
pip install keycardai-fastmcp
Quick Start
from fastmcp import FastMCP
from keycardai.fastmcp import AccessContext, AuthProvider
auth_provider = AuthProvider(
zone_id="abc1234",
mcp_server_name="My Server",
mcp_base_url="http://localhost:8000",
)
mcp = FastMCP("My Server", auth=auth_provider.get_remote_auth_provider())
@mcp.tool()
async def call_external_api(
query: str,
access: AccessContext = auth_provider.grant("https://api.example.com"),
):
token = access.access("https://api.example.com").access_token
return f"Results for {query} (token starts with {token[:8]})"
Declaring the grant as a typed parameter default injects the populated
AccessContext per request; the parameter never appears in the tool's input
schema. Exchange failures are recorded on the AccessContext (check
access.has_errors() / access.get_errors()), never raised. Granting
multiple resources is all-or-nothing: if any exchange fails, the context
carries that resource's error and no tokens.
If you lint with flake8-bugbear or Ruff's B008 rule (function call in
argument default), exempt your tool modules: the call-in-default is the
intended spelling here, the same pattern as FastAPI's Depends. In
pyproject.toml:
[tool.ruff.lint.per-file-ignores]
"src/my_server/tools/*.py" = ["B008"]
Migrating from the decorator form
The decorator form (@auth_provider.grant(...) above the tool) still works
from the same object. Reading the result via ctx.get_state("keycardai") is
deprecated and emits a DeprecationWarning; helpers that only hold the
FastMCP Context can use await AccessContext.from_context(ctx) instead.
The warning fires once per tool, at decoration time (module import). If your
test or CI setup escalates warnings to errors (-W error,
filterwarnings = ["error"] in pytest config), importing a server module
that still uses the old form will raise instead of warn. Either migrate the
tools to the injected-parameter form, or allow this warning explicitly:
filterwarnings = ["error", 'default:Tool .* uses the grant decorator:DeprecationWarning']
Configuration from the environment
AuthProvider reads its zone and application credential from the environment
when they are not passed explicitly.
Zone: set KEYCARD_ZONE_URL to the full zone URL. KEYCARD_ZONE_ID and
KEYCARD_BASE_URL still work but emit a DeprecationWarning; migrate as
follows:
| Deprecated | Canonical replacement |
|---|---|
KEYCARD_ZONE_ID="abc1234" |
KEYCARD_ZONE_URL="https://abc1234.keycard.cloud" |
KEYCARD_ZONE_ID="abc1234" + KEYCARD_BASE_URL="https://custom.example.com" |
KEYCARD_ZONE_URL="https://abc1234.custom.example.com" |
Application credential: discovery is delegated to
keycardai.oauth.server.discover_credential. KEYCARD_APPLICATION_CREDENTIAL_TYPE
selects client_secret, workload_identity or web_identity
(eks_workload_identity is accepted as a legacy alias). Without a selector,
exactly one source may be configured: KEYCARD_CLIENT_ID +
KEYCARD_CLIENT_SECRET, an injected workload token file
(AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE, AWS_WEB_IDENTITY_TOKEN_FILE,
AZURE_FEDERATED_TOKEN_FILE or KEYCARD_EKS_WORKLOAD_IDENTITY_TOKEN_FILE), or
KEYCARD_WEB_IDENTITY_KEY_STORAGE_DIR. More than one source with no selector
fails at startup with an ambiguity error naming the selector as the remedy.
Testing
Fake delegated access without patching internals:
from keycardai.fastmcp.testing import mock_access_context
with mock_access_context(access_token="fake_token"):
... # grants resolve to an AccessContext serving fake_token
The bare access_token form serves the token for any resource, so it will
not catch a mistyped resource URL in an access(...) call. Pass
resource_tokens={...} when the test should enforce which resources the
tool reads; resources outside the dict raise ResourceAccessError, matching
production.
Migration from keycardai-mcp-fastmcp
The keycardai-mcp-fastmcp package is retired. Its final release, 0.21.0,
stays on PyPI so existing pins keep resolving: from keycardai.mcp.integrations.fastmcp import AuthProvider emits a
DeprecationWarning pointing here and returns the same class. New code
should depend on keycardai-fastmcp and import from keycardai.fastmcp.
Metadata
Release files for keycardai-fastmcp 0.7.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| keycardai_fastmcp-0.7.2.tar.gz | 166.4 kB | Without provenance | Details for keycardai_fastmcp-0.7.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| keycardai_fastmcp-0.7.2-py3-none-any.whl | Python 3 | none | any | Details for keycardai_fastmcp-0.7.2-py3-none-any.whl |
Total release size: 189.4 kB
Release files / keycardai_fastmcp-0.7.2.tar.gz
| Download URL | keycardai_fastmcp-0.7.2.tar.gz |
|---|---|
| Size | 166.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
32aa8cc0671e924d5a822154ce31a4c0d78357e58710c3a18ddcb14bcd292ee6
|
|
BLAKE2b-256 checksum How to use checksums |
808f278e8ce664a92eb262171019b725ca76c43990d7fda483a47ce479acc0d0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / keycardai_fastmcp-0.7.2-py3-none-any.whl
| Download URL | keycardai_fastmcp-0.7.2-py3-none-any.whl |
|---|---|
| Size | 23.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f2334958d28a34319292dad025b19977996bb0661c6b6c1963b3f68cd766c553
|
|
BLAKE2b-256 checksum How to use checksums |
b40f8f732953c262f0071df6b963e9fffc9a60c24033d199751aa8d72eced070
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for keycardai-fastmcp 0.7.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.