<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Steve Smith</title>
    <description>The latest articles on DEV Community by Steve Smith (@stevysmith).</description>
    <link>https://dev.to/stevysmith</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3971876%2F3538b426-98b2-478a-ba86-b7460c7fe225.png</url>
      <title>DEV Community: Steve Smith</title>
      <link>https://dev.to/stevysmith</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stevysmith"/>
    <language>en</language>
    <item>
      <title>Give your AI coding agent a publish-HTML button (with MCP)</title>
      <dc:creator>Steve Smith</dc:creator>
      <pubDate>Sat, 06 Jun 2026 22:22:54 +0000</pubDate>
      <link>https://dev.to/stevysmith/give-your-ai-coding-agent-a-publish-html-button-with-mcp-1ghi</link>
      <guid>https://dev.to/stevysmith/give-your-ai-coding-agent-a-publish-html-button-with-mcp-1ghi</guid>
      <description>&lt;p&gt;Your coding agent writes HTML all day. A quick dashboard to eyeball some data. A PR writeup with a rendered diff. A status report, a Mermaid diagram, a one-off internal tool. Then what? You screenshot it into Slack, paste it into a gist, or spin up a Vercel project for a file you will delete tomorrow.&lt;/p&gt;

&lt;p&gt;There is a verb missing from the agent toolbox: &lt;strong&gt;publish&lt;/strong&gt;. Not deploy. Publish. One file in, one private URL out.&lt;/p&gt;

&lt;p&gt;This post is about how to add that verb to any MCP-compatible agent, why "private by default" matters more than it sounds, and what the publish primitive looks like in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of the problem
&lt;/h2&gt;

&lt;p&gt;A deploy is a project. It expects a repo, a build, a config, a domain. That is the right amount of ceremony for a product and far too much for the artifact-shaped output an agent emits dozens of times a session.&lt;/p&gt;

&lt;p&gt;What an agent actually needs is closer to a paste-bin with teeth:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It writes a file. It gets back a URL. No project, no build step.&lt;/li&gt;
&lt;li&gt;The URL is private by default, because agent output routinely embeds real data: API responses, customer rows, the prompt context itself.&lt;/li&gt;
&lt;li&gt;When the agent revises the artifact, the same URL updates in place. You do not want 30 links from 30 iterations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Model Context Protocol (MCP) is the clean way to expose exactly this. If you have not used MCP, the one-line version: it is the standard every major AI assistant now speaks for calling tools, so a tool you expose once works in Claude Code, Cursor, Codex, Claude.ai, and the rest. (Longer primer: &lt;a href="https://stacktr.ee/blog/mcp-servers-explained-for-developers" rel="noopener noreferrer"&gt;https://stacktr.ee/blog/mcp-servers-explained-for-developers&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  The publish tool, conceptually
&lt;/h2&gt;

&lt;p&gt;A publish-oriented MCP server needs one core tool and a few supporting ones. In MCP terms the action is a &lt;strong&gt;tool&lt;/strong&gt; (model-controlled), the list of what you have published is a &lt;strong&gt;resource&lt;/strong&gt; (the client reads it), and a saved "publish this privately" flow is a &lt;strong&gt;prompt&lt;/strong&gt; (the user invokes it). If that tools/resources/prompts split is new to you, here is the breakdown: &lt;a href="https://stacktr.ee/blog/mcp-resources-vs-tools-vs-prompts" rel="noopener noreferrer"&gt;https://stacktr.ee/blog/mcp-resources-vs-tools-vs-prompts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tool call itself is mundane, which is the point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="c1"&gt;// the agent calls:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;publish_html(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dashboard.html"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;// it gets back:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://stacktr.ee/p/3f9a2c7b1e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"expires"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"24h"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole interaction. The agent hands you a link. You send it to a teammate, who opens it with no account and no login.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "private by default" is the real feature
&lt;/h2&gt;

&lt;p&gt;Public-by-default hosting made sense when humans hand-published finished pages. It is the wrong default for machine-generated HTML, because the agent does not pause to ask whether this particular file contains anything sensitive. It usually does.&lt;/p&gt;

&lt;p&gt;Private by default flips the burden. The URL is unguessable, so the link itself is the credential. There is no directory listing, no search indexing, no crawl. If you need more, you add a layer: a shared password, or an email-domain gate so only &lt;code&gt;@yourco.com&lt;/code&gt; addresses can open it. For the genuinely sensitive case, end-to-end encryption keeps the host from ever seeing plaintext.&lt;/p&gt;

&lt;p&gt;None of that requires the agent to make a judgment call. The safe thing is the default thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in one command
&lt;/h2&gt;

&lt;p&gt;I build &lt;a href="https://stacktr.ee" rel="noopener noreferrer"&gt;Stacktree&lt;/a&gt;, which is one implementation of this primitive: an MCP server for publishing HTML, private by default. Wiring it into your agent is a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx stacktree-install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It detects Claude Code, Cursor, Codex, OpenCode, and Amp, writes the MCP config for each, and the publish tools show up in your agent automatically. The first publish is anonymous and the link lives 24 hours, so you can prove it out before you even make an account.&lt;/p&gt;

&lt;p&gt;It is MIT-licensed on the client side and listed in the official MCP registry as &lt;code&gt;ee.stacktr/publish&lt;/code&gt;. Source for the server package: &lt;a href="https://github.com/stevysmith/stacktree-mcp" rel="noopener noreferrer"&gt;https://github.com/stevysmith/stacktree-mcp&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The broader point
&lt;/h2&gt;

&lt;p&gt;Whether or not you use Stacktree, the pattern is worth internalizing: as agents generate more artifacts, the missing infrastructure is not more compute or a fancier framework. It is small, sharp primitives that fit the agent loop. Publish is one of them. A file goes in, a private link comes out, and the agent can replace it in place when it iterates.&lt;/p&gt;

&lt;p&gt;Happy Building!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>webdev</category>
      <category>resources</category>
    </item>
  </channel>
</rss>
