Heads up — the easy free way to put an AI-built page online usually makes it public and searchable on Google. Pagelive keeps yours private →
+ +

Guide · July 21, 2026 · 10 min read

Publish HTML from Claude Code: one MCP call after setup

Claude Code just built you something — a landing page, a client proposal, a report, a demo, a deck rendered as HTML — and now you need it live at a URL you can paste into an email. The building was the easy part. The annoying part is everything after: open a browser, log into a host, create a project, run a deploy, wait, copy the URL back. Every one of those steps yanks you out of the terminal you were just working in, and half the time you fumble the deploy config on the first try.

There's a shorter path. If you want to publish HTML from Claude Code and get a link back without leaving the terminal, the agent can do it in a single tool call over MCP — once you've added and authorized the connector, which is a one-time step. But that's the right move for exactly one shape of problem, and the wrong move for two others. Below is the honest version of the landscape — publish-over-MCP, tunnels, and real deploys — so you pick the one that fits and the link you hand someone isn't broken by morning.

+ +

Getting what the agent built onto a live URL without leaving the terminal

Claude Code can run shell commands, so it can already drive a normal deploy — vercel --prod, wrangler pages deploy — and I'll come back to that. But the lowest-friction path is a hosting service that exposes an MCP tool the agent calls directly. You say "publish this file as a page and give me the link," the agent calls the tool with your HTML, the service hosts it, the URL comes back in the same turn. No browser, no login, no build.

The distinction that decides everything: this path hosts pages — self-contained HTML — not a running backend or a live dev server. If what you built is a static artifact (a proposal, a one-pager, a deck, a rendered report), it fits perfectly. If it's a Node app with a live API, or a Vite dev server you want someone to poke at, you need a tunnel or a real deploy instead. Hold onto that split; it's the whole basis for choosing right.

+ +

How publishing over MCP actually works

MCP (Model Context Protocol) is an open JSON-RPC protocol for wiring agents to tools. Claude Code is an MCP host; each server it connects to exposes tools — functions with a defined input schema — that the agent can discover and call.

So "publishing over MCP" isn't magic. A hosting service runs an MCP server exposing a publish_page-style tool. Claude Code calls it with your HTML as an argument. The server stores the file, serves it, and returns a URL in the tool result. The agent prints that URL back to you. The whole round trip happens inside one turn — that's the entire appeal. The first use still requires adding and authorizing the connector once; after that, it really is a single call.

There are two ways to connect such a server, and they fail differently, so both are worth knowing.

A. Add a remote HTTP server from the CLI.

claude mcp add --transport http <name> <url>

Then run /mcp to complete OAuth if the server needs it. --scope controls reach: local (default, just you in this project), project (shared via a checked-in .mcp.json), or user (you, everywhere). One trap if you hand-edit .mcp.json: the transport key must be "type": "http". An entry with a url but no type is treated as a stdio command; Claude Code skips that server and reports an error naming it — so add "type": "http". The mechanics are in the Claude Code MCP docs.

B. Use a claude.ai connector — no CLI at all. If you're logged into Claude Code with a claude.ai subscription account, any connector you've added at claude.ai (Settings → Connectors) shows up in Claude Code automatically and appears in /mcp.

Here's the failure mode that wastes people an afternoon: claude.ai connectors load only when your active auth is the subscription login. They do not appear when Claude Code is running on an ANTHROPIC_API_KEY, a CLAUDE_CODE_OAUTH_TOKEN from claude setup-token, or a Bedrock/Vertex provider. If a connector you expect is missing from /mcp, run /status to check the active auth method, then /login with the claude.ai account. It looks like the connector is broken; it's an auth-mode mismatch.

Once connected either way, you don't type a command. You describe the outcome — "publish this as a page, put a password on it, give me the link" — and the agent picks the tool and calls it.

+ +

Can the agent update the same URL when the code changes?

Yes, and this is what makes a publish tool worth more than a one-shot paste. A decent publish server exposes a create tool and an update tool keyed to the same page, so the URL stays put while the content behind it moves. Pagelive, for example, exposes a remote MCP connector where publish_page returns a slug and URL, and calling it again with that slug replaces the content at the same address.

That gives you a loop worth having:

  1. Agent builds the page, you publish, you get a URL.
  2. You paste that URL into an email to your client. Once.
  3. You keep iterating — "fix the pricing table, then update the page."
  4. The client refreshes. Same link, new version.

A tunnel can't give you this: it depends on a running process, so stop the agent or close your laptop and the preview disappears, even if the hostname stays the same. A real deploy keeps the URL too — but it means standing up and configuring a hosting project first. Vercel, Netlify and Cloudflare Pages all keep a stable production URL across deploys, so Pagelive's advantage here is narrow and specific: updating a private, tracked HTML send without creating and configuring a hosting project.

+ +

Can I keep it private or password-protect it?

This is where the options split hard, and precision matters, because "the URL is random" is not the same as "the page is private."

  • Tunnels are public-by-obscurity. An ngrok or cloudflared URL is reachable by anyone who has it. A bare tunnel has no auth, though ngrok can add Basic Auth or OAuth through Traffic Policy even on the free plan (free OAuth is capped at three monthly active identities). A random subdomain by itself isn't protection; it's a public URL that hasn't been shared yet. Fine for a quick look, worth locking down for anything sensitive.
  • Static hosts (Cloudflare Pages, Vercel, Netlify) normally serve production deployments public. Protection varies by host: Vercel password protection is a paid feature, while Cloudflare Pages previews can sit behind Cloudflare Access. Indexing also varies — Cloudflare Pages preview URLs already send X-Robots-Tag: noindex, but production URLs need their own indexing controls.
  • Publish-tool services can bake privacy in. Pagelive pages are unlisted and noindex by default; anyone with the link can still open an unpassworded page, so add a password — enforced at the edge, before the page is sent — when possession of the URL should not be enough. Public and indexed is opt-in. For a client proposal or an internal report, that default is the correct behavior, because "lock it down afterward" is exactly the step people forget.

That's one option that defaults to unlisted, not the only way to get a private link — you can lock down a static host too, it's just more steps and easier to skip. But if unlisted-by-default plus a password on the same call matches your job, it removes the step you'd otherwise forget. One caveat worth stating plainly: a password gates possession of the password, not identity — Pagelive does not verify who a viewer is or restrict a link to one named person, so don't treat it as per-recipient access control.

Same class of tool, one more note: because these services sit in front of the page, Pagelive records whether and when the recipient opened it, how long they spent, and which countries the opens came from — view tracking a raw static host won't give you without wiring up analytics yourself (and generic analytics don't necessarily tell you it was the intended recipient). Genuinely useful for a proposal you sent a prospect; pointless for a throwaway demo. Take it or leave it on that basis.

+ +

How this compares to a tunnel (ngrok) or a real deploy

Each of these is the right answer for a different job. Don't let the convenience of one-call publish talk you into it when you're actually doing one of the other two.

Publish via MCP tool — the topic here. Agent calls a hosted publish tool, stable URL comes back in one turn. Best when: you built a self-contained HTML artifact and want to send a link from inside the agent, keep that link as you iterate, and optionally keep it private or tracked. Limits: it hosts pages, not a running backend. Test the published page after the first publish — self-contained HTML with its assets inlined is the most portable, and the least likely to render differently once it's off your machine. It needs a one-time connector setup (OAuth). And tool calls run under Claude Code's request timeout, so a genuinely enormous single upload can time out.

Tunnel — ngrok or cloudflared. ngrok http 3000 puts your locally-running app on a public URL in seconds. Cloudflare's quick tunnel does the same with no account: cloudflared tunnel --url http://localhost:3000 hands back a *.trycloudflare.com URL (TryCloudflare docs, ngrok getting started). Best when: you need to demo a running server — a React dev server with live reload, an API, a webhook receiver — or test on a real phone. It mirrors your localhost in real time, which no page publisher can do. Downsides: the URL is live only while your machine and the tunnel process run — close the laptop and the link dies. ngrok's free tier now gives you one persistent assigned dev domain (so the hostname is stable), but the endpoint still dies when the process stops, and browser traffic hits an ngrok warning page before the site loads — a bad look to hand a client. cloudflared quick tunnels are ephemeral too. Great dev tool, wrong tool for "here's a link that stays up."

Real deploy — Cloudflare Pages, Vercel, Netlify, Surge, GitHub Pages. The agent can run these itself from the shell: npx wrangler pages deploy ./dist, vercel --prod, netlify deploy --prod, surge ./dist, or push to a Pages branch (Cloudflare Pages docs). Best when: it's a real project you'll own and grow — a site or app with a build step, a domain you control, long-term SEO. You get a permanent URL, global CDN, HTTPS, and proper custom domains. Downsides: setup cost (account, project link, deploy config); whether each change re-runs a build depends on the project and command — a raw static directory can be redeployed as-is, while a framework project rebuilds. For a single throwaway artifact it's more machinery than the payoff justifies. But "deploy from the agent" is real — Claude Code runs the shell, so it can drive these end to end. It's just a build-and-deploy, not a one-call publish.

One surface not to confuse with these: Claude Code can render an app locally so you can eyeball it, but that's for looking, not sending — it doesn't hand you a shareable public URL. claude.ai Artifacts render and share HTML, but that lives in the chat product; from the CLI you reach equivalent hosting through a connector, which is the MCP-publish path above.

Quick decision table:

Your needRight tool
Send a stable link to a built HTML artifact, keep iterating, maybe private/tracked, from the agentMCP publish tool (Pagelive fits)
Show a running local server, live reload, or webhooksTunnel (ngrok, cloudflared)
A real site or app you'll own and grow — custom domain, SEOReal host (Pages, Vercel, Netlify)
Just eyeball what the agent built, no sharingLocal preview
Send an arbitrary file blob (zip, video, binary)File transfer, not a page publisher
+ +

The takeaway

Match the tool to the shape of the thing. Built a self-contained page and want a stable, sendable link — ideally unlisted, ideally one you can keep updating behind the same URL? A publish-over-MCP tool does it in one call (after a one-time connector setup) without leaving Claude Code, and Pagelive is a clean fit for that specific case. Demoing a running server? Use a tunnel and accept that the link lives and dies with your process. Building something you'll own for the long haul? Do the real deploy and put your own domain on it. One-call publish is a genuinely nice workflow — just don't reach for it when the job is really one of the other two.

+ +

Frequently asked

How do I publish HTML from Claude Code without leaving the terminal? +

Connect a hosting service that exposes an MCP publish tool, authorize it once, then tell the agent to publish the file. It calls the tool and the live URL comes back in the same turn — no browser, no login, no build step.

Can Claude Code update the same URL when the code changes? +

Yes, if the publish tool exposes an update keyed to the page. You paste the link into an email once, keep iterating, and the recipient refreshes to the new version at the same address.

Can I keep a page published from Claude Code private? +

It depends on the tool. Tunnels and most static hosts are public by default. A publish-tool service like Pagelive defaults to unlisted and noindex and takes an optional edge password — though anyone with the link and password can open it; it doesn't verify identity.

When should I use a tunnel like ngrok instead? +

When you need to demo a running server — a live dev server, an API, a webhook receiver — not a static page. A tunnel mirrors your localhost in real time, but the link stops working when your machine or the tunnel process stops.

MCP publish vs a real deploy — which do I want? +

Publish-over-MCP fits a self-contained HTML artifact you want to send fast and keep private. A real deploy on Cloudflare Pages, Vercel, or Netlify fits a site or app you'll own and grow, with a build step and a custom domain.

Related: use Claude Code remotely · publish a website Claude built

+ +

Publish what Claude Code builds — in one call.

Add the Pagelive connector once, then tell Claude Code to publish. You get a private, tracked link back without leaving the terminal. Free for 5 pages, no card.