MCP Integration

Catalogian supports the Model Context Protocol (MCP), letting AI agents query your product catalog changes directly — no custom integration work required. Connect once and your agents can list sources, query delta events, and retrieve full row-level field data.

Claude.ai (OAuth — Recommended)

Claude.ai supports OAuth — no API key or config file needed. Works on web and desktop. Configure once and it syncs everywhere.

  1. Open SettingsConnectors
  2. Click Add custom connector
  3. Enter Catalogian for the name
  4. Enter https://api.catalogian.com/v1/mcp for the URL
  5. Click Add
  6. Find Catalogian in the connectors list and click Connect — you'll be redirected to Catalogian to authorize, then returned to Claude.

After connecting, enable it per-conversation by clicking + in the chat input → Connectors→ toggle Catalogian on.

Note:Configure once on Claude.ai web — settings sync automatically to Claude desktop and mobile.

Connecting

The MCP endpoint accepts standard Streamable HTTP transport:

POST https://api.catalogian.com/v1/mcp
Authorization: Bearer <your-api-key>

Use a Catalogian API key (cat_live_...) from the Keys page in your dashboard. Create it with Read only scope — MCP only reads data, and a read-scoped key prevents any accidental writes via the REST API.

Claude Desktop / API Key (Advanced)

The API key method also works for Cursor, VS Code, and other MCP clients. Add this to your claude_desktop_config.json on macOS at ~/Library/Application Support/Claude/claude_desktop_config.json. Restart Claude Desktop. Your sources will appear as available tools.

{
  "mcpServers": {
    "catalogian": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://api.catalogian.com/v1/mcp",
        "--header",
        "Authorization: Bearer cat_live_your_key_here"
      ]
    }
  }
}

Note: Claude Desktop requires the mcp-remote proxy for HTTP MCP servers — the type: "http" syntax is not yet supported in stable builds. For local or staging testing over HTTP, add "--allow-http" as an additional arg after the URL. Create your API key with Read only scope from the Keys page — MCP only needs read access.

Available Tools

list_sources

List all feed sources for the current user. No parameters required.

Example response:

[
  {
    "id": "cmmfyryl30005ygld7m5596gm",
    "name": "My Product Feed",
    "slug": "my-product-feed",
    "status": "active",
    "format": "csv",
    "lastCheckedAt": "2026-03-08T20:00:00.000Z",
    "vanityUrl": "https://catalogian.com/feeds/acme/my-product-feed"
  }
]

get_source_by_slug

Look up a source by its human-readable slug. Returns source details including the internal ID needed for other tools.

Input:

{ "sourceSlug": "product-catalog" }

Example response:

{
  "id": "cmmfyryl30005ygld7m5596gm",
  "name": "Product Catalog",
  "slug": "product-catalog",
  "url": "https://example.com/feed.csv",
  "type": "http",
  "status": "active",
  "format": "csv",
  "keyField": "sku",
  "lastCheckedAt": "2026-03-08T20:00:00.000Z",
  "createdAt": "2026-01-15T10:30:00.000Z"
}

get_delta

Get delta events for a feed source. Returns change summaries with counts and affected keys.

Input parameters:

ParamDescription
sourceIdThe source ID (use this or sourceSlug)
sourceSlugThe source slug — alternative to sourceId
sinceISO 8601 timestamp — only return events after this time
limitMax results (default 50, max 200)

Example response:

[
  {
    "id": "evt_01j...",
    "snapshotId": "snap_01j...",
    "sourceId": "cmmfyryl30005ygld7m5596gm",
    "detectedAt": "2026-03-08T20:00:00.000Z",
    "newCount": 14,
    "changedCount": 3,
    "deletedCount": 0,
    "unchangedCount": 49983,
    "totalCount": 50000,
    "newKeys": ["sku-9001", "sku-9002"],
    "changedKeys": ["sku-1234"],
    "deletedKeys": []
  }
]

get_delta_rows

Get the actual row-level field data for a specific delta event. This is the most data-rich tool — it returns the complete field values for new, changed, and deleted rows.

Input parameters:

ParamDescription
sourceIdThe source ID (use this or sourceSlug)
sourceSlugThe source slug — alternative to sourceId
deltaEventIdThe delta event ID (from get_delta results)
changeTypenew | changed | deleted | all (default: all)
limitMax rows per page (default 100, max 500)
offsetPagination offset (default 0)

Example response:

{
  "deltaEventId": "evt_01j...",
  "rows": [
    {
      "key": "sku-1234",
      "changeType": "changed",
      "fields": {
        "sku": "sku-1234",
        "title": "Widget Pro (Updated)",
        "price": "29.99",
        "availability": "in_stock"
      }
    },
    {
      "key": "sku-9001",
      "changeType": "new",
      "fields": {
        "sku": "sku-9001",
        "title": "New Gadget",
        "price": "49.99",
        "availability": "in_stock"
      }
    }
  ],
  "total": 17,
  "hasMore": false
}

get_snapshot_rows

Read rows from the current snapshot of a source. Use this to inspect live feed data — paginate with cursor for large feeds.

Input parameters:

ParamDescription
sourceIdSource ID (use get_source_by_slug to resolve from slug)
sourceSlugSource slug — alternative to sourceId
limitRows per page (default 20, max 100)
cursorPagination cursor from previous response (omit for first page)

Example response:

{
  "rows": [
    {
      "rowKey": "sku-1234",
      "data": {
        "sku": "sku-1234",
        "title": "Widget Pro",
        "price": "29.99",
        "availability": "in_stock"
      }
    },
    {
      "rowKey": "sku-5678",
      "data": {
        "sku": "sku-5678",
        "title": "Gadget Plus",
        "price": "49.99",
        "availability": "in_stock"
      }
    }
  ],
  "total": 50000,
  "hasMore": true,
  "nextCursor": "sku-5678",
  "snapshotId": "abc123...",
  "snapshotCreatedAt": "2026-03-08T20:00:00.000Z"
}

sample_snapshot

Random or stratified sample from a feed snapshot. Use stratifyBy to get representative rows across brand, category, or any field. Ideal starting point for AI analysis of large feeds.

profile_snapshot

Feed-level quality report: field cardinality, null rates, top value distributions, data type hints, and stratification recommendations. Run this first to understand a large feed before sampling or querying.

download_snapshot

Export the full current snapshot of a source as a CSV or JSON file. Returns a pre-signed download URL valid for 1 hour. Use this when you want to download, save, or analyze the complete feed data.

Input parameters:

ParamDescription
sourceIdThe source ID (use this or sourceSlug)
sourceSlugThe source slug — alternative to sourceId
formatcsv | json (default: csv)

Example response:

Your file is ready: https://r2.example.com/exports/usr_01j.../src_01j.../20260310T120000Z.csv?X-Amz-...

Rows: 50000 | Format: csv | Expires: 2026-03-10T13:00:00.000Z

snapshot_schema

Get the field structure of a source's current snapshot. Returns all field names with null rates and example values. Use this first to understand what fields are available before running query_snapshot.

Input: sourceId or sourceSlug

Example response:

Snapshot schema for source cmmfyryl30005ygld7m5596gm
Snapshot: snap_01j... (created 2026-03-08T20:00:00.000Z)
Total rows: 50000 | Sampled: 100

Fields (5):
  availability (null 0%) — e.g. "in_stock", "out_of_stock"
  brand (null 2%) — e.g. "Acme", "BrandX", "WidgetCo"
  price (null 0%) — e.g. "29.99", "49.99", "9.99"
  sku (null 0%) — e.g. "sku-1234", "sku-5678"
  title (null 0%) — e.g. "Widget Pro", "Gadget Plus"

query_snapshot

Run server-side aggregations on a source's full snapshot data. Handles 100K+ row feeds efficiently. Use for: unique values (distinct), counts, group-by breakdowns, min/max/avg/sum, or filtered row subsets.

Input parameters:

ParamDescription
sourceIdThe source ID (use this or sourceSlug)
sourceSlugThe source slug — alternative to sourceId
operationdistinct | count | group_by | min | max | avg | sum | filter
fieldField name from snapshot_schema (required for all except count)
filterOperatoreq | neq | contains | gt | lt | gte | lte (for filter)
filterValueValue to compare against (for filter)
limitMax results (default 100, max 500)
cursorPagination cursor for filter operation

Example — group by availability:

{
  "sourceSlug": "product-catalog",
  "operation": "group_by",
  "field": "availability"
}

Response:

{
  "type": "group_by",
  "field": "availability",
  "groups": [
    { "value": "in_stock", "count": 42150 },
    { "value": "out_of_stock", "count": 7340 },
    { "value": "preorder", "count": 510 }
  ]
}

filter_snapshot_rows

Filter rows from a source's current snapshot using one or more conditions (AND-joined). Handles 100K+ row feeds server-side — only matching rows are returned. Supports text, numeric, and null checks. Paginate with cursor for large result sets.

Input parameters:

ParamDescription
sourceIdThe source ID (use this or sourceSlug)
sourceSlugThe source slug — alternative to sourceId
conditionsArray of filter conditions (AND-joined). Each has field, operator, and optional value
conditions[].operatoreq | neq | contains | starts_with | gt | lt | gte | lte | is_null | is_not_null
fieldsFields to include in output (default: all) — use to reduce response size on wide feeds
limitRows per page (default 20, max 100)
cursorPagination cursor from previous response

Example — find SKUs where price > 50 and stock = 0:

{
  "sourceSlug": "product-catalog",
  "conditions": [
    { "field": "price", "operator": "gt", "value": "50" },
    { "field": "stock", "operator": "eq", "value": "0" }
  ],
  "fields": ["sku", "title", "price", "stock"]
}

Response:

Found ~142 matching rows (showing first 20)

Row 1 (key: sku-1234):
  sku: sku-1234
  title: Widget Pro
  price: 89.99
  stock: 0

Row 2 (key: sku-5678):
  sku: sku-5678
  title: Gadget Plus
  price: 59.99
  stock: 0

...

More results available — use cursor: "clxyz..."

download_filtered_snapshot

Export only the rows matching filter conditions as a CSV or JSON file. Returns a pre-signed download URL valid for 1 hour. Use this after filter_snapshot_rowsto export just the matching subset — not the full feed.

Input parameters:

ParamDescription
sourceIdThe source ID (use this or sourceSlug)
sourceSlugThe source slug — alternative to sourceId
conditionsArray of filter conditions (AND-joined), same as filter_snapshot_rows
formatcsv | json (default: csv)

Example — export out-of-stock items as CSV:

{
  "sourceSlug": "product-catalog",
  "conditions": [
    { "field": "availability", "operator": "eq", "value": "out_of_stock" }
  ],
  "format": "csv"
}

Response:

Your filtered export is ready: https://r2.example.com/exports/usr_.../src_.../filtered-20260310T120000Z.csv?X-Amz-...

Matched rows: 7340 | Format: csv | Conditions: 1
Snapshot date: 2026-03-08T20:00:00.000Z
Link expires: 2026-03-10T13:00:00.000Z

compare_snapshots

Compare two snapshots of a source to see what changed — rows added, removed, or modified. By default compares the two most recent snapshots. Specify sinceDate to compare against a historical snapshot.

Input parameters:

ParamDescription
sourceIdThe source ID (use this or sourceSlug)
sourceSlugThe source slug — alternative to sourceId
sinceDateISO date (e.g. "2026-03-07") — compare latest snapshot against nearest snapshot before this date
sinceSnapshotIdCompare against this specific snapshot ID
limitMax changed rows to show (default 50, max 200)

Example — what changed since last Tuesday:

{
  "sourceSlug": "product-catalog",
  "sinceDate": "2026-03-03"
}

Response:

Comparing snapshots: 2026-03-02T20:00:00.000Z → 2026-03-10T20:00:00.000Z

Added: 12 rows
Removed: 3 rows
Modified: 47 rows

ADDED (12):
  SKU-9901: {"title":"New Widget Pro","price":"49.99",...}
  ...

REMOVED (3):
  SKU-1234: {"title":"Discontinued Gadget","price":"19.99",...}
  ...

MODIFIED (47):
  SKU-5678:
    before: {"title":"Widget","price":"29.99"}
    after:  {"title":"Widget","price":"24.99"}

search_snapshot

Full-text keyword search across all fields in a source snapshot. Returns rows containing the search terms anywhere in their data, ranked by relevance. Good for finding products by name, description, or any text content.

Input parameters:

ParamDescription
sourceIdThe source ID (use this or sourceSlug)
sourceSlugThe source slug — alternative to sourceId
querySearch terms (e.g. "wireless headphones" or "nike running shoes")
limitResults per page (default 20, max 100)
cursorPagination cursor from previous response
fieldsFields to include in output (default: all)

Example — find wireless headphones:

{
  "sourceSlug": "product-catalog",
  "query": "wireless headphones",
  "limit": 5
}

Response:

Found rows matching "wireless headphones" (ranked by relevance):

Result 1 (key: SKU-4401, relevance: 0.075):
  title: Wireless Headphones Pro
  brand: Sony
  price: 149.99
  category: Electronics

Result 2 (key: SKU-4402, relevance: 0.061):
  title: Bluetooth Wireless Over-Ear Headphones
  brand: JBL
  price: 89.99

More results available — use cursor: "SKU-4402"

sample_snapshot

Random or stratified sample from a snapshot. Use stratifyBy for representative rows across brand/category/etc. Good starting point for AI analysis of large feeds.

Input parameters:

ParamDescription
sourceIdThe source ID (use this or sourceSlug)
sourceSlugThe source slug — alternative to sourceId
nTotal rows to return (1–500, default 50). Ignored when stratifyBy is set.
stratifyByFields to stratify by (max 3). Returns rowsPerGroup rows per unique combination.
rowsPerGroupRows per unique combination when stratifyBy is set (1–20, default 2). Total capped at 500.
fieldsFields to include in output (default: all)

Example — stratified sample by brand:

{
  "sourceSlug": "product-catalog",
  "stratifyBy": ["brand", "condition"],
  "rowsPerGroup": 2,
  "fields": ["title", "brand", "price", "condition"]
}

Response:

Sampled 94 rows from 50,234 total, stratified by brand × condition, 47 groups × 2 rows/group

Row 1 (key: SKU-00001):
  title: Nike Air Max 270
  brand: Nike
  price: 150.00
  condition: new

Row 2 (key: SKU-00045):
  title: Nike Pegasus 40
  brand: Nike
  price: 120.00
  condition: refurbished

profile_snapshot

Feed-level quality report: field cardinality, null rates, value distributions, type hints, and stratification recommendations. Use before sampling or querying a large feed.

Input parameters:

ParamDescription
sourceIdThe source ID (use this or sourceSlug)
sourceSlugThe source slug — alternative to sourceId
topNTop N values to show for low/medium cardinality fields (1–50, default 10)

Example:

{
  "sourceSlug": "product-catalog",
  "topN": 5
}

Response:

Feed Profile: product-catalog (snapshot: 2026-03-18, 50,000 rows, 34 fields)

── LOW CARDINALITY ──────────────────────
  condition (3 values, 0% null, text)
    new: 48,000  refurbished: 1,500  used: 500

  brand (47 values, 0% null, text)
    Nike: 3,200  Adidas: 2,800  Puma: 1,100  ...

── MEDIUM CARDINALITY ───────────────────
  color (120 values, 5% null, text)
  size (89 values, 12% null, text)

── HIGH CARDINALITY ─────────────────────
  price (4,823 values, 0% null, numeric)
  title (49,847 values, 0% null, text)

── UNIQUE / IDENTIFIER ──────────────────
  id  sku  row_key

── CONSTANT ─────────────────────────────
  currency = "USD"

Stratification recommendation:
  Best fields: condition, brand, google_product_category
  Try: sample_snapshot(sourceSlug: "product-catalog", stratifyBy: ["condition","brand"], rowsPerGroup: 3)

get_health

Get health information for a feed source. Returns a health score and diagnostic indicators.

Input: sourceId or sourceSlug

Example response:

{
  "score": 100,
  "indicators": {
    "isActive": true,
    "etagSupported": true,
    "hasBeenChecked": true,
    "checkIsFresh": true
  }
}

Example Agent Workflow

When a user asks "What changed in my product catalog today?", an agent can:

  1. Call list_sources to find available sources
  2. Call get_delta with since set to the start of today to find recent events
  3. Call get_delta_rows on the latest event with changeType: "changed" to get actual field data
  4. Summarize: "12 products changed today — 3 price drops, 8 went out of stock, 1 title update."

Example get_delta_rows call:

{
  "sourceSlug": "product-catalog",
  "deltaEventId": "evt_01j...",
  "changeType": "changed",
  "limit": 50
}

Snapshot Workflow

When working with snapshot data, follow this natural sequence:

  1. snapshot_schema — discover available fields and their types
  2. filter_snapshot_rows — preview matching rows (e.g. price > 50 AND stock = 0)
  3. download_filtered_snapshot — export just the matches as CSV/JSON
  4. query_snapshot — run aggregations (count, group_by, avg, etc.)
  5. download_snapshot — export the full snapshot as CSV/JSON

Recommended System Prompt

Add this to your Claude Desktop system prompt for optimal tool usage:

When working with Catalogian sources: always call snapshot_schema first to understand the data structure before querying or filtering. Use filter_snapshot_rows for finding specific records, query_snapshot for aggregations, download_filtered_snapshot to export just the matching rows, and download_snapshot to export the full feed.

Tips

  • • Use get_source_by_slug when you know the slug but not the internal ID
  • • Use the since parameter on get_delta for incremental polling — only fetch what's new
  • • Use changeType filter on get_delta_rows to focus on specific change categories
  • • Use snapshot_schema first to discover available fields before running query_snapshot or filter_snapshot_rows
  • • Use filter_snapshot_rows for multi-condition filtering — supports text, numeric, and null checks with AND logic
  • • Use query_snapshot for server-side aggregations on large feeds — much faster than paginating through all rows
  • • Use get_snapshot_rows to read current feed data — paginate with cursor for large feeds
  • • Use download_filtered_snapshot to export only matching rows as CSV/JSON — same conditions as filter_snapshot_rows
  • • Use download_snapshot to export the entire snapshot as a CSV or JSON file — returns a pre-signed URL valid for 1 hour
  • • Use compare_snapshots to diff two snapshots — see what rows were added, removed, or modified between two points in time
  • • Use search_snapshot for full-text keyword search — finds products by name, description, or any text content, ranked by relevance
  • • Use profile_snapshot before sampling — it reveals field cardinality, null rates, and recommends fields for stratified sampling
  • • Use sample_snapshot with stratifyBy for representative samples across categories — much better than random sampling for analysis
  • • Results are paginated via limit + offset (deltas) or cursor (snapshots) — use hasMore to detect when to fetch more