@ansvar/ch-environmental-compliance-mcp 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.
Files changed (113) hide show
  1. package/.github/workflows/check-freshness.yml +49 -0
  2. package/.github/workflows/ci.yml +21 -0
  3. package/.github/workflows/codeql.yml +25 -0
  4. package/.github/workflows/ghcr-build.yml +45 -0
  5. package/.github/workflows/gitleaks.yml +18 -0
  6. package/.github/workflows/ingest.yml +59 -0
  7. package/.github/workflows/publish.yml +24 -0
  8. package/CHANGELOG.md +15 -0
  9. package/CODEOWNERS +1 -0
  10. package/COVERAGE.md +50 -0
  11. package/DISCLAIMER.md +48 -0
  12. package/Dockerfile +26 -0
  13. package/LICENSE +17 -0
  14. package/PRIVACY.md +23 -0
  15. package/README.md +116 -0
  16. package/SECURITY.md +25 -0
  17. package/TOOLS.md +142 -0
  18. package/data/coverage.json +24 -0
  19. package/data/database.db +0 -0
  20. package/data/sources.yml +36 -0
  21. package/dist/db.d.ts +25 -0
  22. package/dist/db.d.ts.map +1 -0
  23. package/dist/db.js +197 -0
  24. package/dist/db.js.map +1 -0
  25. package/dist/http-server.d.ts +2 -0
  26. package/dist/http-server.d.ts.map +1 -0
  27. package/dist/http-server.js +274 -0
  28. package/dist/http-server.js.map +1 -0
  29. package/dist/jurisdiction.d.ts +18 -0
  30. package/dist/jurisdiction.d.ts.map +1 -0
  31. package/dist/jurisdiction.js +16 -0
  32. package/dist/jurisdiction.js.map +1 -0
  33. package/dist/metadata.d.ts +10 -0
  34. package/dist/metadata.d.ts.map +1 -0
  35. package/dist/metadata.js +22 -0
  36. package/dist/metadata.js.map +1 -0
  37. package/dist/server.d.ts +3 -0
  38. package/dist/server.d.ts.map +1 -0
  39. package/dist/server.js +220 -0
  40. package/dist/server.js.map +1 -0
  41. package/dist/tools/about.d.ts +15 -0
  42. package/dist/tools/about.d.ts.map +1 -0
  43. package/dist/tools/about.js +27 -0
  44. package/dist/tools/about.js.map +1 -0
  45. package/dist/tools/check-environmental-compliance.d.ts +30 -0
  46. package/dist/tools/check-environmental-compliance.d.ts.map +1 -0
  47. package/dist/tools/check-environmental-compliance.js +103 -0
  48. package/dist/tools/check-environmental-compliance.js.map +1 -0
  49. package/dist/tools/check-freshness.d.ts +15 -0
  50. package/dist/tools/check-freshness.d.ts.map +1 -0
  51. package/dist/tools/check-freshness.js +26 -0
  52. package/dist/tools/check-freshness.js.map +1 -0
  53. package/dist/tools/get-ammonia-rules.d.ts +24 -0
  54. package/dist/tools/get-ammonia-rules.d.ts.map +1 -0
  55. package/dist/tools/get-ammonia-rules.js +31 -0
  56. package/dist/tools/get-ammonia-rules.js.map +1 -0
  57. package/dist/tools/get-bff-requirements.d.ts +26 -0
  58. package/dist/tools/get-bff-requirements.d.ts.map +1 -0
  59. package/dist/tools/get-bff-requirements.js +36 -0
  60. package/dist/tools/get-bff-requirements.js.map +1 -0
  61. package/dist/tools/get-buffer-zone-rules.d.ts +23 -0
  62. package/dist/tools/get-buffer-zone-rules.d.ts.map +1 -0
  63. package/dist/tools/get-buffer-zone-rules.js +30 -0
  64. package/dist/tools/get-buffer-zone-rules.js.map +1 -0
  65. package/dist/tools/get-eip-requirements.d.ts +31 -0
  66. package/dist/tools/get-eip-requirements.d.ts.map +1 -0
  67. package/dist/tools/get-eip-requirements.js +40 -0
  68. package/dist/tools/get-eip-requirements.js.map +1 -0
  69. package/dist/tools/get-nutrient-loss-limits.d.ts +24 -0
  70. package/dist/tools/get-nutrient-loss-limits.d.ts.map +1 -0
  71. package/dist/tools/get-nutrient-loss-limits.js +31 -0
  72. package/dist/tools/get-nutrient-loss-limits.js.map +1 -0
  73. package/dist/tools/get-water-protection-zones.d.ts +32 -0
  74. package/dist/tools/get-water-protection-zones.d.ts.map +1 -0
  75. package/dist/tools/get-water-protection-zones.js +36 -0
  76. package/dist/tools/get-water-protection-zones.js.map +1 -0
  77. package/dist/tools/list-sources.d.ts +18 -0
  78. package/dist/tools/list-sources.d.ts.map +1 -0
  79. package/dist/tools/list-sources.js +61 -0
  80. package/dist/tools/list-sources.js.map +1 -0
  81. package/dist/tools/search-environmental-rules.d.ts +25 -0
  82. package/dist/tools/search-environmental-rules.d.ts.map +1 -0
  83. package/dist/tools/search-environmental-rules.js +26 -0
  84. package/dist/tools/search-environmental-rules.js.map +1 -0
  85. package/docker-compose.yml +12 -0
  86. package/eslint.config.js +26 -0
  87. package/package.json +54 -0
  88. package/scripts/ingest.ts +911 -0
  89. package/server.json +16 -0
  90. package/src/db.ts +238 -0
  91. package/src/http-server.ts +307 -0
  92. package/src/jurisdiction.ts +30 -0
  93. package/src/metadata.ts +32 -0
  94. package/src/server.ts +244 -0
  95. package/src/tools/about.ts +28 -0
  96. package/src/tools/check-environmental-compliance.ts +143 -0
  97. package/src/tools/check-freshness.ts +42 -0
  98. package/src/tools/get-ammonia-rules.ts +44 -0
  99. package/src/tools/get-bff-requirements.ts +52 -0
  100. package/src/tools/get-buffer-zone-rules.ts +43 -0
  101. package/src/tools/get-eip-requirements.ts +57 -0
  102. package/src/tools/get-nutrient-loss-limits.ts +44 -0
  103. package/src/tools/get-water-protection-zones.ts +50 -0
  104. package/src/tools/list-sources.ts +75 -0
  105. package/src/tools/search-environmental-rules.ts +35 -0
  106. package/tests/db.test.ts +80 -0
  107. package/tests/helpers/seed-db.ts +173 -0
  108. package/tests/jurisdiction.test.ts +35 -0
  109. package/tests/tools/about.test.ts +26 -0
  110. package/tests/tools/check-freshness.test.ts +50 -0
  111. package/tests/tools/list-sources.test.ts +61 -0
  112. package/tests/tools/search-environmental-rules.test.ts +47 -0
  113. package/tsconfig.json +19 -0
@@ -0,0 +1,36 @@
1
+ import { buildMeta } from '../metadata.js';
2
+ import { validateJurisdiction } from '../jurisdiction.js';
3
+ export function handleGetWaterProtectionZones(db, args) {
4
+ const jv = validateJurisdiction(args.jurisdiction);
5
+ if (!jv.valid)
6
+ return jv.error;
7
+ let sql = 'SELECT * FROM water_protection_zones WHERE jurisdiction = ?';
8
+ const params = [jv.jurisdiction];
9
+ if (args.zone_type) {
10
+ sql += ' AND LOWER(zone_type) = LOWER(?)';
11
+ params.push(args.zone_type);
12
+ }
13
+ sql += ' ORDER BY zone_type';
14
+ const zones = db.all(sql, params);
15
+ if (zones.length === 0 && args.zone_type) {
16
+ return {
17
+ error: 'not_found',
18
+ message: `No water protection zone of type '${args.zone_type}' found. Valid types: S1, S2, S3, Sm, Zu.`,
19
+ };
20
+ }
21
+ return {
22
+ jurisdiction: jv.jurisdiction,
23
+ zones_count: zones.length,
24
+ zones: zones.map(z => ({
25
+ zone_type: z.zone_type,
26
+ name: z.name,
27
+ restrictions: z.restrictions,
28
+ description: z.description,
29
+ legal_basis: z.legal_basis,
30
+ })),
31
+ _meta: buildMeta({
32
+ source_url: 'https://www.bafu.admin.ch/bafu/de/home/themen/wasser/fachinformationen/gewaesserschutz.html',
33
+ }),
34
+ };
35
+ }
36
+ //# sourceMappingURL=get-water-protection-zones.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-water-protection-zones.js","sourceRoot":"","sources":["../../src/tools/get-water-protection-zones.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAQ1D,MAAM,UAAU,6BAA6B,CAAC,EAAY,EAAE,IAAyB;IACnF,MAAM,EAAE,GAAG,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC,KAAK,CAAC;IAE/B,IAAI,GAAG,GAAG,6DAA6D,CAAC;IACxE,MAAM,MAAM,GAAc,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC;IAE5C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,GAAG,IAAI,kCAAkC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC;IAED,GAAG,IAAI,qBAAqB,CAAC;IAE7B,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,CAGjB,GAAG,EAAE,MAAM,CAAC,CAAC;IAEhB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACzC,OAAO;YACL,KAAK,EAAE,WAAW;YAClB,OAAO,EAAE,qCAAqC,IAAI,CAAC,SAAS,2CAA2C;SACxG,CAAC;IACJ,CAAC;IAED,OAAO;QACL,YAAY,EAAE,EAAE,CAAC,YAAY;QAC7B,WAAW,EAAE,KAAK,CAAC,MAAM;QACzB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACrB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;SAC3B,CAAC,CAAC;QACH,KAAK,EAAE,SAAS,CAAC;YACf,UAAU,EAAE,6FAA6F;SAC1G,CAAC;KACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { buildMeta } from '../metadata.js';
2
+ import type { Database } from '../db.js';
3
+ interface Source {
4
+ name: string;
5
+ authority: string;
6
+ official_url: string;
7
+ retrieval_method: string;
8
+ update_frequency: string;
9
+ license: string;
10
+ coverage: string;
11
+ last_retrieved?: string;
12
+ }
13
+ export declare function handleListSources(db: Database): {
14
+ sources: Source[];
15
+ _meta: ReturnType<typeof buildMeta>;
16
+ };
17
+ export {};
18
+ //# sourceMappingURL=list-sources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-sources.d.ts","sourceRoot":"","sources":["../../src/tools/list-sources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,CAAA;CAAE,CA4D1G"}
@@ -0,0 +1,61 @@
1
+ import { buildMeta } from '../metadata.js';
2
+ export function handleListSources(db) {
3
+ const lastIngest = db.get('SELECT value FROM db_metadata WHERE key = ?', ['last_ingest']);
4
+ const sources = [
5
+ {
6
+ name: 'Gewaesserschutzgesetz (GSchG) / Gewaesserschutzverordnung (GSchV)',
7
+ authority: 'BAFU (Bundesamt fuer Umwelt)',
8
+ official_url: 'https://www.bafu.admin.ch/bafu/de/home/themen/wasser/fachinformationen/gewaesserschutz.html',
9
+ retrieval_method: 'PDF_EXTRACT',
10
+ update_frequency: 'periodic (amendments as enacted)',
11
+ license: 'Swiss Federal Administration — free reuse',
12
+ coverage: 'Grundwasserschutzzonen S1-S3/Sm/Zu, Pufferstreifen, Gewaesserraum',
13
+ last_retrieved: lastIngest?.value,
14
+ },
15
+ {
16
+ name: 'Luftreinhalte-Verordnung (LRV) / Ammoniak-Emissionsfaktoren',
17
+ authority: 'BAFU / Agroscope',
18
+ official_url: 'https://www.bafu.admin.ch/bafu/de/home/themen/luft/fachinformationen/luftschadstoffquellen/emissionen-der-landwirtschaft.html',
19
+ retrieval_method: 'PDF_EXTRACT',
20
+ update_frequency: 'periodic (Agrammon model updates)',
21
+ license: 'Swiss Federal Administration — free reuse',
22
+ coverage: 'Ammoniakemissionen nach Ausbringtechnik, Lagerung, Tierkategorie',
23
+ last_retrieved: lastIngest?.value,
24
+ },
25
+ {
26
+ name: 'Direktzahlungsverordnung (DZV) — BFF-Typen und OELN',
27
+ authority: 'BLW (Bundesamt fuer Landwirtschaft)',
28
+ official_url: 'https://www.blw.admin.ch/blw/de/home/instrumente/direktzahlungen/biodiversitaetsbeitraege.html',
29
+ retrieval_method: 'PDF_EXTRACT',
30
+ update_frequency: 'annual (with DZV revisions)',
31
+ license: 'Swiss Federal Administration — free reuse',
32
+ coverage: 'BFF-Typen QI/QII, Beitraege, Mindestanteil, botanische Kriterien',
33
+ last_retrieved: lastIngest?.value,
34
+ },
35
+ {
36
+ name: 'Pa.Iv. 19.475 — Absenkpfad Naehrstoffverluste',
37
+ authority: 'Parlament / BLW',
38
+ official_url: 'https://www.blw.admin.ch/blw/de/home/nachhaltige-produktion/umwelt/naehrstoffe.html',
39
+ retrieval_method: 'PDF_EXTRACT',
40
+ update_frequency: 'annual targets through 2030',
41
+ license: 'Swiss Federal Administration — free reuse',
42
+ coverage: 'N- und P-Verlust-Reduktionsziele, jaehrliche Absenkpfade',
43
+ last_retrieved: lastIngest?.value,
44
+ },
45
+ {
46
+ name: 'VBBo — Verordnung ueber Belastungen des Bodens',
47
+ authority: 'BAFU',
48
+ official_url: 'https://www.bafu.admin.ch/bafu/de/home/themen/boden/fachinformationen/bodenschutz.html',
49
+ retrieval_method: 'PDF_EXTRACT',
50
+ update_frequency: 'periodic',
51
+ license: 'Swiss Federal Administration — free reuse',
52
+ coverage: 'Schwermetall-Richtwerte (Cd, Cu, Zn, Pb), Massnahmen bei Ueberschreitung',
53
+ last_retrieved: lastIngest?.value,
54
+ },
55
+ ];
56
+ return {
57
+ sources,
58
+ _meta: buildMeta(),
59
+ };
60
+ }
61
+ //# sourceMappingURL=list-sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-sources.js","sourceRoot":"","sources":["../../src/tools/list-sources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAc3C,MAAM,UAAU,iBAAiB,CAAC,EAAY;IAC5C,MAAM,UAAU,GAAG,EAAE,CAAC,GAAG,CAAoB,6CAA6C,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;IAE7G,MAAM,OAAO,GAAa;QACxB;YACE,IAAI,EAAE,mEAAmE;YACzE,SAAS,EAAE,8BAA8B;YACzC,YAAY,EAAE,6FAA6F;YAC3G,gBAAgB,EAAE,aAAa;YAC/B,gBAAgB,EAAE,kCAAkC;YACpD,OAAO,EAAE,2CAA2C;YACpD,QAAQ,EAAE,mEAAmE;YAC7E,cAAc,EAAE,UAAU,EAAE,KAAK;SAClC;QACD;YACE,IAAI,EAAE,6DAA6D;YACnE,SAAS,EAAE,kBAAkB;YAC7B,YAAY,EAAE,+HAA+H;YAC7I,gBAAgB,EAAE,aAAa;YAC/B,gBAAgB,EAAE,mCAAmC;YACrD,OAAO,EAAE,2CAA2C;YACpD,QAAQ,EAAE,kEAAkE;YAC5E,cAAc,EAAE,UAAU,EAAE,KAAK;SAClC;QACD;YACE,IAAI,EAAE,qDAAqD;YAC3D,SAAS,EAAE,qCAAqC;YAChD,YAAY,EAAE,gGAAgG;YAC9G,gBAAgB,EAAE,aAAa;YAC/B,gBAAgB,EAAE,6BAA6B;YAC/C,OAAO,EAAE,2CAA2C;YACpD,QAAQ,EAAE,kEAAkE;YAC5E,cAAc,EAAE,UAAU,EAAE,KAAK;SAClC;QACD;YACE,IAAI,EAAE,+CAA+C;YACrD,SAAS,EAAE,iBAAiB;YAC5B,YAAY,EAAE,qFAAqF;YACnG,gBAAgB,EAAE,aAAa;YAC/B,gBAAgB,EAAE,6BAA6B;YAC/C,OAAO,EAAE,2CAA2C;YACpD,QAAQ,EAAE,0DAA0D;YACpE,cAAc,EAAE,UAAU,EAAE,KAAK;SAClC;QACD;YACE,IAAI,EAAE,gDAAgD;YACtD,SAAS,EAAE,MAAM;YACjB,YAAY,EAAE,wFAAwF;YACtG,gBAAgB,EAAE,aAAa;YAC/B,gBAAgB,EAAE,UAAU;YAC5B,OAAO,EAAE,2CAA2C;YACpD,QAAQ,EAAE,0EAA0E;YACpF,cAAc,EAAE,UAAU,EAAE,KAAK;SAClC;KACF,CAAC;IAEF,OAAO;QACL,OAAO;QACP,KAAK,EAAE,SAAS,EAAE;KACnB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { type Database } from '../db.js';
2
+ interface SearchArgs {
3
+ query: string;
4
+ topic?: string;
5
+ jurisdiction?: string;
6
+ limit?: number;
7
+ }
8
+ export declare function handleSearchEnvironmentalRules(db: Database, args: SearchArgs): {
9
+ error: string;
10
+ supported: readonly string[];
11
+ message: string;
12
+ } | {
13
+ query: string;
14
+ jurisdiction: "CH";
15
+ results_count: number;
16
+ results: {
17
+ title: string;
18
+ body: string;
19
+ topic: string;
20
+ relevance_rank: number;
21
+ }[];
22
+ _meta: import("../metadata.js").Meta;
23
+ };
24
+ export {};
25
+ //# sourceMappingURL=search-environmental-rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-environmental-rules.d.ts","sourceRoot":"","sources":["../../src/tools/search-environmental-rules.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpD,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,8BAA8B,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU;;;;;;;;;;;;;;;EAuB5E"}
@@ -0,0 +1,26 @@
1
+ import { buildMeta } from '../metadata.js';
2
+ import { validateJurisdiction } from '../jurisdiction.js';
3
+ import { ftsSearch } from '../db.js';
4
+ export function handleSearchEnvironmentalRules(db, args) {
5
+ const jv = validateJurisdiction(args.jurisdiction);
6
+ if (!jv.valid)
7
+ return jv.error;
8
+ const limit = Math.min(args.limit ?? 20, 50);
9
+ let results = ftsSearch(db, args.query, limit);
10
+ if (args.topic) {
11
+ results = results.filter(r => r.topic.toLowerCase().includes(args.topic.toLowerCase()));
12
+ }
13
+ return {
14
+ query: args.query,
15
+ jurisdiction: jv.jurisdiction,
16
+ results_count: results.length,
17
+ results: results.map(r => ({
18
+ title: r.title,
19
+ body: r.body,
20
+ topic: r.topic,
21
+ relevance_rank: r.rank,
22
+ })),
23
+ _meta: buildMeta(),
24
+ };
25
+ }
26
+ //# sourceMappingURL=search-environmental-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-environmental-rules.js","sourceRoot":"","sources":["../../src/tools/search-environmental-rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAiB,MAAM,UAAU,CAAC;AASpD,MAAM,UAAU,8BAA8B,CAAC,EAAY,EAAE,IAAgB;IAC3E,MAAM,EAAE,GAAG,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC,KAAK,CAAC;IAE/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7C,IAAI,OAAO,GAAG,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAE/C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC3F,CAAC;IAED,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,YAAY,EAAE,EAAE,CAAC,YAAY;QAC7B,aAAa,EAAE,OAAO,CAAC,MAAM;QAC7B,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACzB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,cAAc,EAAE,CAAC,CAAC,IAAI;SACvB,CAAC,CAAC;QACH,KAAK,EAAE,SAAS,EAAE;KACnB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ services:
2
+ ch-environmental-compliance-mcp:
3
+ build: .
4
+ ports:
5
+ - "3000:3000"
6
+ environment:
7
+ - NODE_ENV=production
8
+ - PORT=3000
9
+ read_only: false
10
+ mem_limit: 128m
11
+ cpus: 0.5
12
+ restart: unless-stopped
@@ -0,0 +1,26 @@
1
+ import tseslint from '@typescript-eslint/eslint-plugin';
2
+ import tsparser from '@typescript-eslint/parser';
3
+
4
+ export default [
5
+ {
6
+ files: ['src/**/*.ts', 'tests/**/*.ts'],
7
+ languageOptions: {
8
+ parser: tsparser,
9
+ parserOptions: {
10
+ ecmaVersion: 2022,
11
+ sourceType: 'module',
12
+ },
13
+ },
14
+ plugins: {
15
+ '@typescript-eslint': tseslint,
16
+ },
17
+ rules: {
18
+ ...tseslint.configs.recommended.rules,
19
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
20
+ '@typescript-eslint/no-explicit-any': 'warn',
21
+ },
22
+ },
23
+ {
24
+ ignores: ['dist/', 'node_modules/', 'scripts/'],
25
+ },
26
+ ];
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@ansvar/ch-environmental-compliance-mcp",
3
+ "mcpName": "io.github.ansvar-systems/ch-environmental-compliance",
4
+ "version": "0.1.0",
5
+ "description": "Swiss environmental compliance data via MCP -- GSchG, LRV, BFF, ammonia rules, Pa.Iv. 19.475, UVP, VBBo",
6
+ "type": "module",
7
+ "main": "dist/server.js",
8
+ "bin": {
9
+ "ch-environmental-compliance-mcp": "dist/server.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "dev": "tsx watch src/server.ts",
14
+ "start": "node dist/server.js",
15
+ "start:http": "node dist/http-server.js",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
18
+ "lint": "eslint src/ tests/",
19
+ "typecheck": "tsc --noEmit",
20
+ "ingest": "tsx scripts/ingest.ts",
21
+ "ingest:fetch": "tsx scripts/ingest.ts --fetch-only",
22
+ "ingest:diff": "tsx scripts/ingest.ts --diff-only",
23
+ "ingest:full": "tsx scripts/ingest.ts --force",
24
+ "build:db": "tsx scripts/build-db.ts",
25
+ "freshness:check": "tsx scripts/check-freshness.ts",
26
+ "coverage:update": "tsx scripts/update-coverage.ts"
27
+ },
28
+ "keywords": ["mcp", "agriculture", "environment", "water-protection", "ammonia", "biodiversity", "switzerland"],
29
+ "author": "Ansvar Systems <info@ansvar.eu>",
30
+ "license": "Apache-2.0",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/Ansvar-Systems/ch-environmental-compliance-mcp"
34
+ },
35
+ "homepage": "https://ansvar.eu/open-agriculture",
36
+ "engines": {
37
+ "node": ">=20"
38
+ },
39
+ "dependencies": {
40
+ "@modelcontextprotocol/sdk": "^1.12.0",
41
+ "better-sqlite3": "^11.0.0",
42
+ "zod": "^3.23.0"
43
+ },
44
+ "devDependencies": {
45
+ "@types/better-sqlite3": "^7.6.0",
46
+ "@types/node": "^20.0.0",
47
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
48
+ "@typescript-eslint/parser": "^8.0.0",
49
+ "eslint": "^9.0.0",
50
+ "tsx": "^4.0.0",
51
+ "typescript": "^5.5.0",
52
+ "vitest": "^2.0.0"
53
+ }
54
+ }