How to Configure Bearer Token Authentication for streamable-http Transport in MCP OpenStack Ops
Bearer token authentication in streamable-http mode is configured via CLI flags (--auth-enable, --secret-key) or environment variables (REMOTE_AUTH_ENABLE, REMOTE_SECRET_KEY), which instantiate a StaticTokenVerifier that validates the Authorization: Bearer <token> header on every HTTP request.
The MCP OpenStack Ops server supports two transport modes: the default stdio for local execution and streamable-http for network-accessible endpoints. When operating in streamable-http mode, enabling bearer token authentication ensures that only requests with valid credentials can access OpenStack operations. This guide explains how the authentication system is architected, configured, and enforced according to the source code in src/mcp_openstack_ops/mcp_main.py.
Understanding the Authentication Architecture
Core Components
The authentication stack relies on three primary components implemented in src/mcp_openstack_ops/mcp_main.py:
StaticTokenVerifier(imported fromfastmcp): A class that maintains a static mapping of secret keys to token metadata (client ID and scopes). It validates incoming Bearer tokens against this mapping._build_static_token_auth(): A factory function (lines 61‑68) that constructs theStaticTokenVerifierusing the user-supplied secret key.- MCP instance wiring: The
mcp.authattribute is assigned the verifier instance (lines 98‑101), enabling thefastmcpframework to automatically enforce authentication on HTTP routes.
Configuration Sources
Authentication parameters can be supplied through two mutually supportive channels:
-
Command-line arguments defined in lines 28‑44:
--auth-enable/--auth-disable(mutually exclusive flags)--secret-key <KEY>(required when auth is enabled)
-
Environment variables processed in lines 78‑82:
REMOTE_AUTH_ENABLE(boolean string:true/false)REMOTE_SECRET_KEY(the secret key string)
The configuration parser prioritizes CLI flags over environment variables, falling back to env vars only when CLI arguments are omitted.
Step-by-Step Configuration Flow
1. Parsing and Validation
When the server initializes, the main() function evaluates the transport type and authentication settings (lines 84‑95). For streamable-http transport, the logic enforces the following constraints:
- If
--auth-enableis set but--secret-keyis empty, the server logs an error and exits immediately. - If authentication is disabled for
streamable-http, a warning is emitted alerting the operator that the endpoint is unprotected.
if transport_type == "streamable-http":
if auth_enable:
if not secret_key:
logger.error("ERROR: Authentication is enabled but no secret key provided.")
return
logger.info("Authentication enabled for streamable-http transport")
else:
logger.warning("WARNING: streamable-http mode without authentication enabled!")
2. Building the Token Verifier
When authentication is enabled, the _build_static_token_auth() function (lines 61‑68) creates a StaticTokenVerifier instance. This verifier maps the secret key to a token payload containing a client ID and scopes:
def _build_static_token_auth(secret_key: str) -> StaticTokenVerifier:
tokens = {
secret_key: {
"client_id": "openstack-ops-client",
"scopes": ["read", "write"],
}
}
return StaticTokenVerifier(tokens=tokens)
3. Wiring into the MCP Instance
Before starting the server, the code assigns the verifier to the mcp.auth attribute (lines 98‑101). This integration point allows the fastmcp framework to intercept incoming HTTP requests and validate the Authorization header:
if auth_enable:
mcp.auth = _build_static_token_auth(secret_key)
else:
mcp.auth = None
4. Server Startup and Enforcement
Finally, the server starts with the streamable-http transport (lines 104‑106). If mcp.auth is set, every request must include a valid Bearer token:
if transport_type == "streamable-http":
mcp.run(transport="streamable-http", host=host, port=port)
Requests presenting an invalid or missing token receive a 401 Unauthorized response from the underlying fastmcp library.
Practical Configuration Examples
Starting the Server with CLI Authentication
Enable bearer token authentication by providing both the enable flag and a secret key:
python -m mcp_openstack_ops \
--type streamable-http \
--host 0.0.0.0 \
--port 8080 \
--auth-enable \
--secret-key mySuperSecretKey123
Configuring via Environment Variables
For containerized deployments, use environment variables instead of CLI flags:
export FASTMCP_TYPE=streamable-http
export FASTMCP_HOST=0.0.0.0
export FASTMCP_PORT=8080
export REMOTE_AUTH_ENABLE=true
export REMOTE_SECRET_KEY=mySuperSecretKey123
python -m mcp_openstack_ops
Making Authenticated Requests
When authentication is enabled, clients must include the Bearer token in the Authorization header. The token value is exactly the secret key configured at startup:
import requests
url = "http://localhost:8080/v1/openstack/instances"
headers = {"Authorization": "Bearer mySuperSecretKey123"}
response = requests.get(url, headers=headers)
print(response.status_code) # 200 if valid
print(response.json())
Handling Unauthenticated Requests
Requests without the Authorization header are rejected with 401 Unauthorized:
import requests
url = "http://localhost:8080/v1/openstack/instances"
response = requests.get(url) # No headers
print(response.status_code) # 401
Security Behavior Matrix
The following table summarizes the runtime behavior based on configuration choices:
| Configuration | Transport | Authentication State | Behavior |
|---|---|---|---|
--type streamable-http --auth-enable --secret-key <key> |
streamable-http | Enabled | Server requires Authorization: Bearer <key> on all requests; invalid/missing tokens return 401. |
--type streamable-http (no auth flags) |
streamable-http | Disabled | Server starts with warning; accepts all requests without token validation. |
--type stdio |
stdio | N/A | Authentication flags ignored; local transport has no network exposure. |
Summary
- Bearer token authentication for
streamable-httptransport is implemented usingfastmcp'sStaticTokenVerifierclass, configured insrc/mcp_openstack_ops/mcp_main.py. - Configuration occurs via CLI flags (
--auth-enable,--secret-key) or environment variables (REMOTE_AUTH_ENABLE,REMOTE_SECRET_KEY), with CLI taking precedence. - The
_build_static_token_auth()function creates a static mapping of the secret key to client metadata, which is assigned tomcp.authbefore server startup. - When enabled, the server requires an
Authorization: Bearer <token>header on every HTTP request, rejecting unauthenticated calls with a 401 response. - The
stdiotransport mode ignores authentication settings entirely, as it operates locally without network exposure.
Frequently Asked Questions
How do I enable bearer token authentication without using CLI arguments?
Set the environment variables REMOTE_AUTH_ENABLE=true and REMOTE_SECRET_KEY=your_secret_key before starting the server. The application checks these variables when CLI flags are omitted, as implemented in lines 78‑82 of src/mcp_openstack_ops/mcp_main.py.
What happens if I enable authentication but forget to provide a secret key?
The server detects this configuration error during startup (lines 84‑95) and exits immediately with an error message: "ERROR: Authentication is enabled but no secret key provided." This prevents the server from running in an insecure state where authentication is expected but cannot be validated.
Is bearer token authentication available in stdio transport mode?
No. The authentication system is only relevant for the streamable-http transport. When running with --type stdio (the default), the server operates locally via standard input/output, and the mcp.auth attribute is ignored by the transport layer. The code explicitly only validates auth configuration when transport_type == "streamable-http".
What is the format of the required Authorization header?
Clients must send the header Authorization: Bearer <token>, where <token> is the exact string provided via --secret-key or REMOTE_SECRET_KEY. The StaticTokenVerifier from the fastmcp library performs an exact string match against the configured secret; there is no JWT decoding or asymmetric signature verification in this implementation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →