Configuration Reference

VariableDescriptionDefault
CONTENT_REPOGit URL or local path to the content repo. Defaults to ../carapace-content (local sibling checkout) if unset — fine for local dev, required (a real URL) for the Cloudflare Pages build, which can't see a local path. Also set this as a Cloudflare Pages project environment variable for the deployed build, not just here for local dev.(unset)
CONTENT_REPO_TOKENFine-grained GitHub PAT, Contents: Read-only, scoped to just the content repo. Embedded into an https:// CONTENT_REPO URL for authenticated cloning — needed because the content repo is private and the Cloudflare Pages build container has no other credentials. Also set this as a Cloudflare Pages project environment variable for the deployed build.(unset)
SITE_URLThe site's real absolute origin — sitemap.xml, canonical tags, and OG tags all require absolute URLs, on any host. Defaults to http://localhost:3000 for local dev. Not the same thing as the old GitHub-Pages-era BASE_PATH/CUSTOM_DOMAIN (removed during the Cloudflare migration, a hosting-subpath quirk) — this is an unavoidable protocol requirement, not a hosting workaround. Must be set as a real Cloudflare Pages project environment variable for production, or sitemap/canonical/ OG URLs will silently point at localhost.(unset)
MCP_PUSH_TOKENOptional. If set, MCP server pushes (publish/preview) authenticate as this token instead of ambient git credentials, so the server can push independently of whoever's running it.(unset)
PUBLISH_MODEdirect (default) pushes straight to main. pr pushes the draft branch and opens a real GitHub PR instead — needs MCP_PUSH_TOKEN scoped with "Pull requests: Write" in addition to "Contents: Write" (a separate fine-grained PAT permission; Contents access alone isn't enough).direct
CLOUDFLARE_DEPLOY_HOOK_URLCloudflare Pages deploy hook URL (Pages project > Settings > Builds & deployments > Deploy Hooks). Used by revalidate()/publish() to trigger a rebuild after content changes — POSTing to this URL is the entire mechanism, no separate token needed. Only needs to exist wherever the MCP server runs.(unset)
CLOUDFLARE_API_TOKENCLOUDFLARE_API_TOKEN: one Account API Token shared by deploy_status and (see below) the R2 image cache's account/project lookups. Create it at My Profile > API Tokens > Create Token > Custom Token, permission Account > Cloudflare Pages > Read. GOTCHA, cost real time to work out: Cloudflare has *two* separate token systems, both confusingly called "API tokens" in different parts of the dashboard. - "User API Tokens" (tied to your login) vs. "Account API Tokens" (tied to the account itself) — always use an Account API Token for anything automated/service-like (this project, CI, etc.), never a User one. Cloudflare's own token-creation UI recommends this too. - Separately: R2 object-level operations (get/put/list individual files) are NOT supported by Cloudflare's native REST API (api.cloudflare.com) at all, confirmed directly — an Account API Token with full "R2 Storage" permissions still gets a flat 403 no matter what permission level you pick. Object operations only work via R2's S3-compatible endpoint (below), a genuinely different auth system (AWS-style signed requests, not a Bearer token). The native API only covers R2 *bucket* management (list/create/delete buckets), not the objects inside them.(unset)
CLOUDFLARE_BUCKET_NAMER2-backed image cache (site/image-cache-remote.ts) — persists the local .image-cache/ across Cloudflare Pages builds, which otherwise start from a fresh checkout every time and re-encode every image from scratch. Optional: unset means local-only caching (still works, just doesn't survive a fresh CI checkout). Uses R2's S3-compatible API (hand-rolled AWS SigV4 signing) — per the gotcha above, this is the only path that actually works for reading/ writing individual objects. Get CLOUDFLARE_S3_ACCESS_KEY_ID and CLOUDFLARE_S3_SECRET_ACCESS_KEY from R2 > Manage R2 API Tokens > Create API Token (permission: Object Read & Write, scoped to this one bucket) — a *different* page than the Account API Token above, and it produces this Access Key/Secret pair specifically, not a token string. CLOUDFLARE_BUCKET_NAME: the R2 bucket's name. CLOUDFLARE_ACCOUNT_ID is shared with the block above — the R2 endpoint is derived from it directly (https://<account-id>.r2.cloudflarestorage.com), no separate endpoint URL needs storing.(unset)
IMAGE_CACHE_PRUNE_AFTER_DAYSOptional, opt-in — unset means image cache entries live in R2 forever. When set, deletes cache entries no longer referenced by any current post once they've gone unreferenced for this many days (a real "last confirmed still in use" tracking manifest, not R2's own last-modified timestamp — see site/image-cache-remote.ts::pruneImageCache for why that distinction matters). Try 30/60/90 depending on how much churn your content sees.(unset)
MCP_ALLOWED_HOSTNAMESComma-separated hostnames for DNS-rebinding protection on the MCP server. Defaults to localhost-only; set this if the server is ever exposed beyond your own machine.(unset)
MCP_TOOL_ALLOWLISTComma-separated MCP tool names. Unset means every tool this server has is registered (normal solo/interactive use). Set to restrict a server instance to a narrow subset — e.g. the docs-refresh CI workflow sets this so its agent structurally cannot call delete_post/rollback/abandon_draft, not just "is told not to" in a prompt.(unset)
PORTPort for the MCP server. Defaults to 3939.(unset)
SITE_NAMESite name/description used in <title>, meta tags, OG tags, the RSS feed, and llms.txt. Both optional — default to "Carapace" and a generic description.(unset)