@ansvar/eu-regulations-mcp 0.2.1 → 0.3.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/README.md +101 -7
- package/data/regulations.db +0 -0
- package/data/seed/gdpr.json +699 -1
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/recital.d.ts +13 -0
- package/dist/tools/recital.d.ts.map +1 -0
- package/dist/tools/recital.js +23 -0
- package/dist/tools/recital.js.map +1 -0
- package/dist/tools/search.d.ts +1 -0
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +55 -18
- package/dist/tools/search.js.map +1 -1
- package/package.json +1 -1
- package/scripts/build-db.ts +62 -0
- package/scripts/ingest-eurlex.ts +87 -0
- package/scripts/reingest-all-with-recitals.sh +81 -0
- package/src/index.ts +33 -0
- package/src/tools/recital.ts +48 -0
- package/src/tools/search.ts +69 -21
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { fileURLToPath } from 'url';
|
|
|
7
7
|
import { dirname, join } from 'path';
|
|
8
8
|
import { searchRegulations } from './tools/search.js';
|
|
9
9
|
import { getArticle } from './tools/article.js';
|
|
10
|
+
import { getRecital } from './tools/recital.js';
|
|
10
11
|
import { listRegulations } from './tools/list.js';
|
|
11
12
|
import { compareRequirements } from './tools/compare.js';
|
|
12
13
|
import { mapControls } from './tools/map.js';
|
|
@@ -80,6 +81,24 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
80
81
|
required: ['regulation', 'article'],
|
|
81
82
|
},
|
|
82
83
|
},
|
|
84
|
+
{
|
|
85
|
+
name: 'get_recital',
|
|
86
|
+
description: 'Retrieve the full text of a specific recital from a regulation. Recitals provide context and interpretation guidance for articles.',
|
|
87
|
+
inputSchema: {
|
|
88
|
+
type: 'object',
|
|
89
|
+
properties: {
|
|
90
|
+
regulation: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
description: 'Regulation ID (e.g., "GDPR", "NIS2", "DORA")',
|
|
93
|
+
},
|
|
94
|
+
recital_number: {
|
|
95
|
+
type: 'number',
|
|
96
|
+
description: 'Recital number (e.g., 1, 83)',
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
required: ['regulation', 'recital_number'],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
83
102
|
{
|
|
84
103
|
name: 'list_regulations',
|
|
85
104
|
description: 'List available regulations and their structure. Without parameters, lists all regulations. With a regulation specified, shows chapters and articles.',
|
|
@@ -209,6 +228,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
209
228
|
content: [{ type: 'text', text: JSON.stringify(article, null, 2) }],
|
|
210
229
|
};
|
|
211
230
|
}
|
|
231
|
+
case 'get_recital': {
|
|
232
|
+
const input = args;
|
|
233
|
+
const recital = await getRecital(database, input);
|
|
234
|
+
if (!recital) {
|
|
235
|
+
return {
|
|
236
|
+
content: [{ type: 'text', text: `Recital ${input.recital_number} not found in ${input.regulation}` }],
|
|
237
|
+
isError: true,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
content: [{ type: 'text', text: JSON.stringify(recital, null, 2) }],
|
|
242
|
+
};
|
|
243
|
+
}
|
|
212
244
|
case 'list_regulations': {
|
|
213
245
|
const input = (args ?? {});
|
|
214
246
|
const result = await listRegulations(database, input);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
export interface GetRecitalInput {
|
|
3
|
+
regulation: string;
|
|
4
|
+
recital_number: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Recital {
|
|
7
|
+
regulation: string;
|
|
8
|
+
recital_number: number;
|
|
9
|
+
text: string;
|
|
10
|
+
related_articles: string[] | null;
|
|
11
|
+
}
|
|
12
|
+
export declare function getRecital(db: Database, input: GetRecitalInput): Promise<Recital | null>;
|
|
13
|
+
//# sourceMappingURL=recital.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recital.d.ts","sourceRoot":"","sources":["../../src/tools/recital.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CACnC;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA8BzB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export async function getRecital(db, input) {
|
|
2
|
+
const { regulation, recital_number } = input;
|
|
3
|
+
const sql = `
|
|
4
|
+
SELECT
|
|
5
|
+
regulation,
|
|
6
|
+
recital_number,
|
|
7
|
+
text,
|
|
8
|
+
related_articles
|
|
9
|
+
FROM recitals
|
|
10
|
+
WHERE regulation = ? AND recital_number = ?
|
|
11
|
+
`;
|
|
12
|
+
const row = db.prepare(sql).get(regulation, recital_number);
|
|
13
|
+
if (!row) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
regulation: row.regulation,
|
|
18
|
+
recital_number: row.recital_number,
|
|
19
|
+
text: row.text,
|
|
20
|
+
related_articles: row.related_articles ? JSON.parse(row.related_articles) : null,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=recital.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recital.js","sourceRoot":"","sources":["../../src/tools/recital.ts"],"names":[],"mappings":"AAcA,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,EAAY,EACZ,KAAsB;IAEtB,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC;IAE7C,MAAM,GAAG,GAAG;;;;;;;;GAQX,CAAC;IAEF,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,cAAc,CAK7C,CAAC;IAEd,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,gBAAgB,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI;KACjF,CAAC;AACJ,CAAC"}
|
package/dist/tools/search.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface SearchResult {
|
|
|
10
10
|
title: string;
|
|
11
11
|
snippet: string;
|
|
12
12
|
relevance: number;
|
|
13
|
+
type?: 'article' | 'recital';
|
|
13
14
|
}
|
|
14
15
|
export declare function searchRegulations(db: Database, input: SearchInput): Promise<SearchResult[]>;
|
|
15
16
|
//# sourceMappingURL=search.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CAC9B;AAiBD,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CA2GzB"}
|
package/dist/tools/search.js
CHANGED
|
@@ -21,35 +21,72 @@ export async function searchRegulations(db, input) {
|
|
|
21
21
|
if (!escapedQuery) {
|
|
22
22
|
return [];
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const params = [escapedQuery];
|
|
25
|
+
// Build optional regulation filter
|
|
26
|
+
let regulationFilter = '';
|
|
27
|
+
if (regulations && regulations.length > 0) {
|
|
28
|
+
const placeholders = regulations.map(() => '?').join(', ');
|
|
29
|
+
regulationFilter = ` AND regulation IN (${placeholders})`;
|
|
30
|
+
params.push(...regulations);
|
|
31
|
+
}
|
|
32
|
+
// Search in articles
|
|
33
|
+
const articlesQuery = `
|
|
26
34
|
SELECT
|
|
27
35
|
articles_fts.regulation,
|
|
28
36
|
articles_fts.article_number as article,
|
|
29
37
|
articles_fts.title,
|
|
30
38
|
snippet(articles_fts, 3, '>>>', '<<<', '...', 32) as snippet,
|
|
31
|
-
bm25(articles_fts) as relevance
|
|
39
|
+
bm25(articles_fts) as relevance,
|
|
40
|
+
'article' as type
|
|
32
41
|
FROM articles_fts
|
|
33
42
|
WHERE articles_fts MATCH ?
|
|
43
|
+
${regulationFilter}
|
|
44
|
+
ORDER BY bm25(articles_fts)
|
|
45
|
+
LIMIT ?
|
|
46
|
+
`;
|
|
47
|
+
// Search in recitals
|
|
48
|
+
const recitalsQuery = `
|
|
49
|
+
SELECT
|
|
50
|
+
recitals_fts.regulation,
|
|
51
|
+
CAST(recitals_fts.recital_number AS TEXT) as article,
|
|
52
|
+
'Recital ' || recitals_fts.recital_number as title,
|
|
53
|
+
snippet(recitals_fts, 2, '>>>', '<<<', '...', 32) as snippet,
|
|
54
|
+
bm25(recitals_fts) as relevance,
|
|
55
|
+
'recital' as type
|
|
56
|
+
FROM recitals_fts
|
|
57
|
+
WHERE recitals_fts MATCH ?
|
|
58
|
+
${regulationFilter}
|
|
59
|
+
ORDER BY bm25(recitals_fts)
|
|
60
|
+
LIMIT ?
|
|
34
61
|
`;
|
|
35
|
-
const params = [escapedQuery];
|
|
36
|
-
if (regulations && regulations.length > 0) {
|
|
37
|
-
const placeholders = regulations.map(() => '?').join(', ');
|
|
38
|
-
sql += ` AND articles_fts.regulation IN (${placeholders})`;
|
|
39
|
-
params.push(...regulations);
|
|
40
|
-
}
|
|
41
|
-
// Order by relevance (bm25 returns negative scores, more negative = more relevant)
|
|
42
|
-
sql += ` ORDER BY bm25(articles_fts)`;
|
|
43
|
-
sql += ` LIMIT ?`;
|
|
44
|
-
params.push(limit);
|
|
45
62
|
try {
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
63
|
+
// Execute both queries
|
|
64
|
+
const articlesParams = [...params, limit];
|
|
65
|
+
const recitalsParams = [...params, limit];
|
|
66
|
+
const articleStmt = db.prepare(articlesQuery);
|
|
67
|
+
const recitalStmt = db.prepare(recitalsQuery);
|
|
68
|
+
const articleRows = articleStmt.all(...articlesParams);
|
|
69
|
+
const recitalRows = recitalStmt.all(...recitalsParams);
|
|
70
|
+
// Combine and sort by relevance, prioritizing articles
|
|
71
|
+
const combined = [...articleRows, ...recitalRows]
|
|
72
|
+
.map(row => ({
|
|
50
73
|
...row,
|
|
51
74
|
relevance: Math.abs(row.relevance),
|
|
52
|
-
}))
|
|
75
|
+
}))
|
|
76
|
+
.sort((a, b) => {
|
|
77
|
+
// First sort by relevance
|
|
78
|
+
if (Math.abs(a.relevance - b.relevance) > 0.01) {
|
|
79
|
+
return b.relevance - a.relevance;
|
|
80
|
+
}
|
|
81
|
+
// If relevance is similar, prioritize articles over recitals
|
|
82
|
+
if (a.type === 'article' && b.type === 'recital')
|
|
83
|
+
return -1;
|
|
84
|
+
if (a.type === 'recital' && b.type === 'article')
|
|
85
|
+
return 1;
|
|
86
|
+
return 0;
|
|
87
|
+
})
|
|
88
|
+
.slice(0, limit);
|
|
89
|
+
return combined;
|
|
53
90
|
}
|
|
54
91
|
catch (error) {
|
|
55
92
|
// If FTS5 query fails (e.g., syntax error), return empty results
|
package/dist/tools/search.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ansvar/eu-regulations-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "The first open-source MCP server for European cybersecurity regulations. Query DORA, NIS2, GDPR, EU AI Act, and more directly from Claude.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
package/scripts/build-db.ts
CHANGED
|
@@ -114,6 +114,43 @@ CREATE TABLE IF NOT EXISTS source_registry (
|
|
|
114
114
|
quality_status TEXT CHECK(quality_status IN ('complete', 'review', 'incomplete')),
|
|
115
115
|
notes TEXT
|
|
116
116
|
);
|
|
117
|
+
|
|
118
|
+
-- Recitals table
|
|
119
|
+
CREATE TABLE IF NOT EXISTS recitals (
|
|
120
|
+
id INTEGER PRIMARY KEY,
|
|
121
|
+
regulation TEXT NOT NULL REFERENCES regulations(id),
|
|
122
|
+
recital_number INTEGER NOT NULL,
|
|
123
|
+
text TEXT NOT NULL,
|
|
124
|
+
related_articles TEXT,
|
|
125
|
+
UNIQUE(regulation, recital_number)
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
-- FTS5 virtual table for recital search
|
|
129
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS recitals_fts USING fts5(
|
|
130
|
+
regulation,
|
|
131
|
+
recital_number,
|
|
132
|
+
text,
|
|
133
|
+
content='recitals',
|
|
134
|
+
content_rowid='id'
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
-- FTS5 triggers for recitals
|
|
138
|
+
CREATE TRIGGER IF NOT EXISTS recitals_ai AFTER INSERT ON recitals BEGIN
|
|
139
|
+
INSERT INTO recitals_fts(rowid, regulation, recital_number, text)
|
|
140
|
+
VALUES (new.id, new.regulation, new.recital_number, new.text);
|
|
141
|
+
END;
|
|
142
|
+
|
|
143
|
+
CREATE TRIGGER IF NOT EXISTS recitals_ad AFTER DELETE ON recitals BEGIN
|
|
144
|
+
INSERT INTO recitals_fts(recitals_fts, rowid, regulation, recital_number, text)
|
|
145
|
+
VALUES('delete', old.id, old.regulation, old.recital_number, old.text);
|
|
146
|
+
END;
|
|
147
|
+
|
|
148
|
+
CREATE TRIGGER IF NOT EXISTS recitals_au AFTER UPDATE ON recitals BEGIN
|
|
149
|
+
INSERT INTO recitals_fts(recitals_fts, rowid, regulation, recital_number, text)
|
|
150
|
+
VALUES('delete', old.id, old.regulation, old.recital_number, old.text);
|
|
151
|
+
INSERT INTO recitals_fts(rowid, regulation, recital_number, text)
|
|
152
|
+
VALUES (new.id, new.regulation, new.recital_number, new.text);
|
|
153
|
+
END;
|
|
117
154
|
`;
|
|
118
155
|
|
|
119
156
|
interface RegulationSeed {
|
|
@@ -135,6 +172,11 @@ interface RegulationSeed {
|
|
|
135
172
|
definition: string;
|
|
136
173
|
article: string;
|
|
137
174
|
}>;
|
|
175
|
+
recitals?: Array<{
|
|
176
|
+
recital_number: number;
|
|
177
|
+
text: string;
|
|
178
|
+
related_articles?: string;
|
|
179
|
+
}>;
|
|
138
180
|
}
|
|
139
181
|
|
|
140
182
|
function buildDatabase() {
|
|
@@ -212,6 +254,23 @@ function buildDatabase() {
|
|
|
212
254
|
}
|
|
213
255
|
}
|
|
214
256
|
|
|
257
|
+
// Insert recitals
|
|
258
|
+
if (regulation.recitals) {
|
|
259
|
+
const insertRecital = db.prepare(`
|
|
260
|
+
INSERT OR IGNORE INTO recitals (regulation, recital_number, text, related_articles)
|
|
261
|
+
VALUES (?, ?, ?, ?)
|
|
262
|
+
`);
|
|
263
|
+
|
|
264
|
+
for (const recital of regulation.recitals) {
|
|
265
|
+
insertRecital.run(
|
|
266
|
+
regulation.id,
|
|
267
|
+
recital.recital_number,
|
|
268
|
+
recital.text,
|
|
269
|
+
recital.related_articles ? JSON.stringify(recital.related_articles) : null
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
215
274
|
// Update source registry with timestamps
|
|
216
275
|
const now = new Date().toISOString();
|
|
217
276
|
const eurLexVersion = regulation.effective_date || now.split('T')[0];
|
|
@@ -221,6 +280,9 @@ function buildDatabase() {
|
|
|
221
280
|
`).run(regulation.id, regulation.celex_id, eurLexVersion, now, regulation.articles.length, regulation.articles.length);
|
|
222
281
|
|
|
223
282
|
console.log(` Loaded ${regulation.articles.length} articles, ${regulation.definitions?.length || 0} definitions`);
|
|
283
|
+
if (regulation.recitals && regulation.recitals.length > 0) {
|
|
284
|
+
console.log(` Loaded ${regulation.recitals.length} recitals`);
|
|
285
|
+
}
|
|
224
286
|
}
|
|
225
287
|
|
|
226
288
|
// Load mappings
|
package/scripts/ingest-eurlex.ts
CHANGED
|
@@ -23,6 +23,12 @@ interface Definition {
|
|
|
23
23
|
article: string;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
interface Recital {
|
|
27
|
+
recital_number: number;
|
|
28
|
+
text: string;
|
|
29
|
+
related_articles?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
26
32
|
interface RegulationData {
|
|
27
33
|
id: string;
|
|
28
34
|
full_name: string;
|
|
@@ -31,6 +37,7 @@ interface RegulationData {
|
|
|
31
37
|
eur_lex_url: string;
|
|
32
38
|
articles: Article[];
|
|
33
39
|
definitions: Definition[];
|
|
40
|
+
recitals?: Recital[];
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
const REGULATION_METADATA: Record<string, { id: string; full_name: string; effective_date?: string }> = {
|
|
@@ -68,6 +75,80 @@ async function fetchEurLexHtml(celexId: string): Promise<string> {
|
|
|
68
75
|
return response.text();
|
|
69
76
|
}
|
|
70
77
|
|
|
78
|
+
function parseRecitals(html: string): Recital[] {
|
|
79
|
+
const dom = new JSDOM(html);
|
|
80
|
+
const doc = dom.window.document;
|
|
81
|
+
|
|
82
|
+
const recitals: Recital[] = [];
|
|
83
|
+
const allText = doc.body?.textContent || '';
|
|
84
|
+
const lines = allText.split('\n').map(l => l.trim()).filter(l => l);
|
|
85
|
+
|
|
86
|
+
let inRecitalsSection = false;
|
|
87
|
+
let currentRecital: { number: number; lines: string[] } | null = null;
|
|
88
|
+
|
|
89
|
+
for (const line of lines) {
|
|
90
|
+
// Detect start of recitals section
|
|
91
|
+
if (line.match(/^Having regard to/i) || line.match(/^Whereas:/i)) {
|
|
92
|
+
inRecitalsSection = true;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Detect end of recitals (usually "HAVE ADOPTED" or "Article 1")
|
|
97
|
+
if (line.match(/^HAVE ADOPTED/i) || line.match(/^Article\s+1$/i)) {
|
|
98
|
+
inRecitalsSection = false;
|
|
99
|
+
if (currentRecital && currentRecital.lines.length > 0) {
|
|
100
|
+
recitals.push({
|
|
101
|
+
recital_number: currentRecital.number,
|
|
102
|
+
text: currentRecital.lines.join('\n\n'),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!inRecitalsSection) continue;
|
|
109
|
+
|
|
110
|
+
// Match recital number: "(1)", "(123)", etc.
|
|
111
|
+
const recitalMatch = line.match(/^\((\d+)\)/);
|
|
112
|
+
if (recitalMatch) {
|
|
113
|
+
// Save previous recital
|
|
114
|
+
if (currentRecital && currentRecital.lines.length > 0) {
|
|
115
|
+
recitals.push({
|
|
116
|
+
recital_number: currentRecital.number,
|
|
117
|
+
text: currentRecital.lines.join('\n\n'),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Start new recital
|
|
122
|
+
currentRecital = {
|
|
123
|
+
number: parseInt(recitalMatch[1]),
|
|
124
|
+
lines: [],
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// Add remaining text after number
|
|
128
|
+
const textAfterNumber = line.substring(recitalMatch[0].length).trim();
|
|
129
|
+
if (textAfterNumber) {
|
|
130
|
+
currentRecital.lines.push(textAfterNumber);
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Add line to current recital
|
|
136
|
+
if (currentRecital && line.length > 0) {
|
|
137
|
+
currentRecital.lines.push(line);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Don't forget the last recital
|
|
142
|
+
if (currentRecital && currentRecital.lines.length > 0) {
|
|
143
|
+
recitals.push({
|
|
144
|
+
recital_number: currentRecital.number,
|
|
145
|
+
text: currentRecital.lines.join('\n\n'),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return recitals;
|
|
150
|
+
}
|
|
151
|
+
|
|
71
152
|
function parseArticles(html: string, celexId: string): { articles: Article[]; definitions: Definition[] } {
|
|
72
153
|
const dom = new JSDOM(html);
|
|
73
154
|
const doc = dom.window.document;
|
|
@@ -182,6 +263,10 @@ async function ingestRegulation(celexId: string, outputPath: string): Promise<vo
|
|
|
182
263
|
const html = await fetchEurLexHtml(celexId);
|
|
183
264
|
console.log(`Fetched ${html.length} bytes`);
|
|
184
265
|
|
|
266
|
+
// Parse recitals BEFORE articles
|
|
267
|
+
const recitals = parseRecitals(html);
|
|
268
|
+
console.log(`Parsed ${recitals.length} recitals`);
|
|
269
|
+
|
|
185
270
|
const { articles, definitions } = parseArticles(html, celexId);
|
|
186
271
|
console.log(`Parsed ${articles.length} articles, ${definitions.length} definitions`);
|
|
187
272
|
|
|
@@ -200,12 +285,14 @@ async function ingestRegulation(celexId: string, outputPath: string): Promise<vo
|
|
|
200
285
|
eur_lex_url: `https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:${celexId}`,
|
|
201
286
|
articles,
|
|
202
287
|
definitions,
|
|
288
|
+
recitals,
|
|
203
289
|
};
|
|
204
290
|
|
|
205
291
|
writeFileSync(outputPath, JSON.stringify(regulation, null, 2));
|
|
206
292
|
console.log(`\nSaved to: ${outputPath}`);
|
|
207
293
|
console.log(`Articles: ${articles.length}`);
|
|
208
294
|
console.log(`Definitions: ${definitions.length}`);
|
|
295
|
+
console.log(`Recitals: ${recitals.length}`);
|
|
209
296
|
}
|
|
210
297
|
|
|
211
298
|
// Main
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Re-ingest all 37 regulations to add recitals
|
|
4
|
+
# Run this script from the project root
|
|
5
|
+
|
|
6
|
+
echo "Re-ingesting all EU regulations with recitals..."
|
|
7
|
+
echo "This will take 5-10 minutes..."
|
|
8
|
+
echo ""
|
|
9
|
+
|
|
10
|
+
REGULATIONS=(
|
|
11
|
+
"32016R0679:gdpr"
|
|
12
|
+
"32022L2555:nis2"
|
|
13
|
+
"32022R2554:dora"
|
|
14
|
+
"32024R1689:ai-act"
|
|
15
|
+
"32024R2847:cra"
|
|
16
|
+
"32019R0881:cybersecurity-act"
|
|
17
|
+
"32025R0038:cyber_solidarity"
|
|
18
|
+
"02002L0058-20091219:eprivacy"
|
|
19
|
+
"32016L0680:led"
|
|
20
|
+
"32024R0482:eucc"
|
|
21
|
+
"02014R0910-20241018:eidas2"
|
|
22
|
+
"32023R2854:data-act"
|
|
23
|
+
"32022R2065:dsa"
|
|
24
|
+
"32022R1925:dma"
|
|
25
|
+
"32022R0868:dga"
|
|
26
|
+
"32018L1972:eecc"
|
|
27
|
+
"32025R0327:ehds"
|
|
28
|
+
"32017R0745:mdr"
|
|
29
|
+
"32017R0746:ivdr"
|
|
30
|
+
"32023R1114:mica"
|
|
31
|
+
"32015L2366:psd2"
|
|
32
|
+
"32014L0065:mifid2"
|
|
33
|
+
"32014R0600:mifir"
|
|
34
|
+
"32011L0061:aifmd"
|
|
35
|
+
"32019R2088:sfdr"
|
|
36
|
+
"32020R0852:eu_taxonomy"
|
|
37
|
+
"32023R0988:gpsr"
|
|
38
|
+
"32023R1230:machinery"
|
|
39
|
+
"32024L2853:pld"
|
|
40
|
+
"32014L0053:red"
|
|
41
|
+
"32022L2464:csrd"
|
|
42
|
+
"32024L1760:csddd"
|
|
43
|
+
"32023R0956:cbam"
|
|
44
|
+
"32023R1115:eudr"
|
|
45
|
+
"32022L2557:cer"
|
|
46
|
+
"42021X0387:un-r155"
|
|
47
|
+
"42021X0388:un-r156"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
TOTAL=${#REGULATIONS[@]}
|
|
51
|
+
CURRENT=0
|
|
52
|
+
|
|
53
|
+
for reg in "${REGULATIONS[@]}"; do
|
|
54
|
+
CURRENT=$((CURRENT + 1))
|
|
55
|
+
IFS=':' read -r celex filename <<< "$reg"
|
|
56
|
+
|
|
57
|
+
echo "[$CURRENT/$TOTAL] Re-ingesting $filename (CELEX: $celex)"
|
|
58
|
+
|
|
59
|
+
if [[ "$celex" == 42021X* ]]; then
|
|
60
|
+
# UN/ECE regulations use different ingestion script
|
|
61
|
+
npx tsx scripts/ingest-unece.ts "$celex" "data/seed/${filename}.json"
|
|
62
|
+
else
|
|
63
|
+
# EU regulations use EUR-Lex ingestion
|
|
64
|
+
npx tsx scripts/ingest-eurlex.ts "$celex" "data/seed/${filename}.json"
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
if [ $? -ne 0 ]; then
|
|
68
|
+
echo " ⚠️ Warning: Failed to ingest $filename"
|
|
69
|
+
fi
|
|
70
|
+
echo ""
|
|
71
|
+
done
|
|
72
|
+
|
|
73
|
+
echo "Re-building database..."
|
|
74
|
+
npm run build:db
|
|
75
|
+
|
|
76
|
+
echo ""
|
|
77
|
+
echo "✅ Done! Checking recital counts..."
|
|
78
|
+
sqlite3 data/regulations.db "SELECT regulation, COUNT(*) as recital_count FROM recitals GROUP BY regulation ORDER BY recital_count DESC LIMIT 10;"
|
|
79
|
+
|
|
80
|
+
echo ""
|
|
81
|
+
echo "Run 'npm test' to verify everything works."
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { dirname, join } from 'path';
|
|
|
12
12
|
|
|
13
13
|
import { searchRegulations, type SearchInput } from './tools/search.js';
|
|
14
14
|
import { getArticle, type GetArticleInput } from './tools/article.js';
|
|
15
|
+
import { getRecital, type GetRecitalInput } from './tools/recital.js';
|
|
15
16
|
import { listRegulations, type ListInput } from './tools/list.js';
|
|
16
17
|
import { compareRequirements, type CompareInput } from './tools/compare.js';
|
|
17
18
|
import { mapControls, type MapControlsInput } from './tools/map.js';
|
|
@@ -93,6 +94,24 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
93
94
|
required: ['regulation', 'article'],
|
|
94
95
|
},
|
|
95
96
|
},
|
|
97
|
+
{
|
|
98
|
+
name: 'get_recital',
|
|
99
|
+
description: 'Retrieve the full text of a specific recital from a regulation. Recitals provide context and interpretation guidance for articles.',
|
|
100
|
+
inputSchema: {
|
|
101
|
+
type: 'object',
|
|
102
|
+
properties: {
|
|
103
|
+
regulation: {
|
|
104
|
+
type: 'string',
|
|
105
|
+
description: 'Regulation ID (e.g., "GDPR", "NIS2", "DORA")',
|
|
106
|
+
},
|
|
107
|
+
recital_number: {
|
|
108
|
+
type: 'number',
|
|
109
|
+
description: 'Recital number (e.g., 1, 83)',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
required: ['regulation', 'recital_number'],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
96
115
|
{
|
|
97
116
|
name: 'list_regulations',
|
|
98
117
|
description: 'List available regulations and their structure. Without parameters, lists all regulations. With a regulation specified, shows chapters and articles.',
|
|
@@ -227,6 +246,20 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
227
246
|
};
|
|
228
247
|
}
|
|
229
248
|
|
|
249
|
+
case 'get_recital': {
|
|
250
|
+
const input = args as unknown as GetRecitalInput;
|
|
251
|
+
const recital = await getRecital(database, input);
|
|
252
|
+
if (!recital) {
|
|
253
|
+
return {
|
|
254
|
+
content: [{ type: 'text', text: `Recital ${input.recital_number} not found in ${input.regulation}` }],
|
|
255
|
+
isError: true,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
content: [{ type: 'text', text: JSON.stringify(recital, null, 2) }],
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
230
263
|
case 'list_regulations': {
|
|
231
264
|
const input = (args ?? {}) as unknown as ListInput;
|
|
232
265
|
const result = await listRegulations(database, input);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
|
|
3
|
+
export interface GetRecitalInput {
|
|
4
|
+
regulation: string;
|
|
5
|
+
recital_number: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Recital {
|
|
9
|
+
regulation: string;
|
|
10
|
+
recital_number: number;
|
|
11
|
+
text: string;
|
|
12
|
+
related_articles: string[] | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function getRecital(
|
|
16
|
+
db: Database,
|
|
17
|
+
input: GetRecitalInput
|
|
18
|
+
): Promise<Recital | null> {
|
|
19
|
+
const { regulation, recital_number } = input;
|
|
20
|
+
|
|
21
|
+
const sql = `
|
|
22
|
+
SELECT
|
|
23
|
+
regulation,
|
|
24
|
+
recital_number,
|
|
25
|
+
text,
|
|
26
|
+
related_articles
|
|
27
|
+
FROM recitals
|
|
28
|
+
WHERE regulation = ? AND recital_number = ?
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const row = db.prepare(sql).get(regulation, recital_number) as {
|
|
32
|
+
regulation: string;
|
|
33
|
+
recital_number: number;
|
|
34
|
+
text: string;
|
|
35
|
+
related_articles: string | null;
|
|
36
|
+
} | undefined;
|
|
37
|
+
|
|
38
|
+
if (!row) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
regulation: row.regulation,
|
|
44
|
+
recital_number: row.recital_number,
|
|
45
|
+
text: row.text,
|
|
46
|
+
related_articles: row.related_articles ? JSON.parse(row.related_articles) : null,
|
|
47
|
+
};
|
|
48
|
+
}
|