@cyanheads/federal-regulations-mcp-server 0.1.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.
- package/AGENTS.md +387 -0
- package/CLAUDE.md +387 -0
- package/Dockerfile +127 -0
- package/LICENSE +201 -0
- package/README.md +372 -0
- package/changelog/0.1.x/0.1.0.md +20 -0
- package/changelog/template.md +127 -0
- package/dist/config/server-config.d.ts +32 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +64 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/resources/definitions/cfr-section.resource.d.ts +14 -0
- package/dist/mcp-server/resources/definitions/cfr-section.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/cfr-section.resource.js +77 -0
- package/dist/mcp-server/resources/definitions/cfr-section.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/document.resource.d.ts +12 -0
- package/dist/mcp-server/resources/definitions/document.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/document.resource.js +38 -0
- package/dist/mcp-server/resources/definitions/document.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/index.d.ts +12 -0
- package/dist/mcp-server/resources/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/index.js +8 -0
- package/dist/mcp-server/resources/definitions/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/browse-cfr.tool.d.ts +73 -0
- package/dist/mcp-server/tools/definitions/browse-cfr.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/browse-cfr.tool.js +205 -0
- package/dist/mcp-server/tools/definitions/browse-cfr.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/find-comments.tool.d.ts +85 -0
- package/dist/mcp-server/tools/definitions/find-comments.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/find-comments.tool.js +271 -0
- package/dist/mcp-server/tools/definitions/find-comments.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/format-utils.d.ts +7 -0
- package/dist/mcp-server/tools/definitions/format-utils.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/format-utils.js +9 -0
- package/dist/mcp-server/tools/definitions/format-utils.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-cfr-section.tool.d.ts +50 -0
- package/dist/mcp-server/tools/definitions/get-cfr-section.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-cfr-section.tool.js +152 -0
- package/dist/mcp-server/tools/definitions/get-cfr-section.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-docket.tool.d.ts +67 -0
- package/dist/mcp-server/tools/definitions/get-docket.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-docket.tool.js +154 -0
- package/dist/mcp-server/tools/definitions/get-docket.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-document.tool.d.ts +51 -0
- package/dist/mcp-server/tools/definitions/get-document.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-document.tool.js +138 -0
- package/dist/mcp-server/tools/definitions/get-document.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/index.d.ts +356 -0
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/index.js +21 -0
- package/dist/mcp-server/tools/definitions/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/list-open-comments.tool.d.ts +47 -0
- package/dist/mcp-server/tools/definitions/list-open-comments.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/list-open-comments.tool.js +179 -0
- package/dist/mcp-server/tools/definitions/list-open-comments.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/search-rules.tool.d.ts +57 -0
- package/dist/mcp-server/tools/definitions/search-rules.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/search-rules.tool.js +185 -0
- package/dist/mcp-server/tools/definitions/search-rules.tool.js.map +1 -0
- package/dist/services/ecfr/ecfr-service.d.ts +54 -0
- package/dist/services/ecfr/ecfr-service.d.ts.map +1 -0
- package/dist/services/ecfr/ecfr-service.js +303 -0
- package/dist/services/ecfr/ecfr-service.js.map +1 -0
- package/dist/services/ecfr/types.d.ts +105 -0
- package/dist/services/ecfr/types.d.ts.map +1 -0
- package/dist/services/ecfr/types.js +7 -0
- package/dist/services/ecfr/types.js.map +1 -0
- package/dist/services/ecfr/xml.d.ts +15 -0
- package/dist/services/ecfr/xml.d.ts.map +1 -0
- package/dist/services/ecfr/xml.js +103 -0
- package/dist/services/ecfr/xml.js.map +1 -0
- package/dist/services/ecfr-mirror/ecfr-mirror.d.ts +43 -0
- package/dist/services/ecfr-mirror/ecfr-mirror.d.ts.map +1 -0
- package/dist/services/ecfr-mirror/ecfr-mirror.js +267 -0
- package/dist/services/ecfr-mirror/ecfr-mirror.js.map +1 -0
- package/dist/services/federal-register/federal-register-service.d.ts +30 -0
- package/dist/services/federal-register/federal-register-service.d.ts.map +1 -0
- package/dist/services/federal-register/federal-register-service.js +241 -0
- package/dist/services/federal-register/federal-register-service.js.map +1 -0
- package/dist/services/federal-register/types.d.ts +138 -0
- package/dist/services/federal-register/types.d.ts.map +1 -0
- package/dist/services/federal-register/types.js +8 -0
- package/dist/services/federal-register/types.js.map +1 -0
- package/dist/services/regulations-gov/regulations-gov-service.d.ts +55 -0
- package/dist/services/regulations-gov/regulations-gov-service.d.ts.map +1 -0
- package/dist/services/regulations-gov/regulations-gov-service.js +283 -0
- package/dist/services/regulations-gov/regulations-gov-service.js.map +1 -0
- package/dist/services/regulations-gov/types.d.ts +148 -0
- package/dist/services/regulations-gov/types.d.ts.map +1 -0
- package/dist/services/regulations-gov/types.js +7 -0
- package/dist/services/regulations-gov/types.js.map +1 -0
- package/dist/services/request-context.d.ts +13 -0
- package/dist/services/request-context.d.ts.map +1 -0
- package/dist/services/request-context.js +23 -0
- package/dist/services/request-context.js.map +1 -0
- package/package.json +94 -0
- package/scripts/_mirror-context.ts +101 -0
- package/scripts/ecfr-mirror-init.ts +36 -0
- package/scripts/ecfr-mirror-refresh.ts +29 -0
- package/scripts/ecfr-mirror-verify.ts +33 -0
- package/server.json +113 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecfr-service.js","sourceRoot":"","sources":["../../../src/services/ecfr/ecfr-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Domain and raw types for the eCFR service (titles, structure,
|
|
3
|
+
* versioner full text, search). Raw types mirror the real API payloads.
|
|
4
|
+
* @module services/ecfr/types
|
|
5
|
+
*/
|
|
6
|
+
/** A title entry from `/versioner/v1/titles.json`. */
|
|
7
|
+
export interface EcfrTitle {
|
|
8
|
+
latestAmendedOn: string | null;
|
|
9
|
+
latestIssueDate: string | null;
|
|
10
|
+
name: string;
|
|
11
|
+
number: number;
|
|
12
|
+
reserved: boolean;
|
|
13
|
+
upToDateAsOf: string | null;
|
|
14
|
+
}
|
|
15
|
+
/** Raw title object from the API. */
|
|
16
|
+
export interface RawEcfrTitle {
|
|
17
|
+
latest_amended_on?: string | null;
|
|
18
|
+
latest_issue_date?: string | null;
|
|
19
|
+
name?: string;
|
|
20
|
+
number?: number;
|
|
21
|
+
reserved?: boolean;
|
|
22
|
+
up_to_date_as_of?: string | null;
|
|
23
|
+
}
|
|
24
|
+
/** A node in a CFR structure tree (title → chapter → … → section). */
|
|
25
|
+
export interface EcfrStructureNode {
|
|
26
|
+
cfrCite: string | null;
|
|
27
|
+
description: string | null;
|
|
28
|
+
identifier: string;
|
|
29
|
+
label: string;
|
|
30
|
+
reserved: boolean;
|
|
31
|
+
type: string;
|
|
32
|
+
}
|
|
33
|
+
/** Raw structure node (recursive `children`). */
|
|
34
|
+
export interface RawEcfrStructureNode {
|
|
35
|
+
children?: RawEcfrStructureNode[];
|
|
36
|
+
identifier?: string;
|
|
37
|
+
label?: string;
|
|
38
|
+
label_description?: string | null;
|
|
39
|
+
reserved?: boolean;
|
|
40
|
+
type?: string;
|
|
41
|
+
}
|
|
42
|
+
/** One section parsed from versioner XML. */
|
|
43
|
+
export interface EcfrSection {
|
|
44
|
+
bodyText: string;
|
|
45
|
+
heading: string;
|
|
46
|
+
section: string;
|
|
47
|
+
}
|
|
48
|
+
/** Result of a codified-text fetch (a section, or a whole part). */
|
|
49
|
+
export interface EcfrSectionResult {
|
|
50
|
+
bodyText: string;
|
|
51
|
+
date: string;
|
|
52
|
+
heading: string;
|
|
53
|
+
part: string;
|
|
54
|
+
section: string | null;
|
|
55
|
+
sections?: EcfrSection[];
|
|
56
|
+
title: number;
|
|
57
|
+
}
|
|
58
|
+
/** One hit from the live eCFR search API. */
|
|
59
|
+
export interface EcfrSearchHit {
|
|
60
|
+
cfrCite: string;
|
|
61
|
+
excerpt: string;
|
|
62
|
+
heading: string;
|
|
63
|
+
hierarchyPath: string;
|
|
64
|
+
part: string;
|
|
65
|
+
section: string | null;
|
|
66
|
+
title: number;
|
|
67
|
+
}
|
|
68
|
+
/** Live search response. */
|
|
69
|
+
export interface EcfrSearchResponse {
|
|
70
|
+
results: EcfrSearchHit[];
|
|
71
|
+
totalCount: number;
|
|
72
|
+
}
|
|
73
|
+
/** Raw live-search result item. */
|
|
74
|
+
export interface RawEcfrSearchResult {
|
|
75
|
+
full_text_excerpt?: string | null;
|
|
76
|
+
headings?: {
|
|
77
|
+
section?: string | null;
|
|
78
|
+
part?: string | null;
|
|
79
|
+
} | null;
|
|
80
|
+
hierarchy?: {
|
|
81
|
+
title?: string | number | null;
|
|
82
|
+
chapter?: string | null;
|
|
83
|
+
subchapter?: string | null;
|
|
84
|
+
part?: string | null;
|
|
85
|
+
subpart?: string | null;
|
|
86
|
+
section?: string | null;
|
|
87
|
+
} | null;
|
|
88
|
+
hierarchy_headings?: {
|
|
89
|
+
title?: string | null;
|
|
90
|
+
chapter?: string | null;
|
|
91
|
+
subchapter?: string | null;
|
|
92
|
+
part?: string | null;
|
|
93
|
+
section?: string | null;
|
|
94
|
+
} | null;
|
|
95
|
+
score?: number | null;
|
|
96
|
+
}
|
|
97
|
+
/** Raw live-search envelope. */
|
|
98
|
+
export interface RawEcfrSearchResponse {
|
|
99
|
+
meta?: {
|
|
100
|
+
total_count?: number;
|
|
101
|
+
total_pages?: number;
|
|
102
|
+
} | null;
|
|
103
|
+
results?: RawEcfrSearchResult[];
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/ecfr/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/services/ecfr/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Minimal, dependency-free extraction of CFR section text from
|
|
3
|
+
* eCFR versioner XML. The versioner returns `<DIV8 TYPE="SECTION">` elements with
|
|
4
|
+
* a `<HEAD>` heading and `<P>` body paragraphs; this module pulls those into a
|
|
5
|
+
* flat `{ section, heading, bodyText }` shape with tags stripped and entities
|
|
6
|
+
* decoded. Used by both the live `get_cfr_section` path and the mirror ingester.
|
|
7
|
+
* @module services/ecfr/xml
|
|
8
|
+
*/
|
|
9
|
+
import type { EcfrSection } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Parse all `<DIV8 TYPE="SECTION">` elements out of an eCFR versioner XML
|
|
12
|
+
* document into flat section records. Returns them in document order.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseSections(xml: string): EcfrSection[];
|
|
15
|
+
//# sourceMappingURL=xml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xml.d.ts","sourceRoot":"","sources":["../../../src/services/ecfr/xml.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA4E9C;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CAexD"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Minimal, dependency-free extraction of CFR section text from
|
|
3
|
+
* eCFR versioner XML. The versioner returns `<DIV8 TYPE="SECTION">` elements with
|
|
4
|
+
* a `<HEAD>` heading and `<P>` body paragraphs; this module pulls those into a
|
|
5
|
+
* flat `{ section, heading, bodyText }` shape with tags stripped and entities
|
|
6
|
+
* decoded. Used by both the live `get_cfr_section` path and the mirror ingester.
|
|
7
|
+
* @module services/ecfr/xml
|
|
8
|
+
*/
|
|
9
|
+
const NAMED_ENTITIES = {
|
|
10
|
+
amp: '&',
|
|
11
|
+
lt: '<',
|
|
12
|
+
gt: '>',
|
|
13
|
+
quot: '"',
|
|
14
|
+
apos: "'",
|
|
15
|
+
nbsp: ' ',
|
|
16
|
+
mdash: '—',
|
|
17
|
+
ndash: '–',
|
|
18
|
+
sect: '§',
|
|
19
|
+
rsquo: '’',
|
|
20
|
+
lsquo: '‘',
|
|
21
|
+
ldquo: '“',
|
|
22
|
+
rdquo: '”',
|
|
23
|
+
hellip: '…',
|
|
24
|
+
deg: '°',
|
|
25
|
+
reg: '®',
|
|
26
|
+
};
|
|
27
|
+
/** Decode the XML/HTML entities that appear in eCFR text. */
|
|
28
|
+
function decodeEntities(text) {
|
|
29
|
+
return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (match, body) => {
|
|
30
|
+
if (body.startsWith('#x') || body.startsWith('#X')) {
|
|
31
|
+
const code = Number.parseInt(body.slice(2), 16);
|
|
32
|
+
return Number.isNaN(code) ? match : String.fromCodePoint(code);
|
|
33
|
+
}
|
|
34
|
+
if (body.startsWith('#')) {
|
|
35
|
+
const code = Number.parseInt(body.slice(1), 10);
|
|
36
|
+
return Number.isNaN(code) ? match : String.fromCodePoint(code);
|
|
37
|
+
}
|
|
38
|
+
return NAMED_ENTITIES[body] ?? match;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Strip XML tags from a fragment and collapse whitespace to readable text.
|
|
43
|
+
* Closing tags are removed without a separator (they close inline runs, so
|
|
44
|
+
* `term</E>.` becomes `term.`, not `term .`); other tags become a space so word
|
|
45
|
+
* boundaries are preserved. Any residual space before sentence punctuation is
|
|
46
|
+
* then tidied.
|
|
47
|
+
*/
|
|
48
|
+
function stripTags(fragment) {
|
|
49
|
+
const withoutTags = fragment.replace(/<\/[^>]+>/g, '').replace(/<[^>]+>/g, ' ');
|
|
50
|
+
return decodeEntities(withoutTags)
|
|
51
|
+
.replace(/\s+/g, ' ')
|
|
52
|
+
.replace(/\s+([.,;:)])/g, '$1')
|
|
53
|
+
.trim();
|
|
54
|
+
}
|
|
55
|
+
/** Extract the first `<HEAD>…</HEAD>` text from a fragment. */
|
|
56
|
+
function extractHead(fragment) {
|
|
57
|
+
const match = fragment.match(/<HEAD[^>]*>([\s\S]*?)<\/HEAD>/i);
|
|
58
|
+
return match?.[1] ? stripTags(match[1]) : '';
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Extract body text from a section fragment: every `<P>` (and `<FP>` formatted
|
|
62
|
+
* paragraph) joined by blank lines, with the HEAD removed so it isn't duplicated.
|
|
63
|
+
*/
|
|
64
|
+
function extractBody(fragment) {
|
|
65
|
+
const paragraphs = [];
|
|
66
|
+
for (const m of fragment.matchAll(/<(P|FP)\b[^>]*>([\s\S]*?)<\/\1>/gi)) {
|
|
67
|
+
const text = stripTags(m[2] ?? '');
|
|
68
|
+
if (text)
|
|
69
|
+
paragraphs.push(text);
|
|
70
|
+
}
|
|
71
|
+
return paragraphs.join('\n\n');
|
|
72
|
+
}
|
|
73
|
+
/** The `N` attribute (section number) of a DIV8 opening tag. */
|
|
74
|
+
function sectionNumber(openTag) {
|
|
75
|
+
const match = openTag.match(/\bN="([^"]+)"/i);
|
|
76
|
+
return match?.[1] ?? null;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Parse all `<DIV8 TYPE="SECTION">` elements out of an eCFR versioner XML
|
|
80
|
+
* document into flat section records. Returns them in document order.
|
|
81
|
+
*/
|
|
82
|
+
export function parseSections(xml) {
|
|
83
|
+
const sections = [];
|
|
84
|
+
for (const m of xml.matchAll(/<DIV8\b([^>]*TYPE="SECTION"[^>]*)>([\s\S]*?)<\/DIV8>/gi)) {
|
|
85
|
+
const openTag = m[1] ?? '';
|
|
86
|
+
const inner = m[2] ?? '';
|
|
87
|
+
const heading = extractHead(inner);
|
|
88
|
+
const body = extractBody(inner);
|
|
89
|
+
const num = sectionNumber(openTag) ?? deriveSectionFromHeading(heading);
|
|
90
|
+
sections.push({
|
|
91
|
+
section: num ?? '',
|
|
92
|
+
heading: heading || (num ? `§ ${num}` : '(untitled section)'),
|
|
93
|
+
bodyText: body,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return sections;
|
|
97
|
+
}
|
|
98
|
+
/** Fallback: pull a section number like "50.1" out of a "§ 50.1 …" heading. */
|
|
99
|
+
function deriveSectionFromHeading(heading) {
|
|
100
|
+
const match = heading.match(/§+\s*([0-9][0-9A-Za-z.\\-]*)/);
|
|
101
|
+
return match?.[1] ?? null;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=xml.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xml.js","sourceRoot":"","sources":["../../../src/services/ecfr/xml.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview EcfrMirror — a MirrorService (Tier-2 SQLite + FTS5) mirror of the
|
|
3
|
+
* codified CFR full text. The CFR is a bounded, slowly-changing corpus queried by
|
|
4
|
+
* exact cite, so it is mirrored once and queried locally (section lookup + FTS5
|
|
5
|
+
* full-text search) instead of paginating the live eCFR versioner per request.
|
|
6
|
+
*
|
|
7
|
+
* Build-time ingest uses `better-sqlite3` on Node; runtime reads go through Bun's
|
|
8
|
+
* `bun:sqlite` — both behind the framework's runtime-agnostic SQLite handle.
|
|
9
|
+
*
|
|
10
|
+
* CRITICAL build-correctness contract: the auxiliary `cfr_part_index` table is
|
|
11
|
+
* created idempotently (`CREATE TABLE IF NOT EXISTS`) at the top of the `sync`
|
|
12
|
+
* routine via the raw handle — NOT via a framework migration. The MirrorService
|
|
13
|
+
* skips migrations on a brand-new DB, so a migration-created aux table fails the
|
|
14
|
+
* cold `mirror:init` with `no such table`. Idempotent DDL at sync start is the
|
|
15
|
+
* contract.
|
|
16
|
+
*
|
|
17
|
+
* @module services/ecfr-mirror/ecfr-mirror
|
|
18
|
+
*/
|
|
19
|
+
import { type Mirror } from '@cyanheads/mcp-ts-core/mirror';
|
|
20
|
+
import type { EcfrSearchHit, EcfrSectionResult } from '../../services/ecfr/types.js';
|
|
21
|
+
/**
|
|
22
|
+
* The mirror instance. Schema declares the section columns plus an FTS5 index
|
|
23
|
+
* over heading + body_text (handled by the framework's schema-gen). The `sync`
|
|
24
|
+
* generator walks the eCFR titles, pulls each title's full XML, parses sections,
|
|
25
|
+
* and yields one page per title — creating the aux table on the first page.
|
|
26
|
+
*/
|
|
27
|
+
export declare const ecfrMirror: Mirror;
|
|
28
|
+
/** Whether the mirror has ever completed a full init (queryable even mid-refresh). */
|
|
29
|
+
export declare function mirrorReady(): Promise<boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* Look up a section's codified text from the mirror by exact cite. Returns null
|
|
32
|
+
* when the section isn't present (caller falls back to the live versioner).
|
|
33
|
+
*/
|
|
34
|
+
export declare function mirrorGetSection(title: number, part: string, section: string): Promise<EcfrSectionResult | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Full-text search the mirror's FTS5 index. Returns hits with a cite assembled
|
|
37
|
+
* from the stored columns.
|
|
38
|
+
*/
|
|
39
|
+
export declare function mirrorSearch(query: string, title: number | undefined, limit: number): Promise<{
|
|
40
|
+
totalCount: number;
|
|
41
|
+
results: EcfrSearchHit[];
|
|
42
|
+
}>;
|
|
43
|
+
//# sourceMappingURL=ecfr-mirror.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecfr-mirror.d.ts","sourceRoot":"","sources":["../../../src/services/ecfr-mirror/ecfr-mirror.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAEL,KAAK,MAAM,EAIZ,MAAM,+BAA+B,CAAC;AAIvC,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAiDjF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,MAyEvB,CAAC;AAEH,sFAAsF;AACtF,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAMpD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAYnC;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC,CA4B3D"}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview EcfrMirror — a MirrorService (Tier-2 SQLite + FTS5) mirror of the
|
|
3
|
+
* codified CFR full text. The CFR is a bounded, slowly-changing corpus queried by
|
|
4
|
+
* exact cite, so it is mirrored once and queried locally (section lookup + FTS5
|
|
5
|
+
* full-text search) instead of paginating the live eCFR versioner per request.
|
|
6
|
+
*
|
|
7
|
+
* Build-time ingest uses `better-sqlite3` on Node; runtime reads go through Bun's
|
|
8
|
+
* `bun:sqlite` — both behind the framework's runtime-agnostic SQLite handle.
|
|
9
|
+
*
|
|
10
|
+
* CRITICAL build-correctness contract: the auxiliary `cfr_part_index` table is
|
|
11
|
+
* created idempotently (`CREATE TABLE IF NOT EXISTS`) at the top of the `sync`
|
|
12
|
+
* routine via the raw handle — NOT via a framework migration. The MirrorService
|
|
13
|
+
* skips migrations on a brand-new DB, so a migration-created aux table fails the
|
|
14
|
+
* cold `mirror:init` with `no such table`. Idempotent DDL at sync start is the
|
|
15
|
+
* contract.
|
|
16
|
+
*
|
|
17
|
+
* @module services/ecfr-mirror/ecfr-mirror
|
|
18
|
+
*/
|
|
19
|
+
import { defineMirror, sqliteMirrorStore, } from '@cyanheads/mcp-ts-core/mirror';
|
|
20
|
+
import { logger, requestContextService } from '@cyanheads/mcp-ts-core/utils';
|
|
21
|
+
import { getServerConfig } from '../../config/server-config.js';
|
|
22
|
+
import { getEcfrService } from '../../services/ecfr/ecfr-service.js';
|
|
23
|
+
import { parseSections } from '../../services/ecfr/xml.js';
|
|
24
|
+
/** Primary table name for the mirror. */
|
|
25
|
+
const TABLE = 'cfr_sections';
|
|
26
|
+
/** Auxiliary table for fast title/part browse. */
|
|
27
|
+
const PART_INDEX_TABLE = 'cfr_part_index';
|
|
28
|
+
/** Composite primary-key value for a section row: `title:part:section`. */
|
|
29
|
+
function rowId(title, part, section) {
|
|
30
|
+
return `${title}:${part}:${section}`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Create the server-owned auxiliary table idempotently. Called once at the top
|
|
34
|
+
* of `sync`, via the raw handle — NEVER through a migration (the runner skips
|
|
35
|
+
* migrations on a fresh DB). `CREATE TABLE IF NOT EXISTS` is safe on every run.
|
|
36
|
+
*/
|
|
37
|
+
function ensureAuxTables(handle) {
|
|
38
|
+
handle.exec(`
|
|
39
|
+
CREATE TABLE IF NOT EXISTS ${PART_INDEX_TABLE} (
|
|
40
|
+
title INTEGER NOT NULL,
|
|
41
|
+
part TEXT NOT NULL,
|
|
42
|
+
section_count INTEGER NOT NULL DEFAULT 0,
|
|
43
|
+
issue_date TEXT,
|
|
44
|
+
PRIMARY KEY (title, part)
|
|
45
|
+
);
|
|
46
|
+
`);
|
|
47
|
+
}
|
|
48
|
+
/** Upsert a part's section count into the aux index. */
|
|
49
|
+
function upsertPartIndex(handle, title, part, count, issueDate) {
|
|
50
|
+
handle
|
|
51
|
+
.prepare(`INSERT INTO ${PART_INDEX_TABLE} (title, part, section_count, issue_date)
|
|
52
|
+
VALUES (?, ?, ?, ?)
|
|
53
|
+
ON CONFLICT(title, part) DO UPDATE SET
|
|
54
|
+
section_count = excluded.section_count,
|
|
55
|
+
issue_date = excluded.issue_date;`)
|
|
56
|
+
.run(title, part, count, issueDate);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The mirror instance. Schema declares the section columns plus an FTS5 index
|
|
60
|
+
* over heading + body_text (handled by the framework's schema-gen). The `sync`
|
|
61
|
+
* generator walks the eCFR titles, pulls each title's full XML, parses sections,
|
|
62
|
+
* and yields one page per title — creating the aux table on the first page.
|
|
63
|
+
*/
|
|
64
|
+
export const ecfrMirror = defineMirror({
|
|
65
|
+
name: 'ecfr-cfr-sections',
|
|
66
|
+
logger,
|
|
67
|
+
store: sqliteMirrorStore({
|
|
68
|
+
path: getServerConfig().ecfrMirrorPath,
|
|
69
|
+
table: TABLE,
|
|
70
|
+
primaryKey: 'id',
|
|
71
|
+
columns: {
|
|
72
|
+
id: 'TEXT',
|
|
73
|
+
title: 'INTEGER',
|
|
74
|
+
part: 'TEXT',
|
|
75
|
+
section: 'TEXT',
|
|
76
|
+
heading: 'TEXT',
|
|
77
|
+
body_text: 'TEXT',
|
|
78
|
+
issue_date: 'TEXT',
|
|
79
|
+
},
|
|
80
|
+
fts: ['heading', 'body_text'],
|
|
81
|
+
indexes: [{ columns: ['title', 'part'] }, { columns: ['issue_date'] }],
|
|
82
|
+
}),
|
|
83
|
+
async *sync({ signal }) {
|
|
84
|
+
const ecfr = getEcfrService();
|
|
85
|
+
const ctx = mirrorContext(signal);
|
|
86
|
+
// Idempotent aux-table DDL at sync start — never a migration.
|
|
87
|
+
const handle = await ecfrMirror.raw();
|
|
88
|
+
ensureAuxTables(handle);
|
|
89
|
+
const scope = scopedTitles();
|
|
90
|
+
const titles = await ecfr.listTitles(ctx);
|
|
91
|
+
for (const title of titles) {
|
|
92
|
+
if (signal.aborted)
|
|
93
|
+
return;
|
|
94
|
+
if (title.reserved)
|
|
95
|
+
continue;
|
|
96
|
+
if (scope && !scope.has(title.number))
|
|
97
|
+
continue;
|
|
98
|
+
const issueDate = title.latestIssueDate ?? title.upToDateAsOf;
|
|
99
|
+
if (!issueDate)
|
|
100
|
+
continue;
|
|
101
|
+
const xml = await fetchTitleXml(ecfr, title.number, issueDate, ctx);
|
|
102
|
+
if (!xml)
|
|
103
|
+
continue;
|
|
104
|
+
const sections = parseSections(xml);
|
|
105
|
+
const records = [];
|
|
106
|
+
const partCounts = new Map();
|
|
107
|
+
for (const s of sections) {
|
|
108
|
+
if (!s.section)
|
|
109
|
+
continue;
|
|
110
|
+
const part = derivePart(s.section);
|
|
111
|
+
records.push({
|
|
112
|
+
id: rowId(title.number, part, s.section),
|
|
113
|
+
title: title.number,
|
|
114
|
+
part,
|
|
115
|
+
section: s.section,
|
|
116
|
+
heading: s.heading,
|
|
117
|
+
body_text: s.bodyText,
|
|
118
|
+
issue_date: issueDate,
|
|
119
|
+
});
|
|
120
|
+
partCounts.set(part, (partCounts.get(part) ?? 0) + 1);
|
|
121
|
+
}
|
|
122
|
+
// Maintain the aux index from the sync mapping (the mirror-owned secondary structure).
|
|
123
|
+
const auxHandle = await ecfrMirror.raw();
|
|
124
|
+
auxHandle.transaction(() => {
|
|
125
|
+
for (const [part, count] of partCounts) {
|
|
126
|
+
upsertPartIndex(auxHandle, title.number, part, count, issueDate);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
yield {
|
|
130
|
+
records,
|
|
131
|
+
checkpoint: issueDate,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
/** Whether the mirror has ever completed a full init (queryable even mid-refresh). */
|
|
137
|
+
export async function mirrorReady() {
|
|
138
|
+
try {
|
|
139
|
+
return await ecfrMirror.ready();
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Look up a section's codified text from the mirror by exact cite. Returns null
|
|
147
|
+
* when the section isn't present (caller falls back to the live versioner).
|
|
148
|
+
*/
|
|
149
|
+
export async function mirrorGetSection(title, part, section) {
|
|
150
|
+
const rows = await ecfrMirror.getByIds([rowId(title, part, section)]);
|
|
151
|
+
const row = rows[0];
|
|
152
|
+
if (!row)
|
|
153
|
+
return null;
|
|
154
|
+
return {
|
|
155
|
+
title,
|
|
156
|
+
part,
|
|
157
|
+
section,
|
|
158
|
+
heading: String(row.heading ?? `§ ${section}`),
|
|
159
|
+
date: String(row.issue_date ?? ''),
|
|
160
|
+
bodyText: String(row.body_text ?? ''),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Full-text search the mirror's FTS5 index. Returns hits with a cite assembled
|
|
165
|
+
* from the stored columns.
|
|
166
|
+
*/
|
|
167
|
+
export async function mirrorSearch(query, title, limit) {
|
|
168
|
+
const result = await ecfrMirror.query({
|
|
169
|
+
match: toFtsQuery(query),
|
|
170
|
+
...(typeof title === 'number'
|
|
171
|
+
? { filters: [{ column: 'title', op: 'eq', value: title }] }
|
|
172
|
+
: {}),
|
|
173
|
+
sort: 'relevance',
|
|
174
|
+
limit,
|
|
175
|
+
offset: 0,
|
|
176
|
+
});
|
|
177
|
+
const results = result.rows.map((row) => {
|
|
178
|
+
const rowTitle = Number(row.title ?? 0);
|
|
179
|
+
const part = String(row.part ?? '');
|
|
180
|
+
const section = row.section ? String(row.section) : null;
|
|
181
|
+
const heading = String(row.heading ?? '(untitled)');
|
|
182
|
+
return {
|
|
183
|
+
title: rowTitle,
|
|
184
|
+
part,
|
|
185
|
+
section,
|
|
186
|
+
heading,
|
|
187
|
+
hierarchyPath: `Title ${rowTitle} › Part ${part}${section ? ` › § ${section}` : ''}`,
|
|
188
|
+
excerpt: excerpt(String(row.body_text ?? ''), query),
|
|
189
|
+
cfrCite: section ? `${rowTitle} CFR ${section}` : `${rowTitle} CFR ${part}`,
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
return { totalCount: result.total, results };
|
|
193
|
+
}
|
|
194
|
+
/** Derive the part identifier from a section number ("50.1" → "50"). */
|
|
195
|
+
function derivePart(section) {
|
|
196
|
+
const idx = section.indexOf('.');
|
|
197
|
+
return idx === -1 ? section : section.slice(0, idx);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Parse the optional `ECFR_MIRROR_TITLES` scope into a set of title numbers.
|
|
201
|
+
* Returns null when unset (mirror all titles). Invalid entries are dropped.
|
|
202
|
+
*/
|
|
203
|
+
function scopedTitles() {
|
|
204
|
+
const raw = getServerConfig().ecfrMirrorTitles;
|
|
205
|
+
if (!raw)
|
|
206
|
+
return null;
|
|
207
|
+
const nums = raw
|
|
208
|
+
.split(',')
|
|
209
|
+
.map((s) => Number.parseInt(s.trim(), 10))
|
|
210
|
+
.filter((n) => Number.isInteger(n) && n >= 1 && n <= 50);
|
|
211
|
+
return nums.length > 0 ? new Set(nums) : null;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Translate a free-text phrase into a safe FTS5 MATCH expression: quote each
|
|
215
|
+
* token to neutralize FTS operators, AND-combine them.
|
|
216
|
+
*/
|
|
217
|
+
function toFtsQuery(query) {
|
|
218
|
+
const tokens = query
|
|
219
|
+
.toLowerCase()
|
|
220
|
+
.replace(/["']/g, ' ')
|
|
221
|
+
.split(/\s+/)
|
|
222
|
+
.filter((t) => t.length > 0);
|
|
223
|
+
if (tokens.length === 0)
|
|
224
|
+
return '""';
|
|
225
|
+
return tokens.map((t) => `"${t}"`).join(' AND ');
|
|
226
|
+
}
|
|
227
|
+
/** Build a short excerpt centered on the first query-token match. */
|
|
228
|
+
function excerpt(body, query) {
|
|
229
|
+
const flat = body.replace(/\s+/g, ' ').trim();
|
|
230
|
+
if (flat.length <= 320)
|
|
231
|
+
return flat;
|
|
232
|
+
const firstToken = query
|
|
233
|
+
.toLowerCase()
|
|
234
|
+
.split(/\s+/)
|
|
235
|
+
.find((t) => t.length > 2);
|
|
236
|
+
const idx = firstToken ? flat.toLowerCase().indexOf(firstToken) : -1;
|
|
237
|
+
if (idx === -1)
|
|
238
|
+
return `${flat.slice(0, 320)}…`;
|
|
239
|
+
const start = Math.max(0, idx - 120);
|
|
240
|
+
return `${start > 0 ? '…' : ''}${flat.slice(start, start + 320)}…`;
|
|
241
|
+
}
|
|
242
|
+
/** Fetch a whole title's XML for the mirror ingest. Returns null on failure. */
|
|
243
|
+
async function fetchTitleXml(ecfr, title, date, ctx) {
|
|
244
|
+
try {
|
|
245
|
+
return await ecfr.fetchFullTitleXml(title, date, ctx);
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
249
|
+
logger.warning(`eCFR mirror: failed to fetch title ${title} (${date}): ${message}`, requestContextService.createRequestContext({ operation: 'ecfr-mirror:fetch-title' }));
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* A minimal `Context` shim for the sync ingester, which runs outside the MCP
|
|
255
|
+
* request pipeline (CLI / cron). The eCFR service reads only `ctx.signal` (and
|
|
256
|
+
* derives its own request context for logging), so the remaining Context surface
|
|
257
|
+
* is stubbed off a real RequestContext base.
|
|
258
|
+
*/
|
|
259
|
+
function mirrorContext(signal) {
|
|
260
|
+
const base = requestContextService.createRequestContext({ operation: 'ecfr-mirror:sync' });
|
|
261
|
+
return {
|
|
262
|
+
...base,
|
|
263
|
+
signal,
|
|
264
|
+
log: logger,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=ecfr-mirror.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecfr-mirror.js","sourceRoot":"","sources":["../../../src/services/ecfr-mirror/ecfr-mirror.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview FederalRegisterService — keyless client for the Federal Register
|
|
3
|
+
* API v1 (federalregister.gov/api/v1). Backs the document search, single-document
|
|
4
|
+
* fetch (with the cross-source docket/CFR handles), and the open-comment-window
|
|
5
|
+
* tools. Each method wraps the full fetch + parse pipeline in `withRetry`;
|
|
6
|
+
* `fetchWithTimeout` throws a classified `McpError` on a non-OK response, and the
|
|
7
|
+
* response parser detects HTML error pages and re-throws them as transient.
|
|
8
|
+
* @module services/federal-register/federal-register-service
|
|
9
|
+
*/
|
|
10
|
+
import type { Context } from '@cyanheads/mcp-ts-core';
|
|
11
|
+
import type { AppConfig } from '@cyanheads/mcp-ts-core/config';
|
|
12
|
+
import type { StorageService } from '@cyanheads/mcp-ts-core/storage';
|
|
13
|
+
import type { FrDocumentDetail, FrSearchParams, FrSearchResponse, OpenCommentsParams, OpenCommentsResponse } from './types.js';
|
|
14
|
+
export declare class FederalRegisterService {
|
|
15
|
+
private readonly baseUrl;
|
|
16
|
+
constructor(_config: AppConfig, _storage: StorageService);
|
|
17
|
+
/** Search Federal Register documents by query, type, agency, and date window. */
|
|
18
|
+
search(params: FrSearchParams, ctx: Context): Promise<FrSearchResponse>;
|
|
19
|
+
/** Fetch one document by FR number, optionally inlining the plain-text body. */
|
|
20
|
+
getDocument(documentNumber: string, includeFullText: boolean, ctx: Context): Promise<FrDocumentDetail>;
|
|
21
|
+
/** List rules currently open for public comment (comment_date window ≥ today). */
|
|
22
|
+
listOpenComments(params: OpenCommentsParams, asOf: string, ctx: Context): Promise<OpenCommentsResponse>;
|
|
23
|
+
/** Fetch + parse JSON with retry; HTML error pages become transient errors. */
|
|
24
|
+
private fetchJson;
|
|
25
|
+
/** Fetch plain text (document body) with retry. */
|
|
26
|
+
private fetchText;
|
|
27
|
+
}
|
|
28
|
+
export declare function initFederalRegisterService(config: AppConfig, storage: StorageService): void;
|
|
29
|
+
export declare function getFederalRegisterService(): FederalRegisterService;
|
|
30
|
+
//# sourceMappingURL=federal-register-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"federal-register-service.d.ts","sourceRoot":"","sources":["../../../src/services/federal-register/federal-register-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAO/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAIrE,OAAO,KAAK,EAEV,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAGhB,kBAAkB,EAClB,oBAAoB,EAGrB,MAAM,YAAY,CAAC;AA+CpB,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc;IAIxD,iFAAiF;IAC3E,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA+B7E,gFAAgF;IAC1E,WAAW,CACf,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,OAAO,EACxB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,gBAAgB,CAAC;IA0C5B,kFAAkF;IAC5E,gBAAgB,CACpB,MAAM,EAAE,kBAAkB,EAC1B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,oBAAoB,CAAC;IA8BhC,+EAA+E;IAC/E,OAAO,CAAC,SAAS;IAiBjB,mDAAmD;IACnD,OAAO,CAAC,SAAS;CAUlB;AA+ED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAE3F;AAED,wBAAgB,yBAAyB,IAAI,sBAAsB,CAOlE"}
|