{
  "markdown": "# hazmat-cfr-mcp\n\nThe complete 49 CFR 172.101 Hazardous Materials Table, as an MCP tool for AI agents — every field cited to a pinned eCFR revision.\n\n[![CI](https://github.com/andretaki/hazmat-cfr-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/andretaki/hazmat-cfr-mcp/actions/workflows/ci.yml)\n[![npm](https://img.shields.io/npm/v/hazmat-cfr-mcp.svg)](https://www.npmjs.com/package/hazmat-cfr-mcp)\n[![MCP](https://img.shields.io/badge/MCP-stdio-blue)](https://modelcontextprotocol.io/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)\n\n![hazmat-cfr-mcp demo](https://raw.githubusercontent.com/andretaki/hazmat-cfr-mcp/main/demo.gif)\n\nGive Claude, Cursor, Codex, and other MCP clients a DOT hazmat lookup, classification, and validation tool backed by the **entire** Hazardous Materials Table — not a sample.\n\nAsk an agent:\n\n> Can I ship 60 L of acetone on a cargo-only aircraft? What are its label, packing, and special-provision requirements?\n\nIt returns the proper shipping name, hazard class, packing group, label codes, packaging references, aircraft limits, vessel stowage, **decoded special provisions**, and CFR citations — in structured JSON.\n\nUse it two ways:\n\n- `hazmat-cfr-mcp` — MCP stdio server for agents\n- `hazmat-cfr` — local CLI for humans, tests, and scripts\n\nNo API keys. No customer data. No carrier contracts. No NMFC. Public CFR only.\n\n## What's in the box\n\n- **~2,700 Hazardous Materials Table entries** (49 CFR 172.101) — every UN/NA entry plus Forbidden materials, ingested directly from the official eCFR.\n- **Special-provision decoding** — all ~420 Column 7 codes (49 CFR 172.102: numeric, A, B, IB, IP, N, R, T, TP, W) expanded into their regulatory text.\n- **Legend decoding** — Column 1 symbols (`+ A D G I W`), Column 10A vessel stowage categories, and Columns 8A–8C packaging references resolved to part-173 sections.\n- **Pinned to a dated eCFR snapshot** so every answer is reproducible and citable to an exact revision.\n- **A curated synonym/CAS layer** so \"IPA\", \"muriatic acid\", or \"bleach\" resolve — kept clearly separate from regulatory data.\n\n## 10-second try\n\n```bash\nnpx -y hazmat-cfr-mcp --help\nnpx -y hazmat-cfr lookup UN1088          # not in any \"sample\" — the whole table is here\nnpx -y hazmat-cfr decode-sp IB2 T8 A3\n```\n\n## Why this exists\n\nFoundation models are weak at regulated shipping details. They may know what acetone is, but they should not guess whether a shipping description is complete, what `IB2` means, or which CFR field backs a label requirement.\n\nThis server gives agents an explicit, cited, **complete** hazmat tool surface so they answer with the regulation instead of a hallucination.\n\n## Accuracy & verification\n\nThis is a compliance-adjacent tool, so correctness is enforced by the build, not by hope:\n\n- The dataset is **generated** from the eCFR versioner API and committed to the repo (see [docs/data-pipeline.md](docs/data-pipeline.md)). It is never hand-edited.\n- The ingest **fails** if any special-provision code referenced by the table does not resolve in 172.102 (documented source errata, e.g. `IP16`, are resolved to an explicit \"referenced but not defined\" note — never fabricated).\n- `test/data-integrity.test.ts` re-checks entry counts, structural validity, referential integrity, and ~22 hand-verified spot-checks on every run.\n- The parsers are unit-tested against fixtures in `test/fixtures/`.\n\n> ⚠️ **Disclaimer.** This is an informational aid that surfaces public CFR text. It is **not legal advice**, not a compliance certification, and not a substitute for a trained hazmat employee. Always verify any shipping decision against the current [eCFR](https://www.ecfr.gov/current/title-49).\n\n## Install and run\n\n```bash\nnpx hazmat-cfr-mcp            # MCP stdio server\nnpx hazmat-cfr lookup UN1090  # CLI\n```\n\nFrom a clone:\n\n```bash\ngit clone https://github.com/andretaki/hazmat-cfr-mcp.git\ncd hazmat-cfr-mcp\nnpm install\nnpm run build\nnpm run demo\n```\n\nCLI:\n\n```bash\nnpx hazmat-cfr lookup UN1090\nnpx hazmat-cfr requirements UN1830          # everything to ship it, in one call\nnpx hazmat-cfr placard 2.3\nnpx hazmat-cfr validate \"UN1090, Acetone, 3, PG II\"\nnpx hazmat-cfr segregation 3 5.1 8\nnpx hazmat-cfr lq 3 II 1000 12 true\nnpx hazmat-cfr decode-sp IB2 T8 A3\nnpx hazmat-cfr decode-pkg nonBulk 202\n```\n\n## MCP client config\n\n```json\n{\n  \"mcpServers\": {\n    \"hazmat-cfr\": {\n      \"command\": \"npx\",\n      \"args\": [\"hazmat-cfr-mcp\"]\n    }\n  }\n}\n```\n\nFor a local checkout, point `command` at `node` and `args` at `dist/server.js`.\n\n## Tools\n\n| Tool | Purpose |\n| --- | --- |\n| `lookup_hazmat_entry` | Look up by UN/NA number or proper shipping name; returns matching entries with decoded symbols and special provisions. |\n| `get_shipping_requirements` | **One call → everything to ship a material:** identity, labels, decoded packaging, special provisions, vessel stowage, placard, and citations. |\n| `classify_shipping_description` | Parse free text into structured fields, then validate it. |\n| `validate_basic_hazmat_description` | Validate structured fields against the full 172.101 table. |\n| `get_label_requirements` | Return hazard label codes and caveats. |\n| `get_placard` | 49 CFR 172.504 placard name + quantity threshold for a hazard class. |\n| `check_basic_segregation` | Conservative pairwise segregation findings (49 CFR 177.848 subset). |\n| `check_limited_quantity_eligibility` | Conservative Class 3/Class 8 LQ-candidate screen. |\n| `decode_special_provision` | Expand Column 7 codes (e.g. `IB2`, `T8`, `A3`) into 49 CFR 172.102 text. |\n| `decode_packaging_reference` | Resolve a Column 8A/8B/8C value to its part-173 section. |\n| `explain_cfr_source` | Explain which public CFR source backs a field or rule. |\n\nExample call:\n\n```json\n{ \"query\": \"UN1090\" }\n```\n\n## Library use\n\n```ts\nimport { defaultCatalog, decodeSpecialProvisions, ECFR_SNAPSHOT_DATE } from \"hazmat-cfr-mcp\";\n\nconst acetone = defaultCatalog.lookup(\"UN1090\");\nconst provisions = decodeSpecialProvisions(acetone.entries[0].specialProvisions);\nconsole.log(`Backed by eCFR snapshot ${ECFR_SNAPSHOT_DATE}`);\n```\n\n## Refreshing the data\n\n```bash\n# bump ECFR_SNAPSHOT_DATE in src/data/snapshot.ts, then:\nnpm run ingest -- --fresh\nnpm test\n```\n\nSee [docs/data-pipeline.md](docs/data-pipeline.md) for the full pipeline.\n\n## Non-goals\n\nNot legal advice; not a replacement for trained hazmat employees; not a full compliance certification engine; not NMFC classification; not carrier contract/tariff analysis. No private customer data, contract rates, or internal business records belong in this repo.\n\n## Safety\n\n```bash\nnpm test\nnpm run typecheck\nnpm run scan:secrets\n```\n\n## Maintainer\n\nAndre Taki — [Alliance Chemical](https://alliancechemical.com) — andre@alliancechemical.com\n\n## License\n\nMIT — the underlying 49 CFR text is a public-domain work of the U.S. government.\n",
  "bytes": 6881,
  "sha": "bc36e98b47bf170986a7e5e6d45caf69171fc99fc502650a98b92842395a1914",
  "repo_slug": "andretaki/hazmat-cfr-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_andretaki_hazmat_cfr_mcp_14efb724/readme"
}