Carillon docs

MCP server

Connect an agent, configure an app, send notifications, manage recurring schedules, and read delivery traces.

For text, number, boolean and date attributes, SDK methods and audience operators, see Tags.

Set up with your agent

Copy a prompt with the quickstart, SDK guides and MCP connection. Sign in or create your account when the agent opens the browser.

Copy setup prompt
Read the prompt
Help me send my first mobile push with Carillon in this project.

Read https://app.carillon.dev/docs/llms.txt, then https://app.carillon.dev/docs/quickstart and the SDK guide matching this codebase:
React Native: https://app.carillon.dev/docs/sdks/react-native
Swift: https://app.carillon.dev/docs/sdks/swift
Kotlin: https://app.carillon.dev/docs/sdks/kotlin

Connect the hosted MCP at https://app.carillon.dev/mcp using OAuth. Open the browser so I can sign in or create an account; never ask for my password.

List my organizations and select the appropriate workspace.
Reuse a matching app or create one after checking the existing apps.

Inspect the code and use the installed SDK API. Get an active mobile key with key_list. Never put a secret key in the mobile app.

Check provider credentials and guide me through any Apple/Firebase steps or device actions you cannot perform. Keep credential files and secrets out of chat and version control.

Configure the SDK, native capabilities and notification permission, then rebuild. Verify the device registration, send one notification only to my chosen test device, and inspect its trace. A provider acceptance is not proof of display on the phone. Report what was verified and what still needs my action.

Read the current MCP tool list; use the documented API or dashboard when a required action is not available as a tool.

Connect an HTTP MCP client to:

https://app.carillon.dev/mcp

For Claude Code:

claude mcp add --transport http carillon https://app.carillon.dev/mcp

Sign in or create an account through the browser when prompted. Signup creates a workspace and resumes the MCP authorization flow. The client receives an OAuth access token with your organization memberships. Access tokens last one hour; refresh tokens last one week.

Use device_list to verify registration, then notification_send_test to send one real notification to a device you select. Read its result with message_trace. Use notification_send for campaigns with audiences, localization and scheduling. Backend integrations can use a secret key with POST /v1/messages.

The tools

Start with organization_list, then app_list. Pass the returned organization and app IDs explicitly to subsequent tools.

ToolArgumentsReads onlyDestructive
device_deleteapp_id, device_id, confirm: trueNoYes
device_listapp_id, q?, platform?, status?, cursor?YesNo
device_tags_readapp_id, device_idYesNo
device_tags_patchapp_id, device_id, tag mapsNoNo
user_tags_readapp_id, external_idYesNo
user_tags_patchapp_id, external_id, tag mapsNoNo
notification_tags_listapp_id, mode?, cursor?YesNo
message_traceapp_id, message_idYesNo
notification_sendapp_id, audience, payload, confirm: true; optional send API fields and idempotency_keyNoNo
notification_send_testapp_id, device_id, title, body?, data?, tags?, confirm: trueNoNo
recurring_listapp_idYesNo
recurring_createapp_id, complete recurring definitionNoNo
recurring_updateapp_id, recurring_id, complete definition, confirm: trueNoYes
recurring_activateapp_id, recurring_id, confirm: trueNoNo
recurring_pauseapp_id, recurring_id, confirm: trueNoYes
recurring_archiveapp_id, recurring_id, confirm: trueNoYes
recurring_historyapp_id, recurring_id, days?, cursor?YesNo
notification_listapp_id, tag?, tags?, without_tag?, include_empty?, mode?, source?, cursor?YesNo
notification_cancelapp_id, message_id, confirm: trueNoYes
device_historyapp_id, device_idYesNo
delivery_traceapp_id, delivery_idYesNo
audience_updateapp_id, audience_id, definition, confirm: trueNoYes
audience_suggestionsapp_id, field, key?, search?, cursor?YesNo
app_healthapp_idYesNo
app_activityapp_idYesNo
notification_statisticsapp_id, since, until, source?, cursor?YesNo
organization_listnoneYesNo
app_listorganization_idYesNo
app_createorganization_id, nameNoNo
credential_setupapp_idYesNo
credential_listapp_idYesNo
credential_uploadapp_id, provider, key_id, team_id?, bundle_id?, materialNoNo
key_listapp_idYesNo
key_createapp_id, type, label?NoNo
key_revokeapp_id, key_id, confirmNoYes
audience_listapp_idYesNo
audience_previewapp_id, definitionYesNo
audience_createapp_id, name, definitionNoNo
audience_deleteapp_id, audience_id, confirmNoYes

notification_send_test requires your confirmation of the device and content. It sends in live mode, not simulated test mode, and must not be retried automatically. It is offered when sending is configured.

The credential pair is only offered where key management is configured, so a tool that would have to refuse the call is not listed.

Permissions and confirmation

Destructive tools require an explicit confirmation. device_delete, key_revoke and audience_delete take a confirm argument and refuse without it, which is where the agent asks you first. Revoking a mobile key breaks device registration in every installed copy of an app until users take an update.

A secret key is shown once, to the agent too. key_create returns its value in that one answer and nowhere else, exactly as the dashboard does. A mobile key stays readable, as it does everywhere else.

An app or organization outside your memberships answers "no such", never "forbidden". The two cases are not distinguishable from the answer.

A refused tool call includes an error and the next action. For example:

No such resource. No app with that id, or you are not a member of the
organization owning it. Call app_list for an organization you belong to.

Authentication · CLI · Send your first notification

Test application data

notification_send_test accepts optional data with the same JSON values, including nested objects and arrays, as a message payload. Ask the user to confirm the device and content before sending; this sends a real notification and a repeated call sends another one.

{
  "app_id": "{{app_id}}",
  "device_id": "{{device_id}}",
  "title": "Open the example conversation",
  "data": { "url": "myapp://chat/42", "unread": 3 },
  "confirm": true
}

Read the returned campaign with message_trace. Poll while status is scheduled or sending. Stop on sent or canceled. A paused campaign requires action before resuming. sent means processing is finished, not that every notification was accepted or displayed; inspect the delivery outcomes for failures. Zero pending deliveries alone is insufficient when scheduled waves remain.

Upload credentials without sharing the file with the client

  1. Call credential_setup with the app ID. It returns the credential screen on the same dashboard environment as this MCP connection.
  2. Open the returned URL and upload the .p8 or service-account JSON file in the dashboard. Sign in there if needed; the URL grants no access by itself.
  3. Call credential_list to verify the saved credential's status and validated_at.

credential_setup reads no local file and uploads nothing. A filesystem path on your computer is not accessible to the hosted MCP server. Use credential_upload only when you intend to provide file contents through your MCP client.

Interpret upload validation

An upload response includes validation with outcome, stage and code:

StageCheck
inputCarillon checked the supplied metadata or parsed the file.
oauthCarillon attempted the Google OAuth token exchange.
providerCarillon checked authentication with APNs or the FCM messaging endpoint.
validationThe overall Carillon validation timed out or raised an unexpected error.
nullNo stage was reported.

outcome: "invalid" records a refusal at that stage. The stage locates the observed failure, not its root cause: an authentication response does not prove the file is wrong. "unreachable" means validation could not finish; the credential is saved without being marked invalid by that attempt. "not_checked" means validation was unavailable.

This diagnostic describes the upload attempt and is not retained by credential_list. The list's last_error remains the last recorded rejection code. Check validated_at: a saved credential with no validation time has not yet been confirmed by a provider. No raw provider response, OAuth token or private key is included in the diagnostic.

Notification tags

Use notification_tags_list with app_id to discover notification labels already used in an app. These are campaign categories, not device or user tags.

{ "app_id": "YOUR_APP_ID", "mode": "live" }

The result contains tags and next_cursor. Each page contains up to 100 distinct labels sorted by label. Pass next_cursor as cursor to read the next page until it is null. Omit mode to include both live and test campaigns.

Reuse these labels in the optional top-level tags field of notification_send, for example "tags": ["new_comment", "social"]. Confirm the audience and content first: this tool sends a real notification. Read the stored tags with message_trace.

Tags accept up to 10 strings of 1-64 characters. Prefer a small, stable vocabulary. See notification tags for the send API and naming guidance.

Send to an audience

notification_send accepts the same message fields as POST /v1/messages, plus app_id, confirm: true and optional idempotency_key. It sends in live mode using the signed-in user's access to the app. Confirm the audience and content before calling it.

{
  "app_id": "YOUR_APP_ID",
  "audience": { "audience_id": "YOUR_SAVED_AUDIENCE_ID" },
  "payload": {
    "title": "New comments",
    "body": "See what is new",
    "localizations": { "fr": { "title": "Nouveaux commentaires" } }
  },
  "tags": ["new_comment"],
  "idempotency_key": "comments-campaign-42",
  "confirm": true
}

Choose one audience: device_ids, external_ids, all: true, or audience_id. Use audience_list, audience_create and audience_preview to prepare a saved audience. The latest saved filters are frozen when recipient resolution begins, then shared by all retries and timezone waves. Devices are resolved at send time.

Optional send_at schedules an instant; local_time with timezone_fallback schedules in recipients' timezones. delivery_rate controls send pacing. dedup_key prevents a repeated business notification for 30 days. The API's validation and billing rules apply.

The result contains the campaign ID. Read it with message_trace. Retry an uncertain request only with the same idempotency_key and identical message fields; without that key, another call can send another notification.

notification_send_test remains available as a shortcut for a single-device integration check. Despite its name, it also sends a real live notification. Both send tools require sending to be configured.

Remove an integration device

Use device_list to identify the exact app and device, then explicitly confirm device_delete with those IDs and confirm: true. The tool removes the device registration, including test-mode devices. It preserves delivery history and usage already counted. A later SDK registration can create the device again; removing a row is not a permanent opt-out.

Backend integrations can also use DELETE /v1/devices/{id} with a secret key carrying devices:delete. Mobile keys cannot delete devices.

Schedule recurring notifications

Use the dedicated recurring_* tools for repeated sends. notification_send creates a single campaign.

  1. Call recurring_list with app_id to read existing definitions, statuses and upcoming dates.
  2. Prepare a saved audience with audience_list, audience_preview and audience_create, or use audience_id: null for all eligible live devices.
  3. Call recurring_create with the complete definition. It returns a draft and its id; nothing sends yet.
  4. Check the returned content, audience and upcoming dates with the user, then call recurring_activate with that recurring_id and confirm: true. An active recurrence sends real pushes automatically.

Example arguments for recurring_create:

{
  "app_id": "YOUR_APP_ID",
  "name": "Monday reminder",
  "audience_id": null,
  "payload": {
    "title": "A small step this week",
    "localizations": { "fr": { "title": "Un petit pas cette semaine" } }
  },
  "tags": ["weekly_reminder"],
  "frequency_days": 7,
  "schedule": {
    "frequency": "weekly",
    "weekdays": [1],
    "month_day": 1,
    "local_time": "09:00",
    "timezone_mode": "recipient",
    "timezone": "Europe/Paris",
    "start_date": "2026-11-02",
    "end_date": null
  }
}

Choose a future start_date. frequency is daily, weekly or monthly. Weekdays use Monday = 1 through Sunday = 7. month_day accepts 1-31 or "last". Supply both weekdays and month_day; only the field relevant to the frequency is used. timezone_mode: "fixed" sends in the specified IANA timezone; "recipient" uses it as the fallback for devices without a timezone. frequency_days is a per-device cooldown for this recurrence, or null for no cooldown.

recurring_update replaces the complete definition. Read recurring_list first and preserve fields you are not changing. Active recurrences remain active; changes apply to future occurrences. Creation has no idempotency key: if the response is lost, check recurring_list before creating another draft.

Use recurring_pause to stop future occurrences and pending deliveries. recurring_activate resumes from the next future occurrence without replaying missed sends. recurring_archive cancels the recurrence permanently and retains its history. Pushes already in flight can still arrive after pausing or archiving. Updates, activation, pause and archive require the user's authorization and confirm: true. Archived recurrences cannot be edited or resumed.

Read recurring_history for the last 1-30 days (default 30). Follow next_cursor until null to read all occurrences. Pass an occurrence's campaign_id as message_id to message_trace for its delivery outcomes. See Recurring messages for schedule rules, frequency limits and lifecycle behavior.

Find and cancel a campaign

Call notification_list with app_id to find campaigns, newest first. Filter by mode (live or test), source (api or dashboard), a single tag, or a tags array. tags matches any listed tag; without_tag: "true" also includes untagged campaigns. include_empty: "false" hides completed campaigns without delivery activity. These two flags use string values "true" and "false".

Pass next_cursor back as cursor until null. Use a returned id as message_id with message_trace to inspect its content and outcomes.

To cancel an identified campaign, authorize the cancellation and call:

{
  "app_id": "YOUR_APP_ID",
  "message_id": "YOUR_CAMPAIGN_ID",
  "confirm": true
}

notification_cancel stops queued deliveries and pending timezone waves. It returns canceled_count and already_sent; the latter also includes sends already in flight, which cannot be recalled. Repeating cancellation is safe. Canceling one occurrence does not stop its recurring schedule; use recurring_pause or recurring_archive to stop the recurrence.

Find a device and inspect its deliveries

device_list accepts q for an external ID or token prefix, platform (ios or android) and status (reachable, opted_out or invalidated). Combine filters to locate the device, and follow next_cursor for additional pages. Tokens remain truncated in results.

{ "app_id": "YOUR_APP_ID", "q": "customer-42", "platform": "ios" }

Call device_history with the returned device_id and app_id for its last 50 retained deliveries. Then call delivery_trace with a delivery's id as delivery_id. The result includes provider errors and timestamps, SDK receipt confirmations, opens and notification content.

received_at records SDK confirmation, which may occur after the push arrived. received_reported_at records when Carillon received that report, potentially later after an offline period. resolved content uses the device's current locale and can differ from the original send. See tracking receipts and opens.

Discover and update audience filters

Call audience_suggestions to discover existing values among eligible live devices. Fields include locale, timezone_id, app_version, app_build, os_version, and typed device or user tags.

For tags, choose field: "tag" without a key to list tag keys, then supply a key to list its values. Use user_tag for user attributes, or number_tag, boolean_tag, date_tag and their user_ equivalents for typed attributes. search narrows suggestions; follow next_cursor until null.

Read the current definition with audience_list, check new filters with audience_preview, then call audience_update with the complete definition, app_id, audience_id and confirm: true. It preserves the audience's ID and name. An empty filter list matches all eligible devices. Updated filters apply to campaigns whose recipient resolution has not started and future recurring occurrences.

Read health and statistics

  • app_health returns device counts, failures and invalidations over seven days, and up to five live campaigns paused by the circuit breaker. Investigate those campaign IDs with message_trace.
  • app_activity returns daily live sent, opened and failed counts for 30 UTC days, device activity snapshots for 90 days and registration totals for 30 days. Missing snapshots are omitted.
  • notification_statistics accepts since and until as ISO timestamps, covering a positive window of at most 90 days. It returns statistics for live campaigns created in that window, optionally filtered by source.

Statistics include totals, per-tag rows and without_tag. A campaign with several tags contributes to each tag, so use totals instead of summing tag rows. Follow next_cursor for additional tag pages. Delivery counts use retained history; sent means provider acceptance, not device display.

On this page