@ansvar/eu-regulations-mcp 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/LICENSE +190 -21
  2. package/README.md +125 -26
  3. package/data/seed/aifmd.json +432 -0
  4. package/data/seed/applicability/ai-act.json +87 -0
  5. package/data/seed/applicability/aifmd.json +74 -0
  6. package/data/seed/applicability/cbam.json +74 -0
  7. package/data/seed/applicability/cer.json +74 -0
  8. package/data/seed/applicability/cra.json +77 -0
  9. package/data/seed/applicability/csddd.json +74 -0
  10. package/data/seed/applicability/csrd.json +74 -0
  11. package/data/seed/applicability/cyber_solidarity.json +74 -0
  12. package/data/seed/applicability/cybersecurity-act.json +69 -0
  13. package/data/seed/applicability/data-act.json +71 -0
  14. package/data/seed/applicability/dga.json +74 -0
  15. package/data/seed/applicability/dma.json +77 -0
  16. package/data/seed/applicability/dsa.json +71 -0
  17. package/data/seed/applicability/eecc.json +74 -0
  18. package/data/seed/applicability/ehds.json +74 -0
  19. package/data/seed/applicability/eidas2.json +86 -0
  20. package/data/seed/applicability/eprivacy.json +74 -0
  21. package/data/seed/applicability/eu_taxonomy.json +74 -0
  22. package/data/seed/applicability/eucc.json +74 -0
  23. package/data/seed/applicability/eudr.json +74 -0
  24. package/data/seed/applicability/gpsr.json +74 -0
  25. package/data/seed/applicability/ivdr.json +74 -0
  26. package/data/seed/applicability/led.json +74 -0
  27. package/data/seed/applicability/machinery.json +74 -0
  28. package/data/seed/applicability/mdr.json +74 -0
  29. package/data/seed/applicability/mica.json +74 -0
  30. package/data/seed/applicability/mifid2.json +74 -0
  31. package/data/seed/applicability/mifir.json +74 -0
  32. package/data/seed/applicability/pld.json +74 -0
  33. package/data/seed/applicability/psd2.json +74 -0
  34. package/data/seed/applicability/red.json +74 -0
  35. package/data/seed/applicability/sfdr.json +74 -0
  36. package/data/seed/applicability/un-r155.json +68 -0
  37. package/data/seed/applicability/un-r156.json +68 -0
  38. package/data/seed/cbam.json +397 -0
  39. package/data/seed/cer.json +233 -0
  40. package/data/seed/csddd.json +205 -0
  41. package/data/seed/csrd.json +50 -0
  42. package/data/seed/cyber_solidarity.json +252 -0
  43. package/data/seed/data-act.json +517 -0
  44. package/data/seed/dga.json +342 -0
  45. package/data/seed/dma.json +499 -0
  46. package/data/seed/dsa.json +686 -0
  47. package/data/seed/eecc.json +981 -0
  48. package/data/seed/ehds.json +638 -0
  49. package/data/seed/eidas2.json +590 -0
  50. package/data/seed/eprivacy.json +115 -0
  51. package/data/seed/eu_taxonomy.json +285 -0
  52. package/data/seed/eucc.json +386 -0
  53. package/data/seed/eudr.json +401 -0
  54. package/data/seed/gpsr.json +462 -0
  55. package/data/seed/ivdr.json +1036 -0
  56. package/data/seed/led.json +480 -0
  57. package/data/seed/machinery.json +513 -0
  58. package/data/seed/mappings/iso27001-ai-act.json +114 -0
  59. package/data/seed/mappings/iso27001-aifmd.json +50 -0
  60. package/data/seed/mappings/iso27001-cbam.json +26 -0
  61. package/data/seed/mappings/iso27001-cer.json +74 -0
  62. package/data/seed/mappings/iso27001-cra.json +130 -0
  63. package/data/seed/mappings/iso27001-csddd.json +50 -0
  64. package/data/seed/mappings/iso27001-csrd.json +26 -0
  65. package/data/seed/mappings/iso27001-cyber_solidarity.json +82 -0
  66. package/data/seed/mappings/iso27001-cybersecurity-act.json +90 -0
  67. package/data/seed/mappings/iso27001-data-act.json +66 -0
  68. package/data/seed/mappings/iso27001-dga.json +50 -0
  69. package/data/seed/mappings/iso27001-dma.json +50 -0
  70. package/data/seed/mappings/iso27001-dsa.json +58 -0
  71. package/data/seed/mappings/iso27001-eecc.json +74 -0
  72. package/data/seed/mappings/iso27001-ehds.json +90 -0
  73. package/data/seed/mappings/iso27001-eidas2.json +106 -0
  74. package/data/seed/mappings/iso27001-eprivacy.json +66 -0
  75. package/data/seed/mappings/iso27001-eu_taxonomy.json +34 -0
  76. package/data/seed/mappings/iso27001-eucc.json +66 -0
  77. package/data/seed/mappings/iso27001-eudr.json +34 -0
  78. package/data/seed/mappings/iso27001-gpsr.json +42 -0
  79. package/data/seed/mappings/iso27001-ivdr.json +66 -0
  80. package/data/seed/mappings/iso27001-led.json +74 -0
  81. package/data/seed/mappings/iso27001-machinery.json +50 -0
  82. package/data/seed/mappings/iso27001-mdr.json +82 -0
  83. package/data/seed/mappings/iso27001-mica.json +66 -0
  84. package/data/seed/mappings/iso27001-mifid2.json +66 -0
  85. package/data/seed/mappings/iso27001-mifir.json +42 -0
  86. package/data/seed/mappings/iso27001-pld.json +26 -0
  87. package/data/seed/mappings/iso27001-psd2.json +82 -0
  88. package/data/seed/mappings/iso27001-red.json +42 -0
  89. package/data/seed/mappings/iso27001-sfdr.json +50 -0
  90. package/data/seed/mappings/iso27001-un-r155.json +130 -0
  91. package/data/seed/mappings/iso27001-un-r156.json +106 -0
  92. package/data/seed/mappings/nist-csf-ai-act.json +138 -0
  93. package/data/seed/mappings/nist-csf-aifmd.json +58 -0
  94. package/data/seed/mappings/nist-csf-cbam.json +42 -0
  95. package/data/seed/mappings/nist-csf-cer.json +90 -0
  96. package/data/seed/mappings/nist-csf-cra.json +130 -0
  97. package/data/seed/mappings/nist-csf-csddd.json +50 -0
  98. package/data/seed/mappings/nist-csf-csrd.json +34 -0
  99. package/data/seed/mappings/nist-csf-cyber_solidarity.json +90 -0
  100. package/data/seed/mappings/nist-csf-cybersecurity-act.json +90 -0
  101. package/data/seed/mappings/nist-csf-data-act.json +50 -0
  102. package/data/seed/mappings/nist-csf-dga.json +58 -0
  103. package/data/seed/mappings/nist-csf-dma.json +42 -0
  104. package/data/seed/mappings/nist-csf-dora.json +210 -0
  105. package/data/seed/mappings/nist-csf-dsa.json +82 -0
  106. package/data/seed/mappings/nist-csf-eecc.json +90 -0
  107. package/data/seed/mappings/nist-csf-ehds.json +98 -0
  108. package/data/seed/mappings/nist-csf-eidas2.json +114 -0
  109. package/data/seed/mappings/nist-csf-eprivacy.json +58 -0
  110. package/data/seed/mappings/nist-csf-eu_taxonomy.json +34 -0
  111. package/data/seed/mappings/nist-csf-eucc.json +66 -0
  112. package/data/seed/mappings/nist-csf-eudr.json +58 -0
  113. package/data/seed/mappings/nist-csf-gdpr.json +178 -0
  114. package/data/seed/mappings/nist-csf-gpsr.json +58 -0
  115. package/data/seed/mappings/nist-csf-ivdr.json +66 -0
  116. package/data/seed/mappings/nist-csf-led.json +74 -0
  117. package/data/seed/mappings/nist-csf-machinery.json +58 -0
  118. package/data/seed/mappings/nist-csf-mdr.json +66 -0
  119. package/data/seed/mappings/nist-csf-mica.json +98 -0
  120. package/data/seed/mappings/nist-csf-mifid2.json +74 -0
  121. package/data/seed/mappings/nist-csf-mifir.json +50 -0
  122. package/data/seed/mappings/nist-csf-nis2.json +194 -0
  123. package/data/seed/mappings/nist-csf-pld.json +34 -0
  124. package/data/seed/mappings/nist-csf-psd2.json +98 -0
  125. package/data/seed/mappings/nist-csf-red.json +58 -0
  126. package/data/seed/mappings/nist-csf-sfdr.json +42 -0
  127. package/data/seed/mappings/nist-csf-un-r155.json +130 -0
  128. package/data/seed/mappings/nist-csf-un-r156.json +98 -0
  129. package/data/seed/mdr.json +1066 -0
  130. package/data/seed/mica.json +1003 -0
  131. package/data/seed/mifid2.json +906 -0
  132. package/data/seed/mifir.json +512 -0
  133. package/data/seed/pld.json +244 -0
  134. package/data/seed/psd2.json +827 -0
  135. package/data/seed/red.json +452 -0
  136. package/data/seed/sfdr.json +228 -0
  137. package/data/seed/un-r155.json +166 -0
  138. package/data/seed/un-r156.json +150 -0
  139. package/dist/http-server.d.ts +9 -0
  140. package/dist/http-server.d.ts.map +1 -0
  141. package/dist/http-server.js +342 -0
  142. package/dist/http-server.js.map +1 -0
  143. package/dist/index.js +4 -4
  144. package/dist/index.js.map +1 -1
  145. package/dist/tools/map.d.ts +1 -1
  146. package/dist/tools/map.d.ts.map +1 -1
  147. package/dist/tools/map.js +3 -3
  148. package/dist/tools/map.js.map +1 -1
  149. package/package.json +6 -2
  150. package/scripts/build-db.ts +20 -8
  151. package/scripts/check-updates.ts +141 -39
  152. package/scripts/ingest-eurlex.ts +9 -1
  153. package/scripts/ingest-unece.ts +368 -0
  154. package/src/http-server.ts +380 -0
  155. package/src/index.ts +4 -4
  156. package/src/tools/map.ts +4 -4
