Skip to main content
Glama
megha2432

Zeotap CDP MCP Server

by megha2432
README.md
# Zeotap CDP MCP Server

An MCP (Model Context Protocol) server that connects Claude to Zeotap's Audience and Destination APIs. Clients can ask questions in plain English — Claude handles all the API calls and ID lookups internally.

---

## What it does

- Fetches audiences, destinations, and sync status from Zeotap
- Compresses API responses by ~85% using tiktoken so Claude can handle more data
- Joins audience + destination data (replicating your SQL join via API calls)
- Accepts org names and audience names — clients never need to know IDs

---

## Files

| File | Purpose |
|---|---|
| `server.py` | MCP server — handles tool calls, API requests, response compression |
| `tools.yaml` | Configuration — org IDs, tool definitions, LLM-friendly descriptions |
| `requirements.txt` | Python dependencies |
| `Skills.md` | Full API blueprint and tool design reference |
| `.env` | Bearer token (not committed — update every hour) |

---

## Setup

**1. Install dependencies**
```bash
python3 -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -r requirements.txt
```

**2. Get your bearer token**
1. Log into [unity.zeotap.com](https://unity.zeotap.com)
2. Open DevTools → Network tab → click any request
3. Copy the `Authorization: Bearer eyJ...` value (just the `eyJ...` part)

**3. Set the token**
```bash
echo 'ZEOTAP_TOKEN=your-token-here' > .env
```

> ⚠️ Tokens expire every **1 hour**. Repeat step 2–3 when you get a 401 error.

**4. Run with MCP Inspector (for testing)**
```bash
npx @modelcontextprotocol/inspector .venv/bin/python server.py
```
Open the URL printed in the terminal.

---

## Adding a new org

Each org needs two IDs. Find them from DevTools when browsing that org in the Zeotap app:

| ID | Where to find | Used for |
|---|---|---|
| Numeric ID (e.g. `1918`) | URL: `/audiences/orgs/1918/...` | Audience APIs |
| UUID (e.g. `efc1d9ad-...`) | Network tab: `/channelSettings/...?orgId=efc1...` | Destination name lookup |

Update `tools.yaml`:
```yaml
audience_org_id: 1918
org_uuid: "efc1d9ad-8bb2-48a2-8c84-46f2e9f2b9b4"
org_name: "Your Org Name"
```

---

## Tools

| Tool | Description | Required params |
|---|---|---|
| `get_org_overview` | Total audiences, status breakdown, top 5 by size | none |
| `search_audiences` | Find audiences by name or status | optional: `query`, `status` |
| `get_audience_full` | Full details + filters + destinations for one audience | `audience_name` or `audience_id` |
| `get_org_full_report` | All audiences joined with their destinations and sync status | none |
| `list_all_destinations` | All destinations configured in the org | none (needs UUID) |
| `get_destination_full` | Details for one destination | `destination_name` or `destination_id` (needs UUID) |
| `list_orgs` | Lists known client orgs with their IDs | none |

---

## Example Claude queries

Once connected to Claude Desktop, clients can ask:

| Question | Tool used |
|---|---|
| "Give me a summary of our audiences" | `get_org_overview` |
| "List all active audiences" | `search_audiences` |
| "Tell me about the Loyalty Program audience" | `get_audience_full` |
| "Which audiences are failing to sync?" | `get_org_full_report` |
| "What platforms is our CDP syncing to?" | `get_org_full_report` |
| "What destinations do we have?" | `list_all_destinations` |

---

## Connect to Claude Desktop

Add to your `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "zeotap-cdp": {
      "command": "/Users/megha/Documents/MCP1/.venv/bin/python",
      "args": ["/Users/megha/Documents/MCP1/server.py"],
      "env": {
        "ZEOTAP_TOKEN": "your-token-here"
      }
    }
  }
}
```

> On Mac, the config file is at:
> `~/Library/Application Support/Claude/claude_desktop_config.json`

Restart Claude Desktop after updating the config.

---

## Audience ↔ Destination Join

The `get_org_full_report` tool replicates this SQL join via two API calls:

```sql
SELECT fpa.name, fpa.status, csw.status, ip.int_partner_name
FROM public_audience_destinations pad
JOIN public_first_party_audience fpa ON pad.first_party_audience_id = fpa.id
JOIN public_channel_service_workflow csw ON pad.latest_channel_service_workflow_id = csw.id
JOIN public_integration_partner ip ON pad.channel_id = ip.int_id
WHERE fpa.org_id = 1918
```

| SQL field | API source |
|---|---|
| `fpa.name`, `fpa.status` | `audienceSummaries` response |
| `csw.status`, `csw.status_detail` | `destinationsSummary.status` + `statusDetail.message` |
| `ip.int_partner_name` | `channelSettings` → `integrationPartnerName` (joined via `channelId = intId`) |
| `channelSegmentId` | `destinationsSummary.integrationDetail.channelSegmentId` |

---

## Token reduction

| Tool | Raw tokens | Minified | Reduction |
|---|---|---|---|
| `get_org_overview` (100 audiences) | ~15,000 | ~800 | ~95% |
| `search_audiences` (20 results) | ~8,000 | ~600 | ~93% |
| `get_audience_full` | ~3,000 | ~300 | ~90% |
| `get_org_full_report` | ~20,000 | ~2,000 | ~90% |