streamable-httpMITupdated 1mo ago
Publish anything for agents ā one API call, MCP server included.
What can you do with htmldrop?
htmldrop turns any HTML, Markdown, PDF, or image artifact into a shareable link in seconds. Reports, dashboards, charts, demos ā anything an agent (or a human) creates. Markdown/text/JSON render into a clean reader page; PDFs and images are served as-is. No git, no build, no dashboard.
Try it now: htmldrop.link ā drag & drop an HTML file, paste HTML source, or POST to the API.
How it works
curl -X POST https://htmldrop.link/publish \
-H "Content-Type: application/json" \
-d '{"html":"<h1>Hello agents</h1>","title":"Demo"}'
{
"url": "https://happy-otter-42.htmldrop.link",
"id": "...",
"subdomain": "happy-otter-42",
"expires_at": "2026-07-17T00:00:00.000Z"
}
Every link gets its own subdomain, an auto-generated Open Graph preview card, and a TTL ā shared artifacts don't live forever.
Connect your agent (MCP)
The hosted MCP server lives at https://htmldrop.link/mcp (Streamable HTTP) and exposes
one tool: publish_html.
Claude Code
claude mcp add --transport http htmldrop https://htmldrop.link/mcp
Claude Desktop
Claude Desktop speaks stdio, so bridge to the hosted server with
mcp-remote. In
claude_desktop_config.json:
{
"mcpServers": {
"htmldrop": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://htmldrop.link/mcp"]
}
}
}
Cursor
Cursor connects to a remote MCP URL directly. In .cursor/mcp.json:
{
"mcpServers": {
"htmldrop": { "url": "https://htmldrop.link/mcp" }
}
}
Codex CLI
In ~/.codex/config.toml:
[mcp_servers.htmldrop]
command = "npx"
args = ["-y", "mcp-remote", "https://htmldrop.link/mcp"]
Self-hosted instance (npm, stdio)
Running your own htmldrop? The htmldrop-mcp
package is a local stdio MCP server that publishes to your storage and
domain:
{
"mcpServers": {
"htmldrop": {
"command": "npx",
"args": ["-y", "htmldrop-mcp"],
"env": {
"BASE_DOMAIN": "your-domain.example",
"CLOUDFLARE_R2_ENDPOINT": "...",
"CLOUDFLARE_R2_ACCESS_KEY_ID": "...",
"CLOUDFLARE_R2_SECRET_ACCESS_KEY": "...",
"CLOUDFLARE_R2_BUCKET_NAME": "..."
}
}
}
}
publish_html tool
| Argument | Type | Description |
|---|---|---|
html |
string | HTML content to publish (or use markdown / url) |
markdown |
string | Markdown content ā rendered into a styled reader page |
url |
string | Remote HTML page to fetch and publish |
title |
string | Optional title for metadata and social cards |
ttl_days |
number | Days until the artifact expires |
password |
string | Optional password protection |
owner_key |
string | Optional key for higher limits and longer TTL |
Full agent-facing docs live in AGENTS.md, also served at htmldrop.link/agents.md.
REST API
| Endpoint | Body | Notes |
|---|---|---|
POST /publish |
JSON { html | markdown, title, ttl_days, password, url } |
Primary endpoint |
POST /publish/raw |
raw body: text/html, text/markdown, text/plain, application/json, text/csv, application/pdf, image/* |
Title via x-htmldrop-title header or ?title= |
POST /publish/from-url |
JSON { url, title, ttl_days, password } |
Fetches and republishes a page |
Pass an owner key in the x-htmldrop-key header for higher rate limits and a
longer default TTL. (x-pin-key is still accepted for backwards compatibility.)
Self-hosting
git clone https://github.com/vin-spiegel/htmldrop.git
cd htmldrop
pnpm install
cp .env.example .env # defaults work out of the box
pnpm dev # http://localhost:3000
The only variable you need to set is BASE_DOMAIN. Everything else has a
working default. Storage falls back to the local filesystem (./data) when no
object store is configured ā no database required.
Environment variables
| Variable | Default | Description |
|---|---|---|
BASE_DOMAIN |
localhost |
Base domain for artifact subdomains. The one value most self-hosters must set. |
PORT |
3000 |
HTTP port (usually set by your host) |
NODE_ENV |
development |
Set to production when deploying |
CLOUDFLARE_R2_ENDPOINT |
ā | S3-compatible endpoint. Set all four R2 vars to use object storage; leave all blank for filesystem |
CLOUDFLARE_R2_ACCESS_KEY_ID |
ā | Object-storage access key |
CLOUDFLARE_R2_SECRET_ACCESS_KEY |
ā | Object-storage secret key |
CLOUDFLARE_R2_BUCKET_NAME |
ā | Bucket name |
ANON_TTL_DAYS |
7 |
TTL for anonymous publishes |
KEY_TTL_DAYS |
30 |
TTL for keyed publishes |
MAX_HTML_SIZE_BYTES |
26214400 |
Upload cap (25 MiB) |
RATE_LIMIT_ANON_PER_MINUTE |
10 |
Per-IP rate limit |
RATE_LIMIT_KEY_PER_MINUTE |
60 |
Per-owner-key rate limit |
Any S3-compatible store works for the CLOUDFLARE_R2_* variables (Cloudflare
R2, AWS S3, MinIO, ā¦). On ephemeral/container hosts, either use object storage
or mount a persistent volume at ./data, or artifacts are lost on redeploy.
Production needs a wildcard DNS record (*.your-domain) pointing at the
server so artifact subdomains resolve.
Deploy to Railway
railway login
railway init --name htmldrop
railway up
Then set BASE_DOMAIN and (optionally) the R2 variables in the Railway
dashboard, and attach your domain plus its wildcard.
Safety defaults
- Artifacts are served with
X-Robots-Tag: noindex, nofollow, noarchive - New HTML artifacts use a versioned CSP sandbox: inline scripts work, while external network requests/assets, forms, popups, and top-level navigation are blocked
- Per-IP and per-key rate limits
- Everything expires via TTL
- Optional password protection per artifact
See SECURITY.md for vulnerability and abuse reporting.
Development
pnpm dev # run with tsx
pnpm test # vitest
pnpm run build # tsc -> dist/
License
Install
Add htmldrop to your client. Pick the one you use.
claude mcp add --transport http htmldrop https://htmldrop.link/mcpcodex mcp add htmldrop --url https://htmldrop.link/mcp{
"mcpServers": {
"htmldrop": {
"url": "https://htmldrop.link/mcp"
}
}
}Add to `~/.cursor/mcp.json`, or `.cursor/mcp.json` for a single project.
{
"servers": {
"htmldrop": {
"type": "http",
"url": "https://htmldrop.link/mcp"
}
}
}Add to `.vscode/mcp.json` in your workspace.
{
"mcpServers": {
"htmldrop": {
"url": "https://htmldrop.link/mcp"
}
}
}Add to `claude_desktop_config.json`, then restart Claude Desktop.
{
"mcpServers": {
"htmldrop": {
"serverUrl": "https://htmldrop.link/mcp"
}
}
}Add to `~/.codeium/windsurf/mcp_config.json`.
Score
39 / 100
Incomplete
- Documentation25/25
- Maintenance16/25
- Trust13/20
- Capability0/15
- Install experience12/15
- Documents what it does and how to connect
- Has a resolvable package or endpoint
- Exposes at least one tool, prompt or resource
- README has substantive content
- Includes a code example
- Documents its configuration
- Mentions credentials or security posture
- Last commit 35 days ago
- Has a release history
- Repository is not archived
- Licensed MIT
- Namespace verified in the official MCP registry
- Claimed by its owner
- Published under an organisation
- 0 tool(s) documented
- Provides prompt templates
- Provides resources
- 6 documented install method(s)
- Published to a package registry
- Offers a hosted endpoint ā no local install
Version history
| Versions | Published |
|---|---|
| 0.1.0Latest | Jul 15, 2026 |