# CopyCat MCP deployment and rollback

## Current status and existing hosting

Website: https://copycat.tech, deployed from GitHub main through Cloudflare Pages
project `copycat`. Account inspection confirmed the GitHub main production branch,
empty build command, and repository-root static output. Staging and production
were deployed and verified over HTTPS on 2026-11-07. See `MCP_RELEASE.md` for version
IDs, live URLs, routes and verification. No credentials are stored in this checkout.

The Worker is independent and has new names: `copycat-mcp-staging` and `copycat-mcp`.
It does not replace the website Pages project. Account inspection found no existing
Workers or route conflicts before rollout. `wrangler.jsonc` env.production now owns
only `copycat.tech/mcp` and `copycat.tech/mcp/*`. The separate workers.dev URL is a
fallback. The guide is served by Pages outside those routes.

## Build and local validation

From repository root (Node 22.12+, pnpm 11.25.0):

```sh
cd mcp
pnpm install --frozen-lockfile
pnpm build
pnpm test
pnpm audit --prod
```

`build` regenerates website/MCP exports, prepares only normalized public assets,
typechecks, and runs `wrangler deploy --env staging --dry-run`. It does not deploy.
Commit generated `api/` with its source. Ignored `mcp/assets/` is rebuilt. Rollout
must use a single source revision; never mix an old index and new article chunks.

## Account inspection and staging

```sh
pnpm exec wrangler login
pnpm exec wrangler whoami
pnpm exec wrangler pages project list
pnpm exec wrangler deployments list --name copycat-mcp-staging
```

Confirm the correct Cloudflare account, identify the existing website project/build
output settings, and inspect zone routes in the dashboard. Verify the new Worker
names are unused or belong to this implementation. Check that rate-limit namespace
IDs `2026110701` (staging) and `2026110702` (production) do not collide with another
account service; change them before first deploy if necessary. Do not overwrite an
unrelated Worker or assume its name implies ownership. Use a scoped API token
instead of interactive login for CI, with only the Worker permissions required;
route changes additionally require the applicable zone route permissions.

Both CopyCat Workers now exist in the verified account. For an update, inspect the
current deployment and use COPYCAT_UPDATE_EXISTING=1. The new-worker flag below is
only for a fresh account/unused name, not a routine update to these live Workers.

After verifying a **new** staging Worker name/account/namespace:

```powershell
$env:COPYCAT_NEW_WORKER_VERIFIED='1'
pnpm deploy:staging
```

For later deployments of an inspected, owned existing Worker, use
`$env:COPYCAT_UPDATE_EXISTING='1'` instead. Deployment script fails closed when it
cannot establish whether the Worker already exists. Keep deployment output/version
IDs in the operator release record, not credentials in Git.

Using the actual workers.dev URL returned by Wrangler:

```sh
pnpm smoke https://copycat-mcp-staging.ACTUAL-SUBDOMAIN.workers.dev/mcp
codex mcp add copycat-staging --url https://copycat-mcp-staging.ACTUAL-SUBDOMAIN.workers.dev/mcp
codex mcp list
```

Ask Codex to search 0x80070005, retrieve article 3079 and retrieve its commands
without executing them. Remove the temporary entry with
`codex mcp remove copycat-staging`. Run Inspector against the actual remote URL
using a separate read-only JSON config analogous to `scripts/inspector.json`.
Check HTTPS health and all six tools/resources, valid article deep links, 404 for
admin/private/static paths, 403 for unapproved Origins, 413 for oversized payloads,
and 429/Retry-After under a controlled quota test. Remote rate limits are approximate
per location. Check existing website desktop/mobile search and article expansion.

## Production and `/mcp` migration

Update the existing production Worker only after staging passes. The active
configuration includes the verified narrow production routes:

```powershell
$env:COPYCAT_STAGING_VERIFIED='1'
$env:COPYCAT_UPDATE_EXISTING='1'
pnpm deploy:production
```

If a production Worker already exists and is verified owned, set
COPYCAT_UPDATE_EXISTING=1 instead of the new-worker flag. Before using workers.dev
as the advertised endpoint, set `PUBLIC_MCP_URL` to its actual URL so health reports
the real endpoint. Update guide endpoint/configuration examples and metadata to
match the verified public URL if `/mcp` cannot be routed safely yet.

