Pendo Ontology MCP Server
# pendo-ontology-mcp
**A semantic ontology layer for Pendo, as an MCP server.** Pairs with the [Pendo MCP server](https://www.pendo.io): Pendo MCP is the *data plane* (live entities, usage, retention, funnels); this server is the *meaning plane* — the business concepts, definitions, entity relationships, causes, and playbooks your workspace has agreed on.
## Why
LLM agents querying product analytics fail in a characteristic way: they don't know what your objects *mean*. Feature and segment names encode tribal knowledge, business terms like "activation" have workspace-specific definitions that live in people's heads, and the relationships between objects and business goals are written down nowhere — so agents ask endless follow-ups and produce confidently wrong answers.
This server is the place where that meaning gets written down — and it's designed so the LLM itself does most of the writing. The flywheel:
```
you ask questions → the model learns what you care about
→ it proposes/records concepts here (you review)
→ every future question is grounded in your definitions
→ answers get sharper → you ask more
```
The ontology store is a single portable JSON file: diffable, version-controllable, and an organizational asset that survives model swaps and agent rewrites.
## What it is (and isn't)
- A **typed JSON graph**, not RDF/OWL. Its consumers are an LLM context window and a human reviewer.
- **Query-language agnostic.** Concepts carry a prose `measurementHint` ("weekly cohort retention over the measured features"), not query templates. The agent turns hints into concrete Pendo MCP calls (`entityUsageTimeSeries`, `cohortRetentionCurve`, …).
- **No LLM calls inside the server.** The client model is the intelligence; this server contributes deterministic guarantees (stable ids, phrase-match floors, coverage gaps) and durable storage.
## Data model
```
STRUCTURAL (synced/pushed, rebuildable) SEMANTIC (the asset)
───────────────────────────────────── ─────────────────────────────
EntityNode Concept
id: "feature:<pendoId>" ← stable name, definition
kind: feature|page|segment| measurementHint (prose)
productArea|trackEvent|object measures: [entity ids]
pendoId ← valid directly in Pendo tools causes[] (+ questionTemplate)
name, appId?, url?, groupId? actions[] (+ questionTemplate)
tags[], source
```
Stable ids mean concept links survive full re-syncs. Entities deleted upstream leave dangling references that are ignored, never destroyed — a later sync may bring them back.
## Install
```bash
git clone <this repo> && cd pendo-ontology-mcp
npm install && npm run build
```
### Claude Code
```bash
claude mcp add pendo-ontology -- node /path/to/pendo-ontology-mcp/dist/index.js
```
### Claude Desktop (`claude_desktop_config.json`)
```json
{
"mcpServers": {
"pendo-ontology": {
"command": "node",
"args": ["/path/to/pendo-ontology-mcp/dist/index.js"],
"env": {
"ONTOLOGY_STORE_PATH": "/path/to/team/ontology.json"
}
}
}
}
```
### Environment
| Variable | Default | Purpose |
|---|---|---|
| `ONTOLOGY_STORE_PATH` | `~/.pendo-ontology/ontology.json` | Where the ontology lives. Point at a repo file to share with your team. |
| `PENDO_INTEGRATION_KEY` | — | Enables the optional `sync_from_pendo` direct REST sync. Not needed when pairing with Pendo MCP. |
| `PENDO_API_BASE` | `https://app.pendo.io/api/v1` | Override for EU/other regions. |
## Tools
| Tool | Purpose |
|---|---|
| `get_product_map` | Overview: entity counts + every concept (definition, measurement hint, measured entities with pendoIds, causes, actions). Call first. |
| `lookup_ontology` | Search entities & concepts by name. Product areas expand into member features. |
| `get_entity_catalogue` | Full registered catalogue, features grouped by area — for picking measure links. |
| `upsert_concept` | Create/update a concept. `autoLink: true` adds deterministic phrase-matched entities. |
| `delete_concept` | Remove a concept (cause links to it are scrubbed). |
| `suggest_links` | Deterministic phrase-match candidates for a problem statement — the precision floor under the model's own semantic picks. |
| `list_coverage_gaps` | Entities no concept measures yet. Join with Pendo MCP usage data to rank concept candidates. |
| `ingest_pendo_payload` | **The easy sync path**: pass a RAW Pendo MCP tool result (`listCountables`, `listProductAreas`, `segmentList`, …) verbatim — array, wrapper object, or JSON string — and it's normalized and merged. Per-item evidence (`elementPathRules` → feature, `url` → page, kind-named wrapper keys) beats the `kind` hint. |
| `register_entities` | Structured push with explicit kinds (merge or replace). Use when you've already reshaped the data. |
| `sync_from_pendo` | Optional direct REST sync (needs `PENDO_INTEGRATION_KEY`). |
**Resource:** `ontology://digest` — a markdown digest of the whole ontology, ready to be pulled into context.
## The pairing workflow (with Pendo MCP)
1. **Seed the structure** — ask Claude:
> "List my product areas and features via Pendo, then register them in the ontology."
Claude calls Pendo MCP (`listProductAreas`, `listCountables`, `segmentList`) and pipes each raw result straight into `ingest_pendo_payload` — no reshaping, no Pendo API key. (Alternatives: `register_entities` for pre-shaped data, or `PENDO_INTEGRATION_KEY` + `sync_from_pendo` for direct REST sync.)
2. **Define what matters** — ask:
> "Define a concept 'Activation': accounts that used ≥3 core features in week 1. Map the entities it measures."
Claude drafts the concept, picks semantically-related entities from `get_entity_catalogue` (plus the `suggest_links` floor), and saves with `upsert_concept`.
3. **Let usage drive coverage** — ask:
> "What high-usage entities aren't covered by any concept?"
Claude joins `list_coverage_gaps` with Pendo MCP usage (`entityUsage`) and proposes new concepts from the gaps.
4. **Ask grounded questions** — from now on:
> "How is Activation trending?"
Claude reads the concept (definition + `measurementHint` + measure pendoIds) and goes straight to the right Pendo MCP calls — no follow-up questions, no guessed IDs, your definition every time.
## Design notes
- **Phrase-matching is the floor, not the ceiling.** Single-token name matching measured 119 false positives for "agent" in a real workspace; two-word phrases stay precise but can't see semantics. The model does the semantic mapping; `suggest_links`/`autoLink` guarantee the obvious matches are never missed.
- **Ontologies don't work on day 1.** Meaning is distilled from use — questions asked, usage observed, definitions clarified. Start with structure + one or two concepts; let the flywheel run.
- **Errors are results.** Lookups return notes, not exceptions; a miss tells the model exactly which fallback to take.
## License
MIT
TDQS
Scored across 11 tools
Most tools have clearly distinct purposes, but get_concept and lookup_ontology both return full concept details, and the three entity ingestion methods (register_entities, ingest_pendo_payload, sync_from_pendo) could confuse agents despite clear descriptions. Overall, the boundaries are well-defined.
All tool names follow a consistent verb_noun snake_case pattern (list_, get_, lookup_, upsert_, delete_, suggest_, register_, ingest_, sync_). The naming is predictable and makes the action and resource clear.
With 11 tools, the server is well-scoped for ontology management. Each tool covers a distinct aspect (concepts, entities, links, ingestion, discovery) without redundancy or bloat.
The tool set provides comprehensive coverage: concept CRUD (upsert_concept, delete_concept, get_concept), ontology overview/search (get_product_map, lookup_ontology), entity cataloging and registration (get_entity_catalogue, register_entities, ingest_pendo_payload, sync_from_pendo), link suggestions (suggest_links), and gap analysis (list_coverage_gaps). No obvious dead ends.