@ansvar/ch-pest-management-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 (108) 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 +16 -0
  9. package/CODEOWNERS +1 -0
  10. package/COVERAGE.md +66 -0
  11. package/DISCLAIMER.md +39 -0
  12. package/Dockerfile +26 -0
  13. package/LICENSE +17 -0
  14. package/PRIVACY.md +23 -0
  15. package/README.md +98 -0
  16. package/SECURITY.md +26 -0
  17. package/TOOLS.md +202 -0
  18. package/data/coverage.json +34 -0
  19. package/data/database.db +0 -0
  20. package/data/sources.yml +57 -0
  21. package/dist/db.d.ts +26 -0
  22. package/dist/db.d.ts.map +1 -0
  23. package/dist/db.js +189 -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 +270 -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 +21 -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 +216 -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-freshness.d.ts +15 -0
  46. package/dist/tools/check-freshness.d.ts.map +1 -0
  47. package/dist/tools/check-freshness.js +26 -0
  48. package/dist/tools/check-freshness.js.map +1 -0
  49. package/dist/tools/get-approved-products.d.ts +38 -0
  50. package/dist/tools/get-approved-products.d.ts.map +1 -0
  51. package/dist/tools/get-approved-products.js +49 -0
  52. package/dist/tools/get-approved-products.js.map +1 -0
  53. package/dist/tools/get-ipm-guidance.d.ts +42 -0
  54. package/dist/tools/get-ipm-guidance.d.ts.map +1 -0
  55. package/dist/tools/get-ipm-guidance.js +40 -0
  56. package/dist/tools/get-ipm-guidance.js.map +1 -0
  57. package/dist/tools/get-pest-details.d.ts +43 -0
  58. package/dist/tools/get-pest-details.d.ts.map +1 -0
  59. package/dist/tools/get-pest-details.js +20 -0
  60. package/dist/tools/get-pest-details.js.map +1 -0
  61. package/dist/tools/get-treatments.d.ts +46 -0
  62. package/dist/tools/get-treatments.d.ts.map +1 -0
  63. package/dist/tools/get-treatments.js +41 -0
  64. package/dist/tools/get-treatments.js.map +1 -0
  65. package/dist/tools/identify-from-symptoms.d.ts +31 -0
  66. package/dist/tools/identify-from-symptoms.d.ts.map +1 -0
  67. package/dist/tools/identify-from-symptoms.js +49 -0
  68. package/dist/tools/identify-from-symptoms.js.map +1 -0
  69. package/dist/tools/list-sources.d.ts +18 -0
  70. package/dist/tools/list-sources.d.ts.map +1 -0
  71. package/dist/tools/list-sources.js +51 -0
  72. package/dist/tools/list-sources.js.map +1 -0
  73. package/dist/tools/search-crop-threats.d.ts +36 -0
  74. package/dist/tools/search-crop-threats.d.ts.map +1 -0
  75. package/dist/tools/search-crop-threats.js +48 -0
  76. package/dist/tools/search-crop-threats.js.map +1 -0
  77. package/dist/tools/search-pests.d.ts +31 -0
  78. package/dist/tools/search-pests.d.ts.map +1 -0
  79. package/dist/tools/search-pests.js +36 -0
  80. package/dist/tools/search-pests.js.map +1 -0
  81. package/docker-compose.yml +12 -0
  82. package/eslint.config.js +23 -0
  83. package/package.json +54 -0
  84. package/scripts/ingest.ts +1037 -0
  85. package/server.json +71 -0
  86. package/src/db.ts +230 -0
  87. package/src/http-server.ts +302 -0
  88. package/src/jurisdiction.ts +30 -0
  89. package/src/metadata.ts +31 -0
  90. package/src/server.ts +239 -0
  91. package/src/tools/about.ts +28 -0
  92. package/src/tools/check-freshness.ts +42 -0
  93. package/src/tools/get-approved-products.ts +68 -0
  94. package/src/tools/get-ipm-guidance.ts +56 -0
  95. package/src/tools/get-pest-details.ts +44 -0
  96. package/src/tools/get-treatments.ts +61 -0
  97. package/src/tools/identify-from-symptoms.ts +64 -0
  98. package/src/tools/list-sources.ts +65 -0
  99. package/src/tools/search-crop-threats.ts +74 -0
  100. package/src/tools/search-pests.ts +49 -0
  101. package/tests/db.test.ts +82 -0
  102. package/tests/helpers/seed-db.ts +187 -0
  103. package/tests/jurisdiction.test.ts +35 -0
  104. package/tests/tools/about.test.ts +27 -0
  105. package/tests/tools/check-freshness.test.ts +58 -0
  106. package/tests/tools/list-sources.test.ts +57 -0
  107. package/tests/tools/search-pests.test.ts +64 -0
  108. package/tsconfig.json +19 -0