The primary config already contains the two verified production routes. For a new
account or migration, inspect existing routes, custom domains, Pages custom-domain association, WAF/bot
rules, and DNS proxying before attaching production routes. A narrowly scoped
example is supplied in `mcp/wrangler.production-route.example.jsonc`; the active
configuration is `wrangler.jsonc` env.production. Both cover:

```json
[
  {"pattern":"copycat.tech/mcp","zone_name":"copycat.tech"},
  {"pattern":"copycat.tech/mcp/*","zone_name":"copycat.tech"}
]
```

**Do not use `copycat.tech/*` or `copycat.tech/mcp*`**: the former hijacks website
hosting and the latter also intercepts `/mcp-guide`. Verify there are no conflicting
routes. After staging and account review, copy/review the production example (or
add these routes to env.production in the primary config) and deploy that exact
configuration. Do not maintain divergent active configurations.

For the supplied standalone route configuration, after review:

```sh
pnpm exec wrangler deploy --config wrangler.production-route.example.jsonc
pnpm smoke https://copycat.tech/mcp
```

The example is deliberately not used by default scripts. Attaching routes may not
be appropriate for the current account setup; keep workers.dev if in doubt and
resolve account routing before migration. Never replace a Pages project or DNS
record to force this route. Ensure MCP paths bypass interactive browser challenges.
Verify `/`, `/api/runtime-catalog.json`, article deep links, `/mcp-guide` and
`/mcp/health` independently. Once live, remove “planned” wording and change guide
deployment status to the verified state; do not advertise an unverified endpoint.

## Environment/binding reference

| Setting | Purpose |
|---|---|
| KNOWLEDGE | Read-only generated static assets binding; no secrets/source packs |
| MCP_RATE_LIMITER | Required Cloudflare rate-limit binding; 120/60 seconds |
| ENVIRONMENT | local / staging / production; controls loopback/Worker hostname policy |
| ALLOWED_HOSTS | Comma-separated exact custom-domain/loopback hostnames |
| ALLOWED_ORIGINS | Comma-separated exact browser Origins; default https://copycat.tech |
| PUBLIC_MCP_URL | Advertised health endpoint; staging empty derives actual origin |
| CLOUDFLARE_API_TOKEN | Optional operator/CI secret, never committed |
| CLOUDFLARE_ACCOUNT_ID | Optional operator account selector, verify before deployment |
| COPYCAT_NEW_WORKER_VERIFIED | Local deployment preflight assertion for a new Worker |
| COPYCAT_UPDATE_EXISTING | Local assertion that existing Worker ownership/config was reviewed |
| COPYCAT_STAGING_VERIFIED | Local production preflight assertion after remote staging tests |

No LLM credentials or runtime application secrets are required. Staging/production
bindings are explicitly specified; review Wrangler output, not inheritance guesses.
The tracked observability setting disables Worker observability. Review account-side
logs and retention separately. Browser Origin additions require explicit review.

## Rollback

Record the current version before each update:

```sh
pnpm exec wrangler deployments list --env production
pnpm exec wrangler versions list --env production
pnpm exec wrangler rollback PREVIOUS_VERSION_ID --env production
```

Use staging's environment for staging rollback. If the production route example
was used, pass `--config wrangler.production-route.example.jsonc` instead of `--env`.
Rollback to the previous version and its matching assets, then repeat health and
smoke tests. Do not roll back to a version whose asset/index revision mismatches.
For a first deployment with no previous version, remove only the two explicitly
added MCP routes in Cloudflare (after verifying ownership); leave existing website
routes/DNS untouched. Disable/delete only this newly created Worker if necessary.
Website guide code can remain and report unavailable; reverting its Git commit is
independent of the MCP Worker. Never reset unrelated user changes.

References: [Cloudflare MCP server guide](https://developers.cloudflare.com/agents/model-context-protocol/guides/remote-mcp-server/),
[Worker routes](https://developers.cloudflare.com/workers/configuration/routing/routes/),
[Worker rollback](https://developers.cloudflare.com/workers/configuration/versions-and-deployments/rollbacks/).
