Skip to content

feat(mcp): authenticated HTTP transport for remote serving - #10

Merged
cunicopia-dev merged 1 commit into
mainfrom
feat/authenticated-http-transport
Jun 27, 2026
Merged

cunicopia-dev merged 1 commit into
mainfrom
feat/authenticated-http-transport

Conversation

@cunicopia-dev

Copy link
Copy Markdown
Owner

What

Adds first-class, opt-in remote serving for the MCP server. Until now kg serve could only be reached as a local stdio pipe; now the same engine and the same file can be served to other machines over the HTTP transports — with zero new dependencies.

Changes

  • --host / --port — bind address for the HTTP transports. Default stays 127.0.0.1:8000 (localhost only); widening the bind is always a deliberate opt-in.
  • KGRDBMS_MCP_TOKEN — when set, the streamable-http/sse transports require Authorization: Bearer <token>. The check is a ~15-line pure-ASGI wrapper using only the stdlib (hmac.compare_digest) over the uvicorn/starlette that the [mcp] extra already installs. The token is read from the environment, never a flag, so it stays out of shell history and the process list.
  • --allow-host — declares the Host header values clients connect by. The MCP transport turns on DNS-rebinding protection with a localhost-only allowlist by default, which would 421 every off-localhost client; this rebuilds the allowlist for the actual bind (bind host + localhost always allowed; host:* wildcard matches any port; * disables checking for proxy-fronted setups).

Philosophy fit

  • Zero new dependency. Everything rides on what [mcp] already pulls in; the core stays dependencies = [].
  • Purely additive. With no flags and no token, kg serve is byte-for-byte the same stdio server. HTTP is a --transport choice.
  • Layered like the rest. Auth governs the connection; the existing invariants + policy gate still governs what a connected client may change.

Tests

Adds coverage for the bearer wrapper (401 missing / 401 wrong / pass-through / lifespan passthrough) and the host allowlist (bind+localhost included; * disables). Full suite green (129 passed).

Docs

New README subsection "Serving remotely (authenticated)" with the kg serve --transport streamable-http recipe and client config.

🤖 Generated with Claude Code

`kg serve` could only be reached as a local stdio pipe. Add first-class,
opt-in remote serving over the HTTP transports with zero new dependencies.

- `--host` / `--port`: bind address for the HTTP transports (default
  127.0.0.1 — localhost only; widening the bind is a deliberate opt-in).
- `KGRDBMS_MCP_TOKEN` env var: when set, streamable-http/sse require an
  `Authorization: Bearer <token>` header. The check is a small pure-ASGI
  wrapper using only the stdlib (`hmac.compare_digest`) over the
  uvicorn/starlette already pulled in by the `[mcp]` extra — no new dep, and
  the token is read from the environment, never a flag.
- `--allow-host`: declares the Host header values clients connect by. The MCP
  transport enables DNS-rebinding protection with a localhost-only allowlist
  by default, which would 421 every off-localhost client; this rebuilds the
  allowlist for the real bind (bind host + localhost always allowed; `*`
  disables checking for proxy-fronted setups).

stdio is unchanged: with no flags and no token, behavior is byte-for-byte
identical. Auth governs the connection; the invariants + policy gate still
governs what a connected client may change. Adds tests for the bearer wrapper
and the host allowlist; documents it under "Serving remotely (authenticated)".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cunicopia-dev
cunicopia-dev merged commit c0ede4b into main Jun 27, 2026
4 checks passed
@cunicopia-dev
cunicopia-dev deleted the feat/authenticated-http-transport branch June 27, 2026 17:24
cunicopia-dev added a commit that referenced this pull request Jun 27, 2026
Authenticated HTTP transport for remote serving (--host/--port/--allow-host,
KGRDBMS_MCP_TOKEN bearer auth; zero new deps; stdio unchanged). See #10.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant