Runtime topology
A 3ngram deployment is four portable pieces:
Everything runs on stock Postgres and Redis, so deploy to whatever you already
operate: the bundled Compose stack on a single host, a PaaS such as Railway or
Fly.io, managed Postgres such as Neon or Supabase, or any Docker-compatible
runtime. The Self-host quickstart starts Postgres, Redis, and the
server with one command.
Deploy verification
After a server deploy, verify the health and OAuth discovery surfaces against your own base URL:Auth and access
3ngram is its own OAuth 2.1 authorization server and resource server.- MCP clients use Client ID Metadata Documents or dynamic registration fallback, PKCE, and OAuth bearer tokens.
- Scripts, CLI, and SDK integrations use API keys through
X-API-Key. - All user-owned database access is tenant-scoped through RLS and the runtime
app_userrole.
Rate limits
Production deployments require Redis for cross-instance limits. Local development can fall back to in-memory buckets, but that is not a production limit. Current limit dimensions are:- per-user on
/mcp; - per-IP on login and OAuth authorization-server endpoints;
- per API key/source on
/api/v1.
rate-limit: store unavailable warnings as a
degraded-protection incident.
Caching
3ngram does not use an application cache for memory data in v1. Postgres is the source of truth; Redis is not a memory cache. The MCP tool and prompt definitions are a separate, deployment-versioned catalog:2026-07-28 responses mark those
tenant-independent lists public-cacheable for one hour.
MCP 2026 compatibility rollout
Keep the migration on a dedicated compatibility track and promote it only after a staging soak:- Apply database migration
0027_cimd_clients.sqlbefore starting the new server. - Exercise one retained DCR client and one public CIMD+PKCE client through
authorization, code exchange, refresh, and
/mcp. - Run the official-client contract tests for both legacy and
2026-07-28. - Verify authorization-server metadata advertises
client_id_metadata_document_supported: truewhile retainingregistration_endpoint. - Monitor OAuth
invalid_client/metadata-fetch failures, protocol negotiation, and the boundedmcp.header_requestsstatus labels during the soak.
Scaling
The server is stateless across requests, so it can run as multiple replicas behind a load balancer once shared-state dependencies are healthy. Before scaling replicas, verify Redis is configured and Postgres connection pressure is acceptable. Database scaling is your Postgres provider’s operation. Background workers use BullMQ, ship as their own image (ghcr.io/b3dmar/3ngram-worker), and are part
of both Compose stacks (docker-compose.yml, compose.selfhost.yml).
Recovery
Use the smallest recovery action that matches the failure:
After recovery, rerun the deploy verification checks and one authenticated read
path before declaring the incident closed.
Current gaps
- Metrics counters are wired, but dashboards and alert policies are not complete.
- The session closer ships on the worker but stays
SESSION_CLOSER_ENABLED=falseuntil its commitment-recall validation bar is measured (see Session continuity); with it off the sweep scheduler is removed and closer jobs no-op, while consolidation, surfacing, and OAuth-client GC always run.