crazyleads-mcp-server
v2.0.0
Published
MCP server for CrazyLeads — leads, dashboards, SQL generation, charts and metrics via AI assistants
Readme
crazyleads-mcp-server
MCP server for CrazyLeads — manage leads, build analytics dashboards, generate SQL, and control charts, metrics, filters, and tabs via AI assistants.
41 tools covering leads management and full dashboard CRUD. Works with any MCP-compatible client: Claude Desktop, Claude Code, Cursor, Windsurf, and others.
Installation
npm install -g crazyleads-mcp-serverOr run directly with npx:
npx crazyleads-mcp-serverConfiguration
The server requires two environment variables:
| Variable | Required | Description |
|----------|----------|-------------|
| CRAZYLEADS_API_KEY | Yes | Your CrazyLeads API key (Bearer token) |
| CRAZYLEADS_PROJECT_ID | Yes | UUID of the project to query |
| CRAZYLEADS_API_URL | No | API base URL (defaults to https://apiserver.crazyleads.com.br) |
Setup
Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"crazyleads": {
"command": "npx",
"args": ["-y", "crazyleads-mcp-server"],
"env": {
"CRAZYLEADS_API_KEY": "your-api-key",
"CRAZYLEADS_PROJECT_ID": "your-project-id"
}
}
}
}Claude Code
claude mcp add crazyleads -- npx -y crazyleads-mcp-server \
--env CRAZYLEADS_API_KEY=your-api-key \
--env CRAZYLEADS_PROJECT_ID=your-project-idCursor
Add to your .cursor/mcp.json:
{
"mcpServers": {
"crazyleads": {
"command": "npx",
"args": ["-y", "crazyleads-mcp-server"],
"env": {
"CRAZYLEADS_API_KEY": "your-api-key",
"CRAZYLEADS_PROJECT_ID": "your-project-id"
}
}
}
}Data Discovery
Before building dashboards with categorical groupings (products, channels, campaigns), the AI runs exploratory queries to discover patterns in your data, then asks you to confirm the mappings.
How it works
- AI explores — Runs
test_sqlqueries per data source to discover distinct values, naming patterns, and data distribution - AI suggests — Presents findings: "Found 4 product families, 3 channel types. How should I group them?"
- User confirms — Provides category names, abbreviations, exclusion rules, and business logic
- AI builds — Creates virtual fields with
CASE WHENexpressions using confirmed context, scoped per data source
Exploration per data source
| Source | What to explore | Example patterns |
|--------|----------------|------------------|
| Hotmart | product_name, tracking_source_sck, offer_code, payment_type | Product families, sales channels, offer variants |
| Facebook/Google Ads | campaign_name, adset_name, ad_name | Product codes in campaign prefix, objectives, audiences |
| Page Events | utm_source, utm_campaign, utm_medium, URL paths | Product codes in UTMs, funnel stages in URL patterns |
Cross-source discovery
The AI can identify linking patterns across sources:
- Campaign name prefix
"VTSD"maps to product"Venda Todo Santo Dia"in Hotmart - UTM campaign
"vtsd-retargeting"maps to the same product in page events - This enables a unified
produtovirtual field across all sources using different field logic per scope
What the AI discovers alone
- Distinct values and frequencies in any data source
- Naming patterns in campaigns, UTMs, URLs, product names
- Cross-source naming conventions (campaign prefix matches product name)
- URL path patterns indicating product or funnel stage
- Data distribution (top products, top campaigns, top traffic sources)
What requires user input
- Internal abbreviations ("VTSD" for "Venda Todo Santo Dia")
- Business rules for exclusions or special filtering
- Accounting logic (commission splits, co-producer rules)
- Category hierarchies and strategic priorities
- Which UTM parameters are reliable vs inconsistent
Data Sources
CrazyLeads connects to multiple data sources. The AI assistant automatically discovers which integrations are available in your project and understands the context of each one before building dashboards.
Pixel / Page Events (page)
Website tracking pixel that captures navigation and user behavior. Always available — no integration setup needed.
- Analyzes: Traffic, pageviews, sessions, unique visitors, UTM attribution, landing pages
- Key metrics: Unique visitors (
COUNT DISTINCT ussid), sessions (COUNT DISTINCT session), pageviews - Grouping: By URL, event type, UTM parameters (source, medium, campaign)
Hotmart / Payment (hotmart / payment)
E-commerce transaction data from the Hotmart platform. Requires Hotmart integration.
- Analyzes: Sales, revenue, refunds, payment methods, products, buyer behavior, commissions
- Domain rule: "Vendas" (sales) = only
APPROVED+COMPLETEstatuses. The table contains all transaction events including cancelled, refunded, chargebacks, etc. - Key metrics: Revenue (
SUM price_value), sales count, average ticket, refund rate - Grouping: By product, buyer, status, payment type, offer, tracking source
Facebook Ads (facebook_ads)
Advertising campaign data from Meta/Facebook Ads. Requires Facebook Ads integration.
- Analyzes: Ad spend, impressions, clicks, CTR, CPC, CPM, conversions, ROAS
- Key metrics: Spend, impressions, clicks, CTR, CPC
- Grouping: By campaign, ad set, ad
Google Ads (google_ads)
Advertising campaign data from Google Ads. Requires Google Ads integration.
- Analyzes: Search/display/video ad performance, keywords, cost per conversion
- Key metrics: Spend, impressions, clicks, CTR, CPC
- Grouping: By campaign, ad group, ad
Conversions (conversion)
Custom conversion events and goals configured in CrazyLeads segments. Requires conversion groups with segments.
- Analyzes: Custom goals like form submissions, sign-ups, specific user actions
- Key fields: Conversion event ID, custom parameters (JSON), email, phone
- Note: Must call
list_conversion_groupsfirst to discover available segments
Custom SQL (custom_sql)
Raw SQL queries for advanced cross-source analysis. Always available.
- Use when: Complex joins, custom calculations, or analysis not covered by other query types
- Full access: Can query any table returned by
list_tables
Cross-Source Analysis
The real power is combining sources with measures:
- CPA (Cost per Acquisition):
SUM(ad_spend) / COUNT(sales) - ROAS (Return on Ad Spend):
SUM(revenue) / SUM(ad_spend) - Conversion Rate:
COUNT(conversions) / COUNT(DISTINCT visitors)
Available Tools (41)
Leads (5 tools)
| Tool | Description |
|------|-------------|
| list_leads | List leads with advanced filtering (status, email, phone, country, segment, feature) and pagination (limit, offset, order_by) |
| get_lead | Get complete lead details — emails, phones, devices, addresses, attributes, merge info, statistics |
| get_lead_timeline | Get lead activity timeline — pageviews, purchases, conversions, events with UTM data. Filterable by activity_types and date range |
| search_leads | Search leads by name, email or phone (OR-based matching) |
| count_leads | Count leads matching filters. Quick statistics without fetching full data |
SQL & Data Discovery (4 tools)
| Tool | Description |
|------|-------------|
| list_tables | List all available tables and columns with data types and descriptions. Call this first to understand available data sources and integrations |
| list_conversion_groups | List conversion groups with their segments. Required before creating queries with query_type: conversion |
| generate_sql | Generate SQL from parameters: query_type, columns, aggregations, group_by, filters, database_id |
| test_sql | Test SQL with LIMIT 10 and return sample results. Validate before creating queries |
Dashboards (4 tools)
| Tool | Description |
|------|-------------|
| list_dashboards | List all dashboards with id, name, date range, query/chart counts |
| get_dashboard | Get full dashboard details including complete config (queries, charts, measures, filters, virtual fields, tabs) |
| create_dashboard | Create a new empty dashboard with name and date period |
| update_dashboard | Update dashboard name or date period (partial update) |
Queries (5 tools)
Queries are data sources that materialize into S3 Parquet datalakes. Charts read from these datalakes.
| Tool | Description |
|------|-------------|
| create_query | Create a query in a dashboard. Supports filter_config (visual builder) or raw sql. Types: page, hotmart, facebook_ads, google_ads, conversion, custom_sql |
| execute_query | Execute queries to materialize datalakes. Must be called after create_query before charts can show data |
| get_query_columns | Get columns from a materialized datalake with descriptions, types, and suggested formatting. Call before add_chart to discover valid field IDs |
| update_query | Update query title, SQL, filter_config, or query_type (partial update). Auto-rebuilds SQL from filter_config when provided |
| delete_query | Delete query with full cascade: removes metrics from charts, cleans filters/groupings, deletes S3 datalake |
Charts (5 tools)
| Tool | Description |
|------|-------------|
| add_chart | Add a chart with metrics (field-based from queries or measure-based from calculated measures). Smart defaults for colors and formatting |
| update_chart | Update chart title, type, metrics, groupings, or layout (partial update) |
| clone_chart | Deep copy a chart with regenerated IDs. Auto-positioned via layout algorithm |
| delete_chart | Delete a chart from a dashboard |
| reorganize_charts | Reorganize layouts: AUTO mode (smart ordering by chart type) or MANUAL mode (explicit positions) |
Measures (3 tools)
Calculated measures combine aggregated fields using formulas (e.g., CPA = SUM(spend) / COUNT(conversions)).
| Tool | Description |
|------|-------------|
| add_measure | Add a measure with expression tokens (filter, operator, input, measure) and format |
| update_measure | Replace a measure's name, expression, and format entirely |
| delete_measure | Delete a measure. Cascade removes metrics referencing it from all charts |
Virtual Fields (3 tools)
Virtual fields are computed SQL columns injected into queries before execution.
| Tool | Description |
|------|-------------|
| add_virtual_field | Add a virtual field with name, type (string/number/date), SQL expression, and scope |
| update_virtual_field | Update a virtual field (partial update) |
| delete_virtual_field | Delete a virtual field from a dashboard |
Filters (3 tools)
Shared dashboard filters that apply to all or specific queries.
| Tool | Description |
|------|-------------|
| add_dashboard_filter | Add a filter with field, type, input_type, value, and query scope |
| update_dashboard_filter | Update a filter (partial update) |
| delete_dashboard_filter | Delete a filter from a dashboard |
Group By (3 tools)
Shared grouping configurations to align multiple queries on the same dimension.
| Tool | Description |
|------|-------------|
| add_group_by_config | Add a grouping on a column across specified queries |
| update_group_by_config | Update a group by configuration (partial update) |
| delete_group_by_config | Delete a group by configuration |
Tabs (6 tools)
Tabs organize charts into logical sections within a dashboard.
| Tool | Description |
|------|-------------|
| list_tabs | List all tabs with chart counts per tab |
| create_tab | Create a new tab (e.g., "Overview", "Ads Performance") |
| rename_tab | Rename an existing tab |
| delete_tab | Delete a tab. Charts are moved to the default "Geral" tab |
| reorder_tabs | Reorder tabs by providing ordered list of tab IDs |
| move_chart_to_tab | Move a chart to a different tab |
Typical Workflow
1. list_tables → discover connected data sources & integrations
2. (understand) → clarify what the user wants to analyze
3. generate_sql → build SQL for your analysis
4. test_sql → validate with sample results
5. create_dashboard → create the dashboard
6. create_query → add data sources (page, hotmart, facebook_ads, etc.)
7. execute_query → materialize datalakes
8. get_query_columns → discover columns and formatting
9. add_chart → visualize with charts
10. add_measure → add calculated cross-source KPIs (CPA, ROAS, etc.)
11. create_tab → organize charts into sectionsChart Types Reference
12 chart types available. The AI chooses the best type based on the analysis goal:
| Type | When to Use | Typical Size |
|------|-------------|--------------|
| chart-kpi | Single headline metrics (revenue, visitors, conversion rate) | w=3, h=2 |
| chart-line | Time-series trends (daily revenue, weekly visitors) | w=6-12, h=4 |
| chart-bar | Categorical comparisons (revenue by product) | w=6, h=4 |
| chart-bar-h | Horizontal bars, better for long labels (campaign names) | w=6, h=4 |
| chart-area | Stacked cumulative trends (traffic sources over time) | w=6-12, h=4 |
| chart-donut | Part-to-whole composition (traffic share %) | w=4-6, h=4 |
| chart-table | Detailed row-by-row data inspection | w=12, h=6 |
| chart-ranking | Top-N leaderboards (top products, top campaigns) | w=6, h=4 |
| chart-funnel | Conversion drop-off (visit → lead → sale) | w=6, h=4 |
| chart-radial | Circular gauge representation | w=4, h=4 |
| chart-radar | Multi-dimensional comparison (spider chart) | w=6, h=4 |
| chart-meta | Metadata/summary display | w=6, h=2 |
Recommended dashboard layout:
- Top row: 3-4 KPI cards
- Middle: Line/area for trends + bar/donut for breakdowns
- Bottom: Table for drill-down + ranking for top-N
KPI Styling
KPI cards support custom styling via kpi_style:
{
"backgroundColor": "#f0f9ff",
"valueColor": "#1e40af",
"labelColor": "#64748b",
"successColor": "#10b981",
"lowColor": "#ef4444",
"icon": "DollarSign"
}Icons use Lucide names: DollarSign, Users, ShoppingCart, TrendingUp, Target, BarChart3, Eye, MousePointer, etc.
Ranking Charts
Ranking charts support gamification:
{
"topN": 10,
"rankingImageField": "product_image_url",
"rankingBarColors": {
"first": "#FFD700",
"second": "#C0C0C0",
"third": "#CD7F32",
"rest": "#94a3b8"
}
}Measure Expressions
Calculated measures combine fields from different queries using expression tokens.
Token Types
| Type | Description | Example |
|------|-------------|---------|
| filter | Query field with aggregation | { type: "filter", id: "query_fb", aggregation: "sum(spend)", position: 1 } |
| operator | Math operator (+, -, *, /, (, )) | { type: "operator", value: "/", position: 2 } |
| input | Numeric constant | { type: "input", value: 100, position: 3 } |
| measure | Reference to another measure | { type: "measure", id: "measure_cpa", position: 4 } |
Common Measure Examples
CPA (Cost per Acquisition):
{
"name": "CPA",
"expression": [
{ "type": "filter", "id": "query_facebook", "aggregation": "sum(spend)", "position": 1 },
{ "type": "operator", "value": "/", "position": 2 },
{ "type": "filter", "id": "query_hotmart", "aggregation": "count(distinct transaction_id)", "position": 3 }
],
"format": { "prefix": "R$ ", "decimalPlaces": 2 }
}ROAS (Return on Ad Spend):
{
"name": "ROAS",
"expression": [
{ "type": "filter", "id": "query_hotmart", "aggregation": "sum(price_value)", "position": 1 },
{ "type": "operator", "value": "/", "position": 2 },
{ "type": "filter", "id": "query_facebook", "aggregation": "sum(spend)", "position": 3 }
],
"format": { "suffix": "x", "decimalPlaces": 2 }
}Conversion Rate (%):
{
"name": "Taxa de Conversao",
"expression": [
{ "type": "filter", "id": "query_hotmart", "aggregation": "count(distinct transaction_id)", "position": 1 },
{ "type": "operator", "value": "/", "position": 2 },
{ "type": "filter", "id": "query_page", "aggregation": "count(distinct ussid)", "position": 3 },
{ "type": "operator", "value": "*", "position": 4 },
{ "type": "input", "value": 100, "position": 5 }
],
"format": { "suffix": "%", "decimalPlaces": 2 }
}Virtual Fields
Computed SQL columns injected into queries before execution.
Scope
{ type: "queryType", value: "hotmart" }— applies to all Hotmart queries{ type: "queryType", value: "facebook_ads" }— applies to all Facebook queries{ type: "queryId", value: "query_abc" }— applies to one specific query
Common SQL Patterns
| Pattern | SQL Expression |
|---------|---------------|
| Categorization | CASE WHEN product_name LIKE '%Curso%' THEN 'Curso' ELSE 'Outros' END |
| High/Low ticket | CASE WHEN price_value > 500 THEN 'high_ticket' ELSE 'low_ticket' END |
| Date formatting | TO_CHAR(day, 'YYYY-MM') |
| URL param extraction | (regexp_match(utm_params, 'source=([^;&%]+)'))[1] |
| Conditional calc | CASE WHEN spend > 0 THEN revenue/spend ELSE 0 END |
Dashboard Filters
Shared filters that apply to all or specific queries.
| Input Type | Description | Use Case |
|------------|-------------|----------|
| select | Dropdown with predefined options | Filter by product, status, campaign |
| text | Free text with operator | Search by name, email, URL |
| date | Date picker | Filter by date range |
| number | Numeric input | Filter by price, quantity |
Text operators: contains, equals, starts_with, ends_with
appliesToQueries: array of query IDs, or null for all queries.
Formatting Reference
{
"prefix": "R$ ",
"suffix": "",
"decimalPlaces": 2,
"decimalSeparator": ",",
"thousandsSeparator": "."
}| Scenario | prefix | suffix | decimalPlaces |
|----------|--------|--------|---------------|
| Brazilian Real | "R$ " | "" | 2 |
| US Dollar | "US$ " | "" | 2 |
| Percentage | "" | "%" | 2 |
| Multiplier | "" | "x" | 2 |
| Integer count | "" | "" | 0 |
Auto-inference: When no format is specified, fields with "spend/price/value/commission" get R$ prefix, "rate/ctr" get % suffix.
Layout Grid
Charts use a 12-column responsive grid:
{
"desktop": { "x": 0, "y": 0, "w": 6, "h": 4 }
}x: Column position (0-11)y: Row positionw: Width in columns (1-12)h: Height in rows
Use reorganize_charts with mode: "AUTO" to let the system handle layout automatically.
Aggregation Functions
| Function | SQL | Example |
|----------|-----|---------|
| count | COUNT(*) | Total rows |
| sum | SUM(field) | sum(spend) |
| avg | AVG(field) | avg(price_value) |
| min | MIN(field) | min(day) |
| max | MAX(field) | max(day) |
| distinct | COUNT(DISTINCT field) | count(distinct ussid) |
In measure expressions, use SQL syntax: "sum(spend)", "count(distinct ussid)", "avg(price_value)".
Multi-Series Charts
Charts can display multiple metrics from the same or different queries.
Single-Query Multi-Series
{
"chart_type": "chart-line",
"title": "Visitors vs Sessions",
"metrics": [
{ "queryId": "query_page", "field": "ussid", "aggregation": "distinct", "label": "Unique Visitors", "color": "#3b82f6" },
{ "queryId": "query_page", "field": "session", "aggregation": "distinct", "label": "Sessions", "color": "#10b981" }
]
}Cross-Query Multi-Series
{
"chart_type": "chart-line",
"title": "Spend vs Revenue",
"metrics": [
{ "queryId": "query_facebook", "field": "spend", "aggregation": "sum", "label": "Ad Spend", "color": "#ef4444" },
{ "queryId": "query_hotmart", "field": "price_value", "aggregation": "sum", "label": "Revenue", "color": "#10b981" }
]
}Groupings
groupings: ["utm_source"]on a line chart = one line PER utm_source valuegroupings: ["product_name"]on a bar chart = one bar group PER productx_axis: typically the date/time column for time-series (auto-inferred if omitted)y_axes: auto-generated from metrics (rarely need to set manually)
Metric-Level Filters
Each metric can have independent filters:
{
"metrics": [
{
"queryId": "query_hotmart", "field": "price_value", "aggregation": "sum",
"label": "Approved Revenue",
"filters": [
{ "field": "status", "fieldType": "string", "operator": "in", "value": ["APPROVED", "COMPLETE"] }
]
},
{
"queryId": "query_hotmart", "field": "price_value", "aggregation": "sum",
"label": "Refunded Revenue",
"filters": [
{ "field": "status", "fieldType": "string", "operator": "equals", "value": "REFUNDED" }
]
}
]
}Filter operators:
- String:
equals,not_equals,contains,not_contains,starts_with,ends_with,in,not_in,is_empty,is_not_empty - Number:
equals,greater_than,less_than,between(usevalueFrom/valueTo) - Date:
equals,before,after,between(usevalueFrom/valueTo)
Date/Time Grouping
For time-series charts:
- Date grouping is handled automatically by the dashboard's date range
- Charts automatically group by the date dimension (
event_date_at) - You do NOT need to add "day" to groupings for basic time-series
- For custom time bucketing, use virtual fields:
- Monthly:
TO_CHAR(event_date_at, 'YYYY-MM') - Weekly:
DATE_TRUNC('week', event_date_at) - Hourly:
DATE_TRUNC('hour', event_date_at)
- Monthly:
- For non-time groupings (e.g., by product), set
groupings: ["product_name"]
execute_query — When to Re-Execute
| Scenario | Re-execute? |
|----------|------------|
| After create_query | YES — always, charts have no data without execution |
| After update_query with SQL/filter_config change | YES — response includes needs_re_execute: true |
| After adding/updating virtual fields | YES — injected SQL columns change materialized data |
| After update_query with title-only change | No — no SQL change |
| After adding/updating charts | No — charts read from existing data |
| After adding measures | No — measures compute at render time |
| After adding filters/group by configs | No — UI-level, don't change materialized data |
If start_date/end_date are omitted in execute_query, it uses the dashboard's configured date range.
group_by_config vs Chart Groupings
Two separate mechanisms:
| Mechanism | Scope | Purpose |
|-----------|-------|---------|
| Chart groupings | Per chart | Controls how one chart renders (split by dimension) |
| group_by_config | Dashboard level | Aligns multiple queries on the same dimension for cross-query charts |
When to use group_by_config: When a chart has metrics from DIFFERENT queries that need to share an axis. Example: Facebook spend + Hotmart revenue on the same daily line chart — both queries need to group by day.
{
"column": "day",
"query_ids": ["query_facebook", "query_hotmart"]
}The column must exist in ALL specified queries (or be a virtual field applied to them).
KPI Goals and Variation
Goals
Set goal parameter on KPI charts:
{ "chart_type": "chart-kpi", "goal": 1000 }Displays a progress bar showing current value vs goal with percentage complete. Uses successColor when met, lowColor when behind.
Automatic Variation
KPIs automatically compare current period vs previous period:
- Green badge (
successColor): value increased (e.g., "+12.5%") - Red badge (
lowColor): value decreased (e.g., "-3.2%")
Conversion IDs
The conversion ID used in create_query is the same value from two sources:
| Source | Field Name | Same ID? |
|--------|-----------|----------|
| list_conversion_groups | conversionSegments[].id | Yes |
| list_tables (type=conversion) | conversion_id | Yes |
Use this same UUID for both database_id AND filter_config.conversion_id in create_query.
Common Pitfalls
| Pitfall | Solution |
|---------|----------|
| Charts created before execute_query | Charts render empty. Always: create_query → execute_query → get_query_columns → add_chart |
| Guessing field names | NEVER guess. Always call get_query_columns after execution |
| Division by zero in measures | Frontend shows "-" or "0" gracefully, but be aware |
| "distinct" vs "count" aggregation | distinct = COUNT(DISTINCT field), count = COUNT(*) |
| Virtual field scope | queryType scope applies to THIS dashboard only, not others |
| Deleting a measure used by other measures | Dependent measures break. Check get_dashboard first |
| "payment" vs "hotmart" query type | Both accepted, backend normalizes to "hotmart" |
License
MIT
