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.0.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.0-py3-none-any.whl (5.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: doorman_mcp-0.1.0.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.0.tar.gz
Algorithm Hash digest
SHA256 08897c91cbbb3b1a5cbf0379ae34a1480b44451e7a236eb1ef7fa8875b7d6e5a
MD5 74249ea18cd5fa7167d6d4c6d1f35e99
BLAKE2b-256 e5070becf9cb09f2f7ca7fc554a0d1bd81bb1d815a7d22e73d3dc1d200fb962e

See more details on using hashes here.

File details

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

File metadata

  • Download URL: doorman_mcp-0.1.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 579de949f1b0b6c7f14999672fa94ee074a729e63969cf36698b344fc2e4f818
MD5 03a8c842052a28282e07a5a58edf1c87
BLAKE2b-256 8e08462595b737f15736145fd8cad6fa88372b0fd1381ea463a8a21698199252

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