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
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
2. Get your bearer token
- Log into unity.zeotap.com
- Open DevTools → Network tab → click any request
- Copy the
Authorization: Bearer eyJ...value (just theeyJ...part)
3. Set the token
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)
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:
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:
{
"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:
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% |