Skip to content

Architecture Note: Authorization

Alexey edited this page Jun 27, 2026 · 1 revision

Architecture Note: Authorization

Context

AI Agent --(transport: stdio | HTTP)--> gramps-web-mcp-rs --(auth)--> Gramps Web API

Authentication from the MCP server to Gramps Web uses Gramps Web's standard mechanism (username/password → JWT, auto-refreshed). One thing worth calling out explicitly: the credentials are held on the MCP side, not per-caller — so anyone who can reach the MCP server inherits whatever access that one Gramps Web account has. There's no per-agent identity once you're past the MCP boundary; the MCP server is the Gramps Web user.

This note is about the other boundary — AI agent → MCP server.

On stdio transport this isn't a network concern: the client launched the server as a subprocess, and the OS process boundary is the trust boundary.

On http transport, this only becomes a problem when the MCP endpoint is exposed beyond a private/local network — i.e. the case we're actually addressing here is a server with the MCP port reachable from the public internet, not a homelab box only reachable over LAN or VPN.

Problem

The MCP specification (2025-03-26 and later) treats any remote (HTTP) MCP server as an OAuth 2.1 resource server. The full model includes:

  • Protected Resource Metadata discovery (RFC 9728, /.well-known/oauth-protected-resource)
  • Authorization Server Metadata / OIDC discovery (RFC 8414)
  • Client registration (pre-registration, CIMD, or Dynamic Client Registration)
  • Authorization Code flow with mandatory PKCE (S256)
  • Resource Indicators (RFC 8707) to bind tokens to this specific server
  • Token validation, scope handling, step-up authorization on insufficient scope

This is the right model for a multi-tenant or enterprise MCP server, where many different users and clients need independently revocable, scoped access, and where an existing IdP (Okta, Entra, etc.) is the source of truth for identity. For a self-hosted, single-user genealogy server, this is significant machinery for no real benefit: one trusted operator, one (or a small, manually-managed set of) AI client(s), no multi-tenancy, no IdP to integrate with. Standing up a full Authorization Server to gate a personal Gramps tree is disproportionate to the actual threat model.

Decision

Use a static bearer token (MCP_AUTH_TOKEN) checked on every request to /mcp:

  • Generated once by the operator: openssl rand -hex 32 (256 bits of entropy)
  • Set as an environment variable on the server, given to the AI client as a header
  • If MCP_AUTH_TOKEN is unset (or empty), auth is disabled and a warning is logged — intended only for deployments already confined to a trusted network
  • Layered with MCP_ALLOWED_HOSTS (Host header allowlist) for basic DNS-rebinding protection, in line with the spec's Origin-validation guidance

It's functionally an API key: one shared secret, compared by equality, for the one deployment. Trade-off, made deliberately: this is not spec-compliant with MCP's mandated OAuth 2.1 model for internet-facing servers — it's a simplification for a use case the full spec wasn't designed around, shared by a large share of self-hosted MCP servers in practice. It should not be used beyond a single trusted operator's personal deployment.

See docs/setup-server.md for the full deployment walkthrough.

Clone this wiki locally