mcp: scaffold Worker, environment guardrails, fake-upstream skeleton, CI

Cloudflare Worker scaffold for the MCP server (Hono, TypeScript strict,
pnpm 11 via corepack, wrangler 4, vitest 4 in workerd).

- wrangler.toml declares local/preview/production; production alone pins
  https://api.storyteller.ai. Binding types are generated by `wrangler types`.
- src/config.ts parses the bindings and asserts the upstream-host
  invariant per environment; src/index.ts fails every request with a 500
  naming the mismatch if the invariant is violated.
- Guardrail tests: config invariant, wrangler.toml environment mapping,
  MCP_ENVIRONMENT referenced only in config.ts and never branched on,
  /healthz through the Worker entry.
- fake-upstream/: separate Worker (artcraft-api-fake) that will hold the
  ported fake API routes; eslint forbids imports across the boundary in
  both directions.
- .github/workflows/mcp.yml: typecheck, lint, format, test on mcp/**;
  production deploy skips with a notice until Cloudflare secrets exist.

pnpm check: typecheck, eslint, prettier, 28 tests passing.

Claude-Session: https://claude.ai/code/session_01H3gfN2NCx3hBXSrZXYHUQ3
This commit is contained in:
Tanish Manku committed 2026-08-24 19:50:00 -07:00
1 parent 984e8d3845
commit 59a7cc5fb4
25 files changed
+3331

No files matched your search

+71
View File
@@ -0,0 +1,71 @@
name: mcp
on:
push:
branches: [main]
paths:
- "mcp/**"
- ".github/workflows/mcp.yml"
pull_request:
paths:
- "mcp/**"
- ".github/workflows/mcp.yml"
defaults:
run:
working-directory: mcp
jobs:
check:
name: typecheck · lint · format · test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
package_json_file: mcp/package.json
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: mcp/pnpm-lock.yaml
- run: pnpm install --frozen-lockfile
- run: pnpm typecheck
- run: pnpm lint
- run: pnpm format
- run: pnpm test
deploy-production:
name: deploy · production
needs: check
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
package_json_file: mcp/package.json
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: mcp/pnpm-lock.yaml
- run: pnpm install --frozen-lockfile
# Deploys are skipped, not failed, until the Cloudflare secrets exist (docs/infra-request.md §2).
- id: creds
run: |
if [ -n "$CLOUDFLARE_API_TOKEN" ] && [ -n "$CLOUDFLARE_ACCOUNT_ID" ]; then
echo "present=true" >> "$GITHUB_OUTPUT"
else
echo "::notice::Cloudflare secrets not configured; skipping deploy."
echo "present=false" >> "$GITHUB_OUTPUT"
fi
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
- if: steps.creds.outputs.present == 'true'
run: pnpm exec wrangler deploy --env production
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}