Skip to content

Repository files navigation

dropthis

One call in, one URL out — on Cloudflare you own.

An agent hands dropthis HTML, a folder, a PDF or a spreadsheet and gets back a permanent URL under your domain. Every drop can carry a password, an expiry date and a noindex rule. The whole product is one Cloudflare Worker and one R2 bucket inside your own account: no dashboard, no server, no third party between the agent and the link. Agents are the only callers — over MCP, the CLI or REST — and humans see only what the agent relays: a URL, a password, a ready-to-send message.

Security note: a drop is arbitrary HTML served as active content. dropthis does not make it safe. Serve drops from a dedicated domain, never from a subdomain of a site whose cookies matter. See SECURITY.md.

Why

  • Your URL, your infrastructure. Drops live at https://drops.example.com/<slug>/ on your Cloudflare account. No *.vercel.app, no drive.google.com, no vendor logo.
  • Permanent. The slug is the drop's identity and never changes. Content is replaced in place at the same URL, atomically, and the edge never serves a stale version.
  • Three policies on every drop.password ("generate" returns a strong one, once), expires ("7d", a date, or "never", within your instance's policy) and noindex (X-Robots-Tag: noindex, nofollow, on by default). An expired link answers 410 and can be revived for 7 days with one call.
  • Agent-native. Five operations — publish, update, get, list, delete — are defined once and generated as REST routes, CLI subcommands and MCP tools, so the three never drift. Every response is one Drop shape; every error is {code, message, remediation, retryable}. Retries carry an idempotency_key and can never make a second drop.
  • Works where your agents run. claude.ai and the Claude desktop app (OAuth connector, paste your key), Claude Code, Cursor and Codex (bearer header), n8n, CI and scripts (REST). Each instance serves its own agent skill at /_skill.md with its URL and limits filled in — one link onboards any agent.
  • Free at personal scale. Cloudflare's Free plan covers a personal instance; egress is free at every scale. Numbers and citations below.

Use cases

  • Marketing pages and games from claude.ai. The agent writes the HTML, publishes it, and hands back a live link — no deploy step, no repo.
  • Client reports. A weekly report at a clean URL on the agency's domain, updated in place every Monday, created_by recording which key made it.
  • Password-protected deliverables.--password generate returns a 16-character password once; the agent sends the link in one message and the password in another.
  • Newsletter landing pages with readable slugs.--slug launch-sept gives https://drops.example.com/launch-sept/ — a link a human can type.
  • Docs generated by agents. A folder with index.html is served as a site; a folder without one gets a generated file list.
  • Throwaway previews that expire.--expires 2d and the link removes itself; nothing to clean up.

How agents use it

An agent connected to an instance reads https://<your-instance>/_skill.md and needs nothing else: the skill names the five tools, the file-entry kinds ({path, text}, {path, base64}, {path, url}, and {path, sha256} on update), this instance's live limits and policy, and the password and expiry rules. MCP is at /_api/mcp; REST is under /_api/v1 with Authorization: Bearer <key>. Files too big for one call go through dropthis_uploadcurl -Tdropthis_commit; the CLI does those three steps itself.

Install (for humans)

You need a Cloudflare account with R2 enabled (Cloudflare's docs call it a checkout flow; the free tier is included). Everything else is the tool's job.

Copy this to your agent

Paste into claude.ai, Claude Code, Cursor or any agent with a terminal:

Read https://raw.githubusercontent.com/dmalis/dropthis/main/skills/dropthis-install/SKILL.md
and follow it: install dropthis on my Cloudflare account and connect it to this client.
Ask me only for what a human must do — my Cloudflare account, enabling R2, and either an
API token or the browser login. Report the URL you end up with.

Or in the terminal

git clone https://github.com/dmalis/dropthis.git &&cd dropthis
npm install && npm run build
# Automation: a token. Create one at https://dash.cloudflare.com/profile/api-tokens with# Workers Scripts — Edit · Workers KV Storage — Edit · Workers R2 Storage — Edit ·# Account Settings — Read (plus Zone DNS — Edit and Zone Workers Routes — Edit for --domain).# At a terminal with no token, init signs you in through the browser instead (one Allow click).export CLOUDFLARE_API_TOKEN=… CLOUDFLARE_ACCOUNT_ID=…
npx ./packages/dropthis init --domain drops.example.com --json # omit --domain for *.workers.dev
npm install -g ./packages/dropthis # `dropthis` on your PATH
dropthis connect --client claude-code # or cursor | codex | claude-ai
dropthis connect # no --client: just this instance's URLs
dropthis publish ./report --title "Q3 report"# → https://drops.example.com/k7x2m9q4pz/

init verifies the credential, pins the account (browser login refuses to guess between several), creates or repairs the bucket and KV namespace by name, mints the admin key and writes its record into the bucket, deploys the Worker with its secret, adds the lifecycle rules, attaches the domain when its zone is in the account, polls for health, runs doctor (a real hello drop: publish, fetch, delete), saves the instance to ~/.config/dropthis/instances.json and prints the connect snippets. Re-running is a repair: "admin_key_status": "existing" and no key is re-revealed; --rotate-admin-key is explicit. --dry-run stops after the preflight. --name <name> is only needed from the second instance on. Result:

{ "ok": true, "name": "main", "worker": "dropthis-main", "bucket": "dropthis-main-drops",
"kv_namespace": "dropthis-main-oauth", "canonical_url": "https://drops.example.com",
"alias_origins": ["https://dropthis-main.<subdomain>.workers.dev"],
"admin_key_status": "created", "admin_key": "",
"steps": [ { "id": "token", "status": "ok" }, … { "id": "doctor", "status": "ok" } ],
"doctor": { "ok": true, "checks": [ ] },
"instances_file": "~/.config/dropthis/instances.json",
"connect": { "mcp_url": "https://drops.example.com/_api/mcp", "clients": { } } }

admin_key appears only on the run that minted it and is saved to instances.json in the same run.

Use

dropthis publish ./report --title "Q3 report"# → URL on stdout
dropthis publish deck.pdf --title "Deck" --password generate --expires 7d --json
dropthis publish ./page --title "Launch" --slug launch-sept # a readable link
dropthis update https://drops.example.com/k7x2m9q4pz/ ./report # new content, same URL
dropthis update k7x2m9q4pz --password generate --json # settings only
dropthis update k7x2m9q4pz --expires 30d # revive an expired link
dropthis get k7x2m9q4pz --files --json # title, settings, meta, file content
dropthis list --q "Q3" --json
dropthis delete k7x2m9q4pz --yes
dropthis user add anna --json # key shown once + connect snippets + ready-to-send message
dropthis user list --json
dropthis user remove anna # revokes the key; every session behind it ends
dropthis config get --json # this instance's policy
dropthis usage --json # drops and bytes per state
dropthis prune --json # dry run; --no-dry-run deletes what is past grace
dropthis doctor --json # the instance proves itself
dropthis instance list --json # what is configured on this machine, with its URLs; never a key
dropthis commands --json # the whole surface, generated from the registry

The same operations are MCP tools (dropthis_publish, dropthis_update, dropthis_get, dropthis_list, dropthis_delete, dropthis_upload, dropthis_commit; admin: dropthis_user_*, dropthis_config_*, dropthis_usage, dropthis_prune, dropthis_doctor, dropthis_doctor_checks) and REST routes under /_api/v1. get, update and delete take the drop's URL or its slug; a URL from another instance is WRONG_INSTANCE.

Credentials: CLOUDFLARE_API_TOKEN for init; DROPTHIS_URL + DROPTHIS_KEY for everything else, or --instance <name> from instances.json (an only instance is the default); dropthis instance list lists them with their URLs and the one a bare command uses. --json prints exactly one JSON document; on publish and update plain stdout is the URL. Exit codes: 0 ok, 1 failure, 2 cancelled, 4 auth required. Never a prompt when stdin is not a terminal. A chosen password arrives on stdin (--password-stdin), never as a flag.

Teams and clients

An instance is a team: every user key sees and edits every drop, created_by says who made it, and leaving is revoking the key. user add returns the key once with a connect object (per-client snippets and a message to forward). claude.ai and the Claude desktop app add /_api/mcp as a connector and log in by pasting the key; on a Team or Enterprise plan an Owner adds the connector once and each member logs in with their own key. A client gets their own instance — init --name client-x — with a separate Worker, bucket and keys, on your account or theirs.

Cost

A personal instance runs on Cloudflare's Free plan. Cloudflare's own numbers, read 2026-09-04:

ResourceFree planPaidSource
Workers requests100,000 / day$5 / month, 10 M included, then $0.30 / Mhttps://developers.cloudflare.com/workers/platform/pricing/
Workers cron triggers5 per account (= 5 instances)250https://developers.cloudflare.com/workers/platform/limits/
R2 storage10 GB-month$0.015 / GB-monthhttps://developers.cloudflare.com/r2/pricing/
R2 writes (Class A)1 M / month$4.50 / Msame
R2 reads (Class B)10 M / month$0.36 / Msame
R2 egressfreefreesame
Workers KV (OAuth sessions only)100,000 reads, 1,000 writes / day, 1 GB$0.50 / M readshttps://developers.cloudflare.com/kv/platform/pricing/

A page view reads the slug pointer, the drop's metadata and the file — three R2 reads when the edge cache misses — so the Free plan's 10 M Class B operations are roughly 3 M page views a month (derived, not measured). An agency hosting 20 client instances pays $5 a month for Workers Paid, once per account. Enabling R2 goes through Cloudflare's checkout flow (https://developers.cloudflare.com/r2/get-started/, read 2026-09-04); the docs do not say whether a card is required.

Against the usual alternatives

Prices read 2026-09-04 from each vendor's own page. "Your domain" means the link can be on a domain you own; "your infra" means the files sit in an account you control.

Free tierPassword protectionYour domainYour infraExpirySource
dropthisCloudflare Free (above)includedyesyes (your Cloudflare account)per drop, 7-day gracethis repository
Tiiny.host1 project, 3 MB, 5,000 visits / monthSolo, $13 / monthSolo, $13 / monthnonot offeredhttps://tiiny.host/pricing
Netlify (incl. Drop)300 credits / month (≈ 15 GB bandwidth)Pro, $20 / monthyesnonot offeredhttps://www.netlify.com/pricing/ · https://docs.netlify.com/manage/security/secure-access-to-sites/site-protection/
VercelHobby, personal and non-commercial use onlyEnterprise, or a $150 / month Pro add-onyesnonot offeredhttps://vercel.com/pricing · https://vercel.com/docs/deployment-protection
S3 + CloudFront1 TB egress and 10 M requests / month always free; S3 Standard $0.023 / GB-monthbuild it yourself (signed URLs or Lambda@Edge)yesyesbuild it yourselfhttps://aws.amazon.com/s3/pricing/ · https://aws.amazon.com/cloudfront/pricing/pay-as-you-go/
Google Drive link15 GBlink-sharing only, no passwordno (google.com)nonot offeredhttps://one.google.com/about/plans

dropthis is not a CDN product or a general host: it is the publish step for content an agent made, with the three policies agents need and nothing else.

How it runs

Worker ── serves /<slug>/* and /_api/v1/* and /_api/mcp and /_skill.md
R2 ── every file and every metadata object; the bucket is the database
KV ── OAuth session storage only (claude.ai and Claude desktop connectors)
cron ── hourly, resumable expiry and prune

No Postgres, no D1, no queue, no build step. The bucket is plain files: rclone sync copies an instance. Design and decisions: AGENTS.md, docs/decisions.md, docs/research/. Machine-readable index: llms.txt.

Licence

Apache-2.0. See LICENSE. Name and logo: TRADEMARKS.md.

About

The publish layer for agents, on Cloudflare you own. One Worker + one R2 bucket; MCP, CLI, REST; password, expiry, noindex on every drop.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages