@ansvar/us-regulations-mcp 1.0.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 (89) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +275 -0
  3. package/data/.gitkeep +0 -0
  4. package/data/regulations.db +0 -0
  5. package/data/seed/applicability/rules.json +74 -0
  6. package/data/seed/mappings/ccpa-nist-csf.json +144 -0
  7. package/data/seed/mappings/hipaa-nist-800-53.json +377 -0
  8. package/dist/index.d.ts +3 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +41 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/ingest/adapters/california-leginfo.d.ts +72 -0
  13. package/dist/ingest/adapters/california-leginfo.d.ts.map +1 -0
  14. package/dist/ingest/adapters/california-leginfo.js +270 -0
  15. package/dist/ingest/adapters/california-leginfo.js.map +1 -0
  16. package/dist/ingest/adapters/ecfr.d.ts +76 -0
  17. package/dist/ingest/adapters/ecfr.d.ts.map +1 -0
  18. package/dist/ingest/adapters/ecfr.js +355 -0
  19. package/dist/ingest/adapters/ecfr.js.map +1 -0
  20. package/dist/ingest/adapters/regulations-gov.d.ts +47 -0
  21. package/dist/ingest/adapters/regulations-gov.d.ts.map +1 -0
  22. package/dist/ingest/adapters/regulations-gov.js +91 -0
  23. package/dist/ingest/adapters/regulations-gov.js.map +1 -0
  24. package/dist/ingest/framework.d.ts +84 -0
  25. package/dist/ingest/framework.d.ts.map +1 -0
  26. package/dist/ingest/framework.js +8 -0
  27. package/dist/ingest/framework.js.map +1 -0
  28. package/dist/tools/action-items.d.ts +23 -0
  29. package/dist/tools/action-items.d.ts.map +1 -0
  30. package/dist/tools/action-items.js +118 -0
  31. package/dist/tools/action-items.js.map +1 -0
  32. package/dist/tools/applicability.d.ts +26 -0
  33. package/dist/tools/applicability.d.ts.map +1 -0
  34. package/dist/tools/applicability.js +49 -0
  35. package/dist/tools/applicability.js.map +1 -0
  36. package/dist/tools/compare.d.ts +20 -0
  37. package/dist/tools/compare.d.ts.map +1 -0
  38. package/dist/tools/compare.js +35 -0
  39. package/dist/tools/compare.js.map +1 -0
  40. package/dist/tools/definitions.d.ts +22 -0
  41. package/dist/tools/definitions.d.ts.map +1 -0
  42. package/dist/tools/definitions.js +43 -0
  43. package/dist/tools/definitions.js.map +1 -0
  44. package/dist/tools/evidence.d.ts +23 -0
  45. package/dist/tools/evidence.d.ts.map +1 -0
  46. package/dist/tools/evidence.js +27 -0
  47. package/dist/tools/evidence.js.map +1 -0
  48. package/dist/tools/list.d.ts +25 -0
  49. package/dist/tools/list.d.ts.map +1 -0
  50. package/dist/tools/list.js +66 -0
  51. package/dist/tools/list.js.map +1 -0
  52. package/dist/tools/map.d.ts +26 -0
  53. package/dist/tools/map.d.ts.map +1 -0
  54. package/dist/tools/map.js +58 -0
  55. package/dist/tools/map.js.map +1 -0
  56. package/dist/tools/registry.d.ts +19 -0
  57. package/dist/tools/registry.d.ts.map +1 -0
  58. package/dist/tools/registry.js +260 -0
  59. package/dist/tools/registry.js.map +1 -0
  60. package/dist/tools/search.d.ts +15 -0
  61. package/dist/tools/search.d.ts.map +1 -0
  62. package/dist/tools/search.js +94 -0
  63. package/dist/tools/search.js.map +1 -0
  64. package/dist/tools/section.d.ts +19 -0
  65. package/dist/tools/section.d.ts.map +1 -0
  66. package/dist/tools/section.js +50 -0
  67. package/dist/tools/section.js.map +1 -0
  68. package/package.json +76 -0
  69. package/scripts/build-db.ts +268 -0
  70. package/scripts/ingest.ts +214 -0
  71. package/scripts/load-seed-data.ts +133 -0
  72. package/scripts/quality-test.ts +346 -0
  73. package/scripts/test-mcp-tools.ts +187 -0
  74. package/scripts/test-remaining-tools.ts +107 -0
  75. package/src/index.ts +55 -0
  76. package/src/ingest/adapters/california-leginfo.ts +322 -0
  77. package/src/ingest/adapters/ecfr.ts +403 -0
  78. package/src/ingest/adapters/regulations-gov.ts +112 -0
  79. package/src/ingest/framework.ts +92 -0
  80. package/src/tools/action-items.ts +164 -0
  81. package/src/tools/applicability.ts +91 -0
  82. package/src/tools/compare.ts +61 -0
  83. package/src/tools/definitions.ts +79 -0
  84. package/src/tools/evidence.ts +53 -0
  85. package/src/tools/list.ts +120 -0
  86. package/src/tools/map.ts +100 -0
  87. package/src/tools/registry.ts +275 -0
  88. package/src/tools/search.ts +132 -0
  89. package/src/tools/section.ts +85 -0
