@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.
- package/.github/workflows/check-freshness.yml +49 -0
- package/.github/workflows/ci.yml +21 -0
- package/.github/workflows/codeql.yml +25 -0
- package/.github/workflows/ghcr-build.yml +45 -0
- package/.github/workflows/gitleaks.yml +18 -0
- package/.github/workflows/ingest.yml +59 -0
- package/.github/workflows/publish.yml +24 -0
- package/CHANGELOG.md +16 -0
- package/CODEOWNERS +1 -0
- package/COVERAGE.md +66 -0
- package/DISCLAIMER.md +39 -0
- package/Dockerfile +26 -0
- package/LICENSE +17 -0
- package/PRIVACY.md +23 -0
- package/README.md +98 -0
- package/SECURITY.md +26 -0
- package/TOOLS.md +202 -0
- package/data/coverage.json +34 -0
- package/data/database.db +0 -0
- package/data/sources.yml +57 -0
- package/dist/db.d.ts +26 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +189 -0
- package/dist/db.js.map +1 -0
- package/dist/http-server.d.ts +2 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +270 -0
- package/dist/http-server.js.map +1 -0
- package/dist/jurisdiction.d.ts +18 -0
- package/dist/jurisdiction.d.ts.map +1 -0
- package/dist/jurisdiction.js +16 -0
- package/dist/jurisdiction.js.map +1 -0
- package/dist/metadata.d.ts +10 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +21 -0
- package/dist/metadata.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +216 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/about.d.ts +15 -0
- package/dist/tools/about.d.ts.map +1 -0
- package/dist/tools/about.js +27 -0
- package/dist/tools/about.js.map +1 -0
- package/dist/tools/check-freshness.d.ts +15 -0
- package/dist/tools/check-freshness.d.ts.map +1 -0
- package/dist/tools/check-freshness.js +26 -0
- package/dist/tools/check-freshness.js.map +1 -0
- package/dist/tools/get-approved-products.d.ts +38 -0
- package/dist/tools/get-approved-products.d.ts.map +1 -0
- package/dist/tools/get-approved-products.js +49 -0
- package/dist/tools/get-approved-products.js.map +1 -0
- package/dist/tools/get-ipm-guidance.d.ts +42 -0
- package/dist/tools/get-ipm-guidance.d.ts.map +1 -0
- package/dist/tools/get-ipm-guidance.js +40 -0
- package/dist/tools/get-ipm-guidance.js.map +1 -0
- package/dist/tools/get-pest-details.d.ts +43 -0
- package/dist/tools/get-pest-details.d.ts.map +1 -0
- package/dist/tools/get-pest-details.js +20 -0
- package/dist/tools/get-pest-details.js.map +1 -0
- package/dist/tools/get-treatments.d.ts +46 -0
- package/dist/tools/get-treatments.d.ts.map +1 -0
- package/dist/tools/get-treatments.js +41 -0
- package/dist/tools/get-treatments.js.map +1 -0
- package/dist/tools/identify-from-symptoms.d.ts +31 -0
- package/dist/tools/identify-from-symptoms.d.ts.map +1 -0
- package/dist/tools/identify-from-symptoms.js +49 -0
- package/dist/tools/identify-from-symptoms.js.map +1 -0
- package/dist/tools/list-sources.d.ts +18 -0
- package/dist/tools/list-sources.d.ts.map +1 -0
- package/dist/tools/list-sources.js +51 -0
- package/dist/tools/list-sources.js.map +1 -0
- package/dist/tools/search-crop-threats.d.ts +36 -0
- package/dist/tools/search-crop-threats.d.ts.map +1 -0
- package/dist/tools/search-crop-threats.js +48 -0
- package/dist/tools/search-crop-threats.js.map +1 -0
- package/dist/tools/search-pests.d.ts +31 -0
- package/dist/tools/search-pests.d.ts.map +1 -0
- package/dist/tools/search-pests.js +36 -0
- package/dist/tools/search-pests.js.map +1 -0
- package/docker-compose.yml +12 -0
- package/eslint.config.js +23 -0
- package/package.json +54 -0
- package/scripts/ingest.ts +1037 -0
- package/server.json +71 -0
- package/src/db.ts +230 -0
- package/src/http-server.ts +302 -0
- package/src/jurisdiction.ts +30 -0
- package/src/metadata.ts +31 -0
- package/src/server.ts +239 -0
- package/src/tools/about.ts +28 -0
- package/src/tools/check-freshness.ts +42 -0
- package/src/tools/get-approved-products.ts +68 -0
- package/src/tools/get-ipm-guidance.ts +56 -0
- package/src/tools/get-pest-details.ts +44 -0
- package/src/tools/get-treatments.ts +61 -0
- package/src/tools/identify-from-symptoms.ts +64 -0
- package/src/tools/list-sources.ts +65 -0
- package/src/tools/search-crop-threats.ts +74 -0
- package/src/tools/search-pests.ts +49 -0
- package/tests/db.test.ts +82 -0
- package/tests/helpers/seed-db.ts +187 -0
- package/tests/jurisdiction.test.ts +35 -0
- package/tests/tools/about.test.ts +27 -0
- package/tests/tools/check-freshness.test.ts +58 -0
- package/tests/tools/list-sources.test.ts +57 -0
- package/tests/tools/search-pests.test.ts +64 -0
- 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
|