agentleFS
okayusokayus/okayus-skills/skills/cloudflare-mcp-claude-tooling/SKILL.md

cloudflare-mcp-claude-tooling

Skill0 starsChanged 6 days agoMITView on GitHub

Wire up the Claude Code project tooling for a Cloudflare Workers project developed inside the docker sandbox — a docs-only Cloudflare MCP, a committed `.claude/settings.json` permission allowlist that denies `git commit`/`push` as an execution-level guard for the "git on the host" rule, the egress-firewall domains the docs MCP needs, and the `grill-with-docs` design step. Use when starting a new Cloudflare project (after the sandbox is up) and you want Claude Code's MCP + permissions + design scaffolding set up deliberately. Covers WHY you take docs-only and route account operations through wrangler instead of the bindings/builds/observability MCP servers (OAuth callback is fragile in a container; they overlap with wrangler anyway), plus the documentation-access recipe for the firewalled agent (server-side WebSearch, per-host OPTIONAL egress for WebFetch, which sites publish `llms.txt`, the Context7 MCP with MDN, Modern Web Guidance at project scope).

  • Commits and pushes

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Before the walking skeleton, stress-test the plan.

    line 79

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Cloudflare MCP + Claude Code project tooling

Get a new Cloudflare Workers project (already running in the claude-code-docker-sandbox) to a state where the in-container Claude Code has: the Cloudflare docs MCP connected, a committed permission allowlist that lets it run pnpm/wrangler/git-read freely while blocking git commit/push, and the grill-with-docs design skill available — so you can stress-test the plan before writing the walking skeleton.

This is the layer between "the sandbox is up" and "build the walking skeleton" (cloudflare-workers-deploy-skeleton).

When to use this skill

  • You just stood up the sandbox for a new Cloudflare Workers project and want the Claude Code tooling configured before coding.
  • You're tempted to add the Cloudflare bindings/builds/observability MCP servers and want the decision framework first.
  • You want the "git stays on the host" rule enforced by configuration, not just documented.

The core decision: docs-only MCP, account ops via wrangler

Cloudflare ships several hosted MCP servers (https://*.mcp.cloudflare.com/mcp). They are not equal:

ServerAuthVerdict
cloudflare-docs (docs.mcp.cloudflare.com)noneTake it. Searches Cloudflare docs — something wrangler cannot do. Connects with no OAuth.
unified Cloudflare API (mcp.cloudflare.com/mcp)OAuth or API tokenSkip by default — same wrangler overlap. If you ever do need account ops via MCP, this is the current first choice (token auth, Code Mode).
cloudflare-bindings (bindings.mcp.cloudflare.com)OAuthSkip. Overlaps wrangler d1/kv/r2.
cloudflare-builds (builds.mcp.cloudflare.com)OAuthSkip.
cloudflare-observability (observability.mcp.cloudflare.com)OAuthSkip. Overlaps wrangler tail.

Why docs-only:

  • The account-touching servers duplicate wrangler, which the in-container agent already runs (allowlisted below). You lose little by leaving them out.
  • OAuth from inside the container is no longer a blocker — since Claude Code 2.1.191, MCP OAuth in headless environments prints the authorization URL and accepts the redirect URL pasted back (same paste-style flow as Claude Code login; --no-browser forces it). No localhost callback, no port publishing. It's still an extra per-rebuild approval dance, but the decisive reason to skip these servers is the wrangler overlap above, not OAuth friction. (Verified against the Claude Code changelog + MCP docs, 2026-08-07.)
  • docs needs no auth and is the highest-value server for writing Workers/wrangler config correctly.

If you later genuinely need an account MCP server, the unified mcp.cloudflare.com/mcp is the current first candidate — it officially supports API-token (Bearer header) auth alongside OAuth. Mint a least-privilege token per the cloudflare-api-token-permissions matrix and pass it via headers with ${ENV} expansion in .mcp.json. Token auth stays callback-free; OAuth is also workable in-container since Claude Code 2.1.191 (paste-the-redirect-URL flow). Lineup verified 2026-08-07.

Files to create (templates in references/)

  1. .mcp.json (project root, committed) — docs-only. Copy references/mcp.json.
    { "mcpServers": { "cloudflare-docs": { "type": "http", "url": "https://docs.mcp.cloudflare.com/mcp" } } }
    Project-scoped MCP servers prompt for a one-time workspace-trust approval the first time Claude Code loads the dir.
  2. .claude/settings.json (project root, committed) — copy references/settings.json. It allowlists the day-to-day commands so the agent isn't prompted constantly, and denies git commit / git push:

    "allow": [ "Bash(pnpm install:*)", ..., "Bash(wrangler d1:*)", "Bash(wrangler tail:*)",
               "Bash(git status:*)", "Bash(git diff:*)", "Bash(gh pr view:*)",
               "WebFetch(domain:developers.cloudflare.com)", "WebFetch(domain:docs.mcp.cloudflare.com)" ],
    "deny":  [ "Bash(git push:*)", "Bash(git commit:*)" ]

    The deny is the point: it turns "git happens on the host, not in the sandbox" from a CLAUDE.md convention into an execution-level guard — the in-container agent literally cannot commit/push (keeping GitHub credentials out of the boundary). Allow only the read git/gh verbs. The template also sets "enableAllProjectMcpServers": false — servers from the committed .mcp.json get approved individually rather than wholesale.

    If the sandbox is later allowed to commit or push, narrow the deny accordingly — a broad Bash(git push:*) deny beats every allow rule. With sandboxed-agent-git-relay: allow git add/commit/checkout/switch, keep only git push denied (its step 7). With sandboxed-agent-github-token-via-1password: allow git push origin claude/* + gh pr create/view/checks and deny force pushes / main / gh pr merge / gh auth instead (its compose-and-git-wiring.md).

  3. .gitignore additions — keep per-user/secret config out of git:
    docker-compose.override.yml        # host-specific skills mount (see sandbox skill)
    .claude/settings.local.json        # per-user overrides; .claude/settings.json IS committed
  4. Egress firewall domains — add to the sandbox's .docker/init-firewall.sh for domain in ... list (then rebuild, see below):
    "developers.cloudflare.com" \   # WebFetch of CF docs
    "docs.mcp.cloudflare.com"       # the docs MCP server
    These can share Cloudflare anycast IPs with other CF hosts — the sandbox template's ipset -exist handles that. Rebuild from the project dir with NO -f so docker-compose.override.yml (skills mount) is not dropped:
    docker compose down && docker compose build && docker compose up -d

The design step: grill-with-docs

Before the walking skeleton, stress-test the plan. Install grill-with-docs at project scope so it travels with the repo and is visible to the in-container agent (it lives under the /workspace bind mount):

mkdir -p <project>/.claude/skills/grill-with-docs
# copy the upstream skill directory WHOLESALE — its internal layout has changed
# before (2026-08 it holds SKILL.md + agents/); don't cherry-pick named files

Then run /grill-with-docs and let it interview you one question at a time, capturing vocabulary in CONTEXT.md and hard-to-reverse decisions in docs/adr/NNNN-*.md. Good first targets: auth method, public/private model, scoring/grading rules — the choices that are expensive to change after code exists.

Giving the sandboxed agent documentation access

The firewall is default-deny, so "look it up in the docs" needs a plan. Three layers, verified on kokemusu 2026-08-22:

LayerMechanismEgress needed
WebSearchruns on Anthropic's backend (api.anthropic.com, already fatal-allowlisted); returns titles + URLs onlynone
WebFetchfetched by the Claude Code process in the containerthe docs host — add it to the firewall's OPTIONAL list (a resolve failure must not kill the container) and, for host sessions, a WebFetch(domain:…) allow rule
MCPcloudflare-docs (no auth) + Context7 (https://mcp.context7.com/mcp, key optional; indexes MDN — mdn/content, ~9 M tokens — plus Hono, Drizzle, React, Vite, Cloudflare Workers)docs.mcp.cloudflare.com, mcp.context7.com

Which sites speak llms.txt (probed 2026-08-22): yes — hono.dev (+ llms-full.txt), orm.drizzle.team (+ full), react.dev, vite.dev, vitest.dev, zod.dev, swr.vercel.app, developers.cloudflare.com, developer.chrome.com/docs/css-ui/; no — MDN, typescriptlang.org, tailwindcss.com, web.dev, playwright.dev (use Context7 or fetch the page). Tell the agent the order in CLAUDE.md: Context7 / cloudflare-docs → llms.txt index then the page (llms-full.txt last, it is huge) → WebSearch, then WebFetch only inside the allowlist.

.mcp.json with both servers (project MCP servers still need the one-time interactive trust approval; claude mcp list shows ⏸ Pending approval until then — after it, ✔ Connected, and an in-container claude -p resolved /mdn/content via Context7 and answered a <dialog closedby> question correctly):

{ "mcpServers": {
    "cloudflare-docs": { "type": "http", "url": "https://docs.mcp.cloudflare.com/mcp" },
    "context7":        { "type": "http", "url": "https://mcp.context7.com/mcp" } } }

OPTIONAL-list entries that worked: mcp.context7.com developer.mozilla.org react.dev hono.dev orm.drizzle.team vite.dev vitest.dev zod.dev developer.chrome.com web.dev. Two caveats: the allowlist is IP-based, so the shared anycast IPs admit sibling sites (hono/drizzle/zod = Cloudflare, react.dev = Vercel, MDN = Fastly, chrome = Google) — acceptable for read-only docs, and why context7.com (the website) stays blocked while mcp.context7.com is open; and mcp.context7.com is an AWS ELB whose IPs can rotate — the firewall resolves at container start, so if Context7 stops answering, restart the container.

Modern Web Guidance (Google Chrome, Apache-2.0 — "use the platform, don't reinvent <dialog> / popover / anchor positioning / container queries in React"): install at project scope so it rides the bind mount and is reviewable — npx skills add GoogleChrome/modern-web-guidance@modern-web-guidance -a claude-code -y → .claude/skills/modern-web-guidance/ (SKILL.md + ~140 guides, 1.3 MB) + skills-lock.json; update with npx skills update. Its search / retrieve run npx -y modern-web-guidance@latest … — the npm registry is already fatal-allowlisted, so it works in the sandbox (first call downloads the package; no call to Google at runtime). The Claude Code plugin route (/plugin marketplace add GoogleChrome/modern-web-guidance) lands in ~/.claude/plugins instead — not visible through the skills mount.

Verify

# docs MCP connected, account servers absent:
# (run AFTER approving workspace trust in an interactive session — since Claude Code
#  2.1.196, unapproved project servers show "⏸ Pending approval" here instead)
docker compose exec -T dev claude mcp list | grep cloudflare        # → cloudflare-docs: ... ✓ Connected
# egress reaches docs, non-allowlisted host still blocked:
docker compose exec -T dev sh -c 'curl -so/dev/null -w "%{http_code}\n" https://docs.mcp.cloudflare.com/'   # 404 = reachable
docker compose exec -T dev sh -c 'curl -so/dev/null -w "%{http_code}\n" https://example.com/'               # 000 = blocked

Gotchas

  • Rebuild from the project dir, no -f — otherwise docker-compose.override.yml (host skills mount) silently unloads. See the sandbox skill's Gotchas.
  • IP-based firewall can't block one anycast host while allowing another on the same IP (docs vs bindings often share IPs). Removing an account server from the allowlist may still leave it TCP-reachable; what actually keeps it unused is omitting it from .mcp.json, not the firewall.
  • .claude/settings.json is committed; .claude/settings.local.json is per-user — never commit the latter (gitignored above). Review a project's settings.json before trusting the repo, since it can widen tool access.
  • Project MCP servers need a one-time trust approval in each fresh checkout (claude mcp reset-project-choices to reset).

Related skills

  • claude-code-docker-sandbox — the egress-firewalled container this runs inside; owns the init-firewall.sh allowlist, the skills-mount override, and the -f gotcha.
  • cloudflare-workers-deploy-skeleton — the next step: the SPA+API+Cron walking skeleton.
  • cloudflare-api-token-permissions — least-privilege tokens, if you opt into Bearer-auth MCP or CI deploys.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.