npm package: @retentioncheck/mcp-server
Description: MCP server for AI-powered churn analysis. Analyze cancellation feedback to identify churn patterns and get actionable recommendations.
Author: Brian Farello
Latest version: 0.6.0

# @retentioncheck/mcp-server

MCP server for AI-powered churn analysis. Analyze customer cancellation feedback to identify churn patterns, severity ratings, and actionable recommendations.

## Tools

### analyze_churn

Analyze cancellation feedback to identify why customers are leaving.

**Input:**
- `feedback` (string, required) — cancellation responses, one per line
- `focus` (string, optional) — narrow analysis to a specific area (e.g., "pricing")

**Output:** Structured JSON with executive summary, priority action, and categorized insights (reason, count, percentage, severity, confidence, examples, recommendation).

### analyze_stripe_churn

Pull canceled subscriptions **directly from Stripe** and analyze them — no middleware, no DB hookup. Each cancellation is enriched with plan, MRR, sub age, and voluntary vs. involuntary context before being fed to Claude.

**Input:**
- `lookback_days` (number, optional) — how many days back to analyze. Defaults to 90. Min 7, max 365.
- `focus` (string, optional) — narrow analysis to a specific area (e.g., "pricing")

**Requires:** `STRIPE_SECRET_KEY` env var. **Use a restricted (read-only) key**, not your live secret key. Create one at [dashboard.stripe.com/apikeys/create](https://dashboard.stripe.com/apikeys/create) with these permissions:

- Subscriptions: **Read**
- Customers: **Read**
- Prices: **Read**

**Output:** Same shape as `analyze_churn`, plus a `stripeContext` block with `totalCanceled`, `activeSubs`, `voluntaryCount`, `involuntaryCount`, `totalMrrLost`, `truncated`, `lowSample`, `nonUsdSkipped`, and `noFeedbackRate`. When there's not enough data, the Churn Health Score is `null` rather than fabricated.

### analyze_sql_churn

Pull canceled subscriptions **directly from Postgres or MySQL** and analyze them — zero middleware, zero backend. You describe your schema in plain arguments (table name, column names) and the tool generates a safe parameterized SELECT query internally.

**Input:**
- `dialect` (`"postgres"` | `"mysql"`, required) — which SQL database you're using.
- `schema` (object, required):
  - `table` (string, required) — table containing subscription/cancellation records.
  - `cancelled_at_column` (string, required) — column storing cancellation timestamp.
  - `reason_column` (string, optional) — column storing cancellation reason.
  - `comment_column` (string, optional) — column storing free-text comments.
  - `mrr_column` (string, optional) — column storing monthly revenue.
  - `mrr_unit` (`"dollars"` | `"cents"`, optional) — defaults to `"dollars"`. Use `"cents"` for Stripe-style integer storage.
  - `customer_tenure_days_column` (string, optional) — column for sub age in days.
  - `status_filter` (object, optional) — `{ column, value }` filter for canceled-only rows.
- `lookback_days` (number, optional) — defaults to 90. Min 7, max 365.
- `focus` (string, optional) — narrow analysis to a specific area.

**Requires:** `POSTGRES_URL` or `MYSQL_URL` env var (matching the `dialect`). **Use a read-only database user**, not your app DB user. Example Postgres setup:

```sql
CREATE USER retentioncheck_readonly WITH PASSWORD 'use-a-strong-password';
GRANT CONNECT ON DATABASE your_db TO retentioncheck_readonly;
GRANT USAGE ON SCHEMA public TO retentioncheck_readonly;
GRANT SELECT ON subscriptions TO retentioncheck_readonly;
```

Example MySQL setup:

```sql
CREATE USER 'retentioncheck_readonly'@'%' IDENTIFIED BY 'use-a-strong-password';
GRANT SELECT ON your_db.subscriptions TO 'retentioncheck_readonly'@'%';
FLUSH PRIVILEGES;
```

**Safety:** 500-row hard cap, 15-second statement timeout, identifier allowlist validation (rejects any table/column name outside `[a-zA-Z_][a-zA-Z0-9_]*`), all literal values parameterized, three schema-mismatch probes before the main query to give actionable errors instead of silent empty output, SSL warning when the connection isn't encrypted. Read-only user is the single most important safety layer. Full design notes in [docs/2026-04-08-analyze-sql-churn-design.md](https://github.com/brianfofficial/retentioncheck-v2/blob/main/docs/2026-04-08-analyze-sql-churn-design.md).

**Output:** Same shape as `analyze_churn`, plus a `sqlContext` block with `dialect`, `dateRange`, `totalCanceled`, `totalMrr`, `truncated`, `lowSample`, `noFeedbackRate`, and `sslEnabled`.

### get_example_analysis

See a pre-computed example analysis. No API key required.

**Input:**
- `scenario` (string, optional) — "b2b-saas" (default), "consumer-app", or "pricing"

## Installation

### Claude Desktop / Claude Code

Add to your MCP config (`claude_desktop_config.json` or `.claude.json`):

```json
{
  "mcpServers": {
    "retentioncheck": {
      "command": "npx",
      "args": ["-y", "@retentioncheck/mcp-server"],
      "env": {
        "ANTHROPIC_API_KEY": "your-anthropic-key",
        "STRIPE_SECRET_KEY": "rk_live_...",
        "POSTGRES_URL": "postgres://ro_user:pass@host:5432/db?sslmode=require",
        "MYSQL_URL": "mysql://ro_user:pass@host:3306/db?ssl=true"
      }
    }
  }
}
```

Only `ANTHROPIC_API_KEY` is required. `STRIPE_SECRET_KEY` is needed for `analyze_stripe_churn`. `POSTGRES_URL` or `MYSQL_URL` is needed for `analyze_sql_churn` (depending on which dialect you use). Omit any you don't need.

### Cursor

Add to Cursor MCP settings with the same configuration.

## Requirements

- Node.js 20+
- Anthropic API key (for `analyze_churn`, `analyze_stripe_churn`, and `analyze_sql_churn`)
- Stripe restricted key (optional, for `analyze_stripe_churn`)
- Postgres or MySQL read-only database user (optional, for `analyze_sql_churn`)

## Example Usage

Ask your AI assistant:
- "Analyze my cancellation feedback" (then paste your data)
- "Show me an example churn analysis"
- "Why are my customers churning?" (then provide feedback)

## Full App

For history, trend tracking, PDF exports, team sharing, and more:
**[retentioncheck.com](https://retentioncheck.com)**

## Anonymous Telemetry

Starting in `0.2.0`, this package sends anonymous usage events to help us understand which tools are used and how. We track:

- A randomly generated install ID (UUID, persisted to `~/.retentioncheck-mcp/install-id.json`)
- Which tool was called (`analyze_churn`, `analyze_stripe_churn`, `analyze_sql_churn`, or `get_example_analysis`)
- Whether the call succeeded or failed (and a generic error category if it failed)
- Item count for analysis tools (how many feedback rows/subscriptions were analyzed)
- For `analyze_sql_churn`: dialect (`postgres` or `mysql`) and whether SSL was enabled
- For `analyze_stripe_churn`: mode (`live` or `test`)
- MCP server version, Node version, platform/arch

We do **NOT** track:

- The feedback text itself
- Your Anthropic API key or any credentials
- Any PII, IP address, hostname, or user identity

To opt out, set `RETENTIONCHECK_TELEMETRY=0` in your MCP server's env config:

```json
{
  "mcpServers": {
    "retentioncheck": {
      "command": "npx",
      "args": ["-y", "@retentioncheck/mcp-server"],
      "env": {
        "ANTHROPIC_API_KEY": "your-api-key-here",
        "RETENTIONCHECK_TELEMETRY": "0"
      }
    }
  }
}
```

You can also delete `~/.retentioncheck-mcp/install-id.json` at any time to reset your anonymous install ID.

## License

MIT