@@ -0,0 +1,346 @@
1
+ #!/usr/bin/env npx tsx
2
+
3
+ /**
4
+ * Comprehensive Quality Test for US Compliance MCP
5
+ * Tests various compliance queries to assess quality and coverage
6
+ */
7
+
8
+ import Database from 'better-sqlite3';
9
+ import { join, dirname } from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ import { searchRegulations } from '../src/tools/search.js';
12
+ import { getSection } from '../src/tools/section.js';
13
+ import { compareRequirements } from '../src/tools/compare.js';
14
+ import { mapControls } from '../src/tools/map.js';
15
+ import { checkApplicability } from '../src/tools/applicability.js';
16
+
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = dirname(__filename);
19
+ const DB_PATH = join(__dirname, '..', 'data', 'regulations.db');
20
+
21
+ const db = new Database(DB_PATH, { readonly: true });
22
+
23
+ interface TestCase {
24
+ name: string;
25
+ category: string;
26
+ test: () => Promise<any>;
27
+ }
28
+
29
+ const tests: TestCase[] = [];
30
+ let passed = 0;
31
+ let failed = 0;
32
+
33
+ function addTest(category: string, name: string, test: () => Promise<any>) {
34
+ tests.push({ category, name, test });
35
+ }
36
+
37
+ // ===== HIPAA QUERIES =====
38
+ addTest('HIPAA', 'Security rule access controls', async () => {
39
+ const result = await searchRegulations(db, {
40
+ query: 'access control security',
41
+ regulation: 'HIPAA',
42
+ limit: 5
43
+ });
44
+ if (!result || result.length === 0) throw new Error('No results');
45
+ console.log(` ๐Ÿ“‹ Found ${result.length} sections`);
46
+ console.log(` ๐Ÿ“ Top result: ${result[0].section} - ${result[0].title}`);
47
+ return result;
48
+ });
49
+
50
+ addTest('HIPAA', 'Audit logs and ePHI access', async () => {
51
+ const result = await searchRegulations(db, {
52
+ query: 'audit log electronic protected health',
53
+ regulation: 'HIPAA',
54
+ limit: 5
55
+ });
56
+ if (!result || result.length === 0) throw new Error('No results');
57
+ console.log(` ๐Ÿ“‹ Found ${result.length} sections`);
58
+ console.log(` ๐Ÿ“ Top result: ${result[0].section}`);
59
+ return result;
60
+ });
61
+
62
+ addTest('HIPAA', 'Encryption requirements', async () => {
63
+ const result = await searchRegulations(db, {
64
+ query: 'encryption transmission storage',
65
+ regulation: 'HIPAA',
66
+ limit: 5
67
+ });
68
+ if (!result || result.length === 0) throw new Error('No results');
69
+ console.log(` ๐Ÿ“‹ Found ${result.length} sections`);
70
+ console.log(` ๐Ÿ“ Top result: ${result[0].section}`);
71
+ return result;
72
+ });
73
+
74
+ addTest('HIPAA', 'Breach notification requirements', async () => {
75
+ const result = await searchRegulations(db, {
76
+ query: 'breach notification timeline',
77
+ regulation: 'HIPAA',
78
+ limit: 5
79
+ });
80
+ if (!result || result.length === 0) throw new Error('No results');
81
+ console.log(` ๐Ÿ“‹ Found ${result.length} sections`);
82
+ console.log(` ๐Ÿ“ Top result: ${result[0].section}`);
83
+ return result;
84
+ });
85
+
86
+ addTest('HIPAA', 'Risk assessment requirements', async () => {
87
+ const result = await searchRegulations(db, {
88
+ query: 'risk assessment analysis',
89
+ regulation: 'HIPAA',
90
+ limit: 5
91
+ });
92
+ if (!result || result.length === 0) throw new Error('No results');
93
+ console.log(` ๐Ÿ“‹ Found ${result.length} sections`);
94
+ console.log(` ๐Ÿ“ Top result: ${result[0].section}`);
95
+ return result;
96
+ });
97
+
98
+ // ===== CCPA QUERIES =====
99
+ addTest('CCPA', 'Consumer rights to data deletion', async () => {
100
+ const result = await searchRegulations(db, {
101
+ query: 'consumer right delete personal information',
102
+ regulation: 'CCPA',
103
+ limit: 5
104
+ });
105
+ if (!result || result.length === 0) throw new Error('No results');
106
+ console.log(` ๐Ÿ“‹ Found ${result.length} sections`);
107
+ console.log(` ๐Ÿ“ Top result: ${result[0].section}`);
108
+ return result;
109
+ });
110
+
111
+ addTest('CCPA', 'Data disclosure requirements', async () => {
112
+ const result = await searchRegulations(db, {
113
+ query: 'disclosure categories personal information',
114
+ regulation: 'CCPA',
115
+ limit: 5
116
+ });
117
+ if (!result || result.length === 0) throw new Error('No results');
118
+ console.log(` ๐Ÿ“‹ Found ${result.length} sections`);
119
+ console.log(` ๐Ÿ“ Top result: ${result[0].section}`);
120
+ return result;
121
+ });
122
+
123
+ addTest('CCPA', 'Do Not Sell opt-out', async () => {
124
+ const result = await searchRegulations(db, {
125
+ query: 'do not sell opt-out',
126
+ regulation: 'CCPA',
127
+ limit: 5
128
+ });
129
+ if (!result || result.length === 0) throw new Error('No results');
130
+ console.log(` ๐Ÿ“‹ Found ${result.length} sections`);
131
+ console.log(` ๐Ÿ“ Top result: ${result[0].section}`);
132
+ return result;
133
+ });
134
+
135
+ // ===== SOX QUERIES =====
136
+ addTest('SOX', 'Section 404 IT controls', async () => {
137
+ const result = await searchRegulations(db, {
138
+ query: 'internal control information technology',
139
+ regulation: 'SOX',
140
+ limit: 5
141
+ });
142
+ if (!result || result.length === 0) throw new Error('No results');
143
+ console.log(` ๐Ÿ“‹ Found ${result.length} sections`);
144
+ console.log(` ๐Ÿ“ Top result: ${result[0].section}`);
145
+ return result;
146
+ });
147
+
148
+ addTest('SOX', 'Financial records retention', async () => {
149
+ const result = await searchRegulations(db, {
150
+ query: 'retention records audit',
151
+ regulation: 'SOX',
152
+ limit: 5
153
+ });
154
+ if (!result || result.length === 0) throw new Error('No results');
155
+ console.log(` ๐Ÿ“‹ Found ${result.length} sections`);
156
+ console.log(` ๐Ÿ“ Top result: ${result[0].section}`);
157
+ return result;
158
+ });
159
+
160
+ // ===== CROSS-REGULATION QUERIES =====
161
+ addTest('Cross-Regulation', 'Compare breach notification timelines', async () => {
162
+ const result = await compareRequirements(db, {
163
+ topic: 'breach notification timeline',
164
+ regulations: ['HIPAA', 'CCPA']
165
+ });
166
+ if (!result || !result.comparisons) throw new Error('No comparison results');
167
+ console.log(` ๐Ÿ“Š Compared ${result.comparisons.length} regulations`);
168
+ for (const comp of result.comparisons) {
169
+ console.log(` - ${comp.regulation}: ${comp.matches?.length || 0} matches`);
170
+ }
171
+ return result;
172
+ });
173
+
174
+ addTest('Cross-Regulation', 'Compare incident response requirements', async () => {
175
+ const result = await compareRequirements(db, {
176
+ topic: 'incident response',
177
+ regulations: ['HIPAA', 'CCPA', 'SOX']
178
+ });
179
+ if (!result || !result.comparisons) throw new Error('No comparison results');
180
+ console.log(` ๐Ÿ“Š Compared ${result.comparisons.length} regulations`);
181
+ for (const comp of result.comparisons) {
182
+ console.log(` - ${comp.regulation}: ${comp.matches?.length || 0} matches`);
183
+ }
184
+ return result;
185
+ });
186
+
187
+ addTest('Cross-Regulation', 'Data protection across all regulations', async () => {
188
+ const result = await compareRequirements(db, {
189
+ topic: 'data protection security',
190
+ regulations: ['HIPAA', 'CCPA', 'SOX']
191
+ });
192
+ if (!result || !result.comparisons) throw new Error('No comparison results');
193
+ console.log(` ๐Ÿ“Š Compared ${result.comparisons.length} regulations`);
194
+ for (const comp of result.comparisons) {
195
+ console.log(` - ${comp.regulation}: ${comp.matches?.length || 0} matches`);
196
+ }
197
+ return result;
198
+ });
199
+
200
+ // ===== CONTROL MAPPINGS =====
201
+ addTest('Control Mappings', 'NIST 800-53 to HIPAA', async () => {
202
+ const result = await mapControls(db, {
203
+ framework: 'NIST_800_53_R5',
204
+ regulation: 'HIPAA'
205
+ });
206
+ if (!result.mappings || result.mappings.length === 0) throw new Error('No mappings');
207
+ console.log(` ๐Ÿ”— Found ${result.mappings.length} mappings`);
208
+ console.log(` ๐Ÿ“ Sample: ${result.mappings[0].control_id} โ†’ ${result.mappings[0].regulation_sections?.slice(0, 3).join(', ')}`);
209
+ return result;
210
+ });
211
+
212
+ addTest('Control Mappings', 'NIST CSF to CCPA', async () => {
213
+ const result = await mapControls(db, {
214
+ framework: 'NIST_CSF_2_0',
215
+ regulation: 'CCPA'
216
+ });
217
+ if (!result.mappings || result.mappings.length === 0) throw new Error('No mappings');
218
+ console.log(` ๐Ÿ”— Found ${result.mappings.length} mappings`);
219
+ console.log(` ๐Ÿ“ Sample: ${result.mappings[0].control_id}`);
220
+ return result;
221
+ });
222
+
223
+ // ===== APPLICABILITY CHECKS =====
224
+ addTest('Applicability', 'Healthcare sector', async () => {
225
+ const result = await checkApplicability(db, { sector: 'healthcare' });
226
+ if (!result.applicable_regulations) throw new Error('No results');
227
+ console.log(` โœ… ${result.applicable_regulations.length} applicable regulations`);
228
+ for (const reg of result.applicable_regulations) {
229
+ console.log(` - ${reg.regulation}: ${reg.confidence}`);
230
+ }
231
+ return result;
232
+ });
233
+
234
+ addTest('Applicability', 'Financial services', async () => {
235
+ const result = await checkApplicability(db, { sector: 'financial' });
236
+ if (!result.applicable_regulations) throw new Error('No results');
237
+ console.log(` โœ… ${result.applicable_regulations.length} applicable regulations`);
238
+ for (const reg of result.applicable_regulations) {
239
+ console.log(` - ${reg.regulation}: ${reg.confidence}`);
240
+ }
241
+ return result;
242
+ });
243
+
244
+ addTest('Applicability', 'E-commerce (California)', async () => {
245
+ const result = await checkApplicability(db, {
246
+ sector: 'technology',
247
+ details: 'e-commerce selling to California consumers'
248
+ });
249
+ if (!result.applicable_regulations) throw new Error('No results');
250
+ console.log(` โœ… ${result.applicable_regulations.length} applicable regulations`);
251
+ for (const reg of result.applicable_regulations) {
252
+ console.log(` - ${reg.regulation}: ${reg.confidence}`);
253
+ }
254
+ return result;
255
+ });
256
+
257
+ // ===== SECTION RETRIEVAL =====
258
+ addTest('Section Retrieval', 'HIPAA Security Rule 164.312', async () => {
259
+ const result = await getSection(db, { regulation: 'HIPAA', section: '164.312' });
260
+ if (!result || !result.text) throw new Error('Section not found');
261
+ console.log(` ๐Ÿ“„ ${result.section_number}: ${result.title}`);
262
+ console.log(` ๐Ÿ“Š Text length: ${result.text.length} chars`);
263
+ return result;
264
+ });
265
+
266
+ addTest('Section Retrieval', 'CCPA 1798.100', async () => {
267
+ const result = await getSection(db, { regulation: 'CCPA', section: '1798.100' });
268
+ if (!result || !result.text) throw new Error('Section not found');
269
+ console.log(` ๐Ÿ“„ ${result.section_number}: ${result.title}`);
270
+ console.log(` ๐Ÿ“Š Text length: ${result.text.length} chars`);
271
+ return result;
272
+ });
273
+
274
+ // ===== EDGE CASES =====
275
+ addTest('Edge Cases', 'Empty query handling', async () => {
276
+ try {
277
+ await searchRegulations(db, { query: '', limit: 5 });
278
+ throw new Error('Should have rejected empty query');
279
+ } catch (error: any) {
280
+ if (error.message.includes('Query cannot be empty')) {
281
+ console.log(' โœ… Correctly rejected empty query');
282
+ return { success: true };
283
+ }
284
+ throw error;
285
+ }
286
+ });
287
+
288
+ addTest('Edge Cases', 'Invalid regulation ID', async () => {
289
+ const result = await searchRegulations(db, {
290
+ query: 'test',
291
+ regulation: 'INVALID',
292
+ limit: 5
293
+ });
294
+ // Should return empty or handle gracefully
295
+ console.log(` โœ… Handled invalid regulation: ${result.length} results`);
296
+ return result;
297
+ });
298
+
299
+ // ===== RUN TESTS =====
300
+ async function runAllTests() {
301
+ console.log('๐Ÿ” US Compliance MCP - Comprehensive Quality Assessment\n');
302
+ console.log('=' .repeat(70));
303
+
304
+ let currentCategory = '';
305
+
306
+ for (const testCase of tests) {
307
+ if (testCase.category !== currentCategory) {
308
+ currentCategory = testCase.category;
309
+ console.log(`\n๐Ÿ“‚ ${currentCategory.toUpperCase()}`);
310
+ console.log('-'.repeat(70));
311
+ }
312
+
313
+ try {
314
+ console.log(`\nโœจ ${testCase.name}`);
315
+ await testCase.test();
316
+ console.log(' โœ… PASSED');
317
+ passed++;
318
+ } catch (error: any) {
319
+ console.log(` โŒ FAILED: ${error.message}`);
320
+ failed++;
321
+ }
322
+ }
323
+
324
+ // Final Summary
325
+ console.log('\n' + '='.repeat(70));
326
+ console.log('๐Ÿ“Š FINAL RESULTS');
327
+ console.log('='.repeat(70));
328
+ console.log(`Total Tests: ${tests.length}`);
329
+ console.log(`โœ… Passed: ${passed} (${Math.round(passed/tests.length * 100)}%)`);
330
+ console.log(`โŒ Failed: ${failed} (${Math.round(failed/tests.length * 100)}%)`);
331
+
332
+ if (failed === 0) {
333
+ console.log('\n๐ŸŽ‰ All quality tests passed! MCP is production-ready.\n');
334
+ } else {
335
+ console.log(`\nโš ๏ธ ${failed} test(s) failed. Review errors above.\n`);
336
+ process.exit(1);
337
+ }
338
+
339
+ db.close();
340
+ }
341
+
342
+ runAllTests().catch(error => {
343
+ console.error('Fatal error:', error);
344
+ db.close();
345
+ process.exit(1);
346
+ });
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env npx tsx
2
+
3
+ /**
4
+ * Test MCP Tools
5
+ * Verifies all MCP tools work correctly with populated database
6
+ */
7
+
8
+ import Database from 'better-sqlite3';
9
+ import { join, dirname } from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ import { searchRegulations } from '../src/tools/search.js';
12
+ import { getSection } from '../src/tools/section.js';
13
+ import { listRegulations } from '../src/tools/list.js';
14
+ import { mapControls } from '../src/tools/map.js';
15
+ import { checkApplicability } from '../src/tools/applicability.js';
16
+ import { getDefinitions } from '../src/tools/definitions.js';
17
+ import { compareRequirements } from '../src/tools/compare.js';
18
+
19
+ const __filename = fileURLToPath(import.meta.url);
20
+ const __dirname = dirname(__filename);
21
+ const DB_PATH = join(__dirname, '..', 'data', 'regulations.db');
22
+
23
+ const db = new Database(DB_PATH, { readonly: true });
24
+
25
+ async function runTests() {
26
+ console.log('๐Ÿงช Testing US Compliance MCP Tools\n');
27
+ let passed = 0;
28
+ let failed = 0;
29
+
30
+ // Test 1: Search Regulations
31
+ console.log('1๏ธโƒฃ Testing search_regulations...');
32
+ try {
33
+ const result = await searchRegulations(db, { query: 'encryption', limit: 5 });
34
+ if (Array.isArray(result) && result.length > 0) {
35
+ console.log(` โœ… Found ${result.length} results for "encryption"`);
36
+ console.log(` Sample: ${result[0].section} - ${result[0].title?.substring(0, 50)}...`);
37
+ passed++;
38
+ } else {
39
+ console.log(` โŒ No results returned (got: ${JSON.stringify(result).substring(0, 100)})`);
40
+ failed++;
41
+ }
42
+ } catch (error) {
43
+ console.log(` โŒ Error: ${error}`);
44
+ failed++;
45
+ }
46
+
47
+ // Test 2: Get Section
48
+ console.log('\n2๏ธโƒฃ Testing get_section...');
49
+ try {
50
+ const result = await getSection(db, { regulation: 'HIPAA', section: '164.308' });
51
+ if (result && result.section_number && result.text) {
52
+ console.log(` โœ… Retrieved section ${result.section_number}`);
53
+ console.log(` Title: ${result.title}`);
54
+ console.log(` Text length: ${result.text.length} chars`);
55
+ passed++;
56
+ } else {
57
+ console.log(` โŒ Section not found or incomplete (got: ${JSON.stringify(result)?.substring(0, 100)})`);
58
+ failed++;
59
+ }
60
+ } catch (error) {
61
+ console.log(` โŒ Error: ${error}`);
62
+ failed++;
63
+ }
64
+
65
+ // Test 3: List Regulations
66
+ console.log('\n3๏ธโƒฃ Testing list_regulations...');
67
+ try {
68
+ const result = await listRegulations(db, {});
69
+ if (result.regulations && result.regulations.length > 0) {
70
+ console.log(` โœ… Found ${result.regulations.length} regulations`);
71
+ console.log(` Regulations: ${result.regulations.map((r: any) => r.id).join(', ')}`);
72
+ passed++;
73
+ } else {
74
+ console.log(' โŒ No regulations returned');
75
+ failed++;
76
+ }
77
+ } catch (error) {
78
+ console.log(` โŒ Error: ${error}`);
79
+ failed++;
80
+ }
81
+
82
+ // Test 4: Map Controls
83
+ console.log('\n4๏ธโƒฃ Testing map_controls...');
84
+ try {
85
+ const result = await mapControls(db, { framework: 'NIST_800_53_R5', regulation: 'HIPAA' });
86
+ if (result.mappings && result.mappings.length > 0) {
87
+ console.log(` โœ… Found ${result.mappings.length} control mappings`);
88
+ console.log(` Sample: ${result.mappings[0].control_id} - ${result.mappings[0].control_name}`);
89
+ console.log(` Coverage: ${result.mappings[0].coverage}, Confidence: ${result.mappings[0].confidence}%`);
90
+ passed++;
91
+ } else {
92
+ console.log(' โŒ No mappings returned');
93
+ failed++;
94
+ }
95
+ } catch (error) {
96
+ console.log(` โŒ Error: ${error}`);
97
+ failed++;
98
+ }
99
+
100
+ // Test 5: Check Applicability
101
+ console.log('\n5๏ธโƒฃ Testing check_applicability...');
102
+ try {
103
+ const result = await checkApplicability(db, { sector: 'healthcare' });
104
+ if (result.applicable_regulations && result.applicable_regulations.length > 0) {
105
+ console.log(` โœ… Found ${result.applicable_regulations.length} applicable regulations for healthcare`);
106
+ console.log(` Sample: ${result.applicable_regulations[0].regulation} - ${result.applicable_regulations[0].confidence}`);
107
+ passed++;
108
+ } else {
109
+ console.log(` โŒ No applicability rules returned (got: ${JSON.stringify(result).substring(0, 100)})`);
110
+ failed++;
111
+ }
112
+ } catch (error) {
113
+ console.log(` โŒ Error: ${error}`);
114
+ failed++;
115
+ }
116
+
117
+ // Test 6: Get Definitions
118
+ console.log('\n6๏ธโƒฃ Testing get_definitions...');
119
+ try {
120
+ const result = await getDefinitions(db, { term: 'health' });
121
+ // Definitions might be empty if not yet extracted
122
+ console.log(` โ„น๏ธ Found ${result.definitions?.length || 0} definitions (expected 0 for MVP)`);
123
+ passed++;
124
+ } catch (error) {
125
+ console.log(` โŒ Error: ${error}`);
126
+ failed++;
127
+ }
128
+
129
+ // Test 7: Compare Requirements
130
+ console.log('\n7๏ธโƒฃ Testing compare_requirements...');
131
+ try {
132
+ const result = await compareRequirements(db, {
133
+ topic: 'data protection',
134
+ regulations: ['HIPAA', 'CCPA']
135
+ });
136
+ if (result.comparisons && result.comparisons.length > 0) {
137
+ console.log(` โœ… Compared ${result.comparisons.length} regulations`);
138
+ for (const comp of result.comparisons) {
139
+ console.log(` - ${comp.regulation}: ${comp.matches?.length || 0} matches`);
140
+ }
141
+ passed++;
142
+ } else {
143
+ console.log(` โŒ No comparison results (got: ${JSON.stringify(result).substring(0, 100)})`);
144
+ failed++;
145
+ }
146
+ } catch (error) {
147
+ console.log(` โŒ Error: ${error}`);
148
+ failed++;
149
+ }
150
+
151
+ // Test 8: List HIPAA Structure
152
+ console.log('\n8๏ธโƒฃ Testing list_regulations with HIPAA structure...');
153
+ try {
154
+ const result = await listRegulations(db, { regulation: 'HIPAA' });
155
+ if (result.structure && result.structure.chapters && result.structure.chapters.length > 0) {
156
+ const totalSections = result.structure.chapters.reduce((sum, ch) => sum + ch.sections.length, 0);
157
+ console.log(` โœ… Found ${totalSections} HIPAA sections in ${result.structure.chapters.length} chapters`);
158
+ console.log(` Sample sections: ${result.structure.chapters[0].sections.slice(0, 3).join(', ')}`);
159
+ passed++;
160
+ } else {
161
+ console.log(` โŒ No structure returned (got: ${JSON.stringify(result).substring(0, 150)})`);
162
+ failed++;
163
+ }
164
+ } catch (error) {
165
+ console.log(` โŒ Error: ${error}`);
166
+ failed++;
167
+ }
168
+
169
+ // Summary
170
+ console.log('\n' + '='.repeat(50));
171
+ console.log(`๐Ÿ“Š Test Results: ${passed} passed, ${failed} failed`);
172
+ console.log('='.repeat(50));
173
+
174
+ if (failed === 0) {
175
+ console.log('๐ŸŽ‰ All tests passed! MCP server is 100% ready.\n');
176
+ } else {
177
+ console.log('โš ๏ธ Some tests failed. Review errors above.\n');
178
+ process.exit(1);
179
+ }
180
+
181
+ db.close();
182
+ }
183
+
184
+ runTests().catch(error => {
185
+ console.error('Fatal error:', error);
186
+ process.exit(1);
187
+ });
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env npx tsx
2
+
3
+ /**
4
+ * Test remaining MCP tools
5
+ */
6
+
7
+ import Database from 'better-sqlite3';
8
+ import { join, dirname } from 'path';
9
+ import { fileURLToPath } from 'url';
10
+ import { getEvidenceRequirements } from '../src/tools/evidence.js';
11
+ import { getComplianceActionItems } from '../src/tools/action-items.js';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+ const DB_PATH = join(__dirname, '..', 'data', 'regulations.db');
16
+
17
+ const db = new Database(DB_PATH, { readonly: true });
18
+
19
+ async function testRemainingTools() {
20
+ console.log('๐Ÿงช Testing Remaining MCP Tools\n');
21
+ let passed = 0;
22
+ let failed = 0;
23
+
24
+ // Test 1: Get Evidence Requirements
25
+ console.log('1๏ธโƒฃ Testing get_evidence_requirements...');
26
+ try {
27
+ const result = await getEvidenceRequirements(db, {
28
+ regulation: 'HIPAA',
29
+ section: '164.308'
30
+ });
31
+ if (result && result.section) {
32
+ console.log(` โœ… Retrieved evidence requirements for ${result.section}`);
33
+ console.log(` ๐Ÿ“‹ Requirements count: ${result.requirements?.length || 0}`);
34
+ if (result.requirements && result.requirements.length > 0) {
35
+ console.log(` ๐Ÿ“ Sample: ${result.requirements[0].category}`);
36
+ }
37
+ passed++;
38
+ } else {
39
+ console.log(` โŒ No evidence requirements returned`);
40
+ failed++;
41
+ }
42
+ } catch (error: any) {
43
+ console.log(` โŒ Error: ${error.message}`);
44
+ failed++;
45
+ }
46
+
47
+ // Test 2: Get Compliance Action Items
48
+ console.log('\n2๏ธโƒฃ Testing get_compliance_action_items...');
49
+ try {
50
+ const result = await getComplianceActionItems(db, {
51
+ regulation: 'HIPAA',
52
+ sections: ['164.312', '164.308']
53
+ });
54
+ if (result && result.action_items) {
55
+ console.log(` โœ… Retrieved ${result.action_items.length} action items`);
56
+ if (result.action_items.length > 0) {
57
+ console.log(` ๐Ÿ“ Sample: ${result.action_items[0].title}`);
58
+ console.log(` ๐ŸŽฏ Priority: ${result.action_items[0].priority}`);
59
+ }
60
+ passed++;
61
+ } else {
62
+ console.log(` โŒ No action items returned`);
63
+ failed++;
64
+ }
65
+ } catch (error: any) {
66
+ console.log(` โŒ Error: ${error.message}`);
67
+ failed++;
68
+ }
69
+
70
+ // Test 3: Test with non-existent section
71
+ console.log('\n3๏ธโƒฃ Testing with non-existent section...');
72
+ try {
73
+ const result = await getEvidenceRequirements(db, {
74
+ regulation: 'HIPAA',
75
+ section: '999.999'
76
+ });
77
+ console.log(` โœ… Handled non-existent section gracefully`);
78
+ passed++;
79
+ } catch (error: any) {
80
+ if (error.message.includes('not found')) {
81
+ console.log(` โœ… Correctly returned error for non-existent section`);
82
+ passed++;
83
+ } else {
84
+ console.log(` โŒ Unexpected error: ${error.message}`);
85
+ failed++;
86
+ }
87
+ }
88
+
89
+ // Summary
90
+ console.log('\n' + '='.repeat(50));
91
+ console.log(`๐Ÿ“Š Test Results: ${passed} passed, ${failed} failed`);
92
+ console.log('='.repeat(50));
93
+
94
+ if (failed === 0) {
95
+ console.log('๐ŸŽ‰ All remaining tools tested successfully!\n');
96
+ } else {
97
+ console.log('โš ๏ธ Some tests failed. Review errors above.\n');
98
+ process.exit(1);
99
+ }
100
+
101
+ db.close();
102
+ }
103
+
104
+ testRemainingTools().catch(error => {
105
+ console.error('Fatal error:', error);
106
+ process.exit(1);
107
+ });
package/src/index.ts ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
+ import {
6
+ CallToolRequestSchema,
7
+ ListToolsRequestSchema,
8
+ } from '@modelcontextprotocol/sdk/types.js';
9
+ import Database from 'better-sqlite3';
10
+ import { fileURLToPath } from 'url';
11
+ import { dirname, join } from 'path';
12
+
13
+ import { registerTools } from './tools/registry.js';
14
+
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = dirname(__filename);
17
+
18
+ // Database path - look for regulations.db in data folder
19
+ const DB_PATH = process.env.US_COMPLIANCE_DB_PATH || join(__dirname, '..', 'data', 'regulations.db');
20
+
21
+ function getDatabase(): Database.Database {
22
+ try {
23
+ return new Database(DB_PATH, { readonly: true });
24
+ } catch (error) {
25
+ throw new Error(`Failed to open database at ${DB_PATH}: ${error}`);
26
+ }
27
+ }
28
+
29
+ const db = getDatabase();
30
+ const server = new Server(
31
+ {
32
+ name: 'us-regulations-mcp',
33
+ version: '0.1.0',
34
+ },
35
+ {
36
+ capabilities: {
37
+ tools: {},
38
+ },
39
+ }
40
+ );
41
+
42
+ // Register all tools using shared registry
43
+ registerTools(server, db);
44
+
45
+ // Start the server
46
+ async function main() {
47
+ const transport = new StdioServerTransport();
48
+ await server.connect(transport);
49
+ console.error('US Regulations MCP server started');
50
+ }
51
+
52
+ main().catch((error) => {
53
+ console.error('Fatal error:', error);
54
+ process.exit(1);
55
+ });