@cyanheads/federal-regulations-mcp-server 0.1.3 → 0.2.0

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.
Files changed (48) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/README.md +16 -7
  4. package/changelog/0.1.x/0.1.4.md +17 -0
  5. package/changelog/0.2.x/0.2.0.md +26 -0
  6. package/dist/mcp-server/resources/definitions/cfr-section.resource.d.ts +4 -0
  7. package/dist/mcp-server/resources/definitions/cfr-section.resource.d.ts.map +1 -1
  8. package/dist/mcp-server/resources/definitions/cfr-section.resource.js +12 -5
  9. package/dist/mcp-server/resources/definitions/cfr-section.resource.js.map +1 -1
  10. package/dist/mcp-server/tools/definitions/browse-cfr.tool.d.ts +12 -0
  11. package/dist/mcp-server/tools/definitions/browse-cfr.tool.d.ts.map +1 -1
  12. package/dist/mcp-server/tools/definitions/browse-cfr.tool.js +91 -22
  13. package/dist/mcp-server/tools/definitions/browse-cfr.tool.js.map +1 -1
  14. package/dist/mcp-server/tools/definitions/find-comments.tool.d.ts +9 -2
  15. package/dist/mcp-server/tools/definitions/find-comments.tool.d.ts.map +1 -1
  16. package/dist/mcp-server/tools/definitions/find-comments.tool.js +50 -21
  17. package/dist/mcp-server/tools/definitions/find-comments.tool.js.map +1 -1
  18. package/dist/mcp-server/tools/definitions/get-cfr-section.tool.d.ts +30 -9
  19. package/dist/mcp-server/tools/definitions/get-cfr-section.tool.d.ts.map +1 -1
  20. package/dist/mcp-server/tools/definitions/get-cfr-section.tool.js +115 -24
  21. package/dist/mcp-server/tools/definitions/get-cfr-section.tool.js.map +1 -1
  22. package/dist/mcp-server/tools/definitions/index.d.ts +32 -4
  23. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  24. package/dist/services/ecfr/cite.d.ts +23 -0
  25. package/dist/services/ecfr/cite.d.ts.map +1 -0
  26. package/dist/services/ecfr/cite.js +29 -0
  27. package/dist/services/ecfr/cite.js.map +1 -0
  28. package/dist/services/ecfr/ecfr-service.d.ts +41 -5
  29. package/dist/services/ecfr/ecfr-service.d.ts.map +1 -1
  30. package/dist/services/ecfr/ecfr-service.js +123 -14
  31. package/dist/services/ecfr/ecfr-service.js.map +1 -1
  32. package/dist/services/ecfr/types.d.ts +72 -1
  33. package/dist/services/ecfr/types.d.ts.map +1 -1
  34. package/dist/services/ecfr/xml.d.ts +20 -9
  35. package/dist/services/ecfr/xml.d.ts.map +1 -1
  36. package/dist/services/ecfr/xml.js +121 -33
  37. package/dist/services/ecfr/xml.js.map +1 -1
  38. package/dist/services/ecfr-mirror/ecfr-mirror.d.ts +33 -4
  39. package/dist/services/ecfr-mirror/ecfr-mirror.d.ts.map +1 -1
  40. package/dist/services/ecfr-mirror/ecfr-mirror.js +159 -39
  41. package/dist/services/ecfr-mirror/ecfr-mirror.js.map +1 -1
  42. package/dist/services/regulations-gov/regulations-gov-service.d.ts +7 -2
  43. package/dist/services/regulations-gov/regulations-gov-service.d.ts.map +1 -1
  44. package/dist/services/regulations-gov/regulations-gov-service.js +42 -3
  45. package/dist/services/regulations-gov/regulations-gov-service.js.map +1 -1
  46. package/package.json +1 -1
  47. package/scripts/ecfr-mirror-verify.ts +22 -5
  48. package/server.json +3 -3
package/AGENTS.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Developer Protocol
2
2
 
3
3
  **Server:** federal-regulations-mcp-server
4
- **Version:** 0.1.3
4
+ **Version:** 0.2.0
5
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
7
  **MCP SDK:** `@modelcontextprotocol/sdk` ^1.30.0
package/CLAUDE.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Developer Protocol
2
2
 
3
3
  **Server:** federal-regulations-mcp-server
4
- **Version:** 0.1.3
4
+ **Version:** 0.2.0
5
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
7
  **MCP SDK:** `@modelcontextprotocol/sdk` ^1.30.0
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  <div align="center">
9
9
 
