Epistemedia

Public API and MCP deployment contract

Source content

Public API and MCP deployment contract

The API and MCP gateway is a read-only projection service. It receives an accepted repository snapshot and exposes no GitHub, contribution, deployment, package-publishing, signing, or arbitrary network-fetch authority.

Local conformance does not mean the production endpoints are live. A provider deployment becomes public state only after external HTTPS read-back records its URL, accepted commit, catalog, frontier, policies, compiler, content digest, limits, and smoke-test results.

Application limits

The gateway enforces the following defaults. A deployment may lower them, but must not raise them without a recorded resource review.

| Environment variable | Default | Enforcement |
| --- | ---: | --- |
| `EPISTEMEDIA_MAX_BODY_BYTES` | `1048576` | Rejects an oversized declared or streamed request body with HTTP 413 |
| `EPISTEMEDIA_MAX_QUERY_BYTES` | `8192` | Rejects an oversized query string with HTTP 414 |
| `EPISTEMEDIA_MAX_RESPONSE_BYTES` | `8388608` | Fails closed before emitting a response larger than the configured bound |
| `EPISTEMEDIA_RATE_LIMIT_PER_MINUTE` | `120` | Sliding-window, per-client-address limit in the single gateway process |
| `EPISTEMEDIA_REQUEST_TIMEOUT_SECONDS` | `15` | Stops waiting for application dispatch and returns HTTP 504 |
| `EPISTEMEDIA_ALLOWED_ORIGINS` | canonical site, `www`, and local loopback origins | Comma-separated exact origins; untrusted MCP Origins receive HTTP 403 before body consumption |

The in-process rate limit is defense in depth, not a distributed quota. The deployment edge must enforce the same or a stricter anonymous limit across replicas and must pass a trustworthy client address. Provider request-body, concurrency, idle-timeout, and response-size settings must be no weaker than the application limits. Record their provider object IDs and observed response headers in the production receipt.

The container starts one unprivileged Uvicorn process with a concurrency limit of 100, backlog of 128, and a five-second keep-alive timeout. The reference Compose service also caps memory, CPU, and process count. Production may use stricter values after load testing.

MCP 2026-07-28

/mcp implements the stateless 2026-07-28 Streamable HTTP binding:

The local stdio adapter uses the same modern request metadata and read-only method implementation without HTTP headers.

Deployment environment

The minimum runtime environment is:

EPISTEMEDIA_ROOT=/app
EPISTEMEDIA_MAX_BODY_BYTES=1048576
EPISTEMEDIA_MAX_QUERY_BYTES=8192
EPISTEMEDIA_MAX_RESPONSE_BYTES=8388608
EPISTEMEDIA_RATE_LIMIT_PER_MINUTE=120
EPISTEMEDIA_REQUEST_TIMEOUT_SECONDS=15
EPISTEMEDIA_ALLOWED_ORIGINS=https://epistemedia.org,https://www.epistemedia.org

No secret is required for anonymous reads. Do not add repository tokens, publisher credentials, DNS credentials, or contribution authority to this service.

Container build identity

The image deliberately excludes .git, developer environments, caches, local

realms, secret-shaped files, and disposable projections from its build

context. Production builds therefore require two public, immutable build

arguments:

EPISTEMEDIA_ACCEPTED_COMMIT=<exact 40-character lowercase release commit>
SOURCE_DATE_EPOCH=<that commit's non-negative Unix timestamp>

The protected container workflow derives both values from the verified release

tag after confirming that its commit is reachable from main. The Dockerfile

rejects missing or malformed values before installing or compiling the public

projection. At runtime, Git metadata is absent and the gateway uses these

validated values to preserve the accepted commit and deterministic source time.

They are public identity metadata, not credentials.

For a local smoke build from an accepted checkout, derive and pass them

explicitly:

export EPISTEMEDIA_ACCEPTED_COMMIT="$(git rev-parse HEAD)"
export SOURCE_DATE_EPOCH="$(git show -s --format=%ct HEAD)"
docker compose build gateway
docker compose up gateway

Do not use unknown, a branch name, an abbreviated hash, or the wall clock for

a release image. A successful local build remains local evidence until its

HTTP endpoints and manifest identity pass the external smoke contract.

Required external smoke checks

After deployment, run the routes in ops/hosting/production-smoke.md and additionally verify: