Skip to content

feat(mcp): bearer-token auth for the MCP HTTP transport#41

Merged
hicksy merged 4 commits into
mainfrom
feat/mcp-http-auth
May 25, 2026
Merged

feat(mcp): bearer-token auth for the MCP HTTP transport#41
hicksy merged 4 commits into
mainfrom
feat/mcp-http-auth

Conversation

@hicksy

@hicksy hicksy commented May 25, 2026

Copy link
Copy Markdown
Member

Adds bearer-token authentication to the MCP HTTP transport, closing the direct-from-tooling gap the Host+Origin allowlist doesn't cover, plus a configurable bind host so the transport can be reached off-loopback.

Closes #27. Unblocks #24.

Auth model

  • Every /mcp request requires Authorization: Bearer <token>. Missing and wrong tokens return a byte-identical 401 (no oracle) with WWW-Authenticate: Bearer realm="dynoxide-mcp" and no resource_metadata. Constant-time compare.
  • Loopback with no token: generated on first run, persisted (~/.config/dynoxide/mcp-token, 0600), printed once with a client snippet; reused silently after.
  • Non-loopback bind requires an explicit token (--mcp-token/--token or DYNOXIDE_MCP_AUTH_TOKEN) or refuses to start.
  • --no-auth is a loopback-only escape hatch (prints a warning).
  • Auth runs outside rmcp's Host/Origin checks, so a token holder spoofing Host still gets 403.

Breaking

  • Library: mcp::serve_http / serve_http_with_shutdown now take HttpOptions instead of a bare port.
  • Users: dynoxide mcp --http clients must now send an Authorization header.

Test plan

  • cargo test, cargo clippy -- -D warnings, cargo fmt --check
  • cargo check --no-default-features --features encryption,http-server
  • Manual: no token -> 401, correct token -> 200, foreign Host + token -> 403

Post-deploy

Watch for sustained 401s from clients that are sending a valid token (failure signal); a transient bump as clients add the header is expected. Rollback if the auth layer rejects validly-tokened requests.

hicksy added 4 commits May 25, 2026 11:33
Every /mcp request now requires an Authorization: Bearer token. Loopback
binds auto-generate and persist a token on first run (printing client-config
guidance); non-loopback binds require an explicit token via --mcp-token/--token
or DYNOXIDE_MCP_AUTH_TOKEN. Also adds a configurable bind host (--mcp-host/--host)
and a Host-allowlist flag for by-name access. Closes #27, unblocks #24.
Update SECURITY.md's threat model for the bearer-token requirement, add
auth flags, client-header config, and rotation/shell-history guidance to the
README, and record the breaking change in the changelog.
The new HTTP-options helper landed between run_mcp's cfg attribute and its
signature, leaving run_mcp ungated and breaking the http-server-without-mcp
feature build.
Trim explicit tokens (consistent with the presented-token and persisted-file
paths), bracket IPv6 literals in operator-added Origin allowlist entries, fsync
the token file so a lost-create-race reader sees a complete token, and make the
token-source error messages subcommand-agnostic. Tolerate a tab after the
Bearer scheme, drop the unused HttpOptions::new, and consolidate IPv6 bracketing
into one helper. Adds tests: loopback still works alongside --allowed-host,
--no-auth+--token still fails off-loopback, and the rejected-token 401 body
matches the missing-token body. Documents the library-signature break and the
Windows token-file story.
@github-actions

Copy link
Copy Markdown

Criterion Benchmark Results

Benchmark Baseline (ns/iter) Current (ns/iter) Change
batch_get_item_100 1,363,787 1,404,852 +3.0%
batch_write_item_25 852,515 836,975 -1.8%
delete_item 42,670 44,147 +3.5%
get_item 13,813 14,402 +4.3%
put_item/put_item/large 298,912 305,720 +2.3%
put_item/put_item/medium 32,050 31,134 -2.9%
put_item/put_item/small 17,818 17,341 -2.7%
query_base_table 1,092,983 1,155,474 +5.7%
query_gsi 20,883 21,508 +3.0%
scan_with_filter 8,370,133 8,891,953 +6.2%
transact_write_items_4 196,331 193,761 -1.3%
update_item 153,438 198,220 +29.2%

All benchmarks within 50% of baseline.

@hicksy hicksy merged commit 036367c into main May 25, 2026
13 checks passed
@hicksy hicksy deleted the feat/mcp-http-auth branch May 25, 2026 12:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement authentication for MCP HTTP transport

1 participant