MCP

Connect an assistant

Everything in the API reference is available to an AI assistant over the Model Context Protocol — one tool per operation, running the very same handlers, under the very same rules. No key is pasted anywhere: the connection is its own credential, granted per client, narrowed to the scopes you tick, and revocable on its own.

The URL

Give any MCP client this one address; it discovers everything else itself:

https://drop.top/api/mcp

Connecting from claude.ai

  1. Open Settings → Connectors.
  2. Choose Add custom connector and paste the URL above.
  3. Claude opens the authorization flow in a browser window. If you are signed in here, the consent screen appears immediately; if not, you sign in first — the assistant never sees your password, only the outcome.
  4. No account yet? Make one there and then. The sign-in page's Create an account link carries the connection request with it, so signing up drops you back exactly where you were rather than on the console with a half-finished handshake behind you. If this is a brand-new account, the consent screen asks one question first — what to call your workspace — because the connection has to act on something.
  5. Review the consent screen (next section), tick what you actually want to grant, and approve.
  6. Back in Claude, the connector lists its tools. Ask it to “list my channels” to see it work.

Disconnecting is yours at both ends: remove the connector in Claude, or — the end that actually revokes the grant — open the studio's API page, find it under Connected assistants, and disconnect. The next connection has to ask you again.

The consent screen is not a yes/no dialog. It lists every capability the connection could have as a checkbox row — the same scopes an API key carries, described in plain words (“Send alerts that can ring phones”, not alerts:send jargon alone). Untick anything and the grant is minted without it: an assistant connected for drafting can be given alerts:write and denied alerts:send, and every send it ever attempts will be refused with a 403 naming the missing scope — until you reconnect and approve it.

If your account can act for more than one workspace, the same screen carries a workspace picker: the grant binds to the workspace you choose there, and only roles that may hold it are offered. An assistant connected to one workspace cannot wander into another — connecting it to a second one is a second consent.

Two things are not on the screen because they are not on offer: an assistant can never create or read API keys (a token that could mint sk_live_ keys would escape its own revocable grant), and the subscriber API is not exposed (that is the handset's surface, not yours).

How discovery works

The whole handshake is standard OAuth 2.1, which is why no client id or key is ever typed in: the client calls /api/mcp unauthenticated and gets a 401 whose WWW-Authenticate header points at the protected-resource metadata (/.well-known/oauth-protected-resource); that names the authorization server, whose own metadata advertises dynamic client registration (RFC 7591); the client registers itself, sends you to authorize, you land on the consent screen above, and approval yields the token the client uses from then on. Every step is the client's to figure out — your part is the one screen.

The tools

20 tools, one per operation. Each requires the scope beside it — a grant without that scope gets a refusal that names it. send_alert and cancel_alert are the REST PATCH action's two halves, split into their own tools so the irreversible verbs are unmistakably separate calls.

ToolScopeWhat it does
get_account account:read Your creator profile
list_webhooks webhooks:read List endpoints
create_webhook webhooks:write Register an endpoint
delete_webhook webhooks:write Remove an endpoint
list_pushers channels:read List your channels
create_pusher channels:write Create a channel
get_pusher channels:read Fetch one channel
update_pusher channels:write Update a channel
delete_pusher channels:write Delete a channel
list_invites channels:read The ways in to a private channel
create_invite channels:write Mint an invite link
revoke_invite channels:write Revoke an invite link
list_alerts alerts:read List a channel's alerts
create_alert alerts:write Compose an alert — draft, schedule or send
get_alert alerts:read Fetch one alert
update_alert alerts:write Edit, send or cancel an alert
send_alert alerts:send Send a draft now, or send a scheduled alert early. Irreversible — an alert cannot be unsent.
cancel_alert alerts:send Withdraw an alert: stops it reaching phones that have not polled; phones that have it keep it.
delete_alert alerts:write Delete a draft or scheduled alert
get_stats analytics:read Account-level statistics

Public or invite-only, never guessed

A channel is one of two things, and they are not variations of each other. A public channel is listed in search and anyone who finds drop.top/<handle> can subscribe. A private one is sealed, not merely unlisted: it is absent from search, and knowing the handle admits nobody — only a phone holding an invite code can subscribe or read a single alert the channel has ever sent, and to everyone else that handle answers exactly as a handle that was never created.

Over the REST API, is_public defaults to true. Over MCP it has no default at all: create_pusher refuses to run without it. That difference is deliberate. A script omitting a field is its author accepting a documented default; a model omitting one is a guess nobody made — and the wrong guess means a school's or an ops team's channel was listed in public search and joinable by strangers for as long as it existed. Turning it private afterwards removes none of them.

So expect an assistant to ask you which one, in plain words, and to say back what it is about to create. Create it private and a first invite link is minted with it and returned in the same reply — a private channel with no way in would be one nobody, including you, could ever join. That link, code and all, is what goes on the poster or into the QR code.

Drafts first, sends deliberately

The MCP server tells every connected model the same thing, and it is worth repeating to the person steering one: an alert cannot be unsent. Cancelling stops it reaching phones that have not polled yet and does nothing at all to the phones that already have it. So compose with send: false unless you have clearly asked to publish, and expect a well-behaved assistant to confirm with you before calling send_alert. If you want that enforced rather than trusted, deny alerts:send at the consent screen — the drafts pile up, and the sending stays a human's button.

And what an alert does on a phone is a request, not a command: a pusher asks; the phone decides. The alert anatomy page has the whole story.