
@dropthis/mcp
Official MCP server for dropthis — publish content (HTML, files, or a URL to fetch) and get back a permanent public URL, from any MCP-compatible agent (Claude Code, Claude Desktop, Cursor, Windsurf, opencode, ChatGPT, n8n, …).
Two ways to connect:
- Local (stdio) —
npx @dropthis/mcp, authenticated with your sk_ API key. Best for coding agents.
- Remote (hosted) —
https://mcp.dropthis.app/mcp over Streamable HTTP, with OAuth for chat clients or a static sk_ Bearer for automation. Best for ChatGPT / claude.ai / n8n.
Local / stdio
Add to your MCP client config:
{
"mcpServers": {
"dropthis": {
"command": "npx",
"args": ["-y", "@dropthis/mcp"],
"env": { "DROPTHIS_API_KEY": "sk_..." }
}
}
}
Get an API key from your dropthis account. The server reads DROPTHIS_API_KEY (and optional DROPTHIS_BASE_URL). Set DROPTHIS_READ_ONLY=true to register only the read tools — a safe way to give an agent read access to your drops with no write/delete risk. Set DROPTHIS_TOOLSETS (e.g. drops) to trim the tool surface to what a session needs (Toolsets). Claude Desktop users can install the one-click .mcpb bundle instead (the API key is stored in your OS keychain).
See docs/setup.md for per-client instructions (Claude Code, Cursor, Windsurf, VS Code, …).
Remote (hosted) connector
Point an MCP-capable client at the hosted endpoint:
https://mcp.dropthis.app/mcp
One-click install (the deep-link opens the editor and adds the remote server):
-
Cursor: Add to Cursor
-
VS Code: Add to VS Code
-
Chat clients (ChatGPT, claude.ai) authenticate via OAuth 2.1 — add the connector URL, sign in with a 6-digit email code (no password), then approve the consent screen, which shows the requested permissions and lets you pick the workspace to publish into.
-
Automation (n8n, CI, custom agents) sends a static Authorization: Bearer sk_... header and skips OAuth. See docs/n8n.md.
-
Read-only: append ?readonly=true to the endpoint (https://mcp.dropthis.app/mcp?readonly=true) to register only the read tools, even for a write-capable credential.
-
Manage or disconnect the connector later from the console's Connected apps page at https://app.dropthis.app.
Tools
dropthis_publish | Publish new content (content | source_url | files | file/paths) → permanent URL |
dropthis_update_content | Publish a new content version to an existing drop, keeping its URL |
dropthis_update_settings | Update a drop's settings (title, visibility, password, noindex, expiry, metadata) and routing (move onto a custom domain / back to the shared pool, rename the vanity slug) |
dropthis_get | Fetch one drop's metadata |
dropthis_get_content | Read back what a drop is serving — its file manifest, or one file's content (the read half of the edit loop) |
dropthis_resolve | Turn a drop's public URL or slug into its drop_… id (owner-scoped) — the recovery path for the id-based tools |
dropthis_list | List your drops (paginated) |
dropthis_list_deployments | List a drop's deployment (version) history |
dropthis_restore_deployment | Roll a drop back to a prior deployment's content (Pro+ version history) — mints a new deployment copying it and makes it current, URL unchanged |
dropthis_analytics | Read a drop's approximate view analytics (Keep+ for counts, Pro+ for country/referer/daily breakdowns) |
dropthis_delete | Delete a drop (requires confirm: true) |
dropthis_account | Authenticated account profile (id, email, status) including the account's limits for preflight sizing |
dropthis_domains_connect | Connect a custom domain (path or dedicated mode) and get the CNAME record to create |
dropthis_domains_verify | Re-check a domain's DNS/TLS and advance its status toward live |
dropthis_domains_get | Read one domain's stored state and DNS instructions (no live DNS check) |
dropthis_domains_list | List the account's custom domains and which is the default publish target |
dropthis_domains_update | Repoint a dedicated domain to another drop, or set/clear the default path domain |
dropthis_domains_delete | Disconnect a custom domain (requires confirm: true) |
dropthis_workspaces | List the workspaces this connection can publish to, and which is active |
dropthis_use_workspace | Switch the active workspace for this connection (persists server-side) |
dropthis_create_workspace | Create a new team workspace (you become its owner) |
dropthis_rename_workspace | Rename a team workspace or change its slug |
dropthis_delete_workspace | Delete a team workspace (owner only; requires confirm: true) |
dropthis_members | List a team workspace's members and their roles |
dropthis_invite_member | Invite an email to a team workspace as admin or member |
dropthis_update_member_role | Change a member's role (owner/admin/member) |
dropthis_remove_member | Remove a member from a workspace, or leave it (requires confirm: true) |
dropthis_invitations | List your own pending workspace invitations |
dropthis_accept_invitation | Accept a workspace invitation and join (by token or invitation id) — the teammate join path |
file/paths are local/stdio only — the hosted Worker omits them from the tool schemas entirely. dropthis_update_content accepts the same content inputs as dropthis_publish; a source_url is fetched server-side (SSRF-guarded) and stored as the new version. The id-based tools (dropthis_update_content, dropthis_update_settings, dropthis_get, dropthis_get_content, dropthis_analytics, dropthis_delete, dropthis_list_deployments, dropthis_restore_deployment) require the full drop_… id from the publish response and are strict id-only: pass a URL or slug and the tool returns an error pointing you at dropthis_resolve, which turns a public URL/slug back into the drop_… id (owner-scoped). Resolve once, then edit by id — persist the drop_… id, since URLs and slugs are locators that can drift. Connections whose OAuth grant lacks the drops:write scope see only the read tools.
dropthis_account returns your account's exact limits.
The team-management tools (dropthis_create_workspace, dropthis_rename_workspace, dropthis_delete_workspace, dropthis_members, dropthis_invite_member, dropthis_update_member_role, dropthis_remove_member, dropthis_invitations, dropthis_accept_invitation) need a team-scoped credential (ADR-0068) — a publish-only key cannot manage teams. Find a workspace id with dropthis_workspaces and a member's accountId with dropthis_members. dropthis_accept_invitation is the teammate's join path: list your invites with dropthis_invitations, then accept by its invitation id (or by the raw token from the invite email).
Workspaces (teams)
Every drop lands in a workspace (ADR-0067). A fresh login homes to your personal workspace; teams are shared workspaces with members and roles. Each connection has one active workspace, and publishes go there by default:
dropthis_workspaces lists the workspaces this connection can act in and flags the active one.
dropthis_use_workspace switches the active workspace; the choice persists server-side across reconnects.
dropthis_publish takes a per-call workspace override — write-side targeting for a new drop.
dropthis_list takes a per-call workspace selector — list another workspace you belong to without switching.
- id-addressed ops (
update_content, update_settings, delete, …) always act in the drop's own workspace (a drop never moves workspace).
dropthis_account echoes the active workspace (name, kind, your role).
A static sk_ API key is pinned to the one workspace it was minted in — dropthis_use_workspace and the per-call workspace override/selector do not apply to it. To act in another workspace with an sk_ key, mint a key in that workspace. OAuth (remote) connections are not pinned and can switch freely.
Permissions & read-only
Write tools (publish, update, delete, domain and team management) require write access; the read tools never do:
- A static
Authorization: Bearer sk_... key is always write-capable (account-scoped).
- An OAuth (remote connector) grant must hold the
drops:write scope to see the write tools. The read tools need no scope, so a grant without drops:write — or any session in read-only mode — sees the read tools alone. A 403 insufficient_scope from a write tool means re-authenticate to request drops:write.
There are two ways to force a read-only session even with a write-capable credential — only the read tools are registered, so there is zero write/delete risk:
- Local / stdio: set the env var
DROPTHIS_READ_ONLY=true.
- Remote: append
?readonly=true to the endpoint (https://mcp.dropthis.app/mcp?readonly=true).
The read tools that stay available in a read-only session are: dropthis_get, dropthis_list, dropthis_list_deployments, dropthis_get_content, dropthis_analytics, dropthis_resolve, dropthis_account, dropthis_domains_list, dropthis_domains_get, dropthis_workspaces, dropthis_members, and dropthis_invitations. Everything else is a write tool and is hidden (dropthis_restore_deployment, a version-history rollback, needs the drops:write scope).
Toolsets (trim the tool surface)
All 29 tools load by default, but a publish-and-edit session rarely needs the 17 domains/workspaces/members/invitations tools. Register a subset to cut the per-session tool prose:
- Local / stdio: set
DROPTHIS_TOOLSETS to a comma list, e.g. DROPTHIS_TOOLSETS=drops.
- Remote: append
?toolsets= to the endpoint (beside ?readonly=), e.g. https://mcp.dropthis.app/mcp?toolsets=drops or ?toolsets=drops,account.
Values: drops (the core publish/edit/read tools — 11), domains (6), workspaces (workspaces + members + invitations — 11), and account (1). Unset, empty, or all-unrecognized → all toolsets (the default). Unknown tokens are ignored. ?readonly= and ?toolsets= compose: each hides tools independently, so ?toolsets=drops&readonly=true leaves only the drop read tools. The tool list is fixed at connect — restart the stdio server (or reconnect the remote connector) after changing the value. A hosted claude.ai connector has no query-param UI, so set it in the connector URL you add.
Multi-file bundles (files input)
A files bundle holds up to 200 files. Each file has a path (bundle-relative, used verbatim in HTML/CSS src/href attributes) and exactly one content source:
content | UTF-8 text: HTML, CSS, JS, JSON, SVG, markdown | Text is sent inline |
source_url | Remote assets: images, video, PDFs, fonts | Server fetches the URL; no bytes pass through your agent. Optional content_type, size_bytes, checksum_sha256, transform |
content_base64 | Small inline binary blobs only | Capped at 64 KiB encoded; rejected with a corrective error above that threshold pointing at source_url |
Never base64-encode an image that is already publicly reachable — use source_url instead. Example bundle with mixed sources:
{
"files": [
{ "path": "index.html", "content": "<html>…<img src='hero.jpg'>…</html>" },
{ "path": "hero.jpg", "source_url": "https://cdn.example.com/hero.jpg" },
{ "path": "logo.png", "source_url": "https://cdn.example.com/logo.png", "content_type": "image/png" }
]
}
Image transforms. A source_url image can carry a transform so the server resizes/re-encodes it on ingest — point at a big original and store a small web-optimised derivative, no scratch bucket needed. Fits inside the box, never upscales, strips metadata. Only with source_url; omit size_bytes/checksum_sha256 (the stored object reflects the output).
{
"files": [
{ "path": "hero.jpg", "source_url": "https://cdn.example.com/original.png", "transform": { "width": 1080, "quality": 78, "format": "jpeg" } }
]
}
Editing a bundle — update_content is a partial update
dropthis_update_content patches by default (mode: "patch"). The files you send are upserted by path; every file you don't mention is carried forward unchanged. So to fix one page, send only that page — a previously-bundled image stays put:
{
"drop_id": "drop_…",
"files": [{ "path": "index.html", "content": "<html>…edited…</html>" }]
}
To remove a file, list its path in delete_paths:
{
"drop_id": "drop_…",
"files": [{ "path": "index.html", "content": "<html>…</html>" }],
"delete_paths": ["assets/old-hero.jpg"]
}
To swap the entire content set in one call, use mode: "replace" — the files you send become the whole drop and everything else is dropped (delete_paths is invalid in replace mode).
Example prompts
Natural-language asks that exercise the main tools (the agent picks the tool):
- Publish — "Publish this HTML report and give me the link." →
dropthis_publish returns a permanent url and the drop_… id.
- Self-contained bundle — "Publish this landing page with its four images" (HTML +
files[] where each image is a source_url). → one drop, images fetched server-side and stored, no hot-linking.
- Edit in place — "Change the headline on that drop." →
dropthis_get_content reads the current file, you edit it, dropthis_update_content ships a new version at the same URL.
- Recover the id — "Update https://abc123.dropthis.app/." →
dropthis_resolve turns the URL into its drop_… id, then dropthis_update_content.
- Custom domain — "Serve my drops at reports.example.com." →
dropthis_domains_connect (path mode) returns the CNAME, then dropthis_domains_verify until live.
Privacy
dropthis is a hosted service: content you publish is sent to and stored by dropthis and served at a public URL. See the privacy policy at https://dropthis.app/privacy and the terms at https://dropthis.app/terms.
Support
Known limitations
- Plan caps apply per drop and per account (size, TTL, custom domains, passwords) across the Free / Keep / Pro / Business tiers — call
dropthis_account to read the active limits before a large publish.
- Binary bytes can't ride in a tool call: inline
content_base64 is capped at 64 KiB. For images/video/PDFs/fonts use source_url (the server fetches a public URL), or, on the local stdio server only, file/paths.
source_url must be publicly reachable over http(s); the server fetches it (SSRF-guarded). A private/localhost URL won't resolve.
- id-only edits: the URL slug is not an id — keep the
drop_… id from publish (or recover it with dropthis_resolve).
- Setting a password is Pro-only; clearing one (
null) is always allowed.
Develop
npm install
npm run dev
npm run dev:worker
npm test
npm run typecheck
npm run lint
npm run build
npm run build:worker
One TypeScript codebase, two outputs: the stdio npm package and the Cloudflare Worker. Both are thin clients over the dropthis REST API (@dropthis/node for stdio, @dropthis/node/edge for the Worker); tool handlers are unit-tested against an injected fake client.
License
MIT