Skip to main content
This page is the operator map for a self-hosted 3ngram. It explains what runs where, what to check after a deploy, and which operational guarantees are intentionally not promised before v1.0. Operations for the managed 3ngram platform are handled by the maintainers and are not covered in this repository.

Runtime topology

A 3ngram deployment is three 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_user role.
The public API reference describes the REST contract. The MCP tool reference describes each tool and its required scope.

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.
If Redis is unavailable, rate limiting fails open so the service keeps serving. Operators should treat repeated 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:
  1. Apply database migration 0027_cimd_clients.sql before starting the new server.
  2. Exercise one retained DCR client and one public CIMD+PKCE client through authorization, code exchange, refresh, and /mcp.
  3. Run the official-client contract tests for both legacy and 2026-07-28.
  4. Verify authorization-server metadata advertises client_id_metadata_document_supported: true while retaining registration_endpoint.
  5. Monitor OAuth invalid_client/metadata-fetch failures, protocol negotiation, and the bounded mcp.header_requests status labels during the soak.
Do not remove DCR during rollback or cleanup. Before CIMD grants are issued, the server can roll back without data cleanup; after issuance, retain a CIMD-capable binary so existing grants continue to resolve. Materialized client rows are foreign-key/display state and must not be treated as fetched-metadata authority.

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; worker packaging and self-host compose support are still follow-up work.

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.
  • Worker deployment packaging is not complete for self-host.