Self-hosted Claude artifacts on Cloudflare

Goal: every Claude surface you use (Desktop, Cowork, Code, CLI) can publish HTML and Markdown artifacts to your own Cloudflare account, and humans can open them at a URL on your domain with per-artifact visibility.

Decisions already made

Question Decision
Viewer access Per artifact: private by default, optionally public or share-link
Domain A subdomain on your existing Cloudflare zone, e.g. artifacts.<domain>
Plan Workers Paid, Zero Trust free tier
Publish path Remote MCP server for all surfaces, plus a wrangler-based skill for large assets

Architecture

One Worker, one hostname, four responsibilities:

  1. /mcp — remote MCP server (McpAgent, Streamable HTTP) behind OAuth 2.1. Claude connects here.
  2. /a/<slug> — viewer. Renders Markdown to HTML on the fly, serves raw HTML under a strict CSP.
  3. /assets/<slug>/<file> — R2 passthrough for images and data files.
  4. / and /login — private index of your artifacts; /login is the only path Cloudflare Access sits on.

Storage:

Rendering:

Auth, two layers

Claude → MCP server. @cloudflare/workers-oauth-provider in front of the MCP route. Its upstream identity provider is a Cloudflare Access for SaaS application (OIDC). Flow: Claude opens the authorize URL, you log in through Access (one-time PIN or your IdP), the Worker mints an MCP token. Same flow for every surface:

Viewer → page. No hostname-level Access, because public artifacts must stay public. Instead:

MCP tools

Tool Purpose
publish slug (optional), title, description, type (md/html), content, visibility. Creates or adds a version. Returns URL.
update Same as publish against an existing slug.
get Returns current content and metadata, so Claude can build on the live version.
list Recent artifacts with URLs.
set_visibility private / public / share; returns share link when relevant.
delete Soft delete (keeps R2 objects for a grace period).
attach_asset Small assets inline (base64, up to ~2 MB). Larger files go through wrangler and are registered with this tool by key.

Claude-side skill

A small skill (installed in ~/.claude/skills, and packaged as a plugin for Desktop/Cowork) that mirrors the built-in Artifact tool’s rules: when a deliverable deserves a page, how to title it, always redeploy to the same slug, prefer Markdown for documents and HTML for apps, and how to push big assets with wrangler r2 object put then attach_asset.

Phases

  1. Prerequisites. Authorize the Cloudflare API MCP servers in this session or confirm details by hand: zone name, Zero Trust org and team domain, an IdP or one-time PIN enabled. Pick the subdomain and a project directory.
  2. Skeleton and viewer. Worker with R2 + D1 bindings, custom domain route, Markdown rendering, public artifacts only. Upload a test file with wrangler and open it. This is the first visible win.
  3. MCP server with OAuth. McpAgent + OAuth provider + Access for SaaS app. Connect from Claude Code first, then Desktop. Publish a page from a chat.
  4. Skill, first cut. Write the skill against the tools that exist so far and use it daily; real use shapes the later phases. Tool descriptions and skill text live in the repo and are versioned together.
  5. Visibility. Access app on /login, JWT verification, share tokens, the private index page.
  6. Rich rendering. Mermaid, chart and vega blocks, highlighting, KaTeX, TOC, dark mode, CSP for raw HTML, asset serving, wrangler asset flow.
  7. Hardening. Size and rate limits, structured logs with observability enabled, R2 lifecycle rule for deleted artifacts, Vitest with the Workers pool, a deploy from CI.

Phases 2 and 3 are the ones worth doing first; everything after is incremental.

Open questions and risks