Skip to main content

Levante OAuth provider for MCP servers (framework-agnostic core + adapters).

Project description

levante-mcp-sdk

OAuth provider for FastMCP servers deployed through Levante. It wraps your MCP server with a RemoteAuthProvider that validates Levante-issued tokens: it verifies the JWT locally against Levante's JWKS and confirms the grant/membership via Levante's introspection endpoint (/api/v1/mcp/introspect), with a short-lived in-memory cache.

Part of the sdks-levante repository. The TypeScript SDK (@levante/mcp-sdk) will live in packages/mcp-sdk/ of the same repo.

Install

pip install levante-mcp-sdk                 # núcleo (solo cliente de introspección)
pip install "levante-mcp-sdk[mcp]"          # + adaptador SDK oficial de Anthropic (mcp)
pip install "levante-mcp-sdk[fastmcp]"      # + adaptador FastMCP v2 (standalone)
pip install "levante-mcp-sdk[jwt]"          # + verificación JWT local

Requires Python >=3.11. The core depends only on httpx; each framework is an optional extra.

Uso con el SDK oficial (mcp.server.fastmcp.FastMCP)

from mcp.server.auth.settings import AuthSettings
from mcp.server.fastmcp import FastMCP
from pydantic import AnyHttpUrl
from levante_mcp_sdk import LevanteConfig
from levante_mcp_sdk.integrations.mcp import LevanteTokenVerifier

cfg = LevanteConfig.from_env()
mcp = FastMCP(
    "my-mcp",
    token_verifier=LevanteTokenVerifier(cfg),
    auth=AuthSettings(
        issuer_url=AnyHttpUrl(cfg.issuer),
        resource_server_url=AnyHttpUrl(cfg.resource),
    ),
)

Uso con FastMCP v2 (standalone)

from fastmcp import FastMCP
from levante_mcp_sdk import LevanteAuthProvider

mcp = FastMCP(name="my-mcp", auth=LevanteAuthProvider.from_env())

LevanteAuthProvider.from_env() reads its configuration from environment variables. When the MCP is deployed through Levante with a levante.yaml, these are injected automatically; you can also set them manually for local development.

Configuration (environment variables)

A typical deployment only needs two variables: LEVANTE_API_KEY and LEVANTE_MCP_RESOURCE. The issuer defaults to the production platform URL, and the introspection endpoint is derived from it ({issuer}/api/v1/mcp/introspect). The remaining variables exist as overrides.

Variable Required Description
LEVANTE_API_KEY yes A real Levante API key (lv_sk_*) the MCP uses to authenticate against /introspect.
LEVANTE_MCP_RESOURCE yes Resource/audience for this MCP — its own public URL.
LEVANTE_ISSUER no (defaults to https://platform.levanteapp.com) OAuth issuer / platform URL. Override for local/staging.
LEVANTE_INTROSPECT_URL no (derived from issuer) Override the introspection endpoint if it isn't {issuer}/api/v1/mcp/introspect.
LEVANTE_JWKS_URI no (only [fastmcp]/[jwt]) JWKS URI for local JWT verification. Not used by the introspection-only path.
LEVANTE_MCP_BASE_URL no (defaults to resource, only [fastmcp]) RemoteAuthProvider base URL.
LEVANTE_REQUIRE_ORG_MEMBERSHIP no (true) If true, denies tokens whose user is no longer an org member.
LEVANTE_FAIL_OPEN no (false) If true, allows requests when introspection is unreachable. Leave false in production.
LEVANTE_CACHE_TTL_SECONDS no (45) TTL of the in-memory introspection cache.

Minimal example:

LEVANTE_API_KEY=lv_sk_...
LEVANTE_MCP_RESOURCE=https://crm-conquer.example.run.app
# Optional override (defaults to https://platform.levanteapp.com):
# LEVANTE_ISSUER=https://staging.levanteapp.com

LEVANTE_API_KEY must be a real key registered in Levante; it cannot be an arbitrary string.

Future enhancement: LEVANTE_JWKS_URI could be auto-discovered via GET {issuer}/.well-known/oauth-authorization-server (which returns jwks_uri). This is deliberately not done at startup to avoid a network call; the introspection-only path needs no JWKS at all.

How it works

  1. JWT verification (local, offline): the bearer token is verified against LEVANTE_JWKS_URI with the expected issuer and audience.
  2. Introspection (cached): the token is checked against LEVANTE_INTROSPECT_URL, which returns whether the grant is active and whether the user is still an org member.
  3. Membership gate: with LEVANTE_REQUIRE_ORG_MEMBERSHIP=true, a non-member is denied even if the JWT is otherwise valid.
  4. On success, Levante identity is attached to the token claims: levante_user_id, levante_org_id, levante_mcp_slug.

Revocations may take up to LEVANTE_CACHE_TTL_SECONDS to take effect on each running instance.

Build

uv build
uv run twine check dist/*

Publishing to PyPI is automated via .github/workflows/publish-python.yml on GitHub release: it checks the tag matches pyproject.toml's version and runs ruff + mypy + pytest + twine before publishing.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

levante_mcp_sdk-0.3.0.tar.gz (109.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

levante_mcp_sdk-0.3.0-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file levante_mcp_sdk-0.3.0.tar.gz.

File metadata

  • Download URL: levante_mcp_sdk-0.3.0.tar.gz
  • Upload date:
  • Size: 109.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for levante_mcp_sdk-0.3.0.tar.gz
Algorithm Hash digest
SHA256 ee64f73144e86327f4b5cdb4ce593af7fe4c77e48171b32e53f3374bafb045a5
MD5 4df1953b0898a8a07968b0a3dfbee95b
BLAKE2b-256 9e029e4bcb4669f34c11312800d54aa37df1ee94b8620a1df99c82783ae4404d

See more details on using hashes here.

Provenance

The following attestation bundles were made for levante_mcp_sdk-0.3.0.tar.gz:

Publisher: publish-python.yml on levante-hub/SDKS-Levante

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file levante_mcp_sdk-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for levante_mcp_sdk-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ca4888194caea6b08aaf6bb4fb306a32c0c441ebb4abc371fece14d173e36975
MD5 a14ce8165b16bbc157ee160a2f61996b
BLAKE2b-256 f3e240ccfff43645f92e0e825e9a2f747ce617d62fd298bdd878a3c529cfac2a

See more details on using hashes here.

Provenance

The following attestation bundles were made for levante_mcp_sdk-0.3.0-py3-none-any.whl:

Publisher: publish-python.yml on levante-hub/SDKS-Levante

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page