MCP server

Adeli runs a Model Context Protocol server, so an AI agent can use the API as typed tools instead of hand-written HTTP requests. The tools are the REST API: each one calls the same endpoint with the same validation, profile scoping, errors, and side effects. Nothing is available over MCP that is not available over REST.

Endpoint and authentication

http
POST https://app.tryadeli.com/mcp
Authorization: Bearer rk_live_...
  • Transport — Streamable HTTP. The server is stateless and answers each request with JSON; there is no session to keep and no event stream to hold open.
  • Key — the same rk_live_ API key you use for REST, created under API keys. See Authentication.
  • Scope — every tool acts on the one profile the key is bound to. profileId is optional on every tool and defaults to that profile.

A missing or revoked key fails the connection with 401 unauthorized and a WWW-Authenticate: Bearer header, before any tool runs.

The key lives in your client's config

MCP clients store the header in a local config file. Read the key from an environment variable where your client supports it, give each machine or agent its own key, and never commit the file. If one leaks, delete that key under API keys — revocation is immediate.

Connect your client

claude mcp add --transport http adeli https://app.tryadeli.com/mcp \
--header "Authorization: Bearer $ADELI_API_KEY"

Claude Code expands $ADELI_API_KEY when you run the command and stores the result in its config. Clients that can only launch local processes reach the server through mcp-remote, which bridges stdio to HTTP.

Check the connection

List the tools with a single request. You should get back the tools described in MCP tools.

bash
curl https://app.tryadeli.com/mcp \
-H "Authorization: Bearer $ADELI_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

To call tools interactively, run npx @modelcontextprotocol/inspector, choose Streamable HTTP, and add the Authorization header.

How tools behave

  • Results are REST bodies. A tool returns exactly the JSON the matching endpoint returns, as structuredContent and as text.
  • Partial is not an error. Reads that span providers can succeed for some accounts and fail for others. That result carries status: "partial" and an errors list, as described in Core concepts, and is not marked as a tool error.
  • Errors keep the envelope. Any 4xx or 5xx becomes a tool error whose content is the usual { "error": { "code", "message", "details" } } body. See Errors for every code.
  • Tools say what they change. Read-only tools are annotated readOnlyHint. disconnect_account and ads_set_status are annotated destructiveHint, so clients that ask before acting will ask.
  • Large reads are truncated in text only. Past about 100 KB, the text copy is cut short and structuredContent still holds the whole body. Filter by platform or accountId to keep responses small.

What MCP does not do

  • No OAuth sign-in. The server takes an API key, so clients that can only connect through an OAuth flow, such as claude.ai custom connectors, cannot add it directly yet. Use mcp-remote from a desktop client instead.
  • No multipart uploads. create_post takes the JSON body of POST /api/v1/posts. For TikTok and YouTube video, pass a public HTTPS video.url rather than base64. Send large files through REST.
  • No key or profile management. Create keys and profiles in the dashboard. A key cannot create a profile, and deleting a profile is not a tool.
  • WhatsApp sends templates only. send_message sends one of the business's approved WhatsApp templates; free-form WhatsApp replies stay in the dashboard inbox. Connecting a WhatsApp number is done on the dashboard's Accounts page.

For agents

If you are an AI agent reading this page, the essentials are:

  1. Call list_accounts first. Every account-level tool takes an accountId from it, and every ads tool takes an adAccountId from ads_list_accounts.
  2. Leave profileId out. It defaults to the only profile your key can reach.
  3. Ask the user before calling create_post, send_message, disconnect_account, ads_create_campaign, ads_create_account, ads_update_account, or ads_delete_campaign. These act on a real customer's real accounts, and an ad account, once created, cannot be deleted.
  4. Never call ads_set_status with ACTIVE unless the user has confirmed the budget and dates in this conversation. It starts spending money.
  5. Publishing to TikTok and YouTube, and Facebook Reels and videos, is asynchronous: poll the matching status tool with the returned publishId. Ask the user for a YouTube video's visibility and whether it is made for kids; never choose either for them.
  6. For anything not covered here, read the adeli://docs/llms.txt resource. It is this entire documentation site as plain text.