lane-mcp-auth
Lane sign-in for an MCP server, in Python. The TypeScript distribution is
@getonlane/mcp-auth.
What it does for your MCP server
- Lane sign-in for agents. Lane is your OAuth authorization server. The library verifies each bearer, serves the protected-resource document, and refuses every tool until the agent registers a session with your server.
- Scopes, guest tools and step-up. A tool names the scopes it needs. A guest calls your public read tools with no Lane account. A missing scope starts a new Lane sign-in.
- Purchases that a human approves. A priced tool answers with a proposal. The user approves the plan in their Lane wallet. Lane then calls the tool with an execution grant, and the library consumes each grant once.
- Plan step events. Lane tells your server what happened to each step it sold, so your server fulfils, frees stock or cancels.
- Telemetry. Lane records sign-ins and tool calls for your server, and
on_gate_eventgives you each gate decision in your own process.
Install
pip install "lane-mcp-auth[fastmcp]"
python -m lane_mcp_auth setup https://acme.com/mcp --name="Acme shop"
setup pairs your terminal with the Lane console and writes LANE_CLIENT_ID,
LANE_CLIENT_SECRET, LANE_VERIFICATION, LANE_RESOURCE and LANE_ISSUER
to .env. The [fastmcp] extra adds only the FastMCP adapter.
Example
One gated tool on FastMCP 4, served over HTTP. The store keeps connections in memory, so it is correct for one process only.
import os
from fastmcp import Context, FastMCP
from fastmcp.server.dependencies import get_http_request
from fastmcp.server.middleware import Middleware
from lane_mcp_auth import ConnectionKey, ConnectionRecord, HttpTokenExchanger, LaneMcpAuth
from lane_mcp_auth.fastmcp import CLAIMS_ATTR, enable_lane_auth, requires
from starlette.middleware import Middleware as AsgiMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response
class MemoryConnections:
def __init__(self) -> None:
self.rows: dict[tuple[str, str], ConnectionRecord] = {}
async def get(self, key: ConnectionKey) -> ConnectionRecord | None:
return self.rows.get((key.sub, key.client_id))
async def put(self, key: ConnectionKey, record: ConnectionRecord) -> ConnectionRecord:
self.rows[(key.sub, key.client_id)] = record
return record
auth = LaneMcpAuth(
resource=os.environ["LANE_RESOURCE"],
client_id=os.environ["LANE_CLIENT_ID"],
announce_secret=os.environ["LANE_CLIENT_SECRET"],
verification=os.environ.get("LANE_VERIFICATION"),
connections=MemoryConnections(),
exchanger=HttpTokenExchanger(
client_id=os.environ["LANE_CLIENT_ID"],
client_secret=os.environ["LANE_CLIENT_SECRET"],
),
)
mcp = FastMCP("acme")
class AttachLaneClaims(Middleware):
async def on_call_tool(self, context, call_next):
claims = get_http_request().state.lane_claims
setattr(context.fastmcp_context.request_context, CLAIMS_ATTR, claims)
return await call_next(context)
class VerifyLaneBearer(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
if request.url.path.startswith("/.well-known/"):
return await call_next(request)
header = request.headers.get("authorization", "")
claims = auth.authenticate(header.removeprefix("Bearer ").strip() or None)
if claims is None:
return Response(status_code=401, headers={"WWW-Authenticate": auth.challenge()})
request.state.lane_claims = claims
return await call_next(request)
mcp.add_middleware(AttachLaneClaims())
enable_lane_auth(mcp, auth)
@mcp.tool()
@requires("read")
async def order_history(ctx: Context) -> str:
return "two orders"
for path in filter(None, auth.metadata_paths()):
@mcp.custom_route(path, methods=["GET"])
async def lane_document(request) -> Response:
return Response(auth.protected_resource_document(), media_type="application/json")
app = mcp.http_app(middleware=[AsgiMiddleware(VerifyLaneBearer)])
Serve app with any ASGI server, for example uvicorn server:app. An agent
that calls order_history is told to call lane_register_session first.
After that call, the tool runs when the connection holds <your host>/read.
Documentation
Start with the quickstart.
- Overview: how the parts fit
- Connections: the store you supply, and what to run in production
- Scopes: Lane scopes, your scopes, guests and step-up
- Customize: staged rollout, guests, revocation, identity
- Charging for a purchase and plan step events
- Telemetry
- Auth library reference: every export, and where Python and TypeScript differ
Licence
MIT
Metadata
Release files for lane-mcp-auth 1.1.0
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 |
|---|---|---|---|---|
| lane_mcp_auth-1.1.0.tar.gz | 201.2 kB | With provenance | Details for lane_mcp_auth-1.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| lane_mcp_auth-1.1.0-py3-none-any.whl | Python 3 | none | any | Details for lane_mcp_auth-1.1.0-py3-none-any.whl |
Total release size: 252.5 kB
Release files / lane_mcp_auth-1.1.0.tar.gz
| Download URL | lane_mcp_auth-1.1.0.tar.gz |
|---|---|
| Size | 201.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e09f71c7fa0c820fb47388be3a90792c885e55a7378443c9fa019ffde20e7dda
|
|
BLAKE2b-256 checksum How to use checksums |
8acf029172141cd1c0bd47937345ea71e6499dc63ed1768e819fc6dcf3e01734
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / lane_mcp_auth-1.1.0-py3-none-any.whl
| Download URL | lane_mcp_auth-1.1.0-py3-none-any.whl |
|---|---|
| Size | 51.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0e7e8fc778ca494ffb30f02e0cbb3661b091c30f6d764b0152875c97b6a62ca5
|
|
BLAKE2b-256 checksum How to use checksums |
8c02cae273028e15caa0fa66e763a65d1225f2baeed297c7080f013d71b9d0a2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logSecurity for lane-mcp-auth 1.1.0
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for lane_mcp_auth-1.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logA 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.