{
  "markdown": "<p align=\"center\">\n  <a href=\"https://htmldrop.link\"><img src=\".github/logo.svg\" width=\"140\" alt=\"htmldrop logo\"></a>\n</p>\n\n<h1 align=\"center\">htmldrop</h1>\n\n<p align=\"center\"><b>Publish anything for agents — one API call, MCP server included.</b></p>\n\n<p align=\"center\">\n  <a href=\"https://htmldrop.link\"><img src=\"https://img.shields.io/badge/htmldrop.link-live-e8503a\" alt=\"htmldrop.link\"></a>\n  <a href=\"https://github.com/vin-spiegel/htmldrop/actions/workflows/ci.yml\"><img src=\"https://github.com/vin-spiegel/htmldrop/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"></a>\n  <a href=\"https://www.npmjs.com/package/htmldrop-mcp\"><img src=\"https://img.shields.io/npm/v/htmldrop-mcp\" alt=\"npm\"></a>\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"MIT\"></a>\n</p>\n\n<p align=\"center\">English · <a href=\"docs/README.ko.md\">한국어</a> · <a href=\"docs/README.ja.md\">日本語</a> · <a href=\"docs/README.zh-CN.md\">简体中文</a> · <a href=\"docs/README.es.md\">Español</a> · <a href=\"docs/README.fr.md\">Français</a> · <a href=\"docs/README.de.md\">Deutsch</a></p>\n\n---\n\nhtmldrop turns any HTML, Markdown, PDF, or image artifact into a shareable\nlink in seconds. Reports, dashboards, charts, demos — anything an agent (or a\nhuman) creates. Markdown/text/JSON render into a clean reader page; PDFs and\nimages are served as-is. No git, no build, no dashboard.\n\n**Try it now: [htmldrop.link](https://htmldrop.link)** — drag & drop an HTML\nfile, paste HTML source, or POST to the API.\n\n## How it works\n\n```bash\ncurl -X POST https://htmldrop.link/publish \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"html\":\"<h1>Hello agents</h1>\",\"title\":\"Demo\"}'\n```\n\n```json\n{\n  \"url\": \"https://happy-otter-42.htmldrop.link\",\n  \"id\": \"...\",\n  \"subdomain\": \"happy-otter-42\",\n  \"expires_at\": \"2026-07-17T00:00:00.000Z\"\n}\n```\n\nEvery link gets its own subdomain, an auto-generated Open Graph preview card,\nand a TTL — shared artifacts don't live forever.\n\n## Connect your agent (MCP)\n\nThe hosted MCP server lives at `https://htmldrop.link/mcp` (Streamable HTTP) and exposes\none tool: `publish_html`.\n\n### Claude Code\n\n```bash\nclaude mcp add --transport http htmldrop https://htmldrop.link/mcp\n```\n\n### Claude Desktop\n\nClaude Desktop speaks stdio, so bridge to the hosted server with\n[`mcp-remote`](https://www.npmjs.com/package/mcp-remote). In\n`claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"htmldrop\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-remote\", \"https://htmldrop.link/mcp\"]\n    }\n  }\n}\n```\n\n### Cursor\n\nCursor connects to a remote MCP URL directly. In `.cursor/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"htmldrop\": { \"url\": \"https://htmldrop.link/mcp\" }\n  }\n}\n```\n\n### Codex CLI\n\nIn `~/.codex/config.toml`:\n\n```toml\n[mcp_servers.htmldrop]\ncommand = \"npx\"\nargs = [\"-y\", \"mcp-remote\", \"https://htmldrop.link/mcp\"]\n```\n\n### Self-hosted instance (npm, stdio)\n\nRunning your own htmldrop? The [`htmldrop-mcp`](https://www.npmjs.com/package/htmldrop-mcp)\npackage is a local stdio MCP server that publishes to **your** storage and\ndomain:\n\n```json\n{\n  \"mcpServers\": {\n    \"htmldrop\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"htmldrop-mcp\"],\n      \"env\": {\n        \"BASE_DOMAIN\": \"your-domain.example\",\n        \"CLOUDFLARE_R2_ENDPOINT\": \"...\",\n        \"CLOUDFLARE_R2_ACCESS_KEY_ID\": \"...\",\n        \"CLOUDFLARE_R2_SECRET_ACCESS_KEY\": \"...\",\n        \"CLOUDFLARE_R2_BUCKET_NAME\": \"...\"\n      }\n    }\n  }\n}\n```\n\n### `publish_html` tool\n\n| Argument | Type | Description |\n|----------|------|-------------|\n| `html` | string | HTML content to publish (or use `markdown` / `url`) |\n| `markdown` | string | Markdown content — rendered into a styled reader page |\n| `url` | string | Remote HTML page to fetch and publish |\n| `title` | string | Optional title for metadata and social cards |\n| `ttl_days` | number | Days until the artifact expires |\n| `password` | string | Optional password protection |\n| `owner_key` | string | Optional key for higher limits and longer TTL |\n\nFull agent-facing docs live in [AGENTS.md](AGENTS.md), also served at\n[htmldrop.link/agents.md](https://htmldrop.link/agents.md).\n\n## REST API\n\n| Endpoint | Body | Notes |\n|----------|------|-------|\n| `POST /publish` | JSON `{ html \\| markdown, title, ttl_days, password, url }` | Primary endpoint |\n| `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=` |\n| `POST /publish/from-url` | JSON `{ url, title, ttl_days, password }` | Fetches and republishes a page |\n\nPass an owner key in the `x-htmldrop-key` header for higher rate limits and a\nlonger default TTL. (`x-pin-key` is still accepted for backwards compatibility.)\n\n## Self-hosting\n\n```bash\ngit clone https://github.com/vin-spiegel/htmldrop.git\ncd htmldrop\npnpm install\ncp .env.example .env   # defaults work out of the box\npnpm dev               # http://localhost:3000\n```\n\n**The only variable you need to set is `BASE_DOMAIN`.** Everything else has a\nworking default. Storage falls back to the local filesystem (`./data`) when no\nobject store is configured — no database required.\n\n### Environment variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| **`BASE_DOMAIN`** | `localhost` | **Base domain for artifact subdomains. The one value most self-hosters must set.** |\n| `PORT` | `3000` | HTTP port (usually set by your host) |\n| `NODE_ENV` | `development` | Set to `production` when deploying |\n| `CLOUDFLARE_R2_ENDPOINT` | — | S3-compatible endpoint. Set all four R2 vars to use object storage; leave all blank for filesystem |\n| `CLOUDFLARE_R2_ACCESS_KEY_ID` | — | Object-storage access key |\n| `CLOUDFLARE_R2_SECRET_ACCESS_KEY` | — | Object-storage secret key |\n| `CLOUDFLARE_R2_BUCKET_NAME` | — | Bucket name |\n| `ANON_TTL_DAYS` | `7` | TTL for anonymous publishes |\n| `KEY_TTL_DAYS` | `30` | TTL for keyed publishes |\n| `MAX_HTML_SIZE_BYTES` | `26214400` | Upload cap (25 MiB) |\n| `RATE_LIMIT_ANON_PER_MINUTE` | `10` | Per-IP rate limit |\n| `RATE_LIMIT_KEY_PER_MINUTE` | `60` | Per-owner-key rate limit |\n\nAny S3-compatible store works for the `CLOUDFLARE_R2_*` variables (Cloudflare\nR2, AWS S3, MinIO, …). On ephemeral/container hosts, either use object storage\nor mount a persistent volume at `./data`, or artifacts are lost on redeploy.\n\nProduction needs a wildcard DNS record (`*.your-domain`) pointing at the\nserver so artifact subdomains resolve.\n\n### Deploy to Railway\n\n```bash\nrailway login\nrailway init --name htmldrop\nrailway up\n```\n\nThen set `BASE_DOMAIN` and (optionally) the R2 variables in the Railway\ndashboard, and attach your domain plus its wildcard.\n\n## Safety defaults\n\n- Artifacts are served with `X-Robots-Tag: noindex, nofollow, noarchive`\n- New HTML artifacts use a versioned CSP sandbox: inline scripts work, while\n  external network requests/assets, forms, popups, and top-level navigation are blocked\n- Per-IP and per-key rate limits\n- Everything expires via TTL\n- Optional password protection per artifact\n\nSee [SECURITY.md](docs/SECURITY.md) for vulnerability and abuse reporting.\n\n## Development\n\n```bash\npnpm dev        # run with tsx\npnpm test       # vitest\npnpm run build  # tsc -> dist/\n```\n\n## License\n\n[MIT](LICENSE)\n",
  "bytes": 7286,
  "sha": "94233d48f57a6db250387f4c2b6b805c523bc740e54ab3e617f76d01a35ffc7a",
  "repo_slug": "vin-spiegel/htmldrop",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_vin_spiegel_htmldrop_21ce9712/readme"
}