lego-catalog
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@lego-catalogsearch for brick 2 x 4 and show its available colors"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
lego-catalog-mcp
A monorepo of read-only Model Context Protocol (MCP) servers, all served from one
Vercel domain under /<server>/mcp. The first (and currently only) server is lego-catalog.
1. What it is
lego-catalog is a read-only remote MCP server (Streamable HTTP, stateless) that exposes the
Rebrickable LEGO catalog (parts, colors, set inventories) from a SQLite snapshot.
The goal: an agent can verify part IDs and colors instead of inventing them.
Deployments require a bearer token (MCP_AUTH_TOKEN): the data is public, the endpoint is not.
Development happens in a private source repository; the public copy at https://github.com/mariansan/lego-catalog-mcp is a reference copy updated from it periodically and runs no CI or deploy automation.
Monorepo layout:
Path | Role |
| One self-contained MCP server (source, tests, snapshot build scripts) |
| Thin Vercel function adapter for that server |
| Public URL path (rewritten to the function in |
| Snapshot sanity check and smoke test |
| Self-hosting guide and security review |
Related MCP server: akm-mcp
2. Your endpoint and how to add it in Claude
This repository does not publish a hosted endpoint. Run the server locally or host your own copy (see the self-hosting guide). Your endpoint will look like:
https://<your-domain>/lego-catalog/mcpIn Claude: Customize -> Connectors -> Add custom connector -> paste your URL -> Authentication: No sign-in, then
under Request headers add authorization = Bearer <your token> and mark it Required. Request headers are in beta
and available to a limited set of organizations; Claude does not show a header value again after you save it, so changing
the token means removing and re-adding the connector [source: Claude's custom connector documentation, read 2026-10-06].
Use the FULL path. The origin alone (
https://<your-domain>) is not an MCP endpoint: it answers 405 to MCP requests, and Claude then shows a misleading sign-in warning. The full path answers 401 without the token.
The self-hosting guide covers adding the connector (including Team/Enterprise steps and per-chat enabling), running locally and hosting your own copy.
3. Tools
All six tools are read-only (annotated readOnlyHint: true, destructiveHint: false, idempotentHint: true,
openWorldHint: false). Arguments are validated strictly: unknown keys are rejected with invalid_input.
Argument types, defaults and bounds below are copied from the zod schemas in mcps/lego-catalog/src/tools.ts and
config.ts.
Tool | Purpose |
| Full-text search over part names and part numbers |
| One part by |
| The Rebrickable color palette, filterable |
| Part list of a set (sets only, not minifigures) |
| Snapshot date, source, row counts, limits |
| Resolve an |
ID vocabulary
part_numis Rebrickable's part number: usually, but not always, the LEGO design number (printed/assembled variants such as6895aor90462pr0004have their ownpart_num).element_ididentifies a design in one color.design_idexists only on element records (theelementstable) and may benull.No BrickLink, LDraw or other external ids are available.
color_idis Rebrickable's color id.
search_parts
Every word in query must match; results are ranked by relevance. Use it to find the right part_num; never guess one.
Argument | Type | Default | Bounds |
| string (required) | - | trimmed, 1-200 chars, at most 20 distinct words; punctuation ignored |
| integer | 25 | 1-100 |
| integer | 0 | 0-10,000 |
{"name": "search_parts", "arguments": {"query": "brick 2 x 4", "limit": 5}}Verified on the live deployment (2026-10-05): this query returns 3001 "Brick 2 x 4" first, total 1708.
get_part
Returns name, category, material, up to 100 colors (most-used first) and up to 25 element records
(element_id, color_id, design_id), plus colors_total, elements_total and *_truncated flags.
Unknown ids return not_found (ids are case-sensitive).
Argument | Type | Default | Bounds |
| string (required) | - | trimmed, 1-64 chars, e.g. |
{"name": "get_part", "arguments": {"part_num": "3001"}}Verified on the live deployment (2026-10-05): category Bricks, 78 colors, 148 elements.
list_colors
About 275 colors (id, name, RGB hex, transparency, num_parts, num_sets, first_year, last_year), ordered by
color_id.
Argument | Type | Default | Bounds |
| string (optional) | - | trimmed, 1-64 chars; case-insensitive substring |
| boolean (optional) | - |
|
| integer | 100 | 1-100 |
| integer | 0 | 0-10,000 |
{"name": "list_colors", "arguments": {"name": "blue", "is_trans": false}}get_set_inventory
Part list of a set. "75192" is read as "75192-1". Minifigure ids (fig-...) are not supported and return
not_found. Uses the highest inventory version unless version is given; the response lists available_versions.
Rows are ordered by part_num, color_id; is_spare rows are not part of the built model; total_quantity counts
non-spare pieces.
Argument | Type | Default | Bounds |
| string (required) | - | 1-32 chars of letters, digits, |
| integer (optional) | highest available | 1-1000 |
| integer | 25 | 1-200 |
| integer | 0 | 0-10,000 |
{"name": "get_set_inventory", "arguments": {"set_num": "75192-1", "limit": 50}}Verified on the live deployment (2026-10-05): "Millennium Falcon", 2017, inventory version 2 of [2, 1], 726 rows. An unknown set returns:
{"error": {"code": "not_found", "message": "No set \"99999999-1\".", "hint": "Set numbers look like \"75192-1\" (number-version)."}}snapshot_info
No arguments. Returns snapshot date, source URL and attribution, build and download timestamps, schema version, the
inventory-version rule, per-table row_counts, the server's limits, and the ID notes. Call it to tell the user how
fresh the data is.
{"name": "snapshot_info", "arguments": {}}Row counts at the 2026-10-05 snapshot: colors 275, parts 64,826, sets 28,444, inventories 47,671, inventory_parts 1,565,757, elements 114,601.
lookup_element
Resolves an element id (one design in one color, as on packaging / Pick a Brick) to part (part_num, name),
color (color_id, name, rgb) and design_id (may be null and may differ from part_num). Unknown ids return
not_found.
Argument | Type | Default | Bounds |
| string (required) | - | trimmed, 1-12 digits |
{"name": "lookup_element", "arguments": {"element_id": "300126"}}("300126" is the format example from the tool's schema; its lookup result was not checked for this README.)
4. Responses and limits
Every response from the tool handlers, success and error alike, carries source ("Rebrickable") and
snapshot_date. Results are returned both as structuredContent and as a JSON text block.
Errors are tool results with isError: true and the shape
{"source", "snapshot_date", "error": {"code", "message", "hint?"}}. Codes: not_found, invalid_input,
unknown_tool, response_too_large, internal_error. Missing data is a structured not_found, never an empty guess.
Known exception: errors raised by the MCP SDK before a handler runs (for example tools/call with non-object
arguments) come back as a JSON-RPC -32603 error without the envelope. A known, accepted limitation; see SEC-L2 in
docs/SECURITY_REVIEW.md.
Pagination (search_parts, list_colors, get_set_inventory): requests take limit and offset; responses add
total, offset, limit, returned, has_more, next_offset (null on the last page) and size_capped.
Limit | Value |
Default page size | 25 ( |
Max page size | 100 ( |
Max | 10,000 |
Search query | 200 characters, 20 distinct words |
Response payload budget | 20,000 characters; rows are dropped past it and |
Hard refusal | A payload still over 24,000 characters becomes |
Request body | 64 KiB (larger gets HTTP 413) |
JSON-RPC batches | Rejected (HTTP 400) |
| HTTP 405 (stateless: no stream or session to manage) |
Snapshot missing or unreadable | HTTP 503 |
Because of the payload budget, get_set_inventory with limit=200 may return fewer rows than requested; follow
next_offset.
Latency, for orientation only: a sequential client-side sample from one machine (2026-10-05, includes network) gave
search_parts p50 about 130 ms and p95 about 200 ms. This is not a cold-start or load test and is not an SLA.
5. Data and refresh
The snapshot is a SQLite file built from Rebrickable's CSV downloads by
pnpm --filter @mcps/lego-catalog build:snapshot.The hosted instance's snapshot is rebuilt periodically by the maintainer. Every response carries
snapshot_date.Rebrickable's Downloads page allows automated downloads of the zipped CSVs at most once a day; do not spam rebuilds. [source: Rebrickable Downloads page, text read 2026-10-06]
The
.sqlitefile is never committed (gitignored) and never published as a download; it is bundled only inside the function.To host your own copy, see docs/SELF_HOSTING.md.
6. Development
Requires Node 22.x (engines in the root package.json; node:sqlite is used and prints an experimental warning) and
pnpm.
pnpm install
pnpm lint # eslint .
pnpm typecheck # tsc --noEmit in every package
pnpm test # vitest in every package
# Build the SQLite snapshot (downloads Rebrickable CSVs; max one automated download per day)
pnpm --filter @mcps/lego-catalog build:snapshot
# Local dev server on http://127.0.0.1:3000/lego-catalog/mcp (PORT env overrides the port)
pnpm --filter @mcps/lego-catalog dev
# Smoke test any endpoint
node scripts/smoke-mcp.mjs --no-auth http://127.0.0.1:3000/lego-catalog/mcp # the dev server has no token checkTests that need the real snapshot skip when LEGO_CATALOG_DB is unset. To run everything, point it at a built
snapshot:
$env:LEGO_CATALOG_DB = "C:\path\to\rebrickable.sqlite"; pnpm testThe server looks for the snapshot in LEGO_CATALOG_DB, then mcps/lego-catalog/data/rebrickable.sqlite.
MCP_AUTH_TOKEN is required by the deployed function: set it as a Sensitive environment variable for Production in
Vercel (at least 32 random characters). If it is unset the function answers 503 to every request (it fails closed).
The smoke test reads the same variable from the environment, never from the command line. The local dev server does not
check it.
7. Security and status
See docs/SECURITY_REVIEW.md for the review and its findings. Honest status:
The deployed function requires
Authorization: Bearer <token>. The token is compared in constant time againstMCP_AUTH_TOKEN; a missing or wrong token gets 401 before the request body is read, and an unset variable gets 503.The local dev server has no token check and listens on 127.0.0.1 only.
The maintainer's deployment is private.
No CORS headers are sent.
8. Attribution and legal
Data: Rebrickable (https://rebrickable.com/downloads/). Rebrickable asks to be acknowledged as the source of the data [source: Rebrickable Downloads page, text read 2026-10-06].
LEGO is a trademark of the LEGO Group; this project is not affiliated with or endorsed by it.
Rebrickable's Terms of Service (section 5.3) forbid training AI models on their content. This server serves data at inference time only. [source: Rebrickable Terms of Service, text read 2026-10-06]
Not covered by the texts read: whether serving data derived from the CSVs is permitted. That question is open. This is not legal advice; read Rebrickable's terms yourself before reuse.
9. License
The code is released under the MIT License, copyright (c) 2026 Marian Sanjur.
The license covers this repository's code only. The catalog data comes from Rebrickable and stays under Rebrickable's own terms (see section 8); it is not relicensed by this project.
This server cannot be deployed
Maintenance
Related MCP Connectors
Search MCP servers, MCP clients and AI agents, and retrieve listing details. Free, read-only access.
Capability registry for the agentic economy. Semantic search over verified MCP server listings.
Read-only MCP server: let AI agents read your ORANO saved-video library, tasks, and memory.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceAn MCP server that exposes authoritative, read-only Conda ecosystem metadata for AI agents, enabling package search, dependency resolution, and other packaging queries without side effects.6BSD 3-Clause
- AlicenseNot gradedqualityAmaintenanceThis MCP server enables AI agents to manage artifacts across sessions by providing tools for searching, retrieving, and registering entries in a persistent ledger, ensuring consistency and traceability of agent outputs.MIT
- AlicenseAqualityCmaintenanceRead-only MCP server providing AI access to verifiable web, GitHub, and local sources, plus a managed fantasy entity catalog, with strong security and provenance tracking.101MIT
- AlicenseAqualityAmaintenanceRead-only MCP server that exposes a design system's tokens, components, conventions, and deprecations as queryable tools, enabling agents to look up canonical values, assess change impact, and detect hardcoded value drift.81 npmMIT