@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,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview regulations_browse_cfr — navigate the CFR hierarchy (structure
|
|
3
|
+
* mode) or full-text-search the codified CFR (search mode) via eCFR. Search runs
|
|
4
|
+
* against the local mirror's FTS5 index when ready, falling back to the live eCFR
|
|
5
|
+
* search API on a cold deploy. Keyless. Feeds regulations_get_cfr_section.
|
|
6
|
+
* @module mcp-server/tools/definitions/browse-cfr.tool
|
|
7
|
+
*/
|
|
8
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
9
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
10
|
+
import { getEcfrService, today } from '../../../services/ecfr/ecfr-service.js';
|
|
11
|
+
import { mirrorReady, mirrorSearch } from '../../../services/ecfr-mirror/ecfr-mirror.js';
|
|
12
|
+
const structureNode = z
|
|
13
|
+
.object({
|
|
14
|
+
type: z
|
|
15
|
+
.string()
|
|
16
|
+
.describe('Node type: title, chapter, subchapter, subpart, part, section, appendix, subject_group, or other (treat unknown types as passthrough).'),
|
|
17
|
+
identifier: z.string().describe('Node identifier (e.g. "40", "I", "50", "50.1").'),
|
|
18
|
+
label: z.string().describe('Human-readable label.'),
|
|
19
|
+
description: z.string().nullable().describe('Label description, or null.'),
|
|
20
|
+
reserved: z.boolean().describe('True when the node is reserved/empty.'),
|
|
21
|
+
cfrCite: z
|
|
22
|
+
.string()
|
|
23
|
+
.nullable()
|
|
24
|
+
.describe('Assembled cite for a part/section → regulations_get_cfr_section; null otherwise.'),
|
|
25
|
+
})
|
|
26
|
+
.describe('One hierarchy node.');
|
|
27
|
+
const searchHit = z
|
|
28
|
+
.object({
|
|
29
|
+
title: z.number().describe('CFR title number.'),
|
|
30
|
+
part: z.string().describe('CFR part.'),
|
|
31
|
+
section: z.string().nullable().describe('Section identifier, or null.'),
|
|
32
|
+
heading: z.string().describe('Section/part heading.'),
|
|
33
|
+
hierarchyPath: z.string().describe('Human-readable hierarchy path.'),
|
|
34
|
+
excerpt: z.string().describe('Matched text snippet.'),
|
|
35
|
+
cfrCite: z.string().describe('Assembled cite → regulations_get_cfr_section.'),
|
|
36
|
+
})
|
|
37
|
+
.describe('One matching CFR section.');
|
|
38
|
+
export const browseCfrTool = tool('regulations_browse_cfr', {
|
|
39
|
+
title: 'regulations_browse_cfr',
|
|
40
|
+
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. The source (mirror or live) is reported on each search result.',
|
|
41
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
42
|
+
input: z.object({
|
|
43
|
+
mode: z
|
|
44
|
+
.enum(['structure', 'search'])
|
|
45
|
+
.describe('"structure": browse the CFR tree (titles, or one title\'s chapters/parts/sections) to find a cite. "search": full-text search the codified CFR for sections matching a phrase.'),
|
|
46
|
+
title: z
|
|
47
|
+
.number()
|
|
48
|
+
.int()
|
|
49
|
+
.min(1)
|
|
50
|
+
.max(50)
|
|
51
|
+
.optional()
|
|
52
|
+
.describe('CFR title number (1–50). Structure mode: omit to list all 50 titles, or provide to expand one title. Search mode: optional filter to restrict to one title.'),
|
|
53
|
+
part: z
|
|
54
|
+
.string()
|
|
55
|
+
.optional()
|
|
56
|
+
.describe("CFR part within the title (structure mode, optional) — narrows the returned tree to one part's sections. Parts can be alphanumeric."),
|
|
57
|
+
query: z
|
|
58
|
+
.union([z.literal(''), z.string().min(2).describe('Search phrase, at least 2 characters.')])
|
|
59
|
+
.optional()
|
|
60
|
+
.describe('Full-text search phrase (search mode, required in that mode). Ignored in structure mode.'),
|
|
61
|
+
date: z
|
|
62
|
+
.union([
|
|
63
|
+
z.literal(''),
|
|
64
|
+
z
|
|
65
|
+
.string()
|
|
66
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
67
|
+
.describe('ISO 8601 date (YYYY-MM-DD).'),
|
|
68
|
+
])
|
|
69
|
+
.optional()
|
|
70
|
+
.describe('Point-in-time date, ISO 8601 (YYYY-MM-DD). Defaults to current. Structure mode uses this date for historical hierarchy; in search mode, a past date enables point-in-time search.'),
|
|
71
|
+
per_page: z
|
|
72
|
+
.number()
|
|
73
|
+
.int()
|
|
74
|
+
.min(1)
|
|
75
|
+
.max(50)
|
|
76
|
+
.optional()
|
|
77
|
+
.default(20)
|
|
78
|
+
.describe('Results per page in search mode (1–50, default 20). Ignored in structure mode.'),
|
|
79
|
+
}),
|
|
80
|
+
output: z.object({
|
|
81
|
+
mode: z.enum(['structure', 'search']).describe('Which mode produced this result.'),
|
|
82
|
+
date: z.string().optional().describe('Resolved point-in-time date (structure mode).'),
|
|
83
|
+
nodes: z
|
|
84
|
+
.array(structureNode)
|
|
85
|
+
.optional()
|
|
86
|
+
.describe('Hierarchy nodes at the requested level (structure mode).'),
|
|
87
|
+
source: z
|
|
88
|
+
.enum(['mirror', 'live'])
|
|
89
|
+
.optional()
|
|
90
|
+
.describe('Provenance: the synced mirror index, or the live eCFR search fallback (search mode).'),
|
|
91
|
+
results: z
|
|
92
|
+
.array(searchHit)
|
|
93
|
+
.optional()
|
|
94
|
+
.describe('Matching CFR sections, this page (search mode).'),
|
|
95
|
+
}),
|
|
96
|
+
enrichment: {
|
|
97
|
+
totalCount: z
|
|
98
|
+
.number()
|
|
99
|
+
.optional()
|
|
100
|
+
.describe('Total search matches before pagination (search mode).'),
|
|
101
|
+
truncated: z.boolean().optional().describe('True when search results were capped at per_page.'),
|
|
102
|
+
shown: z.number().optional().describe('Results returned on this page (search mode).'),
|
|
103
|
+
notice: z.string().optional().describe('Guidance when nothing matched.'),
|
|
104
|
+
},
|
|
105
|
+
errors: [
|
|
106
|
+
{
|
|
107
|
+
reason: 'query_required',
|
|
108
|
+
code: JsonRpcErrorCode.InvalidParams,
|
|
109
|
+
when: 'mode="search" with no query phrase.',
|
|
110
|
+
recovery: 'Provide a query phrase for search mode, or switch to mode="structure" to browse.',
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
reason: 'title_not_found',
|
|
114
|
+
code: JsonRpcErrorCode.NotFound,
|
|
115
|
+
when: 'Structure mode with a title outside 1–50, or a part not found in the title.',
|
|
116
|
+
recovery: 'Omit title to list all titles, or pick a number in 1–50 and a part that exists.',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
reason: 'no_results',
|
|
120
|
+
code: JsonRpcErrorCode.NotFound,
|
|
121
|
+
when: 'Search mode returned zero matches.',
|
|
122
|
+
recovery: 'Broaden the phrase or drop the title filter and retry.',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
reason: 'upstream_unavailable',
|
|
126
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
127
|
+
when: 'eCFR returned a 5xx, timed out, or served an HTML error page (live path).',
|
|
128
|
+
recovery: 'Retry after a brief wait; the eCFR API may be momentarily down.',
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
async handler(input, ctx) {
|
|
132
|
+
const service = getEcfrService();
|
|
133
|
+
if (input.mode === 'structure') {
|
|
134
|
+
if (input.title === undefined) {
|
|
135
|
+
const nodes = await service.listTitleNodes(ctx);
|
|
136
|
+
return { mode: 'structure', date: input.date || today(), nodes };
|
|
137
|
+
}
|
|
138
|
+
// The eCFR versioner 404s when the date is past the title's most recent
|
|
139
|
+
// issue date (e.g. "today" before a title's next amendment publishes), so
|
|
140
|
+
// resolve an explicit-free request to the title's latest issue date rather
|
|
141
|
+
// than today(). A user-supplied historical date is honored as given.
|
|
142
|
+
const date = input.date || (await service.latestIssueDate(input.title, ctx));
|
|
143
|
+
const nodes = await service.browseStructure(input.title, input.part || undefined, date, ctx);
|
|
144
|
+
return { mode: 'structure', date, nodes };
|
|
145
|
+
}
|
|
146
|
+
// search mode
|
|
147
|
+
const query = input.query?.trim();
|
|
148
|
+
if (!query) {
|
|
149
|
+
throw ctx.fail('query_required', undefined, { ...ctx.recoveryFor('query_required') });
|
|
150
|
+
}
|
|
151
|
+
const ready = await mirrorReady();
|
|
152
|
+
const useMirror = ready && !input.date;
|
|
153
|
+
const response = useMirror
|
|
154
|
+
? await mirrorSearch(query, input.title, input.per_page)
|
|
155
|
+
: await service.search(query, input.title, input.per_page, ctx);
|
|
156
|
+
ctx.enrich.total(response.totalCount);
|
|
157
|
+
if (response.results.length === 0) {
|
|
158
|
+
ctx.enrich.notice(`No CFR sections matched "${query}". Broaden the phrase or drop the title filter.`);
|
|
159
|
+
return {
|
|
160
|
+
mode: 'search',
|
|
161
|
+
source: useMirror ? 'mirror' : 'live',
|
|
162
|
+
results: [],
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
if (response.results.length >= input.per_page && response.totalCount > input.per_page) {
|
|
166
|
+
ctx.enrich.truncated({
|
|
167
|
+
shown: response.results.length,
|
|
168
|
+
cap: input.per_page,
|
|
169
|
+
guidance: `${response.totalCount} total matches. Raise per_page (max 50) or narrow the phrase.`,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
mode: 'search',
|
|
174
|
+
source: useMirror ? 'mirror' : 'live',
|
|
175
|
+
results: response.results,
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
format: (result) => {
|
|
179
|
+
const lines = [];
|
|
180
|
+
// Render by field presence (not `mode`): structure and search results are
|
|
181
|
+
// mutually exclusive at runtime, so a real payload renders exactly one block.
|
|
182
|
+
if (result.nodes) {
|
|
183
|
+
lines.push(`**CFR structure** (mode: ${result.mode}, as of ${result.date ?? 'current'})`);
|
|
184
|
+
lines.push('');
|
|
185
|
+
for (const n of result.nodes) {
|
|
186
|
+
const reserved = n.reserved ? ' _(reserved)_' : '';
|
|
187
|
+
const cite = n.cfrCite ? ` — \`${n.cfrCite}\` → regulations_get_cfr_section` : '';
|
|
188
|
+
const desc = n.description && n.description !== n.label ? ` — ${n.description}` : '';
|
|
189
|
+
lines.push(`- **${n.type}** ${n.identifier}: ${n.label}${desc}${reserved}${cite}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (result.results || result.source) {
|
|
193
|
+
lines.push(`**CFR full-text search** (mode: ${result.mode}, source: ${result.source ?? 'live'})`);
|
|
194
|
+
lines.push('');
|
|
195
|
+
for (const h of result.results ?? []) {
|
|
196
|
+
lines.push(`### ${h.cfrCite} — ${h.heading} [Title ${h.title}, Part ${h.part}, § ${h.section ?? 'n/a'}]`);
|
|
197
|
+
lines.push(`_${h.hierarchyPath}_`);
|
|
198
|
+
lines.push(h.excerpt);
|
|
199
|
+
lines.push('');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return [{ type: 'text', text: lines.join('\n').trim() }];
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
//# sourceMappingURL=browse-cfr.tool.js.map
|
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview regulations_find_comments — fetch public comments on a Federal
|
|
3
|
+
* Register document or a Regulations.gov docket, or one comment's full detail and
|
|
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.
|
|
7
|
+
* @module mcp-server/tools/definitions/find-comments.tool
|
|
8
|
+
*/
|
|
9
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
10
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
11
|
+
export declare const findCommentsTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
12
|
+
docket_id: z.ZodOptional<z.ZodString>;
|
|
13
|
+
document_object_id: z.ZodOptional<z.ZodString>;
|
|
14
|
+
fr_document_number: z.ZodOptional<z.ZodString>;
|
|
15
|
+
comment_id: z.ZodOptional<z.ZodString>;
|
|
16
|
+
per_page: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
17
|
+
page: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
18
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
19
|
+
mode: z.ZodEnum<{
|
|
20
|
+
list: "list";
|
|
21
|
+
detail: "detail";
|
|
22
|
+
}>;
|
|
23
|
+
target: z.ZodOptional<z.ZodString>;
|
|
24
|
+
comments: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
25
|
+
commentId: z.ZodString;
|
|
26
|
+
title: z.ZodString;
|
|
27
|
+
documentType: z.ZodString;
|
|
28
|
+
postedDate: z.ZodString;
|
|
29
|
+
agencyId: z.ZodNullable<z.ZodString>;
|
|
30
|
+
objectId: z.ZodString;
|
|
31
|
+
withdrawn: z.ZodBoolean;
|
|
32
|
+
}, z.core.$strip>>>;
|
|
33
|
+
commentId: z.ZodOptional<z.ZodString>;
|
|
34
|
+
title: z.ZodOptional<z.ZodString>;
|
|
35
|
+
docketId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
36
|
+
commentOnDocumentId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
37
|
+
postedDate: z.ZodOptional<z.ZodString>;
|
|
38
|
+
receivedDate: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
39
|
+
submitterName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
40
|
+
organization: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
41
|
+
bodyText: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
42
|
+
attachmentOnly: z.ZodOptional<z.ZodBoolean>;
|
|
43
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
44
|
+
title: z.ZodString;
|
|
45
|
+
formats: z.ZodArray<z.ZodObject<{
|
|
46
|
+
format: z.ZodString;
|
|
47
|
+
fileUrl: z.ZodString;
|
|
48
|
+
size: z.ZodNullable<z.ZodNumber>;
|
|
49
|
+
}, z.core.$strip>>;
|
|
50
|
+
}, z.core.$strip>>>;
|
|
51
|
+
withdrawn: z.ZodOptional<z.ZodBoolean>;
|
|
52
|
+
restrictReason: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
53
|
+
}, z.core.$strip>, readonly [{
|
|
54
|
+
readonly reason: "auth_required";
|
|
55
|
+
readonly code: JsonRpcErrorCode.Unauthorized;
|
|
56
|
+
readonly when: "REGULATIONS_GOV_API_KEY is not configured.";
|
|
57
|
+
readonly recovery: "Set the REGULATIONS_GOV_API_KEY env var (free key at https://api.data.gov/signup/). The Federal Register and eCFR tools work without it.";
|
|
58
|
+
}, {
|
|
59
|
+
readonly reason: "target_required";
|
|
60
|
+
readonly code: JsonRpcErrorCode.InvalidParams;
|
|
61
|
+
readonly when: "None of docket_id / document_object_id / fr_document_number / comment_id was given.";
|
|
62
|
+
readonly recovery: "Provide one targeting parameter — a docket ID, a document object ID, an FR document number, or a comment ID.";
|
|
63
|
+
}, {
|
|
64
|
+
readonly reason: "not_found";
|
|
65
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
66
|
+
readonly when: "The target docket/document/comment has no comments or does not exist.";
|
|
67
|
+
readonly recovery: "Verify the ID; comments often attach to the docket's primary document — try docket_id to widen, or check the docket reached its comment period.";
|
|
68
|
+
}, {
|
|
69
|
+
readonly reason: "rate_limited";
|
|
70
|
+
readonly code: JsonRpcErrorCode.RateLimited;
|
|
71
|
+
readonly when: "Regulations.gov returned 429.";
|
|
72
|
+
readonly retryable: true;
|
|
73
|
+
readonly recovery: "Wait and retry — the per-key hourly limit (1,000/hr) was hit.";
|
|
74
|
+
}, {
|
|
75
|
+
readonly reason: "upstream_unavailable";
|
|
76
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
77
|
+
readonly when: "Regulations.gov returned a 5xx or timed out.";
|
|
78
|
+
readonly recovery: "Retry after a brief wait.";
|
|
79
|
+
}], {
|
|
80
|
+
readonly totalCount: z.ZodOptional<z.ZodNumber>;
|
|
81
|
+
readonly truncated: z.ZodOptional<z.ZodBoolean>;
|
|
82
|
+
readonly shown: z.ZodOptional<z.ZodNumber>;
|
|
83
|
+
readonly notice: z.ZodOptional<z.ZodString>;
|
|
84
|
+
}>;
|
|
85
|
+
//# sourceMappingURL=find-comments.tool.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview regulations_find_comments — fetch public comments on a Federal
|
|
3
|
+
* Register document or a Regulations.gov docket, or one comment's full detail and
|
|
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.
|
|
7
|
+
* @module mcp-server/tools/definitions/find-comments.tool
|
|
8
|
+
*/
|
|
9
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
10
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
11
|
+
import { getRegulationsGovService } from '../../../services/regulations-gov/regulations-gov-service.js';
|
|
12
|
+
import { escapePipes } from './format-utils.js';
|
|
13
|
+
export const findCommentsTool = tool('regulations_find_comments', {
|
|
14
|
+
title: 'regulations_find_comments',
|
|
15
|
+
description: "Fetch public comments on a Federal Register document or a Regulations.gov docket — the unique corpus of what citizens and organizations actually submitted. Provide exactly one targeting parameter: docket_id (all comments in a docket, broadest), document_object_id (comments on one document, from regulations_get_docket), fr_document_number (convenience — resolves the FR number to its Regulations.gov document internally), or comment_id (one comment's full detail and attachments). The list endpoint returns no body text or attachment info — call with comment_id to read a comment's body. 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. Requires REGULATIONS_GOV_API_KEY (free at https://api.data.gov/signup/).",
|
|
16
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
17
|
+
input: z.object({
|
|
18
|
+
docket_id: z
|
|
19
|
+
.string()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Fetch all comments in a docket by docket ID (e.g. "EPA-HQ-OAR-2025-0194"). Broadest scope. One of docket_id / document_object_id / fr_document_number / comment_id is required.'),
|
|
22
|
+
document_object_id: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Fetch comments on one specific document by its Regulations.gov object ID (the objectId from regulations_get_docket's documents). Comments usually attach to the docket's primary (proposed-rule) document."),
|
|
26
|
+
fr_document_number: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('Convenience: fetch comments for a Federal Register document by its FR number (e.g. "2025-14555"). Resolves to the Regulations.gov document internally. Saves a get_document → get_docket hop.'),
|
|
30
|
+
comment_id: z
|
|
31
|
+
.string()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe('Fetch one comment\'s full detail and attachments by its Regulations.gov comment ID (e.g. "EPA-HQ-OAR-2025-0194-31102"). Use to read a single comment\'s body after finding it in a list.'),
|
|
34
|
+
per_page: z
|
|
35
|
+
.number()
|
|
36
|
+
.int()
|
|
37
|
+
.min(5)
|
|
38
|
+
.max(250)
|
|
39
|
+
.optional()
|
|
40
|
+
.default(25)
|
|
41
|
+
.describe('Comments per page (5–250, default 25). Regulations.gov requires a minimum page size of 5.'),
|
|
42
|
+
page: z
|
|
43
|
+
.number()
|
|
44
|
+
.int()
|
|
45
|
+
.min(1)
|
|
46
|
+
.max(20)
|
|
47
|
+
.optional()
|
|
48
|
+
.default(1)
|
|
49
|
+
.describe('Page number (1-based). Regulations.gov caps a query at 20 pages (5,000 records); for a high-volume docket this surfaces a sample — narrow by document_object_id.'),
|
|
50
|
+
}),
|
|
51
|
+
output: z.object({
|
|
52
|
+
mode: z.enum(['list', 'detail']).describe('Which mode produced this result.'),
|
|
53
|
+
// --- list mode ---
|
|
54
|
+
target: z
|
|
55
|
+
.string()
|
|
56
|
+
.optional()
|
|
57
|
+
.describe('What was queried — docket / document / FR doc (list mode).'),
|
|
58
|
+
comments: z
|
|
59
|
+
.array(z
|
|
60
|
+
.object({
|
|
61
|
+
commentId: z.string().describe('Comment ID — chains into comment_id for full detail.'),
|
|
62
|
+
title: z.string().describe('Comment title (e.g. "Comment from Gates, Andrew").'),
|
|
63
|
+
documentType: z.string().describe('Document type (e.g. "Public Submission").'),
|
|
64
|
+
postedDate: z.string().describe('Posted date.'),
|
|
65
|
+
agencyId: z.string().nullable().describe('Agency ID, or null.'),
|
|
66
|
+
objectId: z.string().describe('Comment object ID.'),
|
|
67
|
+
withdrawn: z.boolean().describe('True when the comment was withdrawn.'),
|
|
68
|
+
})
|
|
69
|
+
.describe('One comment summary.'))
|
|
70
|
+
.optional()
|
|
71
|
+
.describe('Comments matching the target, this page (list mode). Bodies/attachments require comment_id detail mode.'),
|
|
72
|
+
// --- detail mode ---
|
|
73
|
+
commentId: z.string().optional().describe('Comment ID (detail mode).'),
|
|
74
|
+
title: z.string().optional().describe('Comment title (detail mode).'),
|
|
75
|
+
docketId: z.string().nullable().optional().describe('Docket ID, or null (detail mode).'),
|
|
76
|
+
commentOnDocumentId: z
|
|
77
|
+
.string()
|
|
78
|
+
.nullable()
|
|
79
|
+
.optional()
|
|
80
|
+
.describe('Document the comment was filed on, or null (detail mode).'),
|
|
81
|
+
postedDate: z.string().optional().describe('Posted date (detail mode).'),
|
|
82
|
+
receivedDate: z
|
|
83
|
+
.string()
|
|
84
|
+
.nullable()
|
|
85
|
+
.optional()
|
|
86
|
+
.describe('Received date, or null (detail mode).'),
|
|
87
|
+
submitterName: z
|
|
88
|
+
.string()
|
|
89
|
+
.nullable()
|
|
90
|
+
.optional()
|
|
91
|
+
.describe('Submitter name when public, or null (detail mode).'),
|
|
92
|
+
organization: z
|
|
93
|
+
.string()
|
|
94
|
+
.nullable()
|
|
95
|
+
.optional()
|
|
96
|
+
.describe('Submitter organization, or null (detail mode).'),
|
|
97
|
+
bodyText: z
|
|
98
|
+
.string()
|
|
99
|
+
.nullable()
|
|
100
|
+
.optional()
|
|
101
|
+
.describe('Comment body, HTML-stripped. A stub ("See Attached") when content is in attachments; null when empty (detail mode).'),
|
|
102
|
+
attachmentOnly: z
|
|
103
|
+
.boolean()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe('True when attachments exist and the body is a stub/empty — the substance is in the attachment files (detail mode).'),
|
|
106
|
+
attachments: z
|
|
107
|
+
.array(z
|
|
108
|
+
.object({
|
|
109
|
+
title: z.string().describe('Attachment title.'),
|
|
110
|
+
formats: z
|
|
111
|
+
.array(z
|
|
112
|
+
.object({
|
|
113
|
+
format: z.string().describe('File format (e.g. "pdf").'),
|
|
114
|
+
fileUrl: z.string().describe('Download URL.'),
|
|
115
|
+
size: z.number().nullable().describe('File size in bytes, or null.'),
|
|
116
|
+
})
|
|
117
|
+
.describe('One downloadable file format.'))
|
|
118
|
+
.describe('Available file formats for the attachment.'),
|
|
119
|
+
})
|
|
120
|
+
.describe('One attachment with its available formats.'))
|
|
121
|
+
.optional()
|
|
122
|
+
.describe('Attachment files — substance lives here when attachmentOnly is true (detail mode).'),
|
|
123
|
+
withdrawn: z
|
|
124
|
+
.boolean()
|
|
125
|
+
.optional()
|
|
126
|
+
.describe('True when the comment was withdrawn (detail mode).'),
|
|
127
|
+
restrictReason: z
|
|
128
|
+
.string()
|
|
129
|
+
.nullable()
|
|
130
|
+
.optional()
|
|
131
|
+
.describe('Reason the comment is restricted, or null (detail mode).'),
|
|
132
|
+
}),
|
|
133
|
+
enrichment: {
|
|
134
|
+
totalCount: z.number().optional().describe('Total comments matching the target (list mode).'),
|
|
135
|
+
truncated: z
|
|
136
|
+
.boolean()
|
|
137
|
+
.optional()
|
|
138
|
+
.describe('True when comments exceed the 5,000-record ceiling (list mode).'),
|
|
139
|
+
shown: z.number().optional().describe('Comments returned on this page (list mode).'),
|
|
140
|
+
notice: z
|
|
141
|
+
.string()
|
|
142
|
+
.optional()
|
|
143
|
+
.describe('Guidance — empty results, or that bodies need comment_id detail mode.'),
|
|
144
|
+
},
|
|
145
|
+
errors: [
|
|
146
|
+
{
|
|
147
|
+
reason: 'auth_required',
|
|
148
|
+
code: JsonRpcErrorCode.Unauthorized,
|
|
149
|
+
when: 'REGULATIONS_GOV_API_KEY is not configured.',
|
|
150
|
+
recovery: 'Set the REGULATIONS_GOV_API_KEY env var (free key at https://api.data.gov/signup/). The Federal Register and eCFR tools work without it.',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
reason: 'target_required',
|
|
154
|
+
code: JsonRpcErrorCode.InvalidParams,
|
|
155
|
+
when: 'None of docket_id / document_object_id / fr_document_number / comment_id was given.',
|
|
156
|
+
recovery: 'Provide one targeting parameter — a docket ID, a document object ID, an FR document number, or a comment ID.',
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
reason: 'not_found',
|
|
160
|
+
code: JsonRpcErrorCode.NotFound,
|
|
161
|
+
when: 'The target docket/document/comment has no comments or does not exist.',
|
|
162
|
+
recovery: "Verify the ID; comments often attach to the docket's primary document — try docket_id to widen, or check the docket reached its comment period.",
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
reason: 'rate_limited',
|
|
166
|
+
code: JsonRpcErrorCode.RateLimited,
|
|
167
|
+
when: 'Regulations.gov returned 429.',
|
|
168
|
+
retryable: true,
|
|
169
|
+
recovery: 'Wait and retry — the per-key hourly limit (1,000/hr) was hit.',
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
reason: 'upstream_unavailable',
|
|
173
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
174
|
+
when: 'Regulations.gov returned a 5xx or timed out.',
|
|
175
|
+
recovery: 'Retry after a brief wait.',
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
async handler(input, ctx) {
|
|
179
|
+
const service = getRegulationsGovService();
|
|
180
|
+
if (!service.hasKey()) {
|
|
181
|
+
throw ctx.fail('auth_required', undefined, { ...ctx.recoveryFor('auth_required') });
|
|
182
|
+
}
|
|
183
|
+
// Detail mode: one comment by ID.
|
|
184
|
+
if (input.comment_id) {
|
|
185
|
+
const detail = await service.getComment(input.comment_id, ctx);
|
|
186
|
+
if (detail.attachmentOnly) {
|
|
187
|
+
ctx.enrich.notice(`The substance of this comment is in ${detail.attachments.length} attachment(s) — see the attachment download URLs.`);
|
|
188
|
+
}
|
|
189
|
+
return { mode: 'detail', ...detail };
|
|
190
|
+
}
|
|
191
|
+
// List mode: resolve the target.
|
|
192
|
+
let filter;
|
|
193
|
+
let target;
|
|
194
|
+
if (input.document_object_id) {
|
|
195
|
+
filter = { commentOnId: input.document_object_id };
|
|
196
|
+
target = `document ${input.document_object_id}`;
|
|
197
|
+
}
|
|
198
|
+
else if (input.fr_document_number) {
|
|
199
|
+
const objectId = await service.resolveFrDocumentObjectId(input.fr_document_number, ctx);
|
|
200
|
+
if (!objectId) {
|
|
201
|
+
throw ctx.fail('not_found', `Federal Register document ${input.fr_document_number} has no Regulations.gov document to pull comments from.`, { recovery: { hint: 'Verify the FR number, or try docket_id to widen the search.' } });
|
|
202
|
+
}
|
|
203
|
+
filter = { commentOnId: objectId };
|
|
204
|
+
target = `FR document ${input.fr_document_number}`;
|
|
205
|
+
}
|
|
206
|
+
else if (input.docket_id) {
|
|
207
|
+
filter = { docketId: input.docket_id };
|
|
208
|
+
target = `docket ${input.docket_id}`;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
throw ctx.fail('target_required', undefined, { ...ctx.recoveryFor('target_required') });
|
|
212
|
+
}
|
|
213
|
+
const result = await service.listComments({ filter, perPage: input.per_page, page: input.page }, ctx);
|
|
214
|
+
ctx.enrich.total(result.totalCount);
|
|
215
|
+
if (result.comments.length === 0) {
|
|
216
|
+
ctx.enrich.notice(`No comments found for ${target}. Comments often attach to the docket's primary document — try docket_id to widen, or check the comment period has opened.`);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
const COMMENT_CEILING = 5000;
|
|
220
|
+
if (result.totalCount > COMMENT_CEILING) {
|
|
221
|
+
ctx.enrich.truncated({
|
|
222
|
+
shown: result.comments.length,
|
|
223
|
+
cap: COMMENT_CEILING,
|
|
224
|
+
guidance: `${result.totalCount} comments exceed the 5,000-record ceiling — this is a sample. Narrow by document_object_id to scope the set.`,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return { mode: 'list', target, comments: result.comments };
|
|
229
|
+
},
|
|
230
|
+
format: (result) => {
|
|
231
|
+
const lines = [];
|
|
232
|
+
// Render by field presence (not `mode`): a real payload is one mode only, so
|
|
233
|
+
// detail keys on the top-level commentId and list keys on comments[].
|
|
234
|
+
if (result.commentId !== undefined) {
|
|
235
|
+
const attachments = result.attachments ?? [];
|
|
236
|
+
lines.push(`# ${result.title ?? '(untitled comment)'}`);
|
|
237
|
+
lines.push(`Comment \`${result.commentId ?? '—'}\` · posted ${result.postedDate ?? '—'} · received ${result.receivedDate ?? '—'}`);
|
|
238
|
+
lines.push(`Submitter: ${result.submitterName ?? '—'} · organization: ${result.organization ?? '—'}`);
|
|
239
|
+
lines.push(`Docket: ${result.docketId ?? '—'} · on document: ${result.commentOnDocumentId ?? '—'}`);
|
|
240
|
+
lines.push(`attachmentOnly: ${result.attachmentOnly ? 'yes' : 'no'} · withdrawn: ${result.withdrawn ? 'yes' : 'no'} · restrictReason: ${result.restrictReason ?? 'none'}`);
|
|
241
|
+
lines.push('');
|
|
242
|
+
if (result.attachmentOnly) {
|
|
243
|
+
lines.push(`> The substance of this comment is in ${attachments.length} attachment(s):`);
|
|
244
|
+
}
|
|
245
|
+
lines.push(result.bodyText ?? '_(no inline body text)_');
|
|
246
|
+
if (attachments.length) {
|
|
247
|
+
lines.push('\n## Attachments');
|
|
248
|
+
for (const a of attachments) {
|
|
249
|
+
const fmts = a.formats
|
|
250
|
+
.map((f) => `${f.format}: [${f.fileUrl}](${f.fileUrl}) (${f.size != null ? `${f.size} bytes` : 'size unknown'})`)
|
|
251
|
+
.join(', ');
|
|
252
|
+
lines.push(`- **${a.title}**: ${fmts}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
lines.push('');
|
|
256
|
+
}
|
|
257
|
+
if (result.comments !== undefined) {
|
|
258
|
+
lines.push(`**Comments on ${result.target ?? 'target'}**`);
|
|
259
|
+
lines.push('');
|
|
260
|
+
lines.push('| Commenter | Type | Posted | Agency | Object ID | Comment ID (→ comment_id for body) |');
|
|
261
|
+
lines.push('|---|---|---|---|---|---|');
|
|
262
|
+
for (const c of result.comments ?? []) {
|
|
263
|
+
const wd = c.withdrawn ? ' (withdrawn)' : '';
|
|
264
|
+
lines.push(`| ${escapePipes(c.title)}${wd} | ${c.documentType} | ${c.postedDate} | ${c.agencyId ?? '—'} | ${c.objectId} | \`${c.commentId}\` |`);
|
|
265
|
+
}
|
|
266
|
+
lines.push('\n_Comment bodies and attachments are only available via detail mode (pass comment_id)._');
|
|
267
|
+
}
|
|
268
|
+
return [{ type: 'text', text: lines.join('\n').trim() }];
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
//# sourceMappingURL=find-comments.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-comments.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/find-comments.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared formatting helpers for tool format() renderers.
|
|
3
|
+
* @module mcp-server/tools/definitions/format-utils
|
|
4
|
+
*/
|
|
5
|
+
/** Escape `|` so cell content doesn't break markdown tables. */
|
|
6
|
+
export declare function escapePipes(text: string): string;
|
|
7
|
+
//# sourceMappingURL=format-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-utils.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/format-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,gEAAgE;AAChE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared formatting helpers for tool format() renderers.
|
|
3
|
+
* @module mcp-server/tools/definitions/format-utils
|
|
4
|
+
*/
|
|
5
|
+
/** Escape `|` so cell content doesn't break markdown tables. */
|
|
6
|
+
export function escapePipes(text) {
|
|
7
|
+
return text.replace(/\|/g, '\\|');
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=format-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-utils.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/format-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,gEAAgE;AAChE,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACpC,CAAC"}
|