10
- [![Version](https://img.shields.io/badge/Version-0.1.3-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/federal-regulations-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.30.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/federal-regulations-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/federal-regulations-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.3-blueviolet.svg?style=flat-square)](https://bun.sh/)
10
+ [![Version](https://img.shields.io/badge/Version-0.2.0-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/federal-regulations-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.30.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/federal-regulations-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/federal-regulations-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.3-blueviolet.svg?style=flat-square)](https://bun.sh/)
11
11
 
12
12
  </div>
13
13
 
@@ -40,7 +40,7 @@ Seven tools across the regulatory workflow. The **Federal Register** and **eCFR*
40
40
  | `regulations_search_rules` | Federal Register | — | Search proposed rules, final rules, notices, and presidential documents by query, type, agency, date range, and open-for-comment status. The primary discovery entry point. |
41
41
  | `regulations_get_document` | Federal Register | — | Fetch one FR document by number — full metadata plus the cross-source handles (docket ID, CFR parts, comment count) that chain into the comment and codified-text tools. |
42
42
  | `regulations_browse_cfr` | eCFR | — | Walk the CFR hierarchy (structure mode) or full-text-search the codified CFR (search mode). Both feed `regulations_get_cfr_section`. |
43
- | `regulations_get_cfr_section` | eCFR | — | Read the codified text of a CFR section or whole part — current or as of a past date. |
43
+ | `regulations_get_cfr_section` | eCFR | — | Read the codified text at a CFR location — a section, a whole part, or an appendix — current or as of a past date. |
44
44
  | `regulations_get_docket` | Regulations.gov | ✔ | Pull a rulemaking docket and the documents filed in it (NPRM, final rule, supporting materials). |
45
45
  | `regulations_find_comments` | Regulations.gov | ✔ | Fetch public comments on a document or docket, or one comment's full body and attachments. Flags attachment-only submissions. |
46
46
  | `regulations_list_open_comments` | Federal Register (+ Reg.gov enrich) | optional | Rules currently open for public comment, closing soonest first. Fully functional keyless; enriches comment counts when keyed. |
@@ -74,20 +74,25 @@ 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
+ - `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
77
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
78
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"
79
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
80
- - Both modes assemble a `cfrCite` that feeds `regulations_get_cfr_section`
82
+ - Both modes assemble a `cfrCite` that feeds `regulations_get_cfr_section`, and both hand appendices back the same way: an `appendix` field with eCFR's verbatim identifier, and a cite that names the appendix rather than the part around it
83
+ - The mirror indexes section text only, so it never matches an appendix — its `sourceScope` says so, since otherwise an appendix that exists and one that does not both read as zero matches
81
84
 
82
85
  ---
83
86
 
84
87
  ### `regulations_get_cfr_section`
85
88
 
86
- Read the codified text of a specific CFR section, or a whole part, via eCFR. Keyless.
89
+ Read the codified text at a CFR location — one section, a whole part, or one appendix — via eCFR. Keyless.
87
90
 
88
91
  - Answers "what does 40 CFR 50.1 say today?" and "...as of 2019-01-01?" — pass `date` for point-in-time text
89
92
  - Provide `title` + `part` + `section` for one section, or omit `section` to fetch the whole part
90
- - Current single-section reads are served from the local mirror when ready (the `source` is reported); historical dates, whole-part fetches, and a cold mirror fall back to the live eCFR versioner
93
+ - Provide `appendix` to read an appendix, passing the identifier verbatim as `regulations_browse_cfr` emits it (`Appendix A-1 to Part 50`, `Schedule I to Part 789`, `Special Federal Aviation Regulation No. 88`) — the identifiers are prose, not letters, and a short form matches nothing
94
+ - A whole-part read names the part's appendices and their headings but does not inline their text; appendices routinely run several times the length of the sections around them, so reading one is a deliberate second call
95
+ - Current single-section reads are served from the local mirror when ready (the `source` is reported); historical dates, whole-part fetches, appendix reads, and a cold mirror fall back to the live eCFR versioner
91
96
  - eCFR retains historical versions back to roughly 2017; a date before coverage is rejected with guidance
92
97
 
93
98
  ---
@@ -99,6 +104,7 @@ Pull a rulemaking docket from Regulations.gov by docket ID (e.g. `EPA-HQ-OAR-202
99
104
  - Docket metadata (title, agency, RIN, abstract) plus the documents filed in it (NPRM, final rule, supporting materials)
100
105
  - Each returned document's `objectId` feeds `regulations_find_comments(document_object_id)`; `frDocNum` chains back to `regulations_get_document`
101
106
  - A docket often holds hundreds of supporting materials — filter `document_types` to `Proposed Rule` / `Rule` to find the rule documents themselves
107
+ - An unknown docket ID returns the tool's not-found error with a recovery hint, not a raw upstream status
102
108
  - Regulations.gov requires a page size of 5–250 and caps a query at 20 pages (5,000 records)
103
109
 
104
110
  ---
@@ -107,7 +113,8 @@ Pull a rulemaking docket from Regulations.gov by docket ID (e.g. `EPA-HQ-OAR-202
107
113
 
108
114
  Fetch public comments — the unique corpus of what citizens and organizations actually submitted. Requires `REGULATIONS_GOV_API_KEY`.
109
115
 
110
- - 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)
116
+ - 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
117
+ - 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
111
118
  - The list endpoint returns no body text or attachment info — call with `comment_id` to read a comment's body
112
119
  - 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
113
120
  - Regulations.gov caps a query at 20 pages (5,000 records); a high-volume docket surfaces a sample, flagged as truncated
@@ -314,10 +321,12 @@ ECFR_MIRROR_TITLES=21,40 bun run mirror:init
314
321
  # Incremental refresh against the latest eCFR issues
315
322
  bun run mirror:refresh
316
323
 
317
- # Report row counts and the last-synced issue date
324
+ # Report row counts, the last-synced issue date, and whether the index is stale
318
325
  bun run mirror:verify
319
326
  ```
320
327
 
328
+ **An index written by an older ingester is not served.** The ingester stamps a version into the mirror once a run has re-derived every title the index holds; when a release changes how rows are derived, an index carrying an older stamp is treated exactly like a cold one — every read falls back to live eCFR until `bun run mirror:refresh` re-derives it. `mirror:verify` says so explicitly, and a refresh removes the rows the previous ingester filed under keys the current one no longer produces. A run that skips a title — a failed fetch, or an `ECFR_MIRROR_TITLES` scope narrower than the index — names it in the log and leaves the stamp unwritten, because those untouched titles are exactly the ones a stamp would certify wrongly.
329
+
321
330
  Until the mirror has completed an init, the codified-text tools run against the live eCFR API — so the server is useful immediately on a fresh deploy; the mirror is a latency/throughput optimization, not a hard dependency. On the HTTP transport a weekly refresh is scheduled automatically (`ECFR_MIRROR_REFRESH_CRON`); stdio operators run the lifecycle scripts above.
322
331
 
323
332
  The mirror database (`./data/ecfr-mirror.sqlite`) is a local artifact — it is git-ignored and excluded from the `.mcpb` bundle, never shipped in the package.
@@ -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))
@@ -0,0 +1,26 @@
1
+ ---
2
+ summary: "regulations_get_cfr_section reads CFR appendices by verbatim identifier, with appendix handles surfaced from regulations_browse_cfr; the eCFR mirror now files dotless-numbered sections under their correct part and versions its ingest so stale rows fall back to live eCFR."
3
+ breaking: true
4
+ security: false
5
+ ---
6
+
7
+ # 0.2.0 — 2026-08-10
8
+
9
+ ## Added
10
+
11
+ - **`regulations_get_cfr_section` `appendix` input** — reads one CFR appendix by its verbatim identifier (`title` + `appendix`, `part` optional but disambiguating); adds `appendix` and `appendices` (a whole-part read's un-inlined appendix identifiers + headings) to the output, plus `location_required` and `conflicting_target` error reasons. ([#6](https://github.com/cyanheads/federal-regulations-mcp-server/issues/6))
12
+ - **`regulations_browse_cfr`** — structure nodes and search hits carry an `appendix` field; an appendix's `cfrCite` now names the appendix itself, not the part around it. ([#6](https://github.com/cyanheads/federal-regulations-mcp-server/issues/6))
13
+ - **`mirror:verify`** — reports whether the index was written by the current ingester, naming `mirror:refresh` as the fix when it wasn't. ([#9](https://github.com/cyanheads/federal-regulations-mcp-server/issues/9))
14
+
15
+ ## Changed
16
+
17
+ - **`regulations_get_cfr_section` `part`** — input is now optional (required unless `appendix` is given); output `part` is nullable. **Breaking**: a caller assuming `part` is always a non-null string must now handle `null` (an appendix hanging off a chapter, subchapter, or subtitle rather than a part).
18
+ - **CFR cites** — a section or appendix cite now names its enclosing part explicitly when the section number doesn't embed it (`14 CFR 241 § 25`, not `14 CFR 25`), applied uniformly to live hits, mirror hits, the read tool, and the `regulations://cfr/{title}/{part}/{section}` resource. ([#9](https://github.com/cyanheads/federal-regulations-mcp-server/issues/9))
19
+ - **eCFR body-text extraction** — keeps `<HD1>`–`<HD7>` subheadings, `<TABLE>` rows (pipe-delimited), the flush-paragraph family (`<FP-1>`, `<FP1-2>`), and an editorial note's `<HED>`/`<PSPACE>`, for sections and appendices alike; previously only `<P>`/`<FP>` paragraphs were kept, which answered 61% of appendix nodes in a sample with an empty body. ([#6](https://github.com/cyanheads/federal-regulations-mcp-server/issues/6))
20
+
21
+ ## Fixed
22
+
23
+ - **eCFR mirror ingest** — a section's part now comes from its enclosing `<DIV5 TYPE="PART">` element instead of the section number cut at its first dot; a part with dotless section identifiers (14 CFR 241: `Section 25`, `Sec. 1-1`) was filing rows under a part named after the section number, so a scoped search or cite could return an unrelated regulation's text. ([#9](https://github.com/cyanheads/federal-regulations-mcp-server/issues/9))
24
+ - **Mirror ingest versioning** — the ingester now stamps an `ingest_version`; rows from a superseded ingester are treated as not ready (every read falls back to live eCFR until `mirror:refresh` re-derives them), and a refresh tombstones rows it no longer writes so corrected or withdrawn rows don't survive beside the fix. ([#9](https://github.com/cyanheads/federal-regulations-mcp-server/issues/9))
25
+ - **`mirror:verify`** — its sample query was passing its result limit into the `part` filter added in 0.1.4, leaving the limit unset. ([#9](https://github.com/cyanheads/federal-regulations-mcp-server/issues/9))
26
+ - **XML paragraph parsing** — a malformed `<FP-1>`/`<FP-2>` closing-tag match could swallow up to 257 KB of content, every paragraph and subheading up to the next plain `</FP>` in the document. ([#6](https://github.com/cyanheads/federal-regulations-mcp-server/issues/6))
@@ -3,6 +3,10 @@
3
3
  * current CFR section, the same payload as regulations_get_cfr_section at the
4
4
  * current date, for clients that support injectable context. Mirror-backed with a
5
5
  * live eCFR fallback. Every datum is also reachable through the tool surface.
6
+ *
7
+ * Sections only. An appendix is addressed by a free-form phrase ("Appendix A-1
8
+ * to Part 50"), not by a path segment, so it stays on the tool surface rather
9
+ * than becoming a URI template whose last component is an encoded sentence.
6
10
  * @module mcp-server/resources/definitions/cfr-section.resource
7
11
  */
8
12
  import { z } from '@cyanheads/mcp-ts-core';
@@ -1 +1 @@
1
- {"version":3,"file":"cfr-section.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/cfr-section.resource.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAKrD,eAAO,MAAM,kBAAkB;;;;wCAiF7B,CAAC"}
1
+ {"version":3,"file":"cfr-section.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/cfr-section.resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAMrD,eAAO,MAAM,kBAAkB;;;;wCAiF7B,CAAC"}
@@ -3,16 +3,21 @@
3
3
  * current CFR section, the same payload as regulations_get_cfr_section at the
4
4
  * current date, for clients that support injectable context. Mirror-backed with a
5
5
  * live eCFR fallback. Every datum is also reachable through the tool surface.
6
+ *
7
+ * Sections only. An appendix is addressed by a free-form phrase ("Appendix A-1
8
+ * to Part 50"), not by a path segment, so it stays on the tool surface rather
9
+ * than becoming a URI template whose last component is an encoded sentence.
6
10
  * @module mcp-server/resources/definitions/cfr-section.resource
7
11
  */
8
12
  import { resource, z } from '@cyanheads/mcp-ts-core';
9
13
  import { notFound } from '@cyanheads/mcp-ts-core/errors';
14
+ import { sectionCite } from '../../../services/ecfr/cite.js';
10
15
  import { getEcfrService } from '../../../services/ecfr/ecfr-service.js';
11
16
  import { mirrorGetSection, mirrorReady } from '../../../services/ecfr-mirror/ecfr-mirror.js';
12
17
  export const cfrSectionResource = resource('regulations://cfr/{title}/{part}/{section}', {
13
18
  name: 'cfr-section',
14
19
  title: 'CFR section (current)',
15
- description: 'Codified text of a current CFR section by title/part/section (e.g. regulations://cfr/40/50/50.1). Mirrors regulations_get_cfr_section at the current date — mirror-backed with a live eCFR fallback.',
20
+ description: 'Codified text of a current CFR section by title/part/section (e.g. regulations://cfr/40/50/50.1). Mirrors regulations_get_cfr_section at the current date — mirror-backed with a live eCFR fallback. Sections only; read an appendix through regulations_get_cfr_section with its `appendix` input.',
16
21
  mimeType: 'application/json',
17
22
  params: z.object({
18
23
  title: z
@@ -28,12 +33,13 @@ export const cfrSectionResource = resource('regulations://cfr/{title}/{part}/{se
28
33
  if (await mirrorReady()) {
29
34
  const hit = await mirrorGetSection(titleNum, params.part, params.section);
30
35
  if (hit) {
31
- const hierarchyPath = await service.hierarchyPath(titleNum, params.part, params.section, hit.date, ctx);
36
+ const hierarchyPath = await service.hierarchyPath(titleNum, { part: params.part, section: params.section }, hit.date, ctx);
32
37
  return {
33
- cfrCite: `${titleNum} CFR ${params.section}`,
38
+ cfrCite: sectionCite(titleNum, params.part, params.section),
34
39
  title: titleNum,
35
40
  part: params.part,
36
41
  section: params.section,
42
+ appendix: null,
37
43
  heading: hit.heading,
38
44
  hierarchyPath,
39
45
  date: hit.date,
@@ -51,12 +57,13 @@ export const cfrSectionResource = resource('regulations://cfr/{title}/{part}/{se
51
57
  section: params.section,
52
58
  });
53
59
  }
54
- const hierarchyPath = await service.hierarchyPath(titleNum, params.part, params.section, result.date, ctx);
60
+ const hierarchyPath = await service.hierarchyPath(titleNum, { part: params.part, section: params.section }, result.date, ctx);
55
61
  return {
56
- cfrCite: `${titleNum} CFR ${params.section}`,
62
+ cfrCite: sectionCite(titleNum, params.part, params.section),
57
63
  title: titleNum,
58
64
  part: params.part,
59
65
  section: params.section,
66
+ appendix: null,
60
67
  heading: result.heading,
61
68
  hierarchyPath,
62
69
  date: result.date,
@@ -1 +1 @@
1
- {"version":3,"file":"cfr-section.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/cfr-section.resource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cfr-section.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/cfr-section.resource.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,11 @@
5
5
  * answer the request; a scoped mirror, an unscoped (all-titles) query it cannot
6
6
  * answer completely, a historical date, or a cold deploy all route to the live
7
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.
8
13
  * @module mcp-server/tools/definitions/browse-cfr.tool
9
14
  */
10
15
  import { z } from '@cyanheads/mcp-ts-core';
@@ -32,6 +37,7 @@ export declare const browseCfrTool: import("@cyanheads/mcp-ts-core").ToolDefinit
32
37
  description: z.ZodNullable<z.ZodString>;
33
38
  reserved: z.ZodBoolean;
34
39
  cfrCite: z.ZodNullable<z.ZodString>;
40
+ appendix: z.ZodNullable<z.ZodString>;
35
41
  }, z.core.$strip>>>;
36
42
  source: z.ZodOptional<z.ZodEnum<{
37
43
  live: "live";
@@ -42,6 +48,7 @@ export declare const browseCfrTool: import("@cyanheads/mcp-ts-core").ToolDefinit
42
48
  title: z.ZodNumber;
43
49
  part: z.ZodString;
44
50
  section: z.ZodNullable<z.ZodString>;
51
+ appendix: z.ZodNullable<z.ZodString>;
45
52
  heading: z.ZodString;
46
53
  hierarchyPath: z.ZodString;
47
54
  excerpt: z.ZodString;
@@ -57,6 +64,11 @@ export declare const browseCfrTool: import("@cyanheads/mcp-ts-core").ToolDefinit
57
64
  readonly code: JsonRpcErrorCode.NotFound;
58
65
  readonly when: "Structure mode with a title outside 1–50, or a part not found in the title.";
59
66
  readonly recovery: "Omit title to list all titles, or pick a number in 1–50 and a part that exists.";
67
+ }, {
68
+ readonly reason: "title_required_for_part";
69
+ readonly code: JsonRpcErrorCode.InvalidParams;
70
+ readonly when: "A part was given with no title. Part identifiers repeat across titles, and eCFR rejects a part filter that names no title.";
71
+ 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.";
60
72
  }, {
61
73
  readonly reason: "date_out_of_range";
62
74
  readonly code: JsonRpcErrorCode.InvalidParams;
@@ -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;;;;;;;;GAQG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAmEjE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8NxB,CAAC"}
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;AAyHjE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0PxB,CAAC"}
@@ -5,24 +5,55 @@
5
5
  * answer the request; a scoped mirror, an unscoped (all-titles) query it cannot
6
6
  * answer completely, a historical date, or a cold deploy all route to the live
7
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.
8
13
  * @module mcp-server/tools/definitions/browse-cfr.tool
9
14
  */
10
15
  import { tool, z } from '@cyanheads/mcp-ts-core';
11
16
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
12
17
  import { getEcfrService, today } from '../../../services/ecfr/ecfr-service.js';
13
18
  import { mirrorReady, mirrorScope, mirrorSearch, } from '../../../services/ecfr-mirror/ecfr-mirror.js';
14
- /** Restriction clause naming the caller's own title filter, if any. */
15
- function titleFilterClause(title) {
16
- return title === undefined ? '' : `, filtered to title ${title}`;
19
+ /** Restriction clause naming the caller's own title (and part) filter, if any. */
20
+ function filterClause(title, part) {
21
+ if (title === undefined)
22
+ return '';
23
+ return part === undefined
24
+ ? `, filtered to title ${title}`
25
+ : `, filtered to title ${title} part ${part}`;
17
26
  }
18
27
  /** Human-readable coverage of the mirror index, for the `sourceScope` field. */
19
- function describeMirrorScope(scope, title) {
28
+ function describeMirrorScope(scope, title, part) {
20
29
  const held = scope.complete ? 'all CFR titles' : `CFR titles ${scope.titles.join(', ')}`;
21
- return `Local mirror index — ${held}${titleFilterClause(title)}, current text only.`;
30
+ // The index holds section text alone, so an appendix match cannot come back
31
+ // from it — which is indistinguishable from no such appendix unless said.
32
+ return `Local mirror index — ${held}${filterClause(title, part)}, current section text only; appendices are not indexed, so no result here is evidence about them.`;
22
33
  }
23
34
  /** Human-readable coverage of the live eCFR search index, for `sourceScope`. */
24
- function describeLiveScope(date, title) {
25
- return `Live eCFR search — all CFR titles${titleFilterClause(title)}, text in effect on ${date}.`;
35
+ function describeLiveScope(date, title, part) {
36
+ return `Live eCFR search — all CFR titles${filterClause(title, part)}, text in effect on ${date}.`;
37
+ }
38
+ /**
39
+ * Canonicalize a caller-supplied part identifier, or `undefined` when nothing is
40
+ * left of it. eCFR matches `hierarchy[part]` exactly, and the mirror matches its
41
+ * `part` column exactly, so "Part 58" and "58 " both return zero rather than an
42
+ * error — strip the spelled-out prefix and the surrounding whitespace that
43
+ * produce that silent miss. A value that is blank to begin with, or blank once
44
+ * stripped, is no filter at all: returning it as one would put "part " in
45
+ * `sourceScope` and claim a restriction the query never carried.
46
+ *
47
+ * Deliberately conservative beyond that: case and leading zeros are left alone.
48
+ * Real part identifiers include an uppercase one (26 CFR 16A) and lowercase
49
+ * suffixes (14 CFR 1203a), and none begin with a zero, so folding either would
50
+ * rewrite a caller's part into a different one.
51
+ */
52
+ function normalizePart(part) {
53
+ return (part
54
+ ?.trim()
55
+ .replace(/^(?:parts?|pts?\.?)\s+/i, '')
56
+ .trim() || undefined);
26
57
  }
27
58
  const structureNode = z
28
59
  .object({
@@ -36,7 +67,11 @@ const structureNode = z
36
67
  cfrCite: z
37
68
  .string()
38
69
  .nullable()
39
- .describe('Assembled cite for a part/section → regulations_get_cfr_section; null otherwise.'),
70
+ .describe('Assembled cite → regulations_get_cfr_section: "40 CFR 50" / "40 CFR 50.1" for a part or section, "Appendix A-1 to Part 50, Title 40" for an appendix. Null on a level with no read path (chapter, subchapter, subpart, subject group).'),
71
+ appendix: z
72
+ .string()
73
+ .nullable()
74
+ .describe('On an appendix node, the identifier to pass straight back as regulations_get_cfr_section\'s `appendix` input; null on every other node type. It is free-form prose, not a letter ("Schedule I to Part 789", "Special Federal Aviation Regulation No. 88"), so pass it verbatim rather than abbreviating it.'),
40
75
  })
41
76
  .describe('One hierarchy node.');
42
77
  const searchHit = z
@@ -47,19 +82,25 @@ const searchHit = z
47
82
  .string()
48
83
  .nullable()
49
84
  .describe('Section identifier, or null when the match is an appendix or a whole part.'),
85
+ appendix: z
86
+ .string()
87
+ .nullable()
88
+ .describe("On an appendix hit, the identifier to pass straight back as regulations_get_cfr_section's `appendix` input; null on a section hit. Always null on a mirror hit — the index holds section text only, so mirror-sourced results never match an appendix."),
50
89
  heading: z
51
90
  .string()
52
91
  .describe('What the matched node is called — the section, appendix, or part heading. Distinct from cfrCite, which is where it lives.'),
53
92
  hierarchyPath: z
54
93
  .string()
55
- .describe('Structural path down to the match, e.g. "Title 40 › Chapter I › Part 51 › § 51.190".'),
94
+ .describe('Path down to the match. A live hit names the part it sits in — "Title 40 › Chapter I › Subchapter C › Part 51 — Requirements for Preparation, Adoption, and Submittal of Implementation Plans › § 51.190" — so the subject matter is readable without a second call. A mirror hit is structural only ("Title 14 › Part 25 › § 25.1043"): the index stores no level names. Check `source` before comparing paths across results.'),
56
95
  excerpt: z.string().describe('Matched text snippet.'),
57
- cfrCite: z.string().describe('Assembled cite → regulations_get_cfr_section.'),
96
+ cfrCite: z
97
+ .string()
98
+ .describe('Assembled cite → regulations_get_cfr_section. A section hit cites the section ("40 CFR 51.190"); an appendix hit cites the appendix in eCFR\'s own form ("Appendix C to Part 58, Title 40"), not the part around it, since the part\'s sections do not contain the matched text.'),
58
99
  })
59
- .describe('One matching CFR section.');
100
+ .describe('One matching CFR section or appendix.');
60
101
  export const browseCfrTool = tool('regulations_browse_cfr', {
61
102
  title: 'regulations_browse_cfr',
62
- description: 'Explore the codified Code of Federal Regulations via eCFR in two modes. "structure" walks the CFR hierarchy (all 50 titles, or one title\'s chapters → parts → sections) to discover a cite when the exact citation is unknown. "search" runs a full-text query across the codified CFR and returns matching sections with their hierarchy path and a snippet. Both modes feed regulations_get_cfr_section. Every search result reports which corpus answered it — the synced local mirror or the live eCFR index — and what that corpus covers, in `source` and `sourceScope`.',
103
+ description: 'Explore the codified Code of Federal Regulations via eCFR in two modes. "structure" walks the CFR hierarchy (all 50 titles, or one title\'s chapters → parts → sections) to discover a cite when the exact citation is unknown. "search" runs a full-text query across the codified CFR and returns matching sections with their hierarchy path and a snippet. Both modes accept title and part to narrow the scope, so a part surfaced by structure mode can be searched directly instead of filtering a whole title\'s hits by eye. Both feed regulations_get_cfr_section. Every search result reports which corpus answered it — the synced local mirror or the live eCFR index — and what that corpus covers, in `source` and `sourceScope`.',
63
104
  annotations: { readOnlyHint: true, openWorldHint: true },
64
105
  input: z.object({
65
106
  mode: z
@@ -75,7 +116,7 @@ export const browseCfrTool = tool('regulations_browse_cfr', {
75
116
  part: z
76
117
  .string()
77
118
  .optional()
78
- .describe("CFR part within the title (structure mode, optional) — narrows the returned tree to one part's sections. Parts can be alphanumeric."),
119
+ .describe('CFR part within the title, in both modes — structure mode narrows the returned tree to that part\'s sections, search mode restricts matches to text inside that part. Requires title; a part on its own is rejected. Parts can be alphanumeric ("1203a", "16A") and are matched exactly, so pass the identifier as eCFR writes it — "58", not "Part 58" or "058".'),
79
120
  query: z
80
121
  .union([z.literal(''), z.string().min(2).describe('Search phrase, at least 2 characters.')])
81
122
  .optional()
@@ -116,7 +157,7 @@ export const browseCfrTool = tool('regulations_browse_cfr', {
116
157
  sourceScope: z
117
158
  .string()
118
159
  .optional()
119
- .describe("What the answering corpus covers — the mirror's title coverage, or the live index and the date it was read at (search mode). Read it before concluding a query found nothing."),
160
+ .describe("What the answering corpus covers — the mirror's title coverage, or the live index and the date it was read at — narrowed by whichever of title and part the call supplied (search mode). Read it before concluding a query found nothing."),
120
161
  results: z
121
162
  .array(searchHit)
122
163
  .optional()
@@ -144,6 +185,12 @@ export const browseCfrTool = tool('regulations_browse_cfr', {
144
185
  when: 'Structure mode with a title outside 1–50, or a part not found in the title.',
145
186
  recovery: 'Omit title to list all titles, or pick a number in 1–50 and a part that exists.',
146
187
  },
188
+ {
189
+ reason: 'title_required_for_part',
190
+ code: JsonRpcErrorCode.InvalidParams,
191
+ when: 'A part was given with no title. Part identifiers repeat across titles, and eCFR rejects a part filter that names no title.',
192
+ 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.',
193
+ },
147
194
  {
148
195
  reason: 'date_out_of_range',
149
196
  code: JsonRpcErrorCode.InvalidParams,
@@ -159,6 +206,15 @@ export const browseCfrTool = tool('regulations_browse_cfr', {
159
206
  ],
160
207
  async handler(input, ctx) {
161
208
  const service = getEcfrService();
209
+ // A part scopes nothing on its own — part numbers repeat across titles, the
210
+ // versioner tree is fetched per title, and eCFR refuses `hierarchy[part]`
211
+ // without `hierarchy[title]`. Saying so beats silently dropping the filter.
212
+ const part = normalizePart(input.part);
213
+ if (part && input.title === undefined) {
214
+ throw ctx.fail('title_required_for_part', undefined, {
215
+ ...ctx.recoveryFor('title_required_for_part'),
216
+ });
217
+ }
162
218
  if (input.mode === 'structure') {
163
219
  if (input.title === undefined) {
164
220
  const nodes = await service.listTitleNodes(ctx);
@@ -169,7 +225,7 @@ export const browseCfrTool = tool('regulations_browse_cfr', {
169
225
  // resolve an explicit-free request to the title's latest issue date rather
170
226
  // than today(). A user-supplied historical date is honored as given.
171
227
  const date = input.date || (await service.latestIssueDate(input.title, ctx));
172
- const nodes = await service.browseStructure(input.title, input.part || undefined, date, ctx);
228
+ const nodes = await service.browseStructure(input.title, part, date, ctx);
173
229
  return { mode: 'structure', date, nodes };
174
230
  }
175
231
  // search mode
@@ -188,19 +244,26 @@ export const browseCfrTool = tool('regulations_browse_cfr', {
188
244
  let provenance;
189
245
  let response;
190
246
  if (answering) {
191
- provenance = { source: 'mirror', sourceScope: describeMirrorScope(answering, input.title) };
192
- response = await mirrorSearch(query, input.title, input.per_page);
247
+ provenance = {
248
+ source: 'mirror',
249
+ sourceScope: describeMirrorScope(answering, input.title, part),
250
+ };
251
+ response = await mirrorSearch(query, input.title, part, input.per_page);
193
252
  }
194
253
  else {
195
254
  // The live index holds every historical version of every section, so a
196
255
  // "current" search still has to name the day it wants.
197
256
  const date = input.date || (await service.currentDate(ctx));
198
- provenance = { source: 'live', sourceScope: describeLiveScope(date, input.title), date };
199
- response = await service.search(query, input.title, input.per_page, date, ctx);
257
+ provenance = {
258
+ source: 'live',
259
+ sourceScope: describeLiveScope(date, input.title, part),
260
+ date,
261
+ };
262
+ response = await service.search(query, input.title, part, input.per_page, date, ctx);
200
263
  }
201
264
  ctx.enrich.total(response.totalCount);
202
265
  if (response.results.length === 0) {
203
- ctx.enrich.notice(`No CFR sections matched "${query}". Corpus searched: ${provenance.sourceScope} Broaden the phrase, drop the title filter, or try another title before concluding no such rule exists.`);
266
+ ctx.enrich.notice(`No CFR sections matched "${query}". Corpus searched: ${provenance.sourceScope} Broaden the phrase, ${part ? 'drop the part filter, ' : ''}drop the title filter, or try another title before concluding no such rule exists.`);
204
267
  return { mode: 'search', ...provenance, results: [] };
205
268
  }
206
269
  if (response.results.length >= input.per_page && response.totalCount > input.per_page) {
@@ -223,7 +286,8 @@ export const browseCfrTool = tool('regulations_browse_cfr', {
223
286
  const reserved = n.reserved ? ' _(reserved)_' : '';
224
287
  const cite = n.cfrCite ? ` — \`${n.cfrCite}\` → regulations_get_cfr_section` : '';
225
288
  const desc = n.description && n.description !== n.label ? ` — ${n.description}` : '';
226
- lines.push(`- **${n.type}** ${n.identifier}: ${n.label}${desc}${reserved}${cite}`);
289
+ const appendix = n.appendix ? ` (appendix: \`${n.appendix}\`)` : '';
290
+ lines.push(`- **${n.type}** ${n.identifier}: ${n.label}${desc}${reserved}${cite}${appendix}`);
227
291
  }
228
292
  }
229
293
  if (result.results || result.source) {
@@ -233,7 +297,12 @@ export const browseCfrTool = tool('regulations_browse_cfr', {
233
297
  lines.push(`_${result.sourceScope ?? 'Corpus scope unreported.'}_`);
234
298
  lines.push('');
235
299
  for (const h of result.results ?? []) {
236
- lines.push(`### ${h.cfrCite} — ${h.heading} [Title ${h.title}, Part ${h.part}, § ${h.section ?? 'n/a'}]`);
300
+ const where = [`Title ${h.title}`, `Part ${h.part}`];
301
+ if (h.section)
302
+ where.push(`§ ${h.section}`);
303
+ if (h.appendix)
304
+ where.push(`appendix ${h.appendix}`);
305
+ lines.push(`### ${h.cfrCite} — ${h.heading} [${where.join(', ')}]`);
237
306
  lines.push(`_${h.hierarchyPath}_`);
238
307
  lines.push(h.excerpt);
239
308
  lines.push('');
@@ -1 +1 @@
1
- {"version":3,"file":"browse-cfr.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/browse-cfr.tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browse-cfr.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/browse-cfr.tool.ts"],"names":[],"mappings":"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"}
@@ -2,8 +2,10 @@
2
2
  * @fileoverview regulations_find_comments — fetch public comments on a Federal
3
3
  * Register document or a Regulations.gov docket, or one comment's full detail and
4
4
  * attachments. The unique corpus of what citizens and organizations submitted.
5
- * Key-gated. Flags when a comment's substance lives in an attachment rather than
6
- * inline text, surfacing the attachment download URLs.
5
+ * Key-gated. Exactly one of the four targeting parameters selects the mode; the
6
+ * handler counts the supplied targets before doing any work, so neither zero nor
7
+ * two can resolve by branch order. Flags when a comment's substance lives in an
8
+ * attachment rather than inline text, surfacing the attachment download URLs.
7
9
  * @module mcp-server/tools/definitions/find-comments.tool
8
10
  */
9
11
  import { z } from '@cyanheads/mcp-ts-core';
@@ -60,6 +62,11 @@ export declare const findCommentsTool: import("@cyanheads/mcp-ts-core").ToolDefi
60
62
  readonly code: JsonRpcErrorCode.InvalidParams;
61
63
  readonly when: "None of docket_id / document_object_id / fr_document_number / comment_id was given.";
62
64
  readonly recovery: "Provide one targeting parameter — a docket ID, a document object ID, an FR document number, or a comment ID.";
65
+ }, {
66
+ readonly reason: "multiple_targets";
67
+ readonly code: JsonRpcErrorCode.InvalidParams;
68
+ readonly when: "More than one of docket_id / document_object_id / fr_document_number / comment_id was given.";
69
+ readonly recovery: "Keep the single target you meant and drop the rest: comment_id reads one comment in detail, the other three list a set. To read a comment found in a docket listing, call again with comment_id alone.";
63
70
  }, {
64
71
  readonly reason: "not_found";
65
72
  readonly code: JsonRpcErrorCode.NotFound;
@@ -1 +1 @@
1
- {"version":3,"file":"find-comments.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/find-comments.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiU3B,CAAC"}
1
+ {"version":3,"file":"find-comments.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/find-comments.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAmBjE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0V3B,CAAC"}