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% |
This server cannot be deployed