@cyanheads/cpsc-recalls-mcp-server
Search and retrieve US consumer product recalls from the CPSC (Consumer Product Safety Commission) via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://cpsc-recalls.caseyjhand.com/mcp
Tools
3 tools for searching and retrieving CPSC consumer product recall data:
| Tool | Description |
|---|---|
cpsc_search_recalls | Search consumer product recalls by product name, brand, retailer, importer, or description keyword, with optional date filtering |
cpsc_get_recall | Full detail for a single recall by recall number — hazards, remedy, products, injuries, images, and the official CPSC page |
cpsc_get_recent | Fetch the most recent recalls ordered newest-first, scoped to a configurable date window |
CPSC jurisdiction: Consumer products only — toys, electronics, furniture, appliances, children's products, tools, and clothing. Food and drugs (FDA), motor vehicles and tires (NHTSA), boats (USCG), and pesticides (EPA) are not in this database. Every response includes a jurisdiction note.
Data sourced from the U.S. Consumer Product Safety Commission via the CPSC public recalls API.
cpsc_search_recalls
Search recalls with flexible filtering across product, organization, and description fields.
- Filter by product name, manufacturer, retailer, importer, or description keyword — all fields are optional substring matches that combine with AND
- Date range filtering via
date_start/date_end(ISO 8601) - Client-side limit (1–200, default 20) applied after fetching all matching records
- Returns hazard descriptions, remedy options, remedy instructions, product list, UPCs, manufacturer/importer/retailer names, images, and the CPSC recall page URL
- Includes
total_foundandtruncatedfields for pagination awareness - Note: the
Hazardfilter param is non-functional in the upstream API — usedescription_searchfor hazard-type keywords like "fire", "choking", or "burn" - When
manufacturerreturns no results, tryimporterorretailer— many recalls list the importer as the primary organization
cpsc_get_recall
Full detail for a single CPSC recall by recall number.
- Accepts modern 5-digit recall numbers (e.g.
"25043") and historical 1998–2001 records with letter suffixes (e.g."99003a") - Returns the complete record: full description, all hazard descriptions, remedy type and instructions, all product variants with unit counts, UPCs, incident/injury narrative, manufacturer and importer names, retailer names with sale date ranges, country of manufacture, images, and coordinated agency recall URLs
- Model numbers are typically embedded in the description text, not in a structured field
- Use
cpsc_search_recallsorcpsc_get_recentto find a recall number first
cpsc_get_recent
Fetch the most recent CPSC recalls, ordered newest-first.
- Configurable look-back window of 1–365 days (default 30)
- Limit of 1–100 results (default 20)
- Always applies a date window — without one, the upstream API returns 9,800+ records
- Returns a lightweight record per recall: number, date, title, hazards, remedy types, product names, and CPSC URL
- Use
cpsc_get_recallto retrieve full detail for any result
Features
Built on @cyanheads/mcp-ts-core:
- Declarative tool definitions — single file per tool, framework handles registration and validation
- Unified error handling — handlers throw, framework catches, classifies, and formats
- Pluggable auth:
none,jwt,oauth - Swappable storage backends:
in-memory,filesystem,Supabase,Cloudflare KV/R2/D1 - Structured logging with optional OpenTelemetry tracing
- STDIO and Streamable HTTP transports
CPSC-specific:
- Full integration with the CPSC saferproducts.gov public recalls API
- Client-side filtering applied over complete API result sets for accurate
total_foundcounts - Jurisdiction boundary documented in every response — prevents misattribution of food, vehicle, or drug recalls
Agent-friendly output:
- Jurisdiction note on every response — agents can route callers to the correct agency (FDA, NHTSA, USCG, EPA) when the product is out of scope
total_found+truncatedfields on search/recent responses — agents can detect when results are clipped and suggest narrowing filterscpsc_urlon every recall — authoritative source link for consumer verification
Getting started
Public Hosted Instance
A public instance is available at https://cpsc-recalls.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"cpsc-recalls-mcp-server": {
"type": "streamable-http",
"url": "https://cpsc-recalls.caseyjhand.com/mcp"
}
}
}
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"cpsc-recalls-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/cpsc-recalls-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"cpsc-recalls-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/cpsc-recalls-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"cpsc-recalls-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/cpsc-recalls-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.3.0 or higher (or Node.js v24+).
- No API key required — the CPSC public recalls API is freely accessible.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/cpsc-recalls-mcp-server.git
- Navigate into the directory:
cd cpsc-recalls-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env if needed — no required API keys
Configuration
All configuration is validated at startup via Zod schemas. Key environment variables:
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http | stdio |
MCP_HTTP_PORT | HTTP server port | 3010 |
MCP_HTTP_HOST | HTTP server host | 127.0.0.1 |
MCP_HTTP_ENDPOINT_PATH | HTTP endpoint path | /mcp |
MCP_PUBLIC_URL | Public origin for TLS-terminating reverse-proxy deployments | — |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error) | info |
LOGS_DIR | Directory for log files (Node.js only) | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1 | in-memory |
OTEL_ENABLED | Enable OpenTelemetry | false |
No server-specific API keys are required. See .env.example for the full list of optional overrides.
Running the server
Local development
-
Build and run the production version:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:http -
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite
Docker
docker build -t cpsc-recalls-mcp-server .
docker run --rm -p 3010:3010 cpsc-recalls-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/cpsc-recalls-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools and inits the CPSC service |
src/mcp-server/tools | Tool definitions (*.tool.ts). Three tools: search, get-recall, get-recent |
src/services/cpsc-recall | CPSC recall service — API client, types, normalization |
Development guide
See CLAUDE.md / AGENTS.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage - Register new tools in the
createApp()arrays insrc/index.ts - Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.