@@ -0,0 +1,380 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * HTTP Server Entry Point for Smithery Hosted Deployment
5
+ *
6
+ * This provides Streamable HTTP transport for remote MCP clients.
7
+ * Use src/index.ts for local stdio-based usage.
8
+ */
9
+
10
+ import { createServer } from 'node:http';
11
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
12
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
13
+ import {
14
+ CallToolRequestSchema,
15
+ ListToolsRequestSchema,
16
+ } from '@modelcontextprotocol/sdk/types.js';
17
+ import Database from 'better-sqlite3';
18
+ import { fileURLToPath } from 'url';
19
+ import { dirname, join } from 'path';
20
+ import { randomUUID } from 'crypto';
21
+
22
+ import { searchRegulations, type SearchInput } from './tools/search.js';
23
+ import { getArticle, type GetArticleInput } from './tools/article.js';
24
+ import { listRegulations, type ListInput } from './tools/list.js';
25
+ import { compareRequirements, type CompareInput } from './tools/compare.js';
26
+ import { mapControls, type MapControlsInput } from './tools/map.js';
27
+ import { checkApplicability, type ApplicabilityInput } from './tools/applicability.js';
28
+ import { getDefinitions, type DefinitionsInput } from './tools/definitions.js';
29
+
30
+ const __filename = fileURLToPath(import.meta.url);
31
+ const __dirname = dirname(__filename);
32
+
33
+ // Database path - look for regulations.db in data folder
34
+ const DB_PATH = process.env.EU_COMPLIANCE_DB_PATH || join(__dirname, '..', 'data', 'regulations.db');
35
+
36
+ // HTTP server port
37
+ const PORT = parseInt(process.env.PORT || '3000', 10);
38
+
39
+ let db: Database.Database;
40
+
41
+ function getDatabase(): Database.Database {
42
+ if (!db) {
43
+ try {
44
+ db = new Database(DB_PATH, { readonly: true });
45
+ } catch (error) {
46
+ throw new Error(`Failed to open database at ${DB_PATH}: ${error}`);
47
+ }
48
+ }
49
+ return db;
50
+ }
51
+
52
+ // Create MCP server instance
53
+ function createMcpServer(): Server {
54
+ const server = new Server(
55
+ {
56
+ name: 'eu-regulations-mcp',
57
+ version: '0.1.0',
58
+ },
59
+ {
60
+ capabilities: {
61
+ tools: {},
62
+ },
63
+ }
64
+ );
65
+
66
+ // Define available tools
67
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
68
+ tools: [
69
+ {
70
+ name: 'search_regulations',
71
+ description: 'Search across all EU regulations for articles matching a query. Returns relevant articles with snippets highlighting matches.',
72
+ inputSchema: {
73
+ type: 'object',
74
+ properties: {
75
+ query: {
76
+ type: 'string',
77
+ description: 'Search query (e.g., "incident reporting", "personal data breach")',
78
+ },
79
+ regulations: {
80
+ type: 'array',
81
+ items: { type: 'string' },
82
+ description: 'Optional: filter to specific regulations (e.g., ["GDPR", "NIS2"])',
83
+ },
84
+ limit: {
85
+ type: 'number',
86
+ description: 'Maximum results to return (default: 10)',
87
+ },
88
+ },
89
+ required: ['query'],
90
+ },
91
+ },
92
+ {
93
+ name: 'get_article',
94
+ description: 'Retrieve the full text of a specific article from a regulation.',
95
+ inputSchema: {
96
+ type: 'object',
97
+ properties: {
98
+ regulation: {
99
+ type: 'string',
100
+ description: 'Regulation ID (e.g., "GDPR", "NIS2", "DORA")',
101
+ },
102
+ article: {
103
+ type: 'string',
104
+ description: 'Article number (e.g., "17", "23")',
105
+ },
106
+ },
107
+ required: ['regulation', 'article'],
108
+ },
109
+ },
110
+ {
111
+ name: 'list_regulations',
112
+ description: 'List available regulations and their structure. Without parameters, lists all regulations. With a regulation specified, shows chapters and articles.',
113
+ inputSchema: {
114
+ type: 'object',
115
+ properties: {
116
+ regulation: {
117
+ type: 'string',
118
+ description: 'Optional: specific regulation to get detailed structure for',
119
+ },
120
+ },
121
+ },
122
+ },
123
+ {
124
+ name: 'compare_requirements',
125
+ description: 'Compare requirements across multiple regulations on a specific topic. Useful for understanding differences in how regulations address similar concerns.',
126
+ inputSchema: {
127
+ type: 'object',
128
+ properties: {
129
+ topic: {
130
+ type: 'string',
131
+ description: 'Topic to compare (e.g., "incident reporting", "risk assessment")',
132
+ },
133
+ regulations: {
134
+ type: 'array',
135
+ items: { type: 'string' },
136
+ description: 'Regulations to compare (e.g., ["DORA", "NIS2"])',
137
+ },
138
+ },
139
+ required: ['topic', 'regulations'],
140
+ },
141
+ },
142
+ {
143
+ name: 'map_controls',
144
+ description: 'Map security framework controls to EU regulation requirements. Shows which articles satisfy specific security controls.',
145
+ inputSchema: {
146
+ type: 'object',
147
+ properties: {
148
+ framework: {
149
+ type: 'string',
150
+ enum: ['ISO27001', 'NIST_CSF'],
151
+ description: 'Control framework: ISO27001 (ISO 27001:2022) or NIST_CSF (NIST Cybersecurity Framework)',
152
+ },
153
+ control: {
154
+ type: 'string',
155
+ description: 'Optional: specific control ID (e.g., "A.5.1" for ISO27001, "PR.AC-1" for NIST CSF)',
156
+ },
157
+ regulation: {
158
+ type: 'string',
159
+ description: 'Optional: filter mappings to specific regulation',
160
+ },
161
+ },
162
+ required: ['framework'],
163
+ },
164
+ },
165
+ {
166
+ name: 'check_applicability',
167
+ description: 'Determine which EU regulations apply to an organization based on sector and characteristics.',
168
+ inputSchema: {
169
+ type: 'object',
170
+ properties: {
171
+ sector: {
172
+ type: 'string',
173
+ enum: ['financial', 'healthcare', 'energy', 'transport', 'digital_infrastructure', 'public_administration', 'manufacturing', 'other'],
174
+ description: 'Organization sector',
175
+ },
176
+ subsector: {
177
+ type: 'string',
178
+ description: 'Optional: more specific subsector (e.g., "bank", "insurance" for financial)',
179
+ },
180
+ member_state: {
181
+ type: 'string',
182
+ description: 'Optional: EU member state (ISO country code)',
183
+ },
184
+ size: {
185
+ type: 'string',
186
+ enum: ['sme', 'large'],
187
+ description: 'Optional: organization size',
188
+ },
189
+ },
190
+ required: ['sector'],
191
+ },
192
+ },
193
+ {
194
+ name: 'get_definitions',
195
+ description: 'Look up official definitions of terms from EU regulations. Terms are defined in each regulation\'s definitions article.',
196
+ inputSchema: {
197
+ type: 'object',
198
+ properties: {
199
+ term: {
200
+ type: 'string',
201
+ description: 'Term to look up (e.g., "personal data", "incident", "processing")',
202
+ },
203
+ regulation: {
204
+ type: 'string',
205
+ description: 'Optional: filter to specific regulation',
206
+ },
207
+ },
208
+ required: ['term'],
209
+ },
210
+ },
211
+ ],
212
+ }));
213
+
214
+ // Handle tool calls
215
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
216
+ const { name, arguments: args } = request.params;
217
+
218
+ try {
219
+ const database = getDatabase();
220
+
221
+ switch (name) {
222
+ case 'search_regulations': {
223
+ const input = args as unknown as SearchInput;
224
+ const results = await searchRegulations(database, input);
225
+ return {
226
+ content: [{ type: 'text', text: JSON.stringify(results, null, 2) }],
227
+ };
228
+ }
229
+
230
+ case 'get_article': {
231
+ const input = args as unknown as GetArticleInput;
232
+ const article = await getArticle(database, input);
233
+ if (!article) {
234
+ return {
235
+ content: [{ type: 'text', text: `Article ${input.article} not found in ${input.regulation}` }],
236
+ isError: true,
237
+ };
238
+ }
239
+ return {
240
+ content: [{ type: 'text', text: JSON.stringify(article, null, 2) }],
241
+ };
242
+ }
243
+
244
+ case 'list_regulations': {
245
+ const input = (args ?? {}) as unknown as ListInput;
246
+ const result = await listRegulations(database, input);
247
+ return {
248
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
249
+ };
250
+ }
251
+
252
+ case 'compare_requirements': {
253
+ const input = args as unknown as CompareInput;
254
+ const result = await compareRequirements(database, input);
255
+ return {
256
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
257
+ };
258
+ }
259
+
260
+ case 'map_controls': {
261
+ const input = args as unknown as MapControlsInput;
262
+ const result = await mapControls(database, input);
263
+ return {
264
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
265
+ };
266
+ }
267
+
268
+ case 'check_applicability': {
269
+ const input = args as unknown as ApplicabilityInput;
270
+ const result = await checkApplicability(database, input);
271
+ return {
272
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
273
+ };
274
+ }
275
+
276
+ case 'get_definitions': {
277
+ const input = args as unknown as DefinitionsInput;
278
+ const result = await getDefinitions(database, input);
279
+ return {
280
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
281
+ };
282
+ }
283
+
284
+ default:
285
+ return {
286
+ content: [{ type: 'text', text: `Unknown tool: ${name}` }],
287
+ isError: true,
288
+ };
289
+ }
290
+ } catch (error) {
291
+ return {
292
+ content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
293
+ isError: true,
294
+ };
295
+ }
296
+ });
297
+
298
+ return server;
299
+ }
300
+
301
+ // Start HTTP server with Streamable HTTP transport
302
+ async function main() {
303
+ const mcpServer = createMcpServer();
304
+
305
+ // Map to store transports by session ID
306
+ const transports = new Map<string, StreamableHTTPServerTransport>();
307
+
308
+ const httpServer = createServer(async (req, res) => {
309
+ const url = new URL(req.url || '/', `http://localhost:${PORT}`);
310
+
311
+ // Health check endpoint
312
+ if (url.pathname === '/health') {
313
+ res.writeHead(200, { 'Content-Type': 'application/json' });
314
+ res.end(JSON.stringify({ status: 'ok', server: 'eu-regulations-mcp' }));
315
+ return;
316
+ }
317
+
318
+ // MCP endpoint
319
+ if (url.pathname === '/mcp') {
320
+ // Get or create session
321
+ const sessionId = req.headers['mcp-session-id'] as string | undefined;
322
+
323
+ let transport: StreamableHTTPServerTransport;
324
+
325
+ if (sessionId && transports.has(sessionId)) {
326
+ // Reuse existing transport for this session
327
+ transport = transports.get(sessionId)!;
328
+ } else {
329
+ // Create new transport with session ID generator
330
+ transport = new StreamableHTTPServerTransport({
331
+ sessionIdGenerator: () => randomUUID(),
332
+ });
333
+
334
+ // Connect MCP server to transport
335
+ await mcpServer.connect(transport);
336
+
337
+ // Store transport by session ID once it's assigned
338
+ transport.onclose = () => {
339
+ if (transport.sessionId) {
340
+ transports.delete(transport.sessionId);
341
+ }
342
+ };
343
+ }
344
+
345
+ // Handle the request
346
+ await transport.handleRequest(req, res);
347
+
348
+ // Store transport if new session was created
349
+ if (transport.sessionId && !transports.has(transport.sessionId)) {
350
+ transports.set(transport.sessionId, transport);
351
+ }
352
+
353
+ return;
354
+ }
355
+
356
+ // 404 for other paths
357
+ res.writeHead(404, { 'Content-Type': 'application/json' });
358
+ res.end(JSON.stringify({ error: 'Not found' }));
359
+ });
360
+
361
+ httpServer.listen(PORT, () => {
362
+ console.error(`EU Regulations MCP server (HTTP) listening on port ${PORT}`);
363
+ console.error(`MCP endpoint: http://localhost:${PORT}/mcp`);
364
+ console.error(`Health check: http://localhost:${PORT}/health`);
365
+ });
366
+
367
+ // Graceful shutdown
368
+ process.on('SIGTERM', () => {
369
+ console.error('Received SIGTERM, shutting down...');
370
+ httpServer.close(() => {
371
+ if (db) db.close();
372
+ process.exit(0);
373
+ });
374
+ });
375
+ }
376
+
377
+ main().catch((error) => {
378
+ console.error('Fatal error:', error);
379
+ process.exit(1);
380
+ });
package/src/index.ts CHANGED
@@ -127,18 +127,18 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
127
127
  },
128
128
  {
129
129
  name: 'map_controls',
130
- description: 'Map ISO 27001:2022 controls to EU regulation requirements. Shows which articles satisfy specific security controls.',
130
+ description: 'Map security framework controls to EU regulation requirements. Shows which articles satisfy specific security controls.',
131
131
  inputSchema: {
132
132
  type: 'object',
133
133
  properties: {
134
134
  framework: {
135
135
  type: 'string',
136
- enum: ['ISO27001'],
137
- description: 'Control framework (currently only ISO27001 supported)',
136
+ enum: ['ISO27001', 'NIST_CSF'],
137
+ description: 'Control framework: ISO27001 (ISO 27001:2022) or NIST_CSF (NIST Cybersecurity Framework)',
138
138
  },
139
139
  control: {
140
140
  type: 'string',
141
- description: 'Optional: specific control ID (e.g., "A.5.1", "A.6.8")',
141
+ description: 'Optional: specific control ID (e.g., "A.5.1" for ISO27001, "PR.AC-1" for NIST CSF)',
142
142
  },
143
143
  regulation: {
144
144
  type: 'string',
package/src/tools/map.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Database } from 'better-sqlite3';
2
2
 
3
3
  export interface MapControlsInput {
4
- framework: 'ISO27001';
4
+ framework: 'ISO27001' | 'NIST_CSF';
5
5
  control?: string;
6
6
  regulation?: string;
7
7
  }
@@ -23,7 +23,7 @@ export async function mapControls(
23
23
  db: Database,
24
24
  input: MapControlsInput
25
25
  ): Promise<ControlMapping[]> {
26
- const { control, regulation } = input;
26
+ const { framework, control, regulation } = input;
27
27
 
28
28
  let sql = `
29
29
  SELECT
@@ -34,10 +34,10 @@ export async function mapControls(
34
34
  coverage,
35
35
  notes
36
36
  FROM control_mappings
37
- WHERE 1=1
37
+ WHERE framework = ?
38
38
  `;
39
39
 
40
- const params: string[] = [];
40
+ const params: string[] = [framework];
41
41
 
42
42
  if (control) {
43
43
  sql += ` AND control_id = ?`;