MCP Setup
Connect AI agents to sharedrop using the Model Context Protocol.
What is MCP?
The Model Context Protocol (MCP) is an open standard for connecting AI agents to external tools and data sources. sharedrop implements an MCP server that lets agents upload HTML, list pages, and share them, all through the standard MCP tool interface.
Remote MCP (Recommended)
The simplest way to connect is using sharedrop's hosted remote MCP endpoint. No installation needed.
Configuration
Most MCP clients (Claude Desktop, Claude Code, Cursor, Windsurf) sign in through the browser: add the server with just the URL, and approve the sign-in on first connect. No API key to create or paste:
{
"mcpServers": {
"sharedrop": {
"url": "https://sharedrop.cloud/api/mcp"
}
}
}
Client without OAuth, or running headless (CI, a remote box)? Add a Bearer API key in
a headers block instead:
{
"mcpServers": {
"sharedrop": {
"url": "https://sharedrop.cloud/api/mcp",
"headers": {
"Authorization": "Bearer sd_your_api_key_here"
}
}
}
}
Replace sd_your_api_key_here with your actual API key. See Authentication for how to create one.
Benefits
- No installation or setup
- Always up to date
- Works with any MCP client that supports remote servers
- Same rate limits as the REST API
Remote-only
The sharedrop MCP server is hosted, so there is no local/stdio package to install or keep alive. If your client doesn't support remote MCP servers, use the REST API or the CLI instead.
Pair the connection with the agent skill so your agent also knows when to reach for sharedrop and which defaults to use.
Available Tools
The MCP server exposes the following tools. Every file, including HTML, uses the same streamed upload pipeline. Supply page_id when replacing an existing page.
Uploading a large or opaque file (a database dump, a build tarball, anything over 30 MB)? On Pro and Team accounts the server also exposes
create_archive_upload,sign_archive_parts,complete_archive, andabort_archivefor streaming download-only archives up to 10 GB. See the Archives guide for the agent flow.
create_upload
Phase 15 direct-streamed upload, step 1 of 2. Reserves an object_key, runs the
tier + storage gate, and mints a 5-minute HS256 upload token. The agent then
streams the body out-of-band with curl -T, and calls finalize_upload to
sanitise and publish.
Use create_upload + finalize_upload for files of any kind (HTML, image, PDF,
Markdown, MHTML, JSON, JSONL), so there is no 4.5 MB Vercel function-body cap on this path
because the body never flows through the Vercel function. This is the only upload
path: raw bytes are never base64-encoded into the MCP envelope.
Size limits: each file can be up to the plan's per-file limit (Free 10 MB,
Pro and Team 100 MB). HTML and other text files (Markdown, code, plain text,
JSON, JSONL, MHTML, skills, Word documents, spreadsheets) and SVG images are
capped at 10 MB on every plan. Larger content can be uploaded as a zip with create_archive_upload
and is stored as a download-only archive (Pro and Team). A bundle finished with
finalize_bundle is capped at the plan's per-file limit across all its files
together. create_upload refuses an oversized file with FILE_SIZE_EXCEEDED
before any bytes are sent; the error carries limitBytes and requestedBytes.
whoami reports these limits up front: entitlements.maxFileSizeBytes (the plan
limit), entitlements.maxTextFileSizeBytes (HTML, other text files and SVG) and
entitlements.maxArchiveBytes (archives, 0 when the plan cannot upload them).
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
filename | string | Yes | Filename including extension (e.g. report.pdf) |
content_type | string | Yes | MIME type (e.g. application/pdf) |
size_bytes | number | Yes | Exact body size in bytes. Must match the Content-Length of the subsequent PUT |
workspace | string | No | Workspace ID. Ignored on workspace-scoped API keys |
reservation_id | string | No | Claim a reserved address (from create_reservation). The finished upload becomes a NEW page at the reserved URL. Mutually exclusive with page_id. See Reserved addresses |
Workspaces are part of the Team plan and are created in the dashboard, not through
MCP. Anyone invited to one can upload to it with workspace, whatever their own plan.
See Workspaces and seats.
Returns: upload_url (the https://uploads.sharedrop.cloud/<object_key>
endpoint the agent PUTs to), upload_token (the 5-min HS256 JWT to put in the
Authorization: Bearer ... header), finalize_url, object_key.
Recommended out-of-band PUT:
curl -X PUT "$UPLOAD_URL" \
-H "Authorization: Bearer $UPLOAD_TOKEN" \
-H "Content-Type: application/pdf" \
-H "Content-Length: $(stat -f%z report.pdf)" \
--data-binary @report.pdf
The upload token expires 5 minutes after issuance. If the PUT fails after
expiry, call create_upload again to mint a fresh token (the previous
object_key is abandoned and gets garbage-collected by the bucket's 24-hour
lifecycle rule).
finalize_upload
Phase 15 direct-streamed upload, step 2 of 2. Validates the upload token,
re-reads the quarantine object, runs the kind-dispatched sanitiser (DOMPurify
for HTML, sharp for images, pdf-lib for PDFs), promotes the sanitised bytes
to the public bucket, and creates the page row.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
object_key | string | Yes | The object_key returned by create_upload |
upload_token | string | Yes | The upload_token returned by create_upload |
title | string | No | Page title. Defaults to the document title (HTML/PDF) or filename stem |
visibility | string | No | private (default), shared, or public |
mode | string | No | HTML only: static or interactive. Default: a new page takes your account's default upload mode (initially interactive; configure in Settings) and a re-upload with page_id keeps the page's current mode. Ignored for non-HTML kinds |
workspace_id | string | No | Workspace ID. Ignored on workspace-scoped API keys |
page_id | string | No | Existing page ID for re-upload (URL stays stable, version recorded) |
folder_id | string | No | Target folder ID for placement. New uploads only (Pro and above); ignored on re-upload |
folder_path | string | No | Target folder by path (e.g. reports/2026), auto-creating any missing segments. New uploads only (Pro and above). folder_id wins if both are set |
slides | boolean | No | HTML only: publish as a slide deck with fullscreen Present mode. Equivalent to a <meta name="sharedrop:kind" content="slides"> marker in the file. Ignored for non-HTML kinds |
Returns: Page URL, page ID, slug, the effective mode, visibility, kind, was_reupload, version (1 for a new page, up by one on every re-upload), scripts_will_run, external_resource_hosts, and a warnings array that is always present (possibly empty). Each warning contains code, detail, count and message; the codes are removed_tag, removed_attribute, images_extracted (inline images moved to hosted storage) and external_refs_block_scripts (external hosts that stop an interactive page's scripts while external network is off). A new page also returns same_title_pages: up to 5 of your pages with exactly the same title, newest first, as a hint to pass page_id if you meant to revise one. sanitiser_warnings (removals only, omitted when empty) is kept for older clients. See finalize for every field.
Busy page: if another upload of the same page is still finishing, the tool returns at once
with an error carrying status: 409, retryable: true, a reason (page_mutation_in_progress
or target_page_pending) and retry_after_seconds. Wait that many seconds and call the same
tool again with the same arguments; do not upload the bytes again. finalize_bundle behaves the
same way.
Example agent flow (PDF, no base64 in the LLM token stream):
1. AGENT: create_upload({ filename: "report.pdf", content_type: "application/pdf", size_bytes: 482190 })
→ { upload_url, upload_token, finalize_url, object_key }
2. AGENT shell: curl -T report.pdf -H "Authorization: Bearer $TOKEN" "$UPLOAD_URL"
→ 201 { ok: true, object_key, bytes: 482190 }
3. AGENT: finalize_upload({ object_key, upload_token, visibility: "public" })
→ { url: "https://sharedrop.cloud/agent/x8vh3p", page_id, ... }
4. AGENT to user: Here is your report: https://sharedrop.cloud/agent/x8vh3p
Notice that no base64 of the PDF was ever placed in the LLM context; the body flows out-of-band, only the URL + small JSON envelopes flow through the model.
Supported file types
create_upload + finalize_upload accept every supported kind, HTML included. The file
extension is authoritative; the content_type parameter is treated as a hint.
| Kind | Extensions | MIME type(s) |
|---|---|---|
| HTML | .html, .htm | text/html |
| MHTML web archives | .mhtml, .mht | multipart/related, application/x-mimearchive |
| Markdown | .md, .markdown | text/markdown |
.pdf | application/pdf | |
| JSON | .json | application/json |
| JSONL | .jsonl | application/jsonl |
| Image (broad support) | .png, .jpg, .jpeg, .webp, .gif, .avif, .bmp, .ico, .apng, .svg | image/png, image/jpeg, image/webp, image/gif, image/avif, image/bmp, image/x-icon, image/apng, image/svg+xml |
| Image (limited browser support) | .heic, .heif, .tif, .tiff | image/heic, image/heif, image/tiff |
| Video | .mp4, .webm, .mov, .m4v | video/mp4, video/webm, video/quicktime |
HTML has one variant: pass slides: true (or include the in-file marker) and the page
publishes as a slide deck with fullscreen Present mode instead of an ordinary page.
Slide decks and Present mode
When you generate a presentation rather than a document, publish it as a deck so the user
can put it straight on a TV or a projector. Structure the HTML as top-level <section>
elements, one per slide, then either add <meta name="sharedrop:kind" content="slides"> to
the file or pass slides: true to finalize_upload. The response comes back with
"kind": "slides".
The user presents it by clicking Present in the dashboard, or by opening the page URL
with ?present=1. On Pro you can also hand them a link that lands straight in Present mode:
// create_ephemeral_link
{ "page_id": "...", "expires_in_seconds": 14400, "present_only": true }
Give the user the returned url verbatim, since that is the copy carrying &present=1.
present_only works on decks only and requires Pro. Full details, including the keyboard
controls and kiosk autoplay, are in the slide decks guide.
Upload and re-upload
There are two business operations, and both run the identical create_upload then PUT then
finalize_upload sequence:
- Upload creates a new page. Omit
page_id. - Re-upload replaces an existing page. Pass the same
page_idtocreate_upload(it is bound into the signed token) and tofinalize_upload. The URL, slug, version history, shares, and folder placement are all preserved, and a new version is recorded.
list_pages
List your uploaded pages.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
limit | number | No | Results per page (default: 50) |
cursor | string | No | Pagination cursor |
Returns: Array of page metadata with pagination.
update_page
Update a page's metadata. Pass slug to rename a public page to a custom address. It requires Pro or higher, allows up to 10 renames per page, and follows the custom-address rules: 3 to 60 lowercase letters, numbers, and hyphens; no leading or trailing hyphen, consecutive hyphens, reserved words, or generated-looking addresses. Previous addresses permanently send a 301 redirect to the current address and cannot be reused. If the page becomes private or shared, it returns to a generated random address and the custom address stops resolving.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
page_id | string | Yes | ID of the page to update |
slug | string | No | Custom address for a public page (Pro plan or higher) |
fetch_page
Pull a page's raw content into the agent's context: its own page, a public one, or one shared to it. Returns a short-lived signed fetch_url plus metadata; the agent then HTTP GETs fetch_url (no auth header; the token is in the URL) to read the raw bytes. This is the content path; get_page stays metadata-only. Not a zip, not the sandboxed viewer wrapper. Available on every tier (entitlements.fetch in whoami).
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
page_id | string | Yes | Page ID to fetch |
Returns: fetch_url, expires_at, content_type, mode, and size. GET fetch_url within ~5 minutes to stream the raw bytes.
Archive pages have no fetch_url. For an archive, fetch_page returns an error with code ARCHIVE_DOWNLOAD_REQUIRED and a download_url: GET it with your Sharedrop Bearer credential and it redirects to the file. An unknown page returns PAGE_NOT_FOUND.
An image or video page that is still in its safety check can only be fetched by its owner. An image, video or archive page whose paying plan lapsed more than 14 days ago cannot be fetched by anyone until the plan is restored. Both return PAGE_NOT_FOUND.
Disappearing links
Pro and Team accounts can hand out a separate link that stops working after a time limit or a number of views. It never changes the page's own visibility or share list.
| Tool | What it does |
|---|---|
create_ephemeral_link | Create a link: page_id, audience ("anyone" or "people"), emails (for "people"), notify, expires_in_seconds, max_views, present_only |
list_ephemeral_links | A page's links with status, views, limits and people |
update_ephemeral_link | Add or remove people: page_id, link_id, add_emails, remove_emails, notify |
revoke_ephemeral_link | Stop a link now |
// create_ephemeral_link: only these people, after they sign in
{ "page_id": "...", "audience": "people", "emails": ["board@example.com"], "max_views": 5 }
Give the user the returned url verbatim. On a "people" link Sharedrop emails each person the
link and its limits (and anyone added later with update_ephemeral_link); pass notify: false if
the user wants to send it themselves. These emails count toward the daily share-email limit (10 on
Free, 500 on Pro, 2000 on Team); when it cannot cover everyone the link is still created and the result
carries email_warning saying how many people were not emailed, with a message to pass on to the user. Full details are in the Disappearing links guide.
share_page
Share a page with someone by email.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
page_id | string | Yes | Page ID to share |
email | string | Yes | Email address to share with |
Returns: Access grant details. share_with_email does the same for one email or a list, and
returns one result per email.
Each recipient gets an invitation email, up to a daily limit per account: 10 on Free, 500 on Pro,
2000 on Team. Over the limit the share still succeeds but no email is sent. Each share that was not emailed
carries its own email_warning (a share with null is emailed), and the top-level email_warning
says how many of the recipients were not emailed. Tell the user, and give them the page URL to send
to those people themselves. See Daily email limit.
Reserved addresses
Reserve a stable sharedrop.cloud address before any content exists, so you can hand out the final URL up front and fill it in later. See the Reserved addresses guide for the full flow and the placeholder/expiry behavior.
create_reservation
Reserve an address and get back the final URL plus a one-time claim token. The claim_token (an sdr_ credential) is shown exactly once and can never be retrieved again, so store it now and hand it to the agent over a secure channel.
Parameters: all optional.
| Name | Type | Required | Description |
|---|---|---|---|
title | string | No | Page title shown once the address is claimed (default Untitled) |
description | string | No | Optional description for your own reference |
intended_agent_name | string | No | Name of the agent this address is held for (shown in the dashboard) |
visibility | string | No | private (default), shared, or public. The claimed page inherits it |
slug | string | No | Optional custom address for a public reservation (Pro plan or higher) |
mode | string | No | HTML render mode the claimed page takes: static or interactive |
expires_at | string | No | ISO 8601 datetime after which an unclaimed reservation expires. Omit to keep it until claimed or revoked |
folder_id | string | No | Pro folder to file the claimed page into |
Returns: the serialized reservation (with the final url) plus the one-time claim_token. Over your plan's cap (Free 2, Pro 25, Team unlimited) the call returns a billing error you can relay to the user.
For slug, use 3 to 60 lowercase letters, numbers, and hyphens. It cannot start or end with a hyphen, contain consecutive hyphens, be a reserved word, or look like a generated address.
Claim the address: call create_upload with reservation_id set to the reservation's id (instead of page_id), then PUT the bytes and call finalize_upload. The first upload becomes a live page at the reserved URL, inheriting the visibility, mode, and folder chosen at reserve time. Subsequent updates use page_id as normal.
list_reservations
List your reserved addresses. Each entry shows its status (reserved, claimed, expired, or revoked), the final URL, and the metadata chosen at reserve time. Claim tokens are one-time and shown only by create_reservation, so they never appear here.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
limit | number | No | Results per page (default: 50) |
cursor | string | No | Pagination cursor |
revoke_reservation
Revoke a reservation. The row is kept (status flips to revoked) and the sdr_ claim token is permanently invalidated.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
reservation_id | string | Yes | ID of the reservation to revoke (from create_reservation or list_reservations) |
Example Workflow
Here is what a typical AI agent interaction looks like with sharedrop MCP:
- Agent generates HTML: Creates a report, dashboard, or visualization
- Agent streams the upload: Calls
create_upload, PUTs the raw HTML to the signed URL, then callsfinalize_uploadwith a title - Agent receives URL: Gets back a shareable
sharedrop.cloudlink - Agent shares the link: Sends the URL to the user in chat, or calls
share_pageto grant email access
User: "Generate a sales dashboard for Q1 2026"
Agent: I'll create that dashboard and share it with you.
[Agent generates HTML dashboard]
[Agent calls create_upload, PUTs the HTML, then finalize_upload]
[Agent receives https://sharedrop.cloud/agent/abc123]
Agent: Here's your Q1 2026 sales dashboard:
https://sharedrop.cloud/agent/abc123
Custom domains
If the account behind the API key has a live custom domain, the url
returned by finalize_upload, get_page, list_pages and update_page is the branded address on
that domain, for example https://share.yourcompany.com/yourhandle/abc123. Surface it to the user
exactly as returned; do not reassemble a URL from a hostname of your own. A page in a Team
workspace uses the workspace's custom domain, which the workspace owner manages.
The MCP server itself stays on sharedrop.cloud, and so does your API key. Only the recipient URL
is branded. A page that is not eligible, a private page or an archive, keeps its sharedrop.cloud
address.
Custom domains cover public pages on subdomains only, using exactly two records: one CNAME for the
share subdomain and one CNAME for the view subdomain. See Custom domains.
Errors worth understanding
The server instructions hand your agent the same short list:
TIER_LIMIT(a new page would pass the plan's page limit, or the file kind is not on the plan: delete a page or upgrade)FILE_SIZE_EXCEEDED(split or compress; HTML and other text files are capped at 10 MB on every plan, so upgrading does not raise that limit; upload larger content as a zip archive on Pro or Team)VALIDATION_ERROR(unsupported file type or bad input)PAYMENT_REQUIRED(the account is read only after a failed payment; the owner must update their card. Reads still work, except that images, video and archives are refused from 14 days after the lock)
"PAYMENT_REQUIRED" Error
A subscription payment failed and was still unpaid 21 days later, so the account is read only. The tool returns the server's message unchanged:
Error [PAYMENT_REQUIRED]: Your account is read only because a payment failed. Update your card at sharedrop.cloud/dashboard/settings/billing to start uploading again.
Relay that message to the person you are working for and stop trying to write. There is no upsell and nothing to retry: only a successful payment lifts the lock, and it lifts on its own when one lands.
The tools that start a write are refused: create_upload, create_archive_upload,
update_page, move_page, restore_page, share_with_email and
create_ephemeral_link. Read tools keep working, so whoami, list_pages,
get_page, fetch_page and list_shares are all still available, and so is
delete_page. The lock drops the plan to Free, so from 14 days after it fetch_page
returns PAGE_NOT_FOUND for images, video and archives until the plan is restored.
See Failed payments.
For a Team workspace the message names the workspace instead, and a member is asked to get a workspace owner to update the card.
Troubleshooting
"UNAUTHORIZED" Error
Your API key is missing or invalid. Verify:
- The key starts with
sd_orsdw_ - The key hasn't been revoked
- The
Authorizationheader format isBearer <key>
"RATE_LIMIT_EXCEEDED" Error
You've hit the rate limit for your plan tier. Wait for the rate limit window to reset (60 seconds) or upgrade your plan for higher limits.
Connection Timeout
Ensure your network can reach https://sharedrop.cloud.