Skip to main content

One-line OAuth for self-hosted MCP servers. Fail-closed by default.

Project description

doorman

One-line OAuth for self-hosted MCP servers.

53% of self-hosted API services ship with static API keys. Only 8.5% implement proper OAuth. For MCP servers exposed to AI agents and human clients alike, that gap is not a configuration choice: it is a vulnerability. Doorman closes it in one line.


Before / After

Before: 28 lines of boilerplate every time

import os
from fastmcp import FastMCP
from fastmcp.server.auth.providers.github import GitHubProvider

mcp = FastMCP("My Server")

# Manually validate every required credential
client_id = os.environ.get("GITHUB_CLIENT_ID")
if not client_id:
    raise ValueError("GITHUB_CLIENT_ID is required")

client_secret = os.environ.get("GITHUB_CLIENT_SECRET")
if not client_secret:
    raise ValueError("GITHUB_CLIENT_SECRET is required")

jwt_secret = os.environ.get("DOORMAN_JWT_SECRET")
if not jwt_secret:
    raise ValueError("DOORMAN_JWT_SECRET is required")

mcp.auth = GitHubProvider(
    client_id=client_id,
    client_secret=client_secret,
    base_url=os.environ.get("DOORMAN_BASE_URL", "http://127.0.0.1:8000"),
    required_scopes=["read:user", "user:email"],
    allowed_client_redirect_uris=["http://localhost:*", "http://127.0.0.1:*"],
    jwt_signing_key=jwt_secret,
    require_authorization_consent=False,
)

After: one line

import doorman
doorman.protect(mcp, github=True)

Quickstart

1. Install

pip install doorman-mcp

2. Set environment variables

Generate a strong JWT secret:

python -c "import secrets; print(secrets.token_urlsafe(48))"

Then export all required variables for your shell:

macOS / Linux (bash/zsh):

export GITHUB_CLIENT_ID=your_client_id
export GITHUB_CLIENT_SECRET=your_client_secret
export DOORMAN_JWT_SECRET=paste_the_generated_secret_here
export DOORMAN_BASE_URL=http://127.0.0.1:8000

Windows (PowerShell):

$env:GITHUB_CLIENT_ID = "your_client_id"
$env:GITHUB_CLIENT_SECRET = "your_client_secret"
$env:DOORMAN_JWT_SECRET = "paste_the_generated_secret_here"
$env:DOORMAN_BASE_URL = "http://127.0.0.1:8000"

Variables set this way last only for the current terminal session. For real deployments use a secrets manager or a gitignored .env file; never commit credentials.

3. Create a GitHub OAuth App

In GitHub → Settings → Developer settings → OAuth Apps → New OAuth App:

  • Homepage URL: http://127.0.0.1:8000
  • Authorization callback URL: http://127.0.0.1:8000/auth/callback

4. Wire doorman into your server

from fastmcp import FastMCP
import doorman

mcp = FastMCP("My Server")
doorman.protect(mcp, github=True)

@mcp.tool()
def hello() -> str:
    return "authenticated!"

mcp.run()

5. Run and connect

python my_server.py

Any MCP client that supports OAuth 2.0 can now connect. The client is redirected to GitHub, authenticates, and receives a short-lived JWT: no static keys, no copy-paste credentials.


Fail-closed by design

Doorman's contract: if auth cannot be configured, the server refuses to start.

  • Missing GITHUB_CLIENT_ID? ValueError; the server does not start.
  • Missing DOORMAN_JWT_SECRET? ValueError; the server does not start.
  • No provider specified at all? ValueError; the server does not start.

There is exactly one escape hatch:

doorman.protect(mcp, allow_unauthenticated=True)

This emits a loud UserWarning and bypasses all auth. It is intended for local development only and must be opted into by name; you cannot accidentally end up in an unprotected state.


Built on FastMCP

Doorman is a thin configuration layer on top of FastMCP's first-class OAuth primitives. It does not replace or wrap FastMCP; it reads your environment, validates credentials, and calls GitHubProvider with safe defaults. All MCP protocol handling, session management, and transport concerns remain in FastMCP.


License

MIT: see LICENSE.

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

doorman_mcp-0.1.1.tar.gz (109.9 kB view details)

Uploaded Source

Built Distribution

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

doorman_mcp-0.1.1-py3-none-any.whl (5.3 kB view details)

Uploaded Python 3

File details

Details for the file doorman_mcp-0.1.1.tar.gz.

File metadata

  • Download URL: doorman_mcp-0.1.1.tar.gz
  • Upload date:
  • Size: 109.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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}

File hashes

Hashes for doorman_mcp-0.1.1.tar.gz
Algorithm Hash digest
SHA256 252b0c1c252fa60a6f5736147736fbcc83d421f85d2555e17a79bd39e129c03f
MD5 192ca318f6b9c26a6b9d55cc513bd62e
BLAKE2b-256 1807363b3ad4bba5c049e263d2ff1ec7cbfcf9a110558150490b538de426147e

See more details on using hashes here.

File details

Details for the file doorman_mcp-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: doorman_mcp-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 5.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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}

File hashes

Hashes for doorman_mcp-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a51c634ad3b8b0988c9b0946f5c5439b55c39126ea0e211363343ea1c220e533
MD5 dac1fcd0f8823f49d63a6b9c6346a1c4
BLAKE2b-256 dbe2628bb2fab2672d8150034cabb633e5a780419cea24ee619f2a3215ffef08

See more details on using hashes here.

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