@@ -0,0 +1,49 @@
1
+ name: Check Data Freshness
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 8 * * *"
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ issues: write
11
+
12
+ jobs:
13
+ freshness:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-node@v4
18
+ with:
19
+ node-version: "20"
20
+ cache: npm
21
+ - run: npm ci
22
+ - name: Check freshness
23
+ id: check
24
+ run: |
25
+ if npm run freshness:check 2>&1; then
26
+ echo "stale=false" >> "$GITHUB_OUTPUT"
27
+ else
28
+ echo "stale=true" >> "$GITHUB_OUTPUT"
29
+ fi
30
+ - name: Create issue if stale
31
+ if: steps.check.outputs.stale == 'true'
32
+ uses: actions/github-script@v7
33
+ with:
34
+ script: |
35
+ const existing = await github.rest.issues.listForRepo({
36
+ owner: context.repo.owner,
37
+ repo: context.repo.repo,
38
+ labels: 'data-stale',
39
+ state: 'open'
40
+ });
41
+ if (existing.data.length === 0) {
42
+ await github.rest.issues.create({
43
+ owner: context.repo.owner,
44
+ repo: context.repo.repo,
45
+ title: 'Data is stale — re-ingestion needed',
46
+ body: 'The daily freshness check detected stale data. Run the ingestion workflow to update.\n\n`gh workflow run ingest.yml`',
47
+ labels: ['data-stale']
48
+ });
49
+ }
@@ -0,0 +1,21 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, dev]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: actions/setup-node@v4
15
+ with:
16
+ node-version: "20"
17
+ cache: npm
18
+ - run: npm ci
19
+ - run: npm run typecheck
20
+ - run: npm run lint
21
+ - run: npm test
@@ -0,0 +1,25 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ schedule:
9
+ - cron: "0 6 * * 1"
10
+
11
+ permissions:
12
+ actions: read
13
+ contents: read
14
+ security-events: write
15
+
16
+ jobs:
17
+ analyze:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: github/codeql-action/init@v3
22
+ with:
23
+ languages: javascript-typescript
24
+ - uses: github/codeql-action/autobuild@v3
25
+ - uses: github/codeql-action/analyze@v3
@@ -0,0 +1,45 @@
1
+ name: Build and Push to GHCR
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ concurrency:
9
+ group: build-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ env:
13
+ REGISTRY: ghcr.io
14
+ IMAGE_NAME: ch-pest-management-mcp
15
+
16
+ permissions:
17
+ contents: read
18
+ packages: write
19
+
20
+ jobs:
21
+ build-and-push:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - uses: docker/setup-buildx-action@v3
26
+ - uses: docker/login-action@v3
27
+ with:
28
+ registry: ghcr.io
29
+ username: ${{ github.actor }}
30
+ password: ${{ secrets.GITHUB_TOKEN }}
31
+ - uses: docker/metadata-action@v5
32
+ id: meta
33
+ with:
34
+ images: ${{ env.REGISTRY }}/ansvar-systems/${{ env.IMAGE_NAME }}
35
+ tags: |
36
+ type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
37
+ type=sha,prefix=sha-,format=short
38
+ - uses: docker/build-push-action@v5
39
+ with:
40
+ context: .
41
+ push: true
42
+ tags: ${{ steps.meta.outputs.tags }}
43
+ platforms: linux/amd64
44
+ cache-from: type=gha
45
+ cache-to: type=gha,mode=max
@@ -0,0 +1,18 @@
1
+ name: Gitleaks
2
+
3
+ on:
4
+ push:
5
+ branches: [main, dev]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ scan:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ with:
15
+ fetch-depth: 0
16
+ - uses: gitleaks/gitleaks-action@v2
17
+ env:
18
+ GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
@@ -0,0 +1,59 @@
1
+ name: Re-ingest Data
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 4 1 * *"
6
+ workflow_dispatch:
7
+ inputs:
8
+ force:
9
+ description: "Force full rebuild even if no changes detected"
10
+ type: boolean
11
+ default: false
12
+
13
+ permissions:
14
+ contents: write
15
+
16
+ jobs:
17
+ ingest:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: actions/setup-node@v4
22
+ with:
23
+ node-version: "20"
24
+ cache: npm
25
+ - run: npm ci
26
+
27
+ - name: Fetch upstream data
28
+ run: npm run ingest:fetch
29
+
30
+ - name: Check for changes
31
+ id: diff
32
+ run: |
33
+ if [ "${{ inputs.force }}" = "true" ] || npm run ingest:diff 2>&1 | grep -q "changes detected"; then
34
+ echo "changed=true" >> "$GITHUB_OUTPUT"
35
+ else
36
+ echo "changed=false" >> "$GITHUB_OUTPUT"
37
+ echo "No upstream changes detected. Skipping rebuild."
38
+ fi
39
+
40
+ - name: Rebuild database
41
+ if: steps.diff.outputs.changed == 'true'
42
+ run: npm run ingest:full
43
+
44
+ - name: Run tests
45
+ if: steps.diff.outputs.changed == 'true'
46
+ run: npm test
47
+
48
+ - name: Update coverage
49
+ if: steps.diff.outputs.changed == 'true'
50
+ run: npm run coverage:update
51
+
52
+ - name: Commit updated database
53
+ if: steps.diff.outputs.changed == 'true'
54
+ run: |
55
+ git config user.name "github-actions[bot]"
56
+ git config user.email "github-actions[bot]@users.noreply.github.com"
57
+ git add data/database.db data/coverage.json data/.source-hashes.json
58
+ git diff --staged --quiet || git commit -m "chore: re-ingest data $(date +%Y-%m-%d)"
59
+ git push
@@ -0,0 +1,24 @@
1
+ name: Publish to npm
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+ id-token: write
10
+
11
+ jobs:
12
+ publish:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-node@v4
17
+ with:
18
+ node-version: "20"
19
+ registry-url: "https://registry.npmjs.org"
20
+ - run: npm ci
21
+ - run: npm run build
22
+ - run: npm publish --provenance --access public
23
+ env:
24
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - 2026-04-05
4
+
5
+ ### Added
6
+
7
+ - Initial release with 10 MCP tools (3 meta + 7 domain)
8
+ - SQLite + FTS5 database with schema for pests, treatments, IPM guidance, approved products
9
+ - Dual transport: stdio (npm) and Streamable HTTP (Docker)
10
+ - Jurisdiction validation (CH supported)
11
+ - Tiered FTS5 search (phrase > AND > prefix > stemmed > OR > LIKE fallback)
12
+ - Data freshness monitoring with 90-day staleness threshold
13
+ - Docker image with non-root user, health check
14
+ - CI/CD: TypeScript build, lint, test, CodeQL, Gitleaks, GHCR image build, ingestion, freshness check
15
+ - Bilingual disclaimer (DE/EN), privacy statement, security policy
16
+ - MCP registry (server.json) with public endpoint at mcp.ansvar.eu
package/CODEOWNERS ADDED
@@ -0,0 +1 @@
1
+ * @ansvar-systems/engineering
package/COVERAGE.md ADDED
@@ -0,0 +1,66 @@
1
+ # Coverage
2
+
3
+ ## Jurisdiction
4
+
5
+ Switzerland (CH) only.
6
+
7
+ ## Dataset Summary
8
+
9
+ | Category | Count |
10
+ |----------|-------|
11
+ | Pests (total) | 23 |
12
+ | -- Insects | 9 |
13
+ | -- Diseases | 8 |
14
+ | -- Weeds | 6 |
15
+ | Treatments | 30 |
16
+ | IPM guidance records | 12 |
17
+ | Approved products | 14 |
18
+ | Prognosis systems | 4 |
19
+ | Crop categories | 4 |
20
+ | Tools | 10 |
21
+
22
+ ## Crop Categories
23
+
24
+ - **Feldbau** (field crops): Winterweizen, Wintergerste, Winterraps, Kartoffeln, Zuckerrueben, Mais
25
+ - **Rebbau** (viticulture): Reben
26
+ - **Obstbau** (fruit): Apfel, Kirsche, Zwetschge
27
+ - **Gemuese** (vegetables): Karotten, Salat, Zwiebeln
28
+
29
+ ## Prognosis Systems
30
+
31
+ | System | Scope | URL |
32
+ |--------|-------|-----|
33
+ | PhytoPRE | Krautfaeule (potato/tomato late blight) | https://www.phytopre.ch |
34
+ | SOPRA | Insect flight forecasting | https://www.sopra.info |
35
+ | FusaProg | Fusarium risk in cereals | https://www.fusaprog.ch |
36
+ | VitiMeteo | Vine disease forecasting | https://www.vitimeteo.info |
37
+
38
+ ## What Is Covered
39
+
40
+ - Pest identification: names (DE), scientific names, lifecycle, damage descriptions, visual identification cues
41
+ - Treatment recommendations: chemical products (W-number, active substance, dosage, waiting period, buffer zone) and non-chemical alternatives (biological, cultural, mechanical)
42
+ - IPM guidance: OELN Schadschwellen (damage thresholds), monitoring methods, cultural controls, prognosis system references
43
+ - Approved products: BLW Pflanzenschutzmittelverzeichnis entries with Auflagen and Aktionsplan status
44
+ - Symptom-based differential diagnosis
45
+
46
+ ## What Is NOT Covered
47
+
48
+ - Real-time prognosis data (PhytoPRE, SOPRA, FusaProg, VitiMeteo provide real-time data on their own portals -- this MCP references the systems but does not replicate live forecasts)
49
+ - Cantonal deviations (some cantons have additional restrictions beyond federal OELN rules)
50
+ - Organic-specific rules (Bio Suisse, Demeter -- only OELN/IP-Suisse requirements are included)
51
+ - Seed treatment products (Beizmittel)
52
+ - Fertiliser interactions with pest management
53
+ - Veterinary pest control (livestock parasites)
54
+ - Forest pest management (Eidg. Forschungsanstalt WSL scope)
55
+
56
+ ## Limitations
57
+
58
+ - Product authorisations change frequently. Always verify current status on [psm.admin.ch](https://www.psm.admin.ch/de/produkte)
59
+ - Professional use of plant protection products requires a Fachbewilligung PSM
60
+ - Schadschwellen values are reference values from Agroscope -- field conditions vary
61
+ - FTS search works best with German terms; English terms have partial coverage
62
+ - Dataset is a curated subset, not a complete mirror of BLW or Agroscope databases
63
+
64
+ ## Data Freshness
65
+
66
+ Run `check_data_freshness` to see the ingestion date. Threshold for staleness: 90 days. Re-ingestion: `gh workflow run ingest.yml`.
package/DISCLAIMER.md ADDED
@@ -0,0 +1,39 @@
1
+ # Haftungsausschluss / Disclaimer
2
+
3
+ ## Keine professionelle Beratung / Not Professional Advice
4
+
5
+ Die von diesem Tool bereitgestellten Daten stellen keine professionelle Pflanzenschutzberatung dar. Die Angaben basieren auf dem Pflanzenschutzmittelverzeichnis des BLW (psm.admin.ch), den Pflanzenschutzempfehlungen von Agroscope, den OELN-Richtlinien und dem Aktionsplan Pflanzenschutzmittel. Die tatsaechlichen Verhaeltnisse auf dem einzelnen Betrieb koennen erheblich abweichen. Vor jeder Anwendung von Pflanzenschutzmitteln (PSM) ist die aktuelle Zulassung im Pflanzenschutzmittelverzeichnis zu pruefen. Fuer die berufliche Anwendung ist eine Fachbewilligung PSM erforderlich.
6
+
7
+ The data served by this tool does not constitute professional crop protection advice. Data is sourced from the BLW Pflanzenschutzmittelverzeichnis (psm.admin.ch), Agroscope pest management recommendations, OELN guidelines, and the Aktionsplan Pflanzenschutzmittel. Individual farm conditions vary. Before any pesticide application, verify the current authorisation in the BLW product register. Professional use requires a Fachbewilligung PSM.
8
+
9
+ ## Datenquellen / Data Sources
10
+
11
+ - **BLW Pflanzenschutzmittelverzeichnis** -- Bundesamt fuer Landwirtschaft (zugelassene Produkte, Wirkstoffe, Auflagen, Wartefristen)
12
+ - **Agroscope Pflanzenschutzempfehlungen** -- Schadschwellen, Ueberwachungsmethoden, Prognosesysteme (PhytoPRE, SOPRA, FusaProg)
13
+ - **AGRIDEA OELN-Pflanzenschutz-Checklisten** -- Pflanzenschutzanforderungen fuer Feldbau, Rebbau, Obstbau
14
+ - **Aktionsplan Pflanzenschutzmittel** -- 50%-Risikoreduktionsziele, IPM-Strategie, Pufferstreifenanforderungen
15
+
16
+ Daten der Bundesverwaltung werden unter dem Grundsatz des oeffentlichen Informationszugangs verwendet.
17
+
18
+ Data from Swiss federal authorities is used under public-sector information access principles.
19
+
20
+ ## Kantonale Unterschiede / Cantonal Variation
21
+
22
+ Swiss pest management regulation includes federal OELN rules and cantonal implementation. This tool provides federal-level reference values. Users must verify cantonal requirements, particularly:
23
+
24
+ - **Pufferstreifen** (buffer zones): may vary by canton and water body classification
25
+ - **Pflanzenschutz in Schutzzonen**: cantonal restrictions in protected areas
26
+ - **Meldepflichten**: cantonal reporting obligations for regulated organisms
27
+ - **Fachbewilligung PSM**: cantonal issuing authorities
28
+
29
+ Bei Unsicherheit die kantonale Pflanzenschutzfachstelle oder AGRIDEA kontaktieren.
30
+
31
+ ## Aktualitaet / Currency
32
+
33
+ Pflanzenschutzmittelzulassungen aendern sich laufend. Schadschwellen werden jaehrlich aktualisiert. Dieses Tool zeigt den Datenstand zum Zeitpunkt der letzten Aktualisierung. Die Funktion `check_data_freshness` zeigt das Alter der Daten.
34
+
35
+ Product authorisations change continuously. Damage thresholds are updated annually. This tool shows data as of the last ingestion run. Use `check_data_freshness` to see the data age.
36
+
37
+ ## Keine Gewaehrleistung / No Warranty
38
+
39
+ This software is provided "as is" without warranty of any kind. See the Apache-2.0 license for details.
package/Dockerfile ADDED
@@ -0,0 +1,26 @@
1
+ FROM node:20-slim AS builder
2
+ RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*
3
+ WORKDIR /app
4
+ COPY package*.json ./
5
+ RUN npm ci
6
+ COPY tsconfig.json ./
7
+ COPY src/ src/
8
+ RUN npm run build
9
+
10
+ FROM node:20-slim
11
+ RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*
12
+ RUN addgroup --system --gid 1001 nodejs && \
13
+ adduser --system --uid 1001 nodejs
14
+ WORKDIR /app
15
+ COPY package*.json ./
16
+ RUN npm ci --omit=dev && npm cache clean --force && apt-get purge -y python3 make g++ && apt-get autoremove -y
17
+ COPY --from=builder /app/dist dist/
18
+ COPY data/ data/
19
+ RUN chown -R nodejs:nodejs /app/data
20
+ USER nodejs
21
+ ENV NODE_ENV=production
22
+ ENV PORT=3000
23
+ EXPOSE 3000
24
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
25
+ CMD node -e "require('http').get('http://localhost:' + process.env.PORT + '/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) })"
26
+ CMD ["node", "dist/http-server.js"]
package/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+
17
+ Copyright 2026 Ansvar Systems
package/PRIVACY.md ADDED
@@ -0,0 +1,23 @@
1
+ # Privacy Statement
2
+
3
+ ## No Data Collection
4
+
5
+ This MCP server:
6
+
7
+ - Does **not** collect, store, or transmit any user data
8
+ - Does **not** use cookies, analytics, or telemetry
9
+ - Does **not** require user accounts or authentication
10
+ - Does **not** log queries or usage patterns
11
+ - Does **not** store any client-side state
12
+
13
+ ## Data Served
14
+
15
+ All data returned by this server is sourced from publicly available Swiss federal publications (BLW, Agroscope, AGRIDEA) and the Aktionsplan Pflanzenschutzmittel. No personal data, proprietary data, or confidential information is included.
16
+
17
+ ## Self-Hosting
18
+
19
+ This server can be self-hosted. When you run it locally via npm or Docker, all processing happens on your machine. No external network calls are made at query time -- all data is embedded in the SQLite database.
20
+
21
+ ## Contact
22
+
23
+ For privacy questions: privacy@ansvar.eu
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Switzerland Pest Management MCP
2
+
3
+ MCP server for Swiss crop protection and pest management data. Covers pests (insects, diseases, weeds), approved plant protection products from the BLW Pflanzenschutzmittelverzeichnis, IPM (Integrierter Pflanzenschutz) guidance with OELN Schadschwellen, and prognosis systems (PhytoPRE, SOPRA, FusaProg, VitiMeteo).
4
+
5
+ Built on data from the Bundesamt fuer Landwirtschaft (BLW), Agroscope, AGRIDEA, and the Aktionsplan Pflanzenschutzmittel.
6
+
7
+ ## Quick Start
8
+
9
+ ### npx (stdio)
10
+
11
+ ```bash
12
+ npx -y @ansvar/ch-pest-management-mcp
13
+ ```
14
+
15
+ ### Docker (Streamable HTTP)
16
+
17
+ ```bash
18
+ docker run -p 3000:3000 ghcr.io/ansvar-systems/ch-pest-management-mcp:latest
19
+ ```
20
+
21
+ ### Public endpoint (Streamable HTTP, no auth)
22
+
23
+ ```
24
+ https://mcp.ansvar.eu/ch-pest-management/mcp
25
+ ```
26
+
27
+ ## Tools
28
+
29
+ 10 tools covering pest identification, treatment lookup, IPM guidance, approved products, and data provenance.
30
+
31
+ | Tool | Description |
32
+ |------|-------------|
33
+ | `about` | Server metadata, version, coverage, data sources |
34
+ | `list_sources` | All data sources with authority, URL, license, freshness |
35
+ | `check_data_freshness` | Ingestion date, staleness status, refresh command |
36
+ | `search_pests` | FTS5 search across pests, diseases, weeds (DE/EN) |
37
+ | `get_pest_details` | Full pest profile: lifecycle, identification, treatments |
38
+ | `get_treatments` | Chemical and non-chemical controls for a pest |
39
+ | `get_ipm_guidance` | IPM guidance per crop: Schadschwellen, monitoring, OELN |
40
+ | `search_crop_threats` | All pests/diseases/weeds threatening a crop |
41
+ | `identify_from_symptoms` | Differential diagnosis from symptom descriptions |
42
+ | `get_approved_products` | BLW-approved products: W-number, substances, Auflagen |
43
+
44
+ Full parameter documentation: [TOOLS.md](TOOLS.md)
45
+
46
+ ## Coverage
47
+
48
+ - **Jurisdiction:** Switzerland (CH)
49
+ - **Pests:** 23 (9 insects, 8 diseases, 6 weeds)
50
+ - **Treatments:** 30
51
+ - **IPM guidance records:** 12
52
+ - **Approved products:** 14
53
+ - **Prognosis systems:** PhytoPRE, SOPRA, FusaProg, VitiMeteo
54
+ - **Crop categories:** Feldbau, Rebbau, Obstbau, Gemuese
55
+ - **Languages:** German (primary), English search supported
56
+
57
+ Full coverage breakdown: [COVERAGE.md](COVERAGE.md)
58
+
59
+ ## Data Sources
60
+
61
+ | Source | Authority | URL |
62
+ |--------|-----------|-----|
63
+ | Pflanzenschutzmittelverzeichnis | BLW | https://www.psm.admin.ch/de/produkte |
64
+ | Pflanzenschutzempfehlungen | Agroscope | https://www.agroscope.admin.ch |
65
+ | OELN-Pflanzenschutz-Checklisten | AGRIDEA | https://www.agridea.ch |
66
+ | Aktionsplan Pflanzenschutzmittel | Bundesrat / BLW | https://www.blw.admin.ch |
67
+
68
+ ## Development
69
+
70
+ ```bash
71
+ npm install
72
+ npm run build
73
+ npm test
74
+ npm run lint
75
+ ```
76
+
77
+ ### Re-ingest data
78
+
79
+ ```bash
80
+ npm run ingest # incremental
81
+ npm run ingest:full # full rebuild
82
+ npm run freshness:check # check staleness
83
+ ```
84
+
85
+ ## License
86
+
87
+ Apache-2.0. See [LICENSE](LICENSE).
88
+
89
+ Data sourced from Swiss federal authorities under public-sector information principles.
90
+
91
+ ## Links
92
+
93
+ - [Ansvar MCP Network](https://ansvar.ai/mcp)
94
+ - [TOOLS.md](TOOLS.md) -- full tool documentation
95
+ - [COVERAGE.md](COVERAGE.md) -- dataset coverage
96
+ - [DISCLAIMER.md](DISCLAIMER.md) -- legal disclaimer (DE/EN)
97
+ - [SECURITY.md](SECURITY.md) -- vulnerability reporting
98
+ - [PRIVACY.md](PRIVACY.md) -- privacy statement
package/SECURITY.md ADDED
@@ -0,0 +1,26 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ If you discover a security vulnerability, please report it responsibly:
6
+
7
+ 1. **Do NOT open a public issue**
8
+ 2. Email security@ansvar.eu with:
9
+ - Description of the vulnerability
10
+ - Steps to reproduce
11
+ - Potential impact
12
+ 3. We will acknowledge within 48 hours and provide a timeline for fix
13
+
14
+ ## Supported Versions
15
+
16
+ | Version | Supported |
17
+ |---------|-----------|
18
+ | Latest | Yes |
19
+
20
+ ## Security Measures
21
+
22
+ - All dependencies scanned via CodeQL, Gitleaks, and GitHub Advanced Security
23
+ - No secrets stored in code -- all data is public domain
24
+ - SQLite database is read-only at runtime
25
+ - Container runs as non-root user (nodejs:1001) with health checks
26
+ - No external network calls at query time -- all data embedded in SQLite