@cyanheads/federal-regulations-mcp-server 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +34 -31
- package/CLAUDE.md +34 -31
- package/Dockerfile +11 -7
- package/LICENSE +1 -1
- package/README.md +14 -6
- package/changelog/0.1.x/0.1.3.md +40 -0
- package/changelog/0.1.x/0.1.4.md +17 -0
- package/changelog/template.md +5 -3
- package/dist/mcp-server/tools/definitions/browse-cfr.tool.d.ts +20 -7
- package/dist/mcp-server/tools/definitions/browse-cfr.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/browse-cfr.tool.js +124 -33
- package/dist/mcp-server/tools/definitions/browse-cfr.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/find-comments.tool.d.ts +10 -3
- package/dist/mcp-server/tools/definitions/find-comments.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/find-comments.tool.js +50 -21
- package/dist/mcp-server/tools/definitions/find-comments.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-cfr-section.tool.d.ts +1 -1
- package/dist/mcp-server/tools/definitions/get-docket.tool.d.ts +2 -2
- package/dist/mcp-server/tools/definitions/index.d.ts +192 -191
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/list-open-comments.tool.d.ts +0 -5
- package/dist/mcp-server/tools/definitions/list-open-comments.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/list-open-comments.tool.js +0 -6
- package/dist/mcp-server/tools/definitions/list-open-comments.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-rules.tool.d.ts +2 -7
- package/dist/mcp-server/tools/definitions/search-rules.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-rules.tool.js +0 -6
- package/dist/mcp-server/tools/definitions/search-rules.tool.js.map +1 -1
- package/dist/services/ecfr/ecfr-service.d.ts +28 -3
- package/dist/services/ecfr/ecfr-service.d.ts.map +1 -1
- package/dist/services/ecfr/ecfr-service.js +147 -20
- package/dist/services/ecfr/ecfr-service.js.map +1 -1
- package/dist/services/ecfr/types.d.ts +38 -20
- package/dist/services/ecfr/types.d.ts.map +1 -1
- package/dist/services/ecfr-mirror/ecfr-mirror.d.ts +41 -7
- package/dist/services/ecfr-mirror/ecfr-mirror.d.ts.map +1 -1
- package/dist/services/ecfr-mirror/ecfr-mirror.js +93 -15
- package/dist/services/ecfr-mirror/ecfr-mirror.js.map +1 -1
- package/dist/services/federal-register/federal-register-service.d.ts.map +1 -1
- package/dist/services/federal-register/federal-register-service.js +6 -3
- package/dist/services/federal-register/federal-register-service.js.map +1 -1
- package/dist/services/regulations-gov/regulations-gov-service.d.ts +7 -2
- package/dist/services/regulations-gov/regulations-gov-service.d.ts.map +1 -1
- package/dist/services/regulations-gov/regulations-gov-service.js +42 -3
- package/dist/services/regulations-gov/regulations-gov-service.js.map +1 -1
- package/package.json +20 -9
- package/scripts/_mirror-context.ts +16 -14
- package/scripts/ecfr-mirror-verify.ts +13 -3
- package/server.json +3 -3
package/AGENTS.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** federal-regulations-mcp-server
|
|
4
|
-
**Version:** 0.1.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.
|
|
4
|
+
**Version:** 0.1.4
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.11.1`
|
|
6
6
|
**Engines:** Bun ≥1.3.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/sdk` ^1.
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/sdk` ^1.30.0
|
|
8
8
|
**Zod:** ^4.4.3
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
@@ -150,12 +150,14 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
150
150
|
| Property | Description |
|
|
151
151
|
|:---------|:------------|
|
|
152
152
|
| `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. |
|
|
153
|
-
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
153
|
+
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.getMany(keys)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
154
154
|
| `ctx.elicit` | Ask user for structured input — form call `(message, schema)` or `.url(message, url)` for an external link. **Check for presence first:** `if (ctx.elicit) { ... }` |
|
|
155
|
+
| `ctx.enrich` | Success-path agent context (empty-result notices, query echo, pagination totals) — `ctx.enrich(...)` or `.notice()` / `.total()` / `.echo()` / `.truncated()`. Reaches `structuredContent` and `content[]`; lands only when the definition declares an `enrichment` block (no-op otherwise). |
|
|
156
|
+
| `ctx.content` | Non-text content blocks — `.image(data, mimeType)`, `.audio(data, mimeType)`, or `ctx.content(block)` for a raw block. Prepended to `content[]` after `format()`; never enters `structuredContent`. |
|
|
155
157
|
| `ctx.signal` | `AbortSignal` for cancellation. |
|
|
156
158
|
| `ctx.progress` | Task progress (present when `task: true`) — `.setTotal(n)`, `.increment()`, `.update(message)`. |
|
|
157
159
|
| `ctx.requestId` | Unique request ID. |
|
|
158
|
-
| `ctx.tenantId` | Tenant ID from JWT
|
|
160
|
+
| `ctx.tenantId` | Tenant ID from JWT; `'default'` for stdio or HTTP with auth off. |
|
|
159
161
|
|
|
160
162
|
---
|
|
161
163
|
|
|
@@ -163,7 +165,7 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
163
165
|
|
|
164
166
|
Handlers throw — the framework catches, classifies, and formats.
|
|
165
167
|
|
|
166
|
-
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required
|
|
168
|
+
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire (`data.recovery.hint`, mirrored into `content[]` text); override with an explicit `{ recovery: { hint: '...' } }` when dynamic runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`) bubble freely and don't need declaring.
|
|
167
169
|
|
|
168
170
|
```ts
|
|
169
171
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
@@ -175,7 +177,7 @@ errors: [
|
|
|
175
177
|
],
|
|
176
178
|
async handler(input, ctx) {
|
|
177
179
|
const item = await db.find(input.id);
|
|
178
|
-
if (!item) throw ctx.fail('no_match', `No item ${input.id}
|
|
180
|
+
if (!item) throw ctx.fail('no_match', `No item ${input.id}`, ctx.recoveryFor('no_match'));
|
|
179
181
|
return item;
|
|
180
182
|
}
|
|
181
183
|
```
|
|
@@ -243,7 +245,7 @@ No prompts in v1 — `createApp({ prompts: [] })`.
|
|
|
243
245
|
|
|
244
246
|
## Skills
|
|
245
247
|
|
|
246
|
-
Skills are modular instructions in `skills/` at the project root. Read them directly when a task matches — e.g., `skills/add-tool/SKILL.md` when adding a tool.
|
|
248
|
+
Skills are modular instructions in `skills/` at the project root. Read them directly when a task matches — e.g., `skills/add-tool/SKILL.md` when adding a tool. `bun run list-skills` prints the full registry.
|
|
247
249
|
|
|
248
250
|
**Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.
|
|
249
251
|
|
|
@@ -263,7 +265,6 @@ Available skills:
|
|
|
263
265
|
| `tool-defs-analysis` | Read-only audit of MCP definition language across the surface — voice, leaks, defaults, recovery hints, output descriptions |
|
|
264
266
|
| `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
|
|
265
267
|
| `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
|
|
266
|
-
| `devcheck` | Lint, format, typecheck, audit |
|
|
267
268
|
| `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
|
|
268
269
|
| `git-wrapup` | Land working-tree changes as a versioned commit + annotated tag — version bump, changelog, verify, tag. Local only. |
|
|
269
270
|
| `release-and-publish` | Push + npm + MCP Registry + GH Release + Docker. Picks up from `git-wrapup` |
|
|
@@ -271,12 +272,14 @@ Available skills:
|
|
|
271
272
|
| `orchestrations` | Chain task skills into a gated multi-phase pipeline — build-out, QA-fix, update-ship — when you can spawn sub-agents |
|
|
272
273
|
| `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
|
|
273
274
|
| `report-issue-local` | File a bug or feature request against this server's own repo via `gh` CLI |
|
|
275
|
+
| `techniques` | Catalog of response/data-shaping techniques — overflow handling, payload shaping, retrieval patterns |
|
|
274
276
|
| `api-auth` | Auth modes, scopes, JWT/OAuth |
|
|
275
277
|
| `api-canvas` | DataCanvas: register tabular data, run SQL, export, plus the `spillover()` helper for big result sets — Tier 3 opt-in |
|
|
276
278
|
| `api-config` | AppConfig, parseConfig, env vars |
|
|
277
279
|
| `api-context` | Context interface, logger, state, progress |
|
|
278
280
|
| `api-errors` | McpError, JsonRpcErrorCode, error patterns |
|
|
279
281
|
| `api-linter` | Definition linter rule catalog — invoked by `bun run lint:mcp` and `devcheck` |
|
|
282
|
+
| `api-mirror` | MirrorService: persistent self-refreshing local mirror (embedded SQLite + FTS5) of a bulk upstream dataset — Tier 3 opt-in |
|
|
280
283
|
| `api-services` | LLM, Speech, Graph services |
|
|
281
284
|
| `api-testing` | createMockContext, test patterns |
|
|
282
285
|
| `api-utils` | Formatting, parsing, security, pagination, scheduling, telemetry helpers |
|
|
@@ -295,32 +298,32 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
295
298
|
|
|
296
299
|
| Command | Purpose |
|
|
297
300
|
|:--------|:--------|
|
|
298
|
-
| `
|
|
299
|
-
| `
|
|
300
|
-
| `
|
|
301
|
-
| `
|
|
301
|
+
| `bun run build` | Compile TypeScript |
|
|
302
|
+
| `bun run rebuild` | Clean + build |
|
|
303
|
+
| `bun run clean` | Remove build artifacts |
|
|
304
|
+
| `bun run devcheck` | Lint + format + typecheck + security + changelog sync |
|
|
302
305
|
| `bun run audit:refresh` | Delete `bun.lock`, reinstall, and re-run `bun audit`. Use when `devcheck` flags a transitive advisory — Bun's `update` is sticky on transitive resolutions, so the advisory may be a stale-lockfile false positive. If it survives the refresh, it's real. |
|
|
303
|
-
| `
|
|
304
|
-
| `
|
|
305
|
-
| `
|
|
306
|
-
| `
|
|
307
|
-
| `
|
|
308
|
-
| `
|
|
309
|
-
| `
|
|
310
|
-
| `
|
|
311
|
-
| `
|
|
312
|
-
| `
|
|
313
|
-
| `
|
|
314
|
-
| `
|
|
315
|
-
| `
|
|
316
|
-
| `
|
|
317
|
-
| `
|
|
306
|
+
| `bun run lint:mcp` | Run the MCP definition linter standalone (rule catalog: `api-linter` skill) |
|
|
307
|
+
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity (run by devcheck) |
|
|
308
|
+
| `bun run list-skills` | Print the skill registry |
|
|
309
|
+
| `bun run tree` | Generate directory structure doc |
|
|
310
|
+
| `bun run format` | Auto-fix formatting (safe fixes only) |
|
|
311
|
+
| `bun run format:unsafe` | Also apply Biome's unsafe autofixes — review the diff; they can change behavior |
|
|
312
|
+
| `bun run test` | Run tests (Vitest — use `bun run test`, not `bun test`) |
|
|
313
|
+
| `bun run start:stdio` | Production mode (stdio) |
|
|
314
|
+
| `bun run start:http` | Production mode (HTTP) |
|
|
315
|
+
| `bun run changelog:build` | Regenerate `CHANGELOG.md` from `changelog/*.md` |
|
|
316
|
+
| `bun run changelog:check` | Verify `CHANGELOG.md` is in sync (used by devcheck) |
|
|
317
|
+
| `bun run bundle` | Build, pack, and clean a `.mcpb` for one-click Claude Desktop install |
|
|
318
|
+
| `bun run mirror:init` | Build the eCFR codified-text mirror (out-of-band, idempotent, resumable). Scope with `ECFR_MIRROR_TITLES`. |
|
|
319
|
+
| `bun run mirror:refresh` | Incremental refresh of the eCFR mirror against the latest eCFR issues |
|
|
320
|
+
| `bun run mirror:verify` | Report mirror row counts and the last-synced issue date |
|
|
318
321
|
|
|
319
322
|
---
|
|
320
323
|
|
|
321
324
|
## Bundling
|
|
322
325
|
|
|
323
|
-
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips dependency-shipped agent docs (`
|
|
326
|
+
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips two classes of `node_modules/**` content that root-anchored `.mcpbignore` patterns cannot reach: dependency-shipped agent docs (`skills/`, `.claude/`, `.agents/`, `SKILL.md`) and platform-specific native bindings, which would otherwise lock the bundle to the platform it was packed on. A server using DataCanvas therefore ships a portable bundle without the DuckDB native — `@duckdb/node-api` is an optional peer loaded lazily, so canvas tools report an actionable install hint and every other tool works normally. MCPB is stdio-only — HTTP and Cloudflare Workers deployments are unaffected. Consumers who don't need it can delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly.
|
|
324
327
|
|
|
325
328
|
**Adding an env var requires both files:** `server.json` (registry discovery, `environmentVariables[]`) and `manifest.json` (bundle install UX, `mcp_config.env` + `user_config`). `lint:packaging` (run by `devcheck`) verifies the env var names match.
|
|
326
329
|
|
|
@@ -338,14 +341,14 @@ Each per-version file opens with YAML frontmatter:
|
|
|
338
341
|
---
|
|
339
342
|
summary: "One-line headline, ≤350 chars" # required — powers the rollup index
|
|
340
343
|
breaking: false # optional — true flags breaking changes
|
|
341
|
-
security: false # optional — true
|
|
344
|
+
security: false # optional — true ONLY for a source-code security fix, never a dependency CVE bump
|
|
342
345
|
---
|
|
343
346
|
|
|
344
347
|
# 0.1.0 — YYYY-MM-DD
|
|
345
348
|
...
|
|
346
349
|
```
|
|
347
350
|
|
|
348
|
-
`breaking: true` renders a `· ⚠️ Breaking` badge — use it when consumers must update code on upgrade (signature changes, removed APIs, config renames). `security: true` renders a `· 🛡️ Security` badge and pairs with a `## Security` body section. When both are set, badges render `· ⚠️ Breaking · 🛡️ Security`.
|
|
351
|
+
`breaking: true` renders a `· ⚠️ Breaking` badge — use it when consumers must update code on upgrade (signature changes, removed APIs, config renames). `security: true` renders a `· 🛡️ Security` badge and pairs with a `## Security` body section — set it only for a security fix in this server's *own source code*, never for a routine dependency or transitive CVE bump (record those under `## Dependencies`). When both are set, badges render `· ⚠️ Breaking · 🛡️ Security`.
|
|
349
352
|
|
|
350
353
|
`agent-notes` is an optional free-form field for maintenance agents processing the release downstream. Content here won't appear in the rendered CHANGELOG — it's consumed by agents running the `maintenance` skill. Use it for adoption instructions that don't fit the human-facing sections: new files to create, fields to populate, one-time migration steps. Omit entirely when there's nothing to say.
|
|
351
354
|
|
package/CLAUDE.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** federal-regulations-mcp-server
|
|
4
|
-
**Version:** 0.1.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.
|
|
4
|
+
**Version:** 0.1.4
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.11.1`
|
|
6
6
|
**Engines:** Bun ≥1.3.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/sdk` ^1.
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/sdk` ^1.30.0
|
|
8
8
|
**Zod:** ^4.4.3
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
@@ -150,12 +150,14 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
150
150
|
| Property | Description |
|
|
151
151
|
|:---------|:------------|
|
|
152
152
|
| `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. |
|
|
153
|
-
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
153
|
+
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.getMany(keys)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
154
154
|
| `ctx.elicit` | Ask user for structured input — form call `(message, schema)` or `.url(message, url)` for an external link. **Check for presence first:** `if (ctx.elicit) { ... }` |
|
|
155
|
+
| `ctx.enrich` | Success-path agent context (empty-result notices, query echo, pagination totals) — `ctx.enrich(...)` or `.notice()` / `.total()` / `.echo()` / `.truncated()`. Reaches `structuredContent` and `content[]`; lands only when the definition declares an `enrichment` block (no-op otherwise). |
|
|
156
|
+
| `ctx.content` | Non-text content blocks — `.image(data, mimeType)`, `.audio(data, mimeType)`, or `ctx.content(block)` for a raw block. Prepended to `content[]` after `format()`; never enters `structuredContent`. |
|
|
155
157
|
| `ctx.signal` | `AbortSignal` for cancellation. |
|
|
156
158
|
| `ctx.progress` | Task progress (present when `task: true`) — `.setTotal(n)`, `.increment()`, `.update(message)`. |
|
|
157
159
|
| `ctx.requestId` | Unique request ID. |
|
|
158
|
-
| `ctx.tenantId` | Tenant ID from JWT
|
|
160
|
+
| `ctx.tenantId` | Tenant ID from JWT; `'default'` for stdio or HTTP with auth off. |
|
|
159
161
|
|
|
160
162
|
---
|
|
161
163
|
|
|
@@ -163,7 +165,7 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
163
165
|
|
|
164
166
|
Handlers throw — the framework catches, classifies, and formats.
|
|
165
167
|
|
|
166
|
-
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required
|
|
168
|
+
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire (`data.recovery.hint`, mirrored into `content[]` text); override with an explicit `{ recovery: { hint: '...' } }` when dynamic runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`) bubble freely and don't need declaring.
|
|
167
169
|
|
|
168
170
|
```ts
|
|
169
171
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
@@ -175,7 +177,7 @@ errors: [
|
|
|
175
177
|
],
|
|
176
178
|
async handler(input, ctx) {
|
|
177
179
|
const item = await db.find(input.id);
|
|
178
|
-
if (!item) throw ctx.fail('no_match', `No item ${input.id}
|
|
180
|
+
if (!item) throw ctx.fail('no_match', `No item ${input.id}`, ctx.recoveryFor('no_match'));
|
|
179
181
|
return item;
|
|
180
182
|
}
|
|
181
183
|
```
|
|
@@ -243,7 +245,7 @@ No prompts in v1 — `createApp({ prompts: [] })`.
|
|
|
243
245
|
|
|
244
246
|
## Skills
|
|
245
247
|
|
|
246
|
-
Skills are modular instructions in `skills/` at the project root. Read them directly when a task matches — e.g., `skills/add-tool/SKILL.md` when adding a tool.
|
|
248
|
+
Skills are modular instructions in `skills/` at the project root. Read them directly when a task matches — e.g., `skills/add-tool/SKILL.md` when adding a tool. `bun run list-skills` prints the full registry.
|
|
247
249
|
|
|
248
250
|
**Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.
|
|
249
251
|
|
|
@@ -263,7 +265,6 @@ Available skills:
|
|
|
263
265
|
| `tool-defs-analysis` | Read-only audit of MCP definition language across the surface — voice, leaks, defaults, recovery hints, output descriptions |
|
|
264
266
|
| `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
|
|
265
267
|
| `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
|
|
266
|
-
| `devcheck` | Lint, format, typecheck, audit |
|
|
267
268
|
| `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
|
|
268
269
|
| `git-wrapup` | Land working-tree changes as a versioned commit + annotated tag — version bump, changelog, verify, tag. Local only. |
|
|
269
270
|
| `release-and-publish` | Push + npm + MCP Registry + GH Release + Docker. Picks up from `git-wrapup` |
|
|
@@ -271,12 +272,14 @@ Available skills:
|
|
|
271
272
|
| `orchestrations` | Chain task skills into a gated multi-phase pipeline — build-out, QA-fix, update-ship — when you can spawn sub-agents |
|
|
272
273
|
| `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
|
|
273
274
|
| `report-issue-local` | File a bug or feature request against this server's own repo via `gh` CLI |
|
|
275
|
+
| `techniques` | Catalog of response/data-shaping techniques — overflow handling, payload shaping, retrieval patterns |
|
|
274
276
|
| `api-auth` | Auth modes, scopes, JWT/OAuth |
|
|
275
277
|
| `api-canvas` | DataCanvas: register tabular data, run SQL, export, plus the `spillover()` helper for big result sets — Tier 3 opt-in |
|
|
276
278
|
| `api-config` | AppConfig, parseConfig, env vars |
|
|
277
279
|
| `api-context` | Context interface, logger, state, progress |
|
|
278
280
|
| `api-errors` | McpError, JsonRpcErrorCode, error patterns |
|
|
279
281
|
| `api-linter` | Definition linter rule catalog — invoked by `bun run lint:mcp` and `devcheck` |
|
|
282
|
+
| `api-mirror` | MirrorService: persistent self-refreshing local mirror (embedded SQLite + FTS5) of a bulk upstream dataset — Tier 3 opt-in |
|
|
280
283
|
| `api-services` | LLM, Speech, Graph services |
|
|
281
284
|
| `api-testing` | createMockContext, test patterns |
|
|
282
285
|
| `api-utils` | Formatting, parsing, security, pagination, scheduling, telemetry helpers |
|
|
@@ -295,32 +298,32 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
295
298
|
|
|
296
299
|
| Command | Purpose |
|
|
297
300
|
|:--------|:--------|
|
|
298
|
-
| `
|
|
299
|
-
| `
|
|
300
|
-
| `
|
|
301
|
-
| `
|
|
301
|
+
| `bun run build` | Compile TypeScript |
|
|
302
|
+
| `bun run rebuild` | Clean + build |
|
|
303
|
+
| `bun run clean` | Remove build artifacts |
|
|
304
|
+
| `bun run devcheck` | Lint + format + typecheck + security + changelog sync |
|
|
302
305
|
| `bun run audit:refresh` | Delete `bun.lock`, reinstall, and re-run `bun audit`. Use when `devcheck` flags a transitive advisory — Bun's `update` is sticky on transitive resolutions, so the advisory may be a stale-lockfile false positive. If it survives the refresh, it's real. |
|
|
303
|
-
| `
|
|
304
|
-
| `
|
|
305
|
-
| `
|
|
306
|
-
| `
|
|
307
|
-
| `
|
|
308
|
-
| `
|
|
309
|
-
| `
|
|
310
|
-
| `
|
|
311
|
-
| `
|
|
312
|
-
| `
|
|
313
|
-
| `
|
|
314
|
-
| `
|
|
315
|
-
| `
|
|
316
|
-
| `
|
|
317
|
-
| `
|
|
306
|
+
| `bun run lint:mcp` | Run the MCP definition linter standalone (rule catalog: `api-linter` skill) |
|
|
307
|
+
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity (run by devcheck) |
|
|
308
|
+
| `bun run list-skills` | Print the skill registry |
|
|
309
|
+
| `bun run tree` | Generate directory structure doc |
|
|
310
|
+
| `bun run format` | Auto-fix formatting (safe fixes only) |
|
|
311
|
+
| `bun run format:unsafe` | Also apply Biome's unsafe autofixes — review the diff; they can change behavior |
|
|
312
|
+
| `bun run test` | Run tests (Vitest — use `bun run test`, not `bun test`) |
|
|
313
|
+
| `bun run start:stdio` | Production mode (stdio) |
|
|
314
|
+
| `bun run start:http` | Production mode (HTTP) |
|
|
315
|
+
| `bun run changelog:build` | Regenerate `CHANGELOG.md` from `changelog/*.md` |
|
|
316
|
+
| `bun run changelog:check` | Verify `CHANGELOG.md` is in sync (used by devcheck) |
|
|
317
|
+
| `bun run bundle` | Build, pack, and clean a `.mcpb` for one-click Claude Desktop install |
|
|
318
|
+
| `bun run mirror:init` | Build the eCFR codified-text mirror (out-of-band, idempotent, resumable). Scope with `ECFR_MIRROR_TITLES`. |
|
|
319
|
+
| `bun run mirror:refresh` | Incremental refresh of the eCFR mirror against the latest eCFR issues |
|
|
320
|
+
| `bun run mirror:verify` | Report mirror row counts and the last-synced issue date |
|
|
318
321
|
|
|
319
322
|
---
|
|
320
323
|
|
|
321
324
|
## Bundling
|
|
322
325
|
|
|
323
|
-
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips dependency-shipped agent docs (`
|
|
326
|
+
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips two classes of `node_modules/**` content that root-anchored `.mcpbignore` patterns cannot reach: dependency-shipped agent docs (`skills/`, `.claude/`, `.agents/`, `SKILL.md`) and platform-specific native bindings, which would otherwise lock the bundle to the platform it was packed on. A server using DataCanvas therefore ships a portable bundle without the DuckDB native — `@duckdb/node-api` is an optional peer loaded lazily, so canvas tools report an actionable install hint and every other tool works normally. MCPB is stdio-only — HTTP and Cloudflare Workers deployments are unaffected. Consumers who don't need it can delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly.
|
|
324
327
|
|
|
325
328
|
**Adding an env var requires both files:** `server.json` (registry discovery, `environmentVariables[]`) and `manifest.json` (bundle install UX, `mcp_config.env` + `user_config`). `lint:packaging` (run by `devcheck`) verifies the env var names match.
|
|
326
329
|
|
|
@@ -338,14 +341,14 @@ Each per-version file opens with YAML frontmatter:
|
|
|
338
341
|
---
|
|
339
342
|
summary: "One-line headline, ≤350 chars" # required — powers the rollup index
|
|
340
343
|
breaking: false # optional — true flags breaking changes
|
|
341
|
-
security: false # optional — true
|
|
344
|
+
security: false # optional — true ONLY for a source-code security fix, never a dependency CVE bump
|
|
342
345
|
---
|
|
343
346
|
|
|
344
347
|
# 0.1.0 — YYYY-MM-DD
|
|
345
348
|
...
|
|
346
349
|
```
|
|
347
350
|
|
|
348
|
-
`breaking: true` renders a `· ⚠️ Breaking` badge — use it when consumers must update code on upgrade (signature changes, removed APIs, config renames). `security: true` renders a `· 🛡️ Security` badge and pairs with a `## Security` body section. When both are set, badges render `· ⚠️ Breaking · 🛡️ Security`.
|
|
351
|
+
`breaking: true` renders a `· ⚠️ Breaking` badge — use it when consumers must update code on upgrade (signature changes, removed APIs, config renames). `security: true` renders a `· 🛡️ Security` badge and pairs with a `## Security` body section — set it only for a security fix in this server's *own source code*, never for a routine dependency or transitive CVE bump (record those under `## Dependencies`). When both are set, badges render `· ⚠️ Breaking · 🛡️ Security`.
|
|
349
352
|
|
|
350
353
|
`agent-notes` is an optional free-form field for maintenance agents processing the release downstream. Content here won't appear in the rendered CHANGELOG — it's consumed by agents running the `maintenance` skill. Use it for adoption instructions that don't fit the human-facing sections: new files to create, fields to populate, one-time migration steps. Omit entirely when there's nothing to say.
|
|
351
354
|
|
package/Dockerfile
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This stage installs all dependencies (including dev), builds the TypeScript
|
|
5
5
|
# source code into JavaScript, and prepares the production assets.
|
|
6
6
|
# ==============================================================================
|
|
7
|
-
FROM oven/bun:1.3 AS build
|
|
7
|
+
FROM oven/bun:1.3.14 AS build
|
|
8
8
|
|
|
9
9
|
WORKDIR /usr/src/app
|
|
10
10
|
|
|
@@ -15,8 +15,10 @@ COPY package.json bun.lock ./
|
|
|
15
15
|
# lifecycle scripts: better-sqlite3's native gyp compile breaks under the bun
|
|
16
16
|
# base image, and it is never loaded at runtime (Bun's built-in bun:sqlite
|
|
17
17
|
# drives the mirror reads; the build-time ingest path resolves it on a real
|
|
18
|
-
# Node host, not in this image).
|
|
19
|
-
|
|
18
|
+
# Node host, not in this image). The BuildKit cache mount persists Bun's global
|
|
19
|
+
# package cache across builds.
|
|
20
|
+
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
21
|
+
bun install --frozen-lockfile --ignore-scripts
|
|
20
22
|
|
|
21
23
|
# Copy the rest of the source code
|
|
22
24
|
COPY . .
|
|
@@ -32,7 +34,7 @@ RUN bun run build
|
|
|
32
34
|
# application. It uses a slim base image and only includes production
|
|
33
35
|
# dependencies and build artifacts.
|
|
34
36
|
# ==============================================================================
|
|
35
|
-
FROM oven/bun:1.3-slim AS production
|
|
37
|
+
FROM oven/bun:1.3.14-slim AS production
|
|
36
38
|
|
|
37
39
|
WORKDIR /usr/src/app
|
|
38
40
|
|
|
@@ -53,14 +55,16 @@ COPY package.json bun.lock ./
|
|
|
53
55
|
|
|
54
56
|
# Install only production dependencies, ignoring any lifecycle scripts (like 'prepare')
|
|
55
57
|
# that are not needed in the final production image.
|
|
56
|
-
RUN bun
|
|
58
|
+
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
59
|
+
bun install --production --frozen-lockfile --ignore-scripts
|
|
57
60
|
|
|
58
61
|
# Conditionally install OpenTelemetry optional peer dependencies (Tier 3).
|
|
59
62
|
# These are not bundled by default to keep the base image lean. Enable at build time
|
|
60
63
|
# with: docker build --build-arg OTEL_ENABLED=true
|
|
61
64
|
ARG OTEL_ENABLED=true
|
|
62
|
-
RUN
|
|
63
|
-
|
|
65
|
+
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
66
|
+
if [ "$OTEL_ENABLED" = "true" ]; then \
|
|
67
|
+
bun add --omit=dev --ignore-scripts @hono/otel \
|
|
64
68
|
@opentelemetry/instrumentation-http \
|
|
65
69
|
@opentelemetry/exporter-metrics-otlp-http \
|
|
66
70
|
@opentelemetry/exporter-trace-otlp-http \
|
package/LICENSE
CHANGED
|
@@ -186,7 +186,7 @@ Apache License
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright 2026 Casey Hand @cyanheads
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/federal-regulations-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/federal-regulations-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -74,7 +74,11 @@ Explore the codified Code of Federal Regulations via eCFR in two modes. Keyless.
|
|
|
74
74
|
|
|
75
75
|
- `structure` mode walks the CFR tree (all 50 titles, or one title's chapters → parts → sections) to discover a cite when the exact citation is unknown
|
|
76
76
|
- `search` mode runs a full-text query across the codified CFR and returns matching sections with their hierarchy path and a snippet
|
|
77
|
-
-
|
|
77
|
+
- `title` and `part` scope both modes, so a part surfaced by `structure` can be searched directly instead of filtering a whole title's hits by eye. A part needs its title in either mode — part numbers repeat across the Code — and is matched exactly, so pass it as eCFR writes it (`58`, not `Part 58` or `058`)
|
|
78
|
+
- A live search hit's `hierarchyPath` names the part it sits in (`Part 51 — Requirements for Preparation, Adoption, and Submittal of Implementation Plans`), so the subject matter is readable without a second call; a mirror hit's path stays structural, because the index stores no level names
|
|
79
|
+
- Search is served from the synced local mirror (FTS5) only when the mirror's title coverage can answer the request — a title it does not hold, an all-titles query against a scoped mirror, a `date`, or a cold deploy all go to the live eCFR search API instead
|
|
80
|
+
- Every search result reports `source` (`mirror` or `live`) and `sourceScope` — which corpus answered and what it covers, so an empty result is never mistaken for "no such regulation"
|
|
81
|
+
- `date` searches the section text in effect that day; eCFR indexes 2017-01-03 onward, and an undated search is pinned to eCFR's current index date rather than spanning every historical version
|
|
78
82
|
- Both modes assemble a `cfrCite` that feeds `regulations_get_cfr_section`
|
|
79
83
|
|
|
80
84
|
---
|
|
@@ -97,6 +101,7 @@ Pull a rulemaking docket from Regulations.gov by docket ID (e.g. `EPA-HQ-OAR-202
|
|
|
97
101
|
- Docket metadata (title, agency, RIN, abstract) plus the documents filed in it (NPRM, final rule, supporting materials)
|
|
98
102
|
- Each returned document's `objectId` feeds `regulations_find_comments(document_object_id)`; `frDocNum` chains back to `regulations_get_document`
|
|
99
103
|
- A docket often holds hundreds of supporting materials — filter `document_types` to `Proposed Rule` / `Rule` to find the rule documents themselves
|
|
104
|
+
- An unknown docket ID returns the tool's not-found error with a recovery hint, not a raw upstream status
|
|
100
105
|
- Regulations.gov requires a page size of 5–250 and caps a query at 20 pages (5,000 records)
|
|
101
106
|
|
|
102
107
|
---
|
|
@@ -105,7 +110,8 @@ Pull a rulemaking docket from Regulations.gov by docket ID (e.g. `EPA-HQ-OAR-202
|
|
|
105
110
|
|
|
106
111
|
Fetch public comments — the unique corpus of what citizens and organizations actually submitted. Requires `REGULATIONS_GOV_API_KEY`.
|
|
107
112
|
|
|
108
|
-
- Target with exactly one of: `docket_id` (all comments in a docket), `document_object_id` (comments on one document), `fr_document_number` (convenience — resolves the FR number to its Regulations.gov document internally), or `comment_id` (one comment's full detail)
|
|
113
|
+
- Target with exactly one of: `docket_id` (all comments in a docket), `document_object_id` (comments on one document), `fr_document_number` (convenience — resolves the FR number to its Regulations.gov document internally), or `comment_id` (one comment's full detail). Supplying two is rejected with an actionable error rather than resolved by precedence
|
|
114
|
+
- An ID Regulations.gov cannot resolve comes back as the tool's not-found error with a recovery hint, whether the API reports it as a 404 or as the 400 it uses for an ID it cannot parse
|
|
109
115
|
- The list endpoint returns no body text or attachment info — call with `comment_id` to read a comment's body
|
|
110
116
|
- When a comment's real content is a PDF/DOCX attachment, the body is a stub and `attachmentOnly` is `true`; the attachment download URLs are returned so the agent knows where the substance lives. The flag reaches both the structured output and the rendered text
|
|
111
117
|
- Regulations.gov caps a query at 20 pages (5,000 records); a high-volume docket surfaces a sample, flagged as truncated
|
|
@@ -145,12 +151,12 @@ Federal-regulations-specific:
|
|
|
145
151
|
- One workflow over three official sources — the agent sees regulatory verbs, not three API clients; which source is hit is a service-layer detail
|
|
146
152
|
- Cross-source stitching — every Federal Register document surfaces its docket ID and CFR-part handles next to the tools that consume them, priming the proposal → comments → final → codified-text trace
|
|
147
153
|
- Keyless core — Federal Register + eCFR (5 of 7 tools) is a complete deployment with no API key; the Regulations.gov leg layers on top
|
|
148
|
-
- Locally mirrored codified CFR — the eCFR is synced once into embedded SQLite + FTS5 and queried by exact cite or full text, with a live-API fallback
|
|
154
|
+
- Locally mirrored codified CFR — the eCFR is synced once into embedded SQLite + FTS5 and queried by exact cite or full text, with a live-API fallback whenever the mirror's title coverage cannot answer the request
|
|
149
155
|
- Three independent service clients, each with its own base URL, retry/backoff, and rate-limit handling (Regulations.gov honors `Retry-After` on 429)
|
|
150
156
|
|
|
151
157
|
Agent-friendly output:
|
|
152
158
|
|
|
153
|
-
- Provenance on every CFR read — `source: "mirror" | "live"` so agents know whether text came from the synced index or the live API
|
|
159
|
+
- Provenance on every CFR read — `source: "mirror" | "live"` so agents know whether text came from the synced index or the live API, and on search a `sourceScope` line naming what that corpus covers
|
|
154
160
|
- Honest truncation — Federal Register (50-page / 5,000-record) and Regulations.gov (20-page / 5,000-record) ceilings are surfaced with guidance to narrow, never silently dropped
|
|
155
161
|
- Attachment-aware comments — `attachmentOnly` flags when a comment's substance is a file rather than inline text, with the download URLs, on both the structured and text surfaces
|
|
156
162
|
- Actionable `auth_required` errors — the two keyed tools name the env var and the free signup URL rather than passing through a raw 401/403
|
|
@@ -284,7 +290,7 @@ All configuration is validated at startup via Zod schemas in `src/config/server-
|
|
|
284
290
|
| `REGULATIONS_GOV_BASE_URL` | Regulations.gov API v4 base URL. | `https://api.regulations.gov/v4` |
|
|
285
291
|
| `ECFR_MIRROR_PATH` | Filesystem path for the eCFR SQLite mirror database. | `./data/ecfr-mirror.sqlite` |
|
|
286
292
|
| `ECFR_MIRROR_REFRESH_CRON` | Cron expression for the weekly mirror refresh (HTTP transport only). | `0 4 * * 0` |
|
|
287
|
-
| `ECFR_MIRROR_TITLES` | Comma-separated CFR title numbers to scope the mirror to (e.g. `21,40`). Omit to mirror all 50 titles. Cites outside the set fall through to the live eCFR API. | — (all titles) |
|
|
293
|
+
| `ECFR_MIRROR_TITLES` | Comma-separated CFR title numbers to scope the mirror to (e.g. `21,40`). Omit to mirror all 50 titles. Cites and searches outside the set fall through to the live eCFR API, as does any all-titles search while this is set. | — (all titles) |
|
|
288
294
|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
289
295
|
| `MCP_HTTP_PORT` | Port for the HTTP server. | `3010` |
|
|
290
296
|
| `MCP_AUTH_MODE` | Auth mode: `none`, `jwt`, or `oauth`. | `none` |
|
|
@@ -298,6 +304,8 @@ See [`.env.example`](./.env.example) for the full list of optional overrides.
|
|
|
298
304
|
|
|
299
305
|
The codified CFR is large (~50 titles, hundreds of MB of XML — Title 40 alone is ~150 MB) but changes far less often than it is queried. This server mirrors it once into an embedded SQLite + FTS5 index and serves `regulations_get_cfr_section` (current single sections) and `regulations_browse_cfr` (full-text search) from it, falling back to the live eCFR API when the mirror has not yet completed an init or a historical/whole-part read is requested.
|
|
300
306
|
|
|
307
|
+
**The mirror answers only what it holds.** A scoped mirror (`ECFR_MIRROR_TITLES`) is consulted for a search only when the requested title is in the set, and never for an all-titles search — a three-title index reporting zero matches for the whole CFR is worse than no index at all. Those requests go to live eCFR instead, and every search result names the corpus that answered it in `sourceScope`.
|
|
308
|
+
|
|
301
309
|
**The mirror is populated out-of-band, never on startup** — a full title sweep takes a while and must not block the server. Build it with:
|
|
302
310
|
|
|
303
311
|
```sh
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "regulations_browse_cfr search fixes (title filter, date, partial-mirror scoping) plus mcp-ts-core ^0.10.9 → ^0.11.1 and dependency-hygiene overrides that clear 20 audit advisories."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.3 — 2026-08-09
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- **`regulations_browse_cfr` search-mode `date`** — now forwarded to eCFR's `date` parameter; an undated query pins to eCFR's current index date instead of matching every historical version of a section alongside its current text. Out-of-range dates raise `date_out_of_range` (`InvalidParams`) naming the indexed window (`2017-01-03` through the current index date). ([#1](https://github.com/cyanheads/federal-regulations-mcp-server/issues/1))
|
|
12
|
+
- **`regulations_browse_cfr` title-scoped search** — sends `hierarchy[title]` instead of the upstream-rejected `conditions[title]`. ([#1](https://github.com/cyanheads/federal-regulations-mcp-server/issues/1))
|
|
13
|
+
- **Search result `heading`** — now taken from eCFR's `headings` map (the node's name) rather than `hierarchy_headings` (its structural label); appendix hits, which carry no `hierarchy.section`, are identified via `hierarchy.appendix` and no longer fall through to `(untitled)`. ([#1](https://github.com/cyanheads/federal-regulations-mcp-server/issues/1))
|
|
14
|
+
- **eCFR mirror search routing** — a scoped mirror (`ECFR_MIRROR_TITLES`) now answers a search only when the requested title is in its indexed set, and never answers an all-titles query unless the index is complete; everything else falls through to live eCFR instead of returning a false empty result from a corpus that never held the answer. Coverage is read from a new `cfr_mirror_meta` table written at sync time, not from the environment the server happens to boot with. ([#2](https://github.com/cyanheads/federal-regulations-mcp-server/issues/2))
|
|
15
|
+
- **`regulations_browse_cfr` output** — every search result now carries `sourceScope`, naming which corpus answered (mirror titles, or the live index and its date); the empty-result `notice` names it too, so a zero-match search is never mistaken for "no such regulation." `mirror:verify` prints the same coverage.
|
|
16
|
+
- **`no_results` error contracts removed** — `regulations_search_rules`, `regulations_list_open_comments`, and `regulations_browse_cfr` no longer declare a `no_results` reason; a zero-match query is a successful empty result with a `notice`, not a domain error, on all three. ([#4](https://github.com/cyanheads/federal-regulations-mcp-server/issues/4))
|
|
17
|
+
|
|
18
|
+
### Dependency bumps
|
|
19
|
+
|
|
20
|
+
- `@cyanheads/mcp-ts-core` ^0.10.9 → ^0.11.1
|
|
21
|
+
- `typescript` ^6.0.3 → ^7.0.2
|
|
22
|
+
- `better-sqlite3` ^12.11.1 → ^13.0.1
|
|
23
|
+
- `@biomejs/biome` 2.5.0 → 2.5.6
|
|
24
|
+
- `@types/node` 26.0.0 → 26.1.2
|
|
25
|
+
- `tsc-alias` ^1.8.17 → ^1.9.1
|
|
26
|
+
- `vitest` ^4.1.9 → ^4.1.10
|
|
27
|
+
- `ignore` ^7.0.5 → ^7.0.6
|
|
28
|
+
- new `overrides` block (`body-parser`, `fast-uri`, `ip-address`, `js-yaml`, `nanoid`, `postcss`) takes `bun audit` from 20 advisories to 0
|
|
29
|
+
|
|
30
|
+
## Added
|
|
31
|
+
|
|
32
|
+
- **Socket install scanner** — `@socketsecurity/bun-security-scanner` wired through `bunfig.toml`; scans every package before install for malware, typosquats, and CVEs.
|
|
33
|
+
- **`minimumReleaseAge` supply-chain guard** — `bunfig.toml` blocks package versions published less than 3 days ago, with `@cyanheads/mcp-ts-core` excluded for same-day framework adoption.
|
|
34
|
+
- **MCPB native-binding strip** — `scripts/clean-mcpb.ts` and `scripts/lint-packaging.ts` now also strip/reject platform-specific native bindings (`@duckdb/node-bindings-*`) from packed bundles, alongside the existing agent-doc strip, so a DataCanvas-enabled server's `.mcpb` stays portable and under the registry size cap.
|
|
35
|
+
- **`.github/SECURITY.md`, `.github/FUNDING.yml`, `.gitattributes`** — template files the project was missing.
|
|
36
|
+
|
|
37
|
+
## Fixed
|
|
38
|
+
|
|
39
|
+
- **Dockerfile** — pinned the `oven/bun` base image to `1.3.14` (was floating `1.3`), added BuildKit cache mounts on every `bun install`/`bun add` layer, and switched the OTel peer-dependency install to `--omit=dev --ignore-scripts`.
|
|
40
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "regulations_find_comments rejects multiple targeting parameters and Regulations.gov invalid-ID 400s map to not_found; regulations_browse_cfr search mode gains a part filter and live search hits name the part in hierarchyPath."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.4 — 2026-08-09
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`regulations_browse_cfr` `part`** — now filters search mode too (`hierarchy[part]` on the live path, an equality filter on the mirror), requiring `title` in either mode via a new `title_required_for_part` error; part values are matched exactly after stripping a spelled-out `Part ` prefix and surrounding whitespace. ([#7](https://github.com/cyanheads/federal-regulations-mcp-server/issues/7))
|
|
12
|
+
- **`regulations_browse_cfr` search hits** — `hierarchyPath` now pairs a live hit's part label with the name eCFR returns beside it (e.g. `Part 51 — Requirements for Preparation, Adoption, and Submittal of Implementation Plans`); mirror hits stay structural, since the index stores no level names. ([#8](https://github.com/cyanheads/federal-regulations-mcp-server/issues/8))
|
|
13
|
+
|
|
14
|
+
## Fixed
|
|
15
|
+
|
|
16
|
+
- **`regulations_find_comments`** — rejects calls supplying more than one of `docket_id` / `document_object_id` / `fr_document_number` / `comment_id` with a new `multiple_targets` error, instead of silently reading `comment_id` and dropping the rest; an empty string still counts as absent. ([#3](https://github.com/cyanheads/federal-regulations-mcp-server/issues/3))
|
|
17
|
+
- **`RegulationsGovService`** — the 400 Regulations.gov returns for an ID it cannot parse (`"Invalid ID: …"`) now maps to the same `not_found` path as a 404, discriminated on the response body so other 400s (bad filter name, bad page size) keep their `InvalidParams` classification. ([#5](https://github.com/cyanheads/federal-regulations-mcp-server/issues/5))
|
package/changelog/template.md
CHANGED
|
@@ -15,9 +15,11 @@ summary: ""
|
|
|
15
15
|
# usage. Flagged as `Breaking` in the rollup.
|
|
16
16
|
breaking: false
|
|
17
17
|
|
|
18
|
-
# Set `true`
|
|
19
|
-
#
|
|
20
|
-
#
|
|
18
|
+
# Set `true` ONLY for a security fix in THIS project's own source code — a
|
|
19
|
+
# vulnerability or hardening in code you ship. A dependency or transitive CVE
|
|
20
|
+
# bump is routine maintenance, NOT a security release: record it under
|
|
21
|
+
# `## Dependencies` (with the advisory ID) and leave this `false`. When true,
|
|
22
|
+
# pairs with the `## Security` section below and flags `Security` in the rollup.
|
|
21
23
|
security: false
|
|
22
24
|
|
|
23
25
|
# Optional free-form notes for maintenance agents processing this release.
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview regulations_browse_cfr — navigate the CFR hierarchy (structure
|
|
3
3
|
* mode) or full-text-search the codified CFR (search mode) via eCFR. Search runs
|
|
4
|
-
* against the local mirror's FTS5 index when
|
|
5
|
-
*
|
|
4
|
+
* against the local mirror's FTS5 index only when the mirror's title coverage can
|
|
5
|
+
* answer the request; a scoped mirror, an unscoped (all-titles) query it cannot
|
|
6
|
+
* answer completely, a historical date, or a cold deploy all route to the live
|
|
7
|
+
* eCFR search API. Keyless. Feeds regulations_get_cfr_section.
|
|
8
|
+
*
|
|
9
|
+
* `title` and `part` scope both modes; a part with no title is refused rather
|
|
10
|
+
* than dropped, since part numbers repeat across titles and eCFR rejects the
|
|
11
|
+
* filter outright. A live search hit's path names the part it sits in, which a
|
|
12
|
+
* mirror hit cannot do — the index stores no level names.
|
|
6
13
|
* @module mcp-server/tools/definitions/browse-cfr.tool
|
|
7
14
|
*/
|
|
8
15
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
@@ -32,9 +39,10 @@ export declare const browseCfrTool: import("@cyanheads/mcp-ts-core").ToolDefinit
|
|
|
32
39
|
cfrCite: z.ZodNullable<z.ZodString>;
|
|
33
40
|
}, z.core.$strip>>>;
|
|
34
41
|
source: z.ZodOptional<z.ZodEnum<{
|
|
35
|
-
mirror: "mirror";
|
|
36
42
|
live: "live";
|
|
43
|
+
mirror: "mirror";
|
|
37
44
|
}>>;
|
|
45
|
+
sourceScope: z.ZodOptional<z.ZodString>;
|
|
38
46
|
results: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
39
47
|
title: z.ZodNumber;
|
|
40
48
|
part: z.ZodString;
|
|
@@ -55,10 +63,15 @@ export declare const browseCfrTool: import("@cyanheads/mcp-ts-core").ToolDefinit
|
|
|
55
63
|
readonly when: "Structure mode with a title outside 1–50, or a part not found in the title.";
|
|
56
64
|
readonly recovery: "Omit title to list all titles, or pick a number in 1–50 and a part that exists.";
|
|
57
65
|
}, {
|
|
58
|
-
readonly reason: "
|
|
59
|
-
readonly code: JsonRpcErrorCode.
|
|
60
|
-
readonly when: "
|
|
61
|
-
readonly recovery: "
|
|
66
|
+
readonly reason: "title_required_for_part";
|
|
67
|
+
readonly code: JsonRpcErrorCode.InvalidParams;
|
|
68
|
+
readonly when: "A part was given with no title. Part identifiers repeat across titles, and eCFR rejects a part filter that names no title.";
|
|
69
|
+
readonly recovery: "Add the title the part belongs to (e.g. title 40 with part 58), or drop part to search or browse the whole title set.";
|
|
70
|
+
}, {
|
|
71
|
+
readonly reason: "date_out_of_range";
|
|
72
|
+
readonly code: JsonRpcErrorCode.InvalidParams;
|
|
73
|
+
readonly when: "Search mode with a date outside eCFR's indexed window (before 2017-01-03, or past its current index date).";
|
|
74
|
+
readonly recovery: "Pick a date inside the window the error names, or omit date to search the current text.";
|
|
62
75
|
}, {
|
|
63
76
|
readonly reason: "upstream_unavailable";
|
|
64
77
|
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browse-cfr.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/browse-cfr.tool.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"browse-cfr.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/browse-cfr.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAqGjE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsPxB,CAAC"}
|