Skip to main content
Glama
catalog-mcp

catalog-mcp

by stevyf93II

catalog-mcp

CI npm

An MCP server that turns any JSON catalog into query tools for AI agents.

Point it at a catalog URL or file — an inventory feed, a product list, the catalog.json that feedmerge publishes — and any MCP client (Claude Desktop, Claude Code, anything speaking the protocol) gets structured filtering, grouping, ranking, and schema discovery over your records.

Node 18+. Two runtime dependencies: the MCP SDK and zod.

Why

Agents are bad at big JSON files and good at tools. Hand an agent a 2 MB catalog and it will truncate, skim, or hallucinate records; hand it catalog_query with a filter grammar and it answers "cheapest record under $30k with these two features" correctly every time, reading only the records that match.

This repo is the generalized version of an MCP server I run in production: a sales-floor AI assistant queries a live inventory catalog through exactly these tools (same filter semantics, same null-price rule, same TTL cache) hundreds of times a day. The pipeline it belongs to:

vendor feed  ->  feedmerge  ->  catalog.json  ->  catalog-mcp  ->  any agent
             (guarded sync)   (versioned)      (query tools)

I run this against my own public inventory feed; the example below uses a neutral catalog so the repo stands alone.

Related MCP server: mcp-db-server

Quickstart

No install needed — wire it into Claude Desktop (claude_desktop_config.json) and npx fetches it on first launch:

{
  "mcpServers": {
    "my-catalog": {
      "command": "npx",
      "args": ["-y", "catalog-mcp"],
      "env": {
        "CATALOG_URL": "https://example.com/catalog.json",
        "CATALOG_KEY": "sku"
      }
    }
  }
}

Then ask the agent things like "what types are in the catalog and what does each cost at the low end?" and watch it compose catalog_schema, catalog_count_by, and catalog_top on its own.

To run it by hand against a local file:

npx -y catalog-mcp --file ./catalog.json --key sku

From source

git clone https://github.com/stevyf93II/catalog-mcp.git
cd catalog-mcp
npm install
npm test                                          # engine, loader, and stdio end-to-end tests

# serve the example catalog
node src/server.js --file examples/telescopes.json --key sku

Tools

Tool

What it does

catalog_query

Filter, sort, paginate, and project records

catalog_get

Fetch one record by its key field

catalog_count_by

Group by a field and count (array fields count each element)

catalog_top

Top-N records by a numeric field, with optional filter

catalog_values

Distinct values of a field with counts — learn a field's vocabulary before filtering on it

catalog_schema

Schema inferred from the records: types, coverage, numeric ranges, sample values

catalog_stats

Record count, source, cache age, optional numeric summaries

All tools are read-only and idempotent, and say so in their MCP annotations.

The filter grammar

One small spec, used by query, count_by, and top:

{
  "eq":       { "type": "reflector", "goto": true },
  "min":      { "aperture_mm": 150 },
  "max":      { "price": 1000 },
  "has":      { "features": ["Parabolic Mirror", "Cooling Fan"] },
  "contains": { "name": "dobsonian" }
}
  • eq — strict equality on any value, including booleans and null.

  • min / max — numeric bounds. A record without a real number in a bounded field is excluded. This rule is load-bearing: in the production catalog a missing price means "call for price", and "show me units under $30k" must never surface a unit whose price is unknown.

  • has — array membership; every listed value must be present.

  • contains — case-insensitive substring on a string field; field "*" searches every string field in the record.

Conditions AND together. An unknown top-level key is an error that names the valid keys, because a silently ignored filter is how an agent confidently reports wrong answers.

Sorting pushes records that lack the sort field to the end, in both directions — "sort by price" shows priced records first, not a wall of nulls.

Configuration

Env var

Flag

Meaning

CATALOG_URL

--url

catalog over HTTP(S) (exactly one of url/file)

CATALOG_FILE

--file

catalog on disk

CATALOG_RECORDS_PATH

--records-path

dot-path to the record array, e.g. data.items

CATALOG_KEY

--key

record key field for catalog_get (default id)

CATALOG_TTL_SEC

--ttl

fetch cache TTL in seconds (default 300)

When CATALOG_RECORDS_PATH is not set, the loader uses the document root if it is an array, or the single top-level array of objects if there is exactly one ({ "meta": ..., "items": [...] } just works). If the document is ambiguous it refuses and names the candidate keys.

On a failed refresh the server serves the last good data instead of erroring — an agent mid-task is better off with five-minute-old records than an exception — and catalog_stats reports the cache age so staleness is never hidden.

Non-goals

  • Not a database. The catalog is read-only and lives in memory; if your data does not fit comfortably in a JSON file, you want a real store.

  • No writes. Nothing here mutates the catalog — that is the sync pipeline's job (see feedmerge).

  • No query language. Five filter keys cover what agents actually ask; anything fancier belongs in code, not in a tool schema.

More from the same author

Vista: iOS LiDAR room scanner · swift-tsdf: TSDF fusion and marching cubes in Swift · feedmerge: vendor feed to versioned JSON catalog · docdrop: append-only Google Docs for AI memory · fal-image-relay: your own fal.ai image endpoint

License

MIT

Available Tools

7 tools
catalog_count_byCount records by fieldA
Read-onlyIdempotent

Group records by a field and count each value, most common first. Array fields count each element. Optional filter applies first.

Inputs: field (required), filter.

catalog_getGet one record by keyA
Read-onlyIdempotent

Fetch a single record by its key field ("id"). Returns { found, record }.

Inputs: key (required), fields.

catalog_queryQuery the catalogA
Read-onlyIdempotent

Filter, sort, and page through catalog records. Returns { count, total_matching, total_records, records }. Use catalog_schema first if you are unsure which fields exist. Example: filter {"eq":{"condition":"used"},"max":{"price":30000},"has":{"features":["Solar"]}}, sort_by "price".

Inputs: limit, fields, filter, offset, +2 more.

catalog_schemaInferred catalog schemaA
Read-onlyIdempotent

Field inventory inferred from the records themselves: type, coverage, numeric min/max, and sample values for categorical fields. Call this first when exploring an unfamiliar catalog.

Inputs: no named parameters.

catalog_statsCatalog totals and freshnessA
Read-onlyIdempotent

Record count, source, cache age, and optional numeric summaries (count/min/max/mean/median) for the fields you name.

Inputs: refresh, numeric_fields.

catalog_topTop N records by a numeric fieldA
Read-onlyIdempotent

Rank records by a numeric field with an optional filter. Example: sort_by "price", sort_dir "asc", filter {"has":{"features":["Bunkhouse"]}} = cheapest records with that feature.

Inputs: sort_by (required), limit, fields, filter, +1 more.

catalog_valuesDistinct values of a fieldA
Read-onlyIdempotent

All distinct values of a field with occurrence counts, most common first. The reliable way to learn a categorical field's vocabulary before filtering on it.

Inputs: field (required), limit.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4/5.0

    Scored across 7 tools

    Disambiguation3/5

    catalog_values and catalog_count_by both return per-value occurrence counts, catalog_top is essentially a sorted special case of catalog_query, and catalog_stats overlaps with catalog_schema's min/max summaries. Each tool has a slightly different focus, but the boundaries are fuzzy enough that an agent could easily misselect.

    Naming Consistency4/5

    All tool names share the catalog_ prefix and snake_case, so the namespace is predictable. The suffixes are not uniformly verb_noun—schema/stats/values are nouns while get/query/count_by/top are verb-like—so it is mostly consistent rather than perfectly patterned.

    Tool Count5/5

    Seven tools is a well-scoped size for a catalog exploration server: enough for schema discovery, statistics, filtering, record retrieval, grouping, and value enumeration without bloat.

    Completeness5/5

    For a read-only catalog/exploration domain, the set covers the full workflow: understand the schema, inspect summary statistics, learn field vocabulary, filter/sort/page records, fetch by id, and aggregate/rank. No obvious dead-end operation is missing.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      An integration layer for AI agents that provides a catalog of tools from various sources (OpenAPI, GraphQL, MCP, etc.) and can be used as an MCP server for compatible agents.
      4,427
      MIT
    • F
      license
      Not graded
      quality
      B
      maintenance
      An MCP server that exposes relational databases (PostgreSQL/MySQL) to AI agents with natural language to SQL query support.
      19
      -
    • A
      license
      Not graded
      quality
      C
      maintenance
      An MCP server that enables AI agents to generate, search, and reason over knowledge graphs from code, databases, docs, and open-data portals without requiring an LLM or API key.
      Apache 2.0