AI Model Catalog MCP Server
AI Model Catalog MCP Server — NVIDIA NIM + Multi-Provider
Status: production-ready v2.3.0 — audited end to end on 2026-08-01 (
AUDIT_2026-08-01.md): 170 unit tests passing, ruff clean,pip-auditclean, CI green, live smoke-tested on both transports. Enterprise hardening: MCP management-tool isolation on HTTP, Prometheus label sanitization, constant-time auth, request correlation, rate limiting + TRUST_PROXY, body/thread caps, security headers everywhere.
An MCP (Model Context Protocol) server that gives any MCP client (Claude Desktop / Claude Code, Cursor, IDEs) a live, audited catalog of AI models:
NVIDIA NIM — canonical source
https://build.nvidia.com/models; fetched without an API key, deprecated models excluded, OpenAPI/templates resolved, cURL + Node.js + Python examples generated, tiered verification evidence stored. The hosted NIM catalog is 100% free to call with an NVIDIA API key.OpenRouter —
https://openrouter.ai/api/v1/models(official API)Nous Portal —
https://inference-api.nousresearch.com/v1/models(official API)opencode Zen —
https://models.dev/api.json(opencode's official catalog; seehttps://opencode.ai/docs/zen)Blackbox AI — official docs pricing table (
docs.blackbox.ai); authenticatedhttps://api.blackbox.ai/v1/modelswhenBLACKBOX_API_KEYis setVercel AI Gateway —
https://ai-gateway.vercel.sh/v1/models(official API)
FREE_ONLY mode
.env (tracked, no secrets) ships with:
FREE_ONLY=yesWith FREE_ONLY=yes, every provider listing — MCP tools, MCP resources, and
HTTP routes — only surfaces free models. Paid models cannot be listed or
looked up directly (server-side enforcement, not client-side filtering).
NVIDIA NIM is exempt because its hosted catalog is 100% free to call.
Free detection per provider uses each official source: :free/-free id
suffixes and zero prompt+completion pricing (OpenRouter/Nous/Vercel), zero/absent
cost (opencode Zen), and "Free" pricing rows (Blackbox docs).
API keys never go into .env — put them in .env.local (gitignored) or real
environment variables. See .env.example.
Quick start (install.sh)
./install.sh --install # venv + deps + tests + build catalog + start services
./install.sh --status # service state, ports, catalog counts
./install.sh --restart # restart both services
./install.sh --update # refresh catalog data, then --restart to serve it
./install.sh --logs # tail service logs
./install.sh --systemd # systemd units (auto-start on boot, auto-restart)
./install.sh --stop / --uninstallPorts live in .env (tracked): MCP_PORT=9100 (MCP + dashboard),
PORT=8787 (JSON API), HOST=127.0.0.1. Real env vars always win;
put secrets only in .env.local.
MCP server (primary interface)
make install # deps
make catalog # build the NIM + provider catalog (key-less)
make mcp # stdio (Claude Desktop / Claude Code)
make mcp-http # Streamable HTTP + dashboard on 127.0.0.1:9100
# http://127.0.0.1:9100/mcp MCP protocol endpoint (Streamable HTTP)
# http://127.0.0.1:9100/dashboard live HTML dashboard (also served at /)
# http://127.0.0.1:9100/health liveness probe
# http://127.0.0.1:9100/ready readiness probeClaude Desktop / Code config (.mcp.json is included in the repo):
{
"mcpServers": {
"nim-catalog": {
"command": "python",
"args": ["mcp_server.py", "--database", "data/active_nvidia_nim.sqlite3"]
}
}
}Tools: search_models, get_model, get_usage_example, get_endpoints,
recommend_models, get_stats, list_tiers, list_publishers (NVIDIA NIM) +
list_providers, search_provider_models, get_provider_model (multi-provider).
Security note: provider-key management tools (openrouter_list_keys,
openrouter_create_key, openrouter_get_key, openrouter_delete_key,
openrouter_key_usage, openrouter_rotate_key, get_provider_keys_status)
exist on the stdio transport only. With --transport http they are removed
from the registry, so the network-facing MCP endpoint never advertises or
honors key administration. The same routes on the JSON API additionally
require CATALOG_API_TOKEN to be set. X-Forwarded-For is ignored by default
— set TRUST_PROXY=1 only when the service sits behind a proxy you control.
Production deployment
Version 2.3.0 — enterprise-grade serving, stdlib-only hardening:
docker compose up -d # API :8787 + MCP HTTP :9100 (hardened containers)
docker compose run --rm refresher # scheduled catalog rebuildFeature | How |
Liveness / readiness |
|
Prometheus metrics |
|
Bearer auth |
|
Request correlation |
|
Rate limiting |
|
Structured logs | JSON access logs to stderr ( |
DoS guards | 1 MiB request-body cap (413), bounded handler-thread pool (64) |
Graceful shutdown | SIGTERM/SIGINT finishes in-flight requests |
Security headers | nosniff, DENY, CSP, no-store on every response (JSON API and MCP HTTP) |
Operations guide: docs/OPERATIONS.md · Security policy:
SECURITY.md · Release notes: CHANGELOG.md
Dashboard
make dashboard generates exports/dashboard.html — a self-contained
(no-CDN) HTML dashboard with KPIs, NIM verification tiers/modalities/
publishers/transports, per-provider totals vs free with fetch health,
a searchable free-model explorer, a searchable NIM model explorer, and a
data-quality panel mirroring validate_project.py. The HTTP service serves
it live at GET /dashboard (also /):
make service # then open http://127.0.0.1:8787/dashboardResources: nim://stats, nim://models, nim://tiers,
nim://models/{publisher}/{slug}[/{language}], providers://catalog,
providers://{provider}/models.
Current audited result
Counts drift as providers add/remove models; the numbers below are from the
last audited run (2026-07-28). Re-run make catalog for fresh numbers — the
/stats endpoint and exports/tiered-audit.json always reflect your local DB.
NVIDIA NIM: Build index 139 → active non-deprecated 124 (57 free-hosted · 96 downloadable · 36 partner)
OpenRouter: 341 models (18 free) · Nous Portal: 289 (5 free) · opencode Zen: 85 (24 free) · Blackbox AI: 47 (2 free) · Vercel AI Gateway: 307 (3 free)
Live inference verification requires
NVIDIA_API_KEY(make verify); gateway reconciliation requires the same key (python ingest_gateway.py).
data/active_nvidia_nim.sqlite3 contains all active official models, the
multi-provider catalog (provider_models), and audit evidence.
exports/verified-working.sqlite3 contains only latest live-verified hosted models.
Gateway /v1/models reconciliation
export NVIDIA_API_KEY='nvapi-...'
python ingest_gateway.py --database data/active_nvidia_nim.sqlite3 --output exports
python export_unified.py --database data/active_nvidia_nim.sqlite3 --output unified-outputThe gateway response currently exposes only four fields: id, object, created, and owned_by. The database preserves all of them in gateway_models, maps aliases to current Build entries, keeps gateway-only IDs, and enriches mapped records with Build OpenAPI/templates/docs. Query the all_model_inventory view for the full union.
Build without API key
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python audit_catalog.py --database data/active_nvidia_nim.sqlite3 build
python providers.py --database data/active_nvidia_nim.sqlite3 --output exports
python audit_catalog.py --database data/active_nvidia_nim.sqlite3 export --output exports
python finalize_audit.py --database data/active_nvidia_nim.sqlite3 --output exportsOptional live verification
export NVIDIA_API_KEY='nvapi-...'
python audit_catalog.py --database data/active_nvidia_nim.sqlite3 verify --rpm 20 --timeout 120The live-test loop runs under the RPM cap, so a full pass can take a while. To resume an interrupted run (skip models already tested, no re-spent credit):
python audit_catalog.py --database data/active_nvidia_nim.sqlite3 verify --resume --rpm 20 --timeout 120One Build catalog ID:
python audit_catalog.py --database data/active_nvidia_nim.sqlite3 verify \
--model z-ai/glm-5.2 --rpm 20 --timeout 120Automated update
chmod +x bin/update-catalog.sh
NIM_VERIFY=0 bin/update-catalog.shSet NIM_VERIFY=1 only when live tests and credit use are intended.
The same pipeline is available as Make targets (make help for the full list):
make install # pip install -r requirements.txt -r requirements-dev.txt -r requirements-mcp.txt
make test # pytest unit suite (no network/API key needed)
make lint # ruff lint gate (same as CI)
make catalog # full key-less pipeline: build -> providers -> upstreams -> finalize -> export -> unified -> validate
make providers # refresh only the multi-provider catalogs
make dashboard # regenerate exports/dashboard.html
make service # read-only catalog HTTP API on 127.0.0.1:8787
make mcp # MCP server over stdio (Claude Desktop / Claude Code)
make mcp-http # MCP server + dashboard over Streamable HTTP on 127.0.0.1:9100
make image # build the catalog_service Docker image
make ci-local # reproduce the CI key-less pipeline locallyTesting
tests/ is a fast, deterministic pytest suite (no network, no API key) that
pins the data-correctness invariants: model-ID validation/de-dup, page
classification, served-id selection, smoke-payload construction, upstream
joining, and deprecation date semantics — plus the security regression
surface (FREE_ONLY floor, management-tool isolation, metrics label
sanitization, X-Forwarded-For handling, LIKE escaping, request correlation,
auth/rate-limit paths). 170 tests, run with make test.
Continuous integration
.github/workflows/ci.yml runs the unit tests (Python 3.11/3.12/3.13), the
pip-audit dependency CVE gate, then the key-less pipeline (build →
upstreams → finalize → export → unified → validate) on every push/PR and
daily, so the build.nvidia.com contract and the pipeline runtime stay
healthy. The serving smoke test asserts FREE_ONLY over the wire.
No API key is required for CI; live verification stays opt-in via
NIM_VERIFY=1 locally or bin/build-strict.sh with an NVIDIA_API_KEY.
Dependabot (.github/dependabot.yml) opens weekly PRs for pip and
GitHub Actions updates, each gated by the same CI.
Two additional CI smoke assertions are proposed (management gate → 403
without token; X-Request-ID header present) — see AUDIT_2026-08-01.md §7.
Apply them with a maintainer token that has the GitHub workflows
permission.
Deployment
catalog_service.py ships as a read-only HTTP API. The included Dockerfile
serves a pre-built catalog over the API (non-root, healthchecked):
make catalog # build data/active_nvidia_nim.sqlite3 first
docker build -t nvidia-nim-catalog .
docker run -p 8787:8787 -v "$PWD/data:/app/data:ro" nvidia-nim-catalogMCP server
mcp_server.py exposes the catalog as a Model Context Protocol server, so
MCP clients (Claude Desktop, Claude Code, Cursor, IDEs) can discover models,
read served IDs/endpoints, and get runnable cURL/Node.js examples on demand —
no copy-pasting from build.nvidia.com. It is a read-only adapter over the same
shared query layer (catalog_queries.py) as the HTTP API, so both transports
behave identically. Build the catalog first (make catalog), then run the
server.
Install the MCP dependency (extra):
pip install -r requirements-mcp.txt # adds the `mcp` SDKRun (the server reads data/active_nvidia_nim.sqlite3 read-only):
make mcp # stdio transport (default; for Claude Desktop / Claude Code)
make mcp-http # Streamable HTTP transport on http://127.0.0.1:9100
# or explicitly:
python mcp_server.py --database data/active_nvidia_nim.sqlite3 # stdio
python mcp_server.py --database data/active_nvidia_nim.sqlite3 --transport http --port 9100Connect from Claude Desktop (stdio)
Add an entry to claude_desktop_config.json (Settings → Developer → Edit Config).
Use the absolute path to the repo and (if needed) the absolute path to your
Python interpreter:
{
"mcpServers": {
"nim-catalog": {
"command": "python",
"args": ["/absolute/path/to/model_fetcher/mcp_server.py",
"--database", "/absolute/path/to/model_fetcher/data/active_nvidia_nim.sqlite3"]
}
}
}Connect from Claude Code (.mcp.json in the project root)
{
"mcpServers": {
"nim-catalog": {
"command": "python",
"args": ["mcp_server.py", "--database", "data/active_nvidia_nim.sqlite3"]
}
}
}Inspect interactively
mcp dev mcp_server.py # opens the MCP Inspector UIWhat the server exposes
Tools (the assistant calls these):
Tool | Description |
| Search by text/modality/tier; filters for |
| Full detail: served_id, operations, endpoints, examples. |
| Runnable cURL / Node.js code for a model. |
| Every endpoint with host, transport, and auth requirement. |
| Steers to |
| Catalog counts, per-tier breakdown, last build time. |
| Verification tiers with counts and guarantees. |
| Multi-provider catalog (OpenRouter, Nous, opencode, Blackbox, Vercel). |
| Provider-key administration — stdio transport only, never on |
serverInfo.version in the MCP handshake reports the application version
(2.3.0), matching GET /version and the catalog_info Prometheus metric.
Resources (URI-addressable): nim://stats, nim://models, nim://tiers,
nim://models/{publisher}/{slug} (full model), and
nim://models/{publisher}/{slug}/{language} (a code example). The catalog id is
publisher/slug; because it contains a slash, the template splits it into two
segments — e.g. nim://models/meta/llama-3.1-8b-instruct/curl.
Prompt: use_nim_model(catalog_id, task) returns a ready-to-run integration
plan.
Notes
The server is read-only; it never writes and never runs the build pipeline. Refresh the catalog by rebuilding the DB on a schedule (
make catalog/ CI).get_statsreports the last build time so freshness is transparent.recommend_modelsdefaults toproduction_only=true, returning only models that actually responded over HTTP — set itfalseto also see official downloadable/specialized models, clearly tagged.Partial-build safety: if the DB was produced by
audit_catalog buildalone (the tiered audit fromfinalize_audit.pynot yet run),get_stats/list_tiersreportaudit_populated: falsewith a clear warning, andrecommend_modelsfalls back to free-endpoint models instead of silently returning an empty list. Runmake catalog(which includesfinalize) for full tiered data.A missing database returns a clear startup error rather than failing silently.
For a complete strict rebuild, including the gateway and gRPC stages:
chmod +x bin/build-strict.sh
NIM_RPM=20 bin/build-strict.shThe strict pipeline now runs Build discovery, authenticated gateway ingestion and gateway-only tests, Build free-endpoint inference tests, gRPC/NVCF health audit, upstream audit, final audit, unified export, and strict export. Gateway-only records remain visible in the unified inventory but enter strict output only after a real inference pass.
Verification policy
live_inference_verified: received HTTP 2xx and eligible for working DB.official_contract_downloadable: active official NIM, but requires local NVIDIA GPU/container deployment.official_contract_specialized_transport: official Build/API contract verified; live testing needs gRPC, media, private access, or special infrastructure.live_test_failed: timeout/404/5xx; retained in audit but excluded from working.
Every model has cURL and Node.js records. For gRPC/private/custom transports, records explicitly state the official alternative instead of fabricating an HTTP request.
Upstream endpoint audit
python audit_upstreams.py --database data/active_nvidia_nim.sqlite3 --output exportsThe audit cross-checks stored endpoints against each model's Build OpenAPI servers, resolved code templates, Build guides, and official NVIDIA docs. Supported upstream families include:
integrate.api.nvidia.com— hosted LLM/chat/embedding and selected APIs;ai.api.nvidia.com— legacy/specialized VLM, retrieval, Cosmos, and AV APIs;health.api.nvidia.com— BioNeMo/biology APIs;optimize.api.nvidia.com— optimization APIs such as cuOpt;climate.api.nvidia.com— climate/weather APIs;grpc.nvcf.nvidia.com:443— hosted NVCF gRPC requiring API key and function ID;localhost— self-hosted NIM management/inference endpoints.
exports/upstream-audit.* records the result. A Build URL with documentation-only means NVIDIA publishes no fixed public upstream (for example private/early-access or internally brokered playgrounds).