You can run the full cf-webmcp stack on your own machine without touching Cloudflare. The local stack is two processes:
- A tiny Node static server on
http://localhost:8081that serves the example-site fixture (the "origin"). - The Worker on
http://localhost:8787viawrangler dev(uses Miniflare under the hood).
Visit http://localhost:8787 and you are hitting the Worker, which proxies to the local origin, injects the bootstrapper, exposes the manifest, and handles tool calls.
- Node.js 20 or higher.
- A fresh clone of the repo.
npm install
npm run build:schema # generates schemas/webmcp.schema.jsonYou need two terminals (one process per terminal).
Terminal 1 - origin:
npm run dev:originServes templates/example-site/origin/ at http://localhost:8081.
Terminal 2 - Worker:
npm run dev:workerBuilds the Worker config against templates/example-site/webmcp.toml, then starts wrangler dev on http://localhost:8787 using wrangler.dev.toml.
With both processes running:
http://localhost:8787/- proxied index.html with the bootstrapper injected. View source to see<link rel="webmcp">in<head>and<script src="/_webmcp/bootstrap.<hash>.js" defer>before</body>. Response also has aLink: ...; rel="webmcp"header.http://localhost:8787/.well-known/webmcp- the tool catalogue manifest.http://localhost:8787/mcp- the auto-generated pairing/landing page.http://localhost:8787/_webmcp/bootstrap.<hash>.js- the registration script that runs in agent-driven browsers. Hash matchesconfig_hashin the manifest.http://localhost:8787/llms.txt- merged version of the origin's llms.txt with the WebMCP block appended between markers.http://localhost:8787/robots.txt- merged version withDisallow: /_webmcp/exec/added.http://localhost:8787/_webmcp/health- operational health JSON.
Tools use POST /_webmcp/exec/:tool_name with a JSON body.
curl -X POST http://localhost:8787/_webmcp/exec/search_pages \
-H 'content-type: application/json' \
-d '{"query":"blog"}'Expected response:
{
"ok": true,
"data": {
"entries": [
{ "url": "http://localhost:8787/blog/hello-world", "lastmod": "2026-05-10" }
]
}
}Try the other tools:
curl -X POST http://localhost:8787/_webmcp/exec/list_posts -d '{}' -H 'content-type: application/json'
curl -X POST http://localhost:8787/_webmcp/exec/get_page -d '{"path":"/about"}' -H 'content-type: application/json'Every tool response is wrapped in a stable envelope. Errors look like:
curl -X POST http://localhost:8787/_webmcp/exec/search_pages \
-H 'content-type: application/json' \
-d '{}'{
"ok": false,
"error": {
"code": "invalid_input",
"message": "missing required field \"query\"",
"retriable": false
}
}npm run preflight -- --config=templates/example-site/webmcp.tomlReports which Worker-claimed paths are free, which will be merged, and which collide. The example-site has /llms.txt and /robots.txt to merge; everything else is free.
- R2-backed widget. Local dev uses
fallback_widget = false. Desktop MCP client pairing flow is exercised in real deploys against R2, not locally. - CF Analytics Engine metrics.
/_webmcp/healthreturnsnullfor executor metrics in local dev. - Bot Management bypass. Headers are sent on origin fetches but the local origin has no WAF to bypass.
If you change the TOML or any source file, wrangler dev hot-reloads the Worker automatically. The build pipeline reruns on save because npm run dev:worker chains npm run build first, then wrangler dev watches for file changes. If you change the config hash, the manifest ETag rotates.