MCP Server

Connect Claude, Cursor, and other AI agents to your Churnkey data.
View Markdown

The Churnkey MCP server (@churnkey/mcp) exposes Churnkey data and operations as Model Context Protocol tools. MCP-aware clients—Claude, Cursor, Claude Code, and others—call these tools to query sessions, payment-recovery analytics, GDPR endpoints, and cancel flow configuration without custom integration code.

The server is open source and authenticates per user via OAuth: every action runs as your Churnkey user, inherits your workspace role, and is recorded in the audit log under your name.

Setup

The server runs locally via npx. Sign in once with the bundled OAuth flow, then configure your MCP client to spawn the server on demand — no credentials go in the client config.

🔑

A workspace admin must enable MCP Access for your user first (Churnkey → Team). MCP access is off by default for every user.

Sign in from a terminal:

npx @churnkey/mcp auth login

Your browser opens the Churnkey consent screen, where you review and approve the permissions the MCP server may use (see Authentication). Tokens are stored in ~/.churnkey/mcp-auth.json with owner-only permissions. npx @churnkey/mcp auth status shows your session; npx @churnkey/mcp auth logout revokes it.

Claude Desktop

Add the following to your Claude Desktop config:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "churnkey": {
      "command": "npx",
      "args": ["-y", "@churnkey/mcp"]
    }
  }
}

Fully quit and reopen Claude Desktop.

Claude Code

Register the server with the Claude Code CLI:

npx @churnkey/mcp auth login
claude mcp add churnkey -- npx -y @churnkey/mcp

Or configure it in a file. Use ~/.claude.json for a global server (available in every project) or .mcp.json in your project root for a project-scoped server (can be checked into source control):

{
  "mcpServers": {
    "churnkey": {
      "command": "npx",
      "args": ["-y", "@churnkey/mcp"]
    }
  }
}

Restart your Claude Code session to load the server.

Cursor

Add the following to ~/.cursor/mcp.json and reload the Cursor window:

{
  "mcpServers": {
    "churnkey": {
      "command": "npx",
      "args": ["-y", "@churnkey/mcp"]
    }
  }
}

Other clients

Any MCP client that supports stdio transport works. Run npx @churnkey/mcp auth login once, then spawn npx -y @churnkey/mcp.

Authentication

MCP authentication is per user (OAuth 2.1 authorization code with PKCE), not workspace-shared. That has three practical consequences:

  • Attribution — every configuration change made through MCP is recorded in the audit log with your user, the MCP client, and the permission used.
  • Role ceiling — an MCP session can never do more than your dashboard role allows. Viewers get read-only tools; publishing and segment changes require a role with Cancel Flow write access.
  • Instant revocation — sessions can be revoked at any time, by you or by an admin, and tokens stop working immediately.

During auth login, the consent screen lists the permissions (scopes) the MCP server requests. Everything within your role's ceiling is pre-checked; you can uncheck any scope before approving, and scopes that expose customer personal data or make live changes are flagged. The granted set is exactly what you approve — nothing more. If you belong to multiple workspaces, the consent screen lets you pick which one to authorize (the role ceiling follows your role in that workspace). Every consent decision (granted scopes, denials) and session revocation is recorded in the audit log.

ScopeGrants
cancel_flows.blueprints.readList/inspect cancel flow blueprints and segments
cancel_flows.blueprints.writeCreate/edit drafts, manage segments, publish
cancel_flows.metrics.readAggregated session metrics
cancel_flows.sessions.readSession-level records
cancel_flows.sessions.read_piiSession records including customer personal data
payment_recovery.metrics.readRecovery campaigns and aggregated amounts
payment_recovery.campaigns.writeUnsubscribe customers from recovery emails
cancel_flows.adaptive_offers.read / .writeAdaptive discount configuration (attach-to-step also needs cancel_flows.blueprints.write)
payment_recovery.blueprints.read / .writeRecovery campaign configs: sequences, cadence, publish
payment_recovery.campaigns.read / .read_piiRunning recovery sequences (identity redacted without read_pii)
ab_test.read / ab_test.writeA/B tests incl. pick-winner (write promotes a variant to 100% of matched traffic)
dns.read / dns.writeHosted-page subdomain/custom-domain setup
stripe_settings.read / stripe_settings.writeBilling provider settings (write is owner/admin only — direct revenue impact)
account.api_usage.readData API usage
account.audit_log.readWorkspace audit trail (owner/admin only)
dsr.read / dsr.writeGDPR/CCPA access and deletion requests (owner/admin only)

To request a narrower set up front: npx @churnkey/mcp auth login --scopes cancel_flows.blueprints.read,cancel_flows.metrics.read.

Personal data redaction

Session reads with cancel_flows.sessions.read (without read_pii) return customer records with personal fields redacted in place: customer.email, customer.id, and custom attribute values come back as "[redacted]" (numbers/dates as null), while non-personal fields (plan, subscription, outcome) are untouched — so tools keep working, just without the identity data. Grant cancel_flows.sessions.read_pii on the consent screen to see the real values.

Rate limits

Configuration writes over MCP are capped at 120 writes per hour per user per scope to contain runaway agents. The limit applies per write permission (e.g. blueprint edits), returns 429 with standard rate-limit headers when exceeded, and does not affect reads.

Sessions and revocation

Your own active MCP sessions are listed under Settings → Account (Your MCP Sessions), each with client, granted scopes, last activity, and a per-session Revoke. Admins see every session in the workspace on Churnkey → Team; disabling a user's MCP access revokes all of their sessions at once. npx @churnkey/mcp auth logout revokes your own session from the terminal. Access tokens are short-lived (~1 hour) and refresh automatically with rotating refresh tokens — a reused (leaked) refresh token revokes the whole session. Revocation takes effect immediately.

Live vs test mode

Mode defaults to live. To work in test mode, set CHURNKEY_MODE=test in the MCP server's environment (stdio), or send x-ck-mode: test per request (Streamable HTTP). A single OAuth login spans both modes — mode is chosen per session, not baked into the credential. get_account reports the effective mode for the current session.

Mode applies to session analytics onlylist_sessions and aggregate_sessions. Those two tools also echo the active mode (Mode: LIVE / Mode: TEST) in their results, so an agent never mistakes empty test-mode data for "no activity." Everything else is mode-independent:

  • Configuration (blueprints, segments, surveys, recovery campaigns, settings) is shared across live and test mode — an edit applies to both.
  • Payment-recovery analytics (list_payment_recoveries, aggregate_payment_recoveries, campaigns, engagement) come from real provider failed-payment events and carry no test/live distinction.
  • get_flow_metrics is live-mode by definition (it joins real invoices).
  • DSR (dsr_access, dsr_delete) looks up a customer by email across the whole workspace, regardless of mode.

Data API keys (deprecated for MCP)

Earlier versions of @churnkey/mcp authenticated with the workspace Data API key (CHURNKEY_APP_ID + CHURNKEY_API_KEY). That still works for read-only tools, but configuration writes (blueprint/segment edits, publish) are rejected without an OAuth user session, and the server prints a deprecation warning. The Data API key itself is unaffected for server-to-server /v1/data/* calls from your own backend — only its use as an MCP credential is deprecated.

Tools

ToolDescription
get_accountIdentity and session context — best called first. Returns the acting workspace (org), the authenticated user, coarse entitlements (active subscription, Intelligence access), the granted OAuth scopes, and the effective live/test mode. Requires no scope.
list_sessionsReturns cancel and dunning sessions, filterable by date range, customer, outcome, plan, segment, A/B test, and more. Up to 500 sessions per call.
aggregate_sessionsReturns session counts grouped by one or more dimensions (saveType, offerType, month, planId, others).
list_payment_recoveriesReturns individual failed-payment recovery campaigns.
aggregate_payment_recoveriesReturns counts and amounts (invoice, recovered, pending, lost) for failed-payment recoveries, in original currency and USD.
list_blueprintsLists the current cancel flow inventory for the authenticated organization: the default flow plus every non-deleted segment flow (including disabled ones), each with status (active, setup_pending, or inactive), published and hasUnpublishedChanges booleans, editableBlueprintId / publishedBlueprintId, and compact draft / publishedBlueprint metadata.
get_blueprintReturns one full cancel flow blueprint by ID, including the steps array. Each step/offer/survey-choice carries its guid for use with the targeted edit tools.
create_blueprintCreates the default organization-level cancel flow draft when the organization does not already have one. Requires confirm: "create_blueprint". Supports template: "empty", "BASIC", "B2B", or "MERGEFIELDS" for prepopulated draft structure.
update_blueprint_draftUpdates top-level fields (name, brandImage, primaryColor, translatedLanguages) on a draft working copy. Passing a published blueprint ID updates the corresponding working copy. Does not publish.
update_blueprint_stepUpdates one draft step by stepGuid or stepIndex without sending the full steps array: step/offer copy, enabled, survey behavior (randomize, followupRequired, minLength), and freeform/confirm config. Copy edits clear stale translations; behavioral flags do not.
update_blueprint_offerUpdates one offer's type and functional config (discount, pause, trial extension, redirect, plan change, contact, rebate) on a draft, addressable on an offer step, a survey choice, or a structured follow-up option by guid. If the target has no offer yet, passing offerType adds one (seeded with default config). contact takes no config; rebate config supports amountType, customAmount, percentAmount, mbgWindowDays, and invoiceScope. Discount autoOptimize (adaptive discounts) requires Churnkey Intelligence — the API rejects it (403) for organizations without access.
edit_survey_structureAdds, removes, or reorders survey response choices, or configures a choice's follow-up (add_choice / remove_choice / reorder_choices / set_followup) on a draft survey step.
add_blueprint_step / remove_blueprint_stepAdds a step at a canonical place (the server builds the base step) or removes a step by stepGuid on a draft.
publish_blueprintPublishes a draft working copy after explicit confirmation (confirm: "publish"). Passing a published blueprint ID publishes the corresponding working copy. Destructive; clients prompt for confirmation.
list_segmentsLists cancel flow segment metadata in priority order (priority index, enabled flag, and the audience filter rules). Includes disabled segments.
list_segment_attributesLists the audience-filter attributes you can target for cancel flow segments: builtIn (the cancel-flow attribute palette, each with valueType, applicable operands, and — for fixed-enum attributes — the allowed values as { value, label }) and custom (your organization's own custom customer attributes).
create_segment_flowCreates a cancel flow segment and an editable draft blueprint linked to it. Requires confirm: "create_segment_flow". New segments are enabled by default (mirroring the dashboard); pass segment.enabled: false only to create a paused segment. Supports the same blueprint templates as create_blueprint; the new draft remains setup-pending until published.
reorder_segmentsReorders cancel flow segment priority after explicit confirmation (confirm: "reorder_segments"). Live-impacting; clients prompt for confirmation.
set_segment_enabledEnables or disables a segment's live targeting after explicit confirmation (confirm: "set_segment_enabled"). Live-impacting.
update_segment_filterReplaces a segment's audience filter rules (whole-array replace) after explicit confirmation (confirm: "update_segment_filter"). Live-impacting. Editing a live (enabled + published) segment additionally requires confirmLiveChange: true, since it changes targeting immediately.
archive_segmentSoft-deletes a cancel flow segment after explicit confirmation (confirm: "archive_segment"). Useful for cleaning up disposable test flows. Destructive; clients prompt for confirmation.
get_flow_metricsCancel flow performance: sessions, customers saved, save rate, boosted revenue (USD + per-currency), outcomes breakdown, and Feedback AI themes (Intelligence plans). Scope by segment, published blueprint version, or A/B test + date range; includes a sample-size warning and a quotable summary.
get_stripe_settings / update_stripe_settingsRead (with per-setting descriptions + recommendations) and change billing provider settings: proration, cancellation timing, pause behavior, invoice handling on pause, coupon stacking, session recording. Writes require confirm: "update_stripe_settings", explain conflicting combinations, and audit-log before/after values. Direct revenue impact.
get_adaptive_offers / update_adaptive_offersRead and configure adaptive (auto-optimized) discounts: strategy presets, percent/duration ranges with guardrails (5–95% in 5% steps), Intelligence gating, learning-period warnings. Attaching to a flow step (via update_blueprint_offer config.autoOptimize) requires both the adaptive-offers and blueprints write scopes.
get_dns_config / set_hosted_subdomain / add_custom_domain / check_domain_status / remove_custom_domainHosted-page domain setup: read state, set the churnkey.co subdomain (live instantly), register custom domains idempotently with the exact DNS records to add on your side, poll propagation/SSL, deregister.
list_recovery_blueprints / get_recovery_blueprint / clone_recovery_blueprint / update_recovery_email / publish_recovery_blueprintPayment recovery campaign configs: full email sequences (cadence, sender, copy), clone as a starting point, per-email edits with CTA/merge-tag validation and dashboard length limits, confirm-gated publish (rebuilds pending sends on in-flight sequences).
update_recovery_email_offers / update_recovery_sms / add_recovery_email / remove_recovery_email / update_recovery_audience / list_recovery_audience_attributes / set_recovery_blueprint_enabledFull recovery campaign editing parity with the dashboard: per-email offers (provider coupon + one-time invoice discount; the first offer auto-fills the CTA text and offers mirror to the paired SMS), SMS editing (org feature gate, one-SMS-segment cap, merge-field validation), add/remove sequence steps (email+SMS pairs), audience rename/filters against the dunning attribute palette (locked during an active A/B test), and the confirm-gated on/off toggle — which saves and publishes in one step, exactly like the dashboard. Exclusion lists and one-time sendOnDate sends remain dashboard-only.
list_recovery_campaigns / get_recovery_campaign_messages / get_recovery_engagement / stop_recovery_campaignRunning per-customer recovery sequences: who's in which step, per-message sends/opens/clicks, per-email engagement rates, and the irreversible confirm-gated interrupt. Customer identity requires the read_pii scope.
list_ab_tests / create_ab_test / start_ab_test / pause_ab_test / complete_ab_test / get_ab_test_metrics / pick_ab_test_winnerFull A/B test lifecycle: clone a segment flow as the variant, edit it with the blueprint tools, run the test, read per-arm metrics with statistical significance, pick the winner (commits the variant to 100% of matched traffic; early decisions require explicit acknowledgement). Two-arm, 50/50 split.
get_audit_logThe workspace audit trail: who changed what and when, with human-readable summaries (before → after diffs), the acting user/client/scope for MCP actions, and source filtering (AI agent vs Data API vs dashboard). Owner/admin role required. The same trail powers the dashboard's Settings → Activity page.
dsr_accessGDPR/CCPA right-to-know lookup by email.
dsr_deleteGDPR/CCPA right-to-delete. Destructive; clients prompt for confirmation.

Tools accept structured input. Filters use enums for known values (saveType, offerType, billingInterval), accept negation through a not object, and accept arrays of dimensions for grouping. The full schema for each tool is exposed through the standard MCP tools/list response.

Configuration writes are granular and split between draft edits, creation, and live-impacting actions. Blueprint edits (update_blueprint_draft, update_blueprint_step, update_blueprint_offer, edit_survey_structure, add_blueprint_step, remove_blueprint_step) mutate the unlocked working copy and send only the targeted fields—never the full steps array. If a client passes a published blueprint ID to any of these (or to publish_blueprint), Churnkey resolves the matching draft working copy for that org or segment.

Because blueprint edits only touch the draft, they do not require a confirmpublish_blueprint is the single live gate and is the one that requires confirm: "publish". Creation tools require their own confirmation literals: create_blueprint creates only the default organization-level draft when one does not already exist, while create_segment_flow is the repeatable path for new segmented cancel flows and smoke tests. Segment tools (create_segment_flow, reorder_segments, set_segment_enabled, update_segment_filter, archive_segment) act on live segment configuration directly, so each requires its own confirm literal. Churnkey records an audit log for every configuration write — attributed to the authenticated user, MCP client, and scope — including whether a published ID was resolved to a working copy. Blueprint configuration is shared across live and test mode.

Segment audience filters

update_segment_filter (and the segment.filter field on create_segment_flow) take an array of rules, each { attribute, operand, value, type? }. The operand and value must match the attribute's value type. Call list_segment_attributes for the supported list plus your organization's own custom attributes. These are the built-in attributes available for cancel flow segments (the cancel-flow palette, matching the dashboard builder):

Value typeOperandsAttributes
Text / ID (value is a list)INCLUDES, NOT_INCLUDESCUSTOMER_EMAIL, PLAN_ID, PRODUCT_ID, CURRENCY, BILLING_INTERVAL (DAY/WEEK/MONTH/YEAR), SUBSCRIPTION_STATUS (ACTIVE/TRIALING/PAST_DUE), SUBSCRIPTION_DISCOUNT (ONCE/REPEATING/FOREVER)
NumberGTE, LTE, BETWEEN, NOT_BETWEENPRICE (major currency units, e.g. dollars — not cents), BILLING_INTERVAL_COUNT, SUBSCRIPTION_AGE_MONTHS
Date (ISO-8601 string)GTE, LTE, BETWEEN, NOT_BETWEENSUBSCRIPTION_START_DATE
Boolean (value [true] or [false])INCLUDESCANCEL_FLOW_WILL_SHOW_CLICK_TO_CANCEL

A few rules govern how these filters behave:

  • The type field is for custom attributes only. Set it (STRING/NUMBER/BOOLEAN/DATE) only on custom attributes. Omit it for built-in attributes — they derive their type automatically, and a stored type makes the dashboard render a duplicate value input, so the API strips it.
  • Fixed-enum attributes need their exact dashboard value. BILLING_INTERVAL, SUBSCRIPTION_STATUS, and SUBSCRIPTION_DISCOUNT must use the exact casing — e.g. MONTH, not month — or the cancel-flow builder shows the value as an unrecognized chip. The allowed set can also be provider-specific (e.g. PAST_DUE only on Stripe/Paddle, DAY only on Chargebee/Paddle). Call list_segment_attributes to get each enum attribute's allowed values as { value, label } for your organization.
  • Some built-in attributes aren't allowed here. Attributes scoped to other products (e.g. CUSTOMER_HAS_PHONE, INVOICE_AMOUNT_DUE, SURVEY_CHOICE) are rejected for cancel flow segments, since the cancel-flow builder can't render them.
  • You can also use your own custom attributes. Any custom customer attribute your organization has defined is supported — it's returned in the custom group of list_segment_attributes.
  • Operands depend on the value type. Text and boolean use INCLUDES/NOT_INCLUDES; numbers and dates use GTE/LTE/BETWEEN/NOT_BETWEEN. GT/LT and EQUAL/NOT_EQUAL are not supported — use GTE/LTE or INCLUDES/NOT_INCLUDES instead.
  • Value counts depend on the operand. BETWEEN and NOT_BETWEEN take exactly two values [low, high]; GTE/LTE take one; INCLUDES/NOT_INCLUDES take the list of matching values.
  • A segment flow needs at least one rule to publish. Its audience filter can't be empty.
  • Publishing doesn't change a segment's enabled state (same as the dashboard). Segments are enabled by default when created, and set_segment_enabled toggles targeting independently.
  • Editing a live segment's audience takes effect immediately. For a segment that is enabled and published, update_segment_filter changes which customers see the flow right away, so it requires an extra confirmLiveChange: true acknowledgment.

Data freshness

list_sessions, aggregate_sessions, list_payment_recoveries, and aggregate_payment_recoveries read from the Churnkey analytics warehouse, which refreshes roughly every 3 hours for sessions and every 20 minutes for payment recoveries. Data more recent than the refresh window does not appear in these responses.

For real-time session reads, query the Data API directly: GET /v1/data/sessions and GET /v1/data/session-aggregation are backed by the live operational store with no lag. Payment-recovery analytics are warehouse-only — there is no real-time Data API equivalent.

dsr_access and dsr_delete read and write the operational store with no lag.

The cancel flow configuration tools—list_blueprints, get_blueprint, create_blueprint, update_blueprint_draft, update_blueprint_step, update_blueprint_offer, edit_survey_structure, add_blueprint_step, remove_blueprint_step, publish_blueprint, list_segments, list_segment_attributes, create_segment_flow, reorder_segments, set_segment_enabled, update_segment_filter, and archive_segment—read and write the operational store with no warehouse lag. Draft blueprint edits are not customer-facing until the draft is published. Copy edits clear stale translations for the affected content, and publishing refreshes translations before the draft becomes live. Segment changes (creation, priority, enabled state, audience filter, archive) take effect immediately after confirmation.

Examples

Sample prompts an MCP client can translate into tool calls:

What was our save rate by month for 2025?

Show the top decline reasons we recovered from last quarter.

Which plans had the most cancellations in March, and what offers were accepted?

Look up all sessions for [email protected].

List my cancel flow blueprints and show me which ones have unpublished drafts.

Create a new segmented cancel flow called "Enterprise save flow" with the basic template, but do not publish it yet.

Update the draft primary color for this blueprint, but do not publish it yet.

Update the header for this cancel flow step without publishing yet.

Change the discount on the final offer to a $15-off coupon for this flow's draft.

Add a "Too expensive" survey choice with a follow-up question, then reorder the choices.

Reorder my cancel flow segments so enterprise customers are evaluated first.

Pause the "Annual plan" segment flow without deleting it.

Archive the disposable test segment flow I created earlier.

References