Wsl Envidat Mcp

io.github.malkreide由 GitHub 帳號 malkreide 發布v0.3.1更新於 Oct 24, 2026

WSL / EnviDat environmental research datasets via CKAN

概覽

AI 產生的概覽

讓助理檢索瑞士 WSL 的 EnviDat 公開環境研究資料集,涵蓋森林、積雪、雪崩與自然災害等主題。

可以做什麼
把 EnviDat 的 CKAN API 包裝成十個唯讀工具與兩個資源。工具支援統一檢索,可依關鍵字、研究領域、機構與地理邊界框篩選,也能取得資料集中繼資料與 DOI、機構與標籤清單、最新資料集、目錄統計,以及雪崩與積雪、森林(含國家森林清查 LFI)、滑坡落石洪水等自然災害的專題查詢。資源用於檢視研究單位與研究領域。
適用情境
當助理需要瑞士環境研究資料時適用,例如雪崩事故紀錄、森林狀況與清查資料、積雪與冰、生物多樣性、景觀或自然災害資料集,並可依關鍵字、領域、機構或地理範圍篩選。
執行需求
需要 Python 3.11+ 以及 pip 或 uv/uvx;以 stdio 方式在本機執行,也可作為 Streamable HTTP 端點執行。所有工具都會即時連線 envidat.ch,因此需要網路。不需要 API 金鑰或帳號。選用環境變數 MCP_TRANSPORT、MCP_HOST 與 PORT 可設定 HTTP 模式。
安裝前請注意
唯讀:所有工具只送出 HTTP GET 請求,不會寫入、修改或刪除任何資料,也不涉及憑證或個人資料。結果取決於上游公開 API,該 API 沒有公開的速率限制,應保守使用 limit 與 rows 參數。Streamable HTTP 模式沒有驗證層,僅適合單一使用者部署或置於具驗證機制的閘道之後;只有在容器內才建議把 MCP_HOST 設為 0.0.0.0。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Wsl Envidat Mcp,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

🇨🇭 Part of the Swiss Public Data MCP Portfolio

wsl-envidat-mcp 🌲❄️⛰️

[Version] [License: MIT] [Python 3.11+] [MCP] [Data Source] [No API Key] [CI]

MCP server connecting AI models to Swiss environmental research data from WSL via EnviDat — forest, snow, avalanches, natural hazards and biodiversity, no API key required.

🇩🇪 Deutsche Version


Phase

This server is in Phase 1: Read-only Wrapper.

PropertyStatus
Read tools✅ 10 tools, all readOnlyHint: true
Write tools❌ none (EnviDat is read-only public data)
Semantic Layer⚠️ partial — three domain tools curate Solr queries
OAuth / Auth Gateway❌ not required (Public Open Data, no API key)
Container hardening✅ multi-stage Dockerfile, non-root
Test suite✅ 38 offline unit tests + 31 live integration tests
Audit run✅ 2026-05-27 (mcp-audit-skill v1.0.0)

Phase-2 ideas (caching layer, semantic aggregation tool combining forest + snow + hazard data into a "Lage-Übersicht"): tracked under docs/.


Overview

The WSL (Eidgenössische Forschungsanstalt für Wald, Schnee und Landschaft / Swiss Federal Research Institute for Forest, Snow and Landscape) is one of Europe's leading environmental research institutes. Its open data platform EnviDat provides access to 1,000+ research datasets, time series of up to 130 years, and data from 6,000+ monitoring stations.

This MCP server exposes the EnviDat CKAN API as 10 tools and 2 resources, enabling AI assistants to search, filter and retrieve WSL research data by keyword, domain, or geographic bounding box — all without an API key.

Anchor demo query: "How was air quality and forest health around Schulhaus Leutschenbach in Zurich — and what does the WSL say about the current forest condition in the canton?"

Demo

[Demo: Claude using wsl_get_avalanche_data, wsl_get_forest_data and wsl_catalog_stats]


Features

  • 10 tools covering full-text search, domain-specific queries, spatial search, and curated thematic tools (avalanche, forest, natural hazards)
  • 2 MCP resources for organizations and research domains
  • 5 research domains: Forest · Biodiversity · Natural Hazards · Snow & Ice · Landscape
  • 815+ datasets, time series since 1890, data from the SLF avalanche research institute
  • No API key required — all data publicly accessible via open licenses
  • Dual transport: stdio (Claude Desktop / local) + Streamable HTTP (cloud deployment)
  • Model-agnostic: works with Claude, GPT-4, and any MCP-compatible client

Prerequisites

  • Python 3.11+
  • pip or uv / uvx
  • Internet connection (live API calls to envidat.ch)

Installation

bash
# Recommended: uvx (no installation needed)uvx wsl-envidat-mcp
# Or with pippip install wsl-envidat-mcp
# Developmentgit clone https://github.com/malkreide/wsl-envidat-mcp.gitcd wsl-envidat-mcppip install -e ".[dev]"

Quickstart

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

json
{  "mcpServers": {    "wsl-envidat": {      "command": "uvx",      "args": ["wsl-envidat-mcp"]    }  }}

Restart Claude Desktop, then ask:

  • "What WSL datasets exist on fatal avalanche accidents in Switzerland?"
  • "Show me forest inventory data from the LFI for the canton of Zurich."
  • "Which natural hazard research data does the SLF publish on EnviDat?"
  • "Are there WSL datasets on drought conditions in summer 2022?"
  • "What biodiversity data is available for alpine ecosystems?"

Configuration

No API key required. Optional environment variables:

VariableDefaultDescription
MCP_TRANSPORTstdioTransport mode: stdio or streamable-http (legacy streamable_http is accepted)
MCP_HOST127.0.0.1Bind address for streamable-http. Use 0.0.0.0 only inside a container.
PORT8000Port for Streamable HTTP mode

Cloud Deployment (Streamable HTTP)

For use via claude.ai in the browser (e.g. on managed workstations without local software):

bash
# Local: keep MCP_HOST at its default 127.0.0.1MCP_TRANSPORT=streamable-http PORT=8000 python -m wsl_envidat_mcp.server
# Container: bind to all interfaces inside the container onlyMCP_TRANSPORT=streamable-http MCP_HOST=0.0.0.0 PORT=8000 python -m wsl_envidat_mcp.server

💡 "stdio for the developer laptop, streamable-http for the browser."

⚠️ Multi-Replica Cloud Deployments: Session state lives in the server. Run a single replica or enable sticky sessions (Railway/Render setting, or sessionAffinity: ClientIP on Kubernetes Services).

⚠️ Multi-Tenant / Unauthenticated Streamable HTTP: This server has no auth layer (auth_model: none). Streamable HTTP without a reverse-proxy + OAuth/API-Gateway is intended only for single-user deployments (e.g. one user's claude.ai browser session). For multi-tenant use, front the server with an authenticating gateway.

Container image (recommended for cloud)

A hardened multi-stage image is published to GitHub Container Registry on every main push and semver tag. Runs as non-root (uid=1000), no build tools in the runtime layer, multi-arch (linux/amd64 + linux/arm64).

The publishing workflow is .github/workflows/container.yml — not publish.yml, which only uploads the Python package to PyPI on a release. container.yml is delivery, not a gate: it does not gate a pull request, and a red run there means the image is missing, not that the code is broken.

bash
docker run --rm -p 8000:8000 \  --read-only --tmpfs /tmp \  --cap-drop=ALL --security-opt=no-new-privileges \  ghcr.io/malkreide/wsl-envidat-mcp:latest

Kubernetes hardening (excerpt):

yaml
securityContext:  runAsNonRoot: true  runAsUser: 1000  readOnlyRootFilesystem: true  allowPrivilegeEscalation: false  capabilities: { drop: ["ALL"] }

Available Tools

ToolDescription
wsl_searchUnified search — combine query, domain, organization, and bbox filters
wsl_get_datasetFull metadata, DOI, download URLs for a specific dataset
wsl_list_organizationsList all WSL research units on EnviDat
wsl_get_organizationDetails of a specific research unit incl. datasets
wsl_list_tagsBrowse available tags/keywords
wsl_get_recent_datasetsMost recently updated datasets
wsl_get_avalanche_dataSLF avalanche & snow data (incl. fatal accidents since 1936)
wsl_get_forest_dataForest data incl. National Forest Inventory (LFI) & Sanasilva
wsl_get_naturgefahren_dataNatural hazard datasets (landslides, rockfall, floods)
wsl_catalog_statsCatalog overview and statistics

Example Use Cases

QueryTool
"Fatal avalanche accidents in Valais since 2000?"wsl_get_avalanche_data
"Forest health data for canton Zurich?"wsl_get_forest_data
"Landslide risk datasets near Brienz?"wsl_get_naturgefahren_data
"Most recent WSL publications on biodiversity?"wsl_search(domain="biodiversitaet")
"Which datasets cover the area around Lake Constance?"wsl_search(bbox=[9.0, 47.5, 9.7, 47.8])
"How many datasets does SLF publish?"wsl_get_organization

Resources

URIDescription
envidat://organization/{name}Research unit (e.g. slf, wsl)
envidat://domain/{domain}Domain overview with top datasets

Valid domain values: wald, biodiversitaet, naturgefahren, schnee_eis, landschaft


Architecture

┌─────────────────┐     ┌───────────────────────────┐     ┌──────────────────────────┐│   Claude / AI   │────▶│    WSL EnviDat MCP        │────▶│       envidat.ch          ││   (MCP Host)    │◀────│    (MCP Server)           │◀────│                          │└─────────────────┘     │                           │     │  CKAN API  (REST/JSON)   │                        │  10 Tools · 2 Resources   │     │  Solr full-text search   │                        │  Stdio | Streamable HTTP  │     │  1,000+ research datasets│                        │                           │     │  815+ open datasets      │                        │  server.py                │     │  Time series since 1890  │                        │  api_client.py            │     └──────────────────────────┘                        └───────────────────────────┘

Infrastructure Components

ComponentMetaphorFunction
api_client.pyLibrarianHandles all HTTP requests to EnviDat CKAN API
server.pyReception deskRegisters all 10 tools and 2 resources with FastMCP
Domain filtersFiling cabinetPre-configured keyword sets per research domain
Bounding box searchMap overlaySpatial filtering via lat/lon coordinates

Project Structure

wsl-envidat-mcp/├── src/wsl_envidat_mcp/│   ├── __init__.py         # Package│   ├── server.py           # MCP server — 10 tools, 2 resources│   └── api_client.py       # HTTP client for EnviDat CKAN API├── tests/│   └── test_integration.py # 11 live API integration tests├── .github/workflows/│   ├── ci.yml              # Gates: lint, format, syntax, import, tests, version sync│   ├── live.yml            # Scheduled live tests against envidat.ch (cron 05:47 UTC)│   ├── container.yml       # Builds & pushes the ghcr.io image (delivery, not a gate)│   └── publish.yml         # Uploads the Python package to PyPI on a release├── pyproject.toml          # Project config (hatchling build backend)├── CHANGELOG.md├── CONTRIBUTING.md         # Contribution guide (English)├── CONTRIBUTING.de.md      # Contribution guide (German)├── SECURITY.md             # Security policy & posture (English)├── SECURITY.de.md          # Security policy & posture (German)├── LICENSE                 # MIT├── README.md               # This file (English)└── README.de.md            # German version

Combination with Other MCP Servers

This server is part of the Swiss Open Data MCP Portfolio and integrates well with:

CombinationUse Case
+ zurich-opendata-mcpUrban climate + forest condition around Zurich
+ swiss-statistics-mcpPopulation data + environmental quality
+ swiss-transport-mcpAvalanche risk + public transport connections
+ fedlex-mcpForest protection law + actual LFI forest condition
+ global-education-mcpCompare environmental education data internationally

Known Limitations

  • Solr search: OR is treated as a stopword — use single, specific search terms per query
  • Domain search: Results depend on WSL's internal keyword tagging — not all datasets are tagged consistently
  • Spatial search: Bounding box filtering is approximate; verify coordinates with individual dataset metadata
  • Live API: All tools make live calls to envidat.ch — results depend on availability of the public API
  • Languages: Dataset metadata is primarily in English and German; some older entries may be in German only

Safety & Limits

  • Read-only: All tools perform HTTP GET requests only — no data is written, modified, or deleted on EnviDat.
  • No personal data: The API returns research metadata, dataset descriptions, and download URLs. No personally identifiable information (PII) is processed or stored by this server.
  • Rate limits: The EnviDat CKAN API is public without documented rate limits. Use limit and rows parameters conservatively. The server enforces a 30-second timeout per request.
  • Data freshness: All tools make live API calls — results reflect the current state of the EnviDat catalog at query time. No caching is performed by this server.
  • Terms of service: Data is subject to the EnviDat Terms of Use. Individual datasets are published under various open licenses (Creative Commons, CC0) — see dataset metadata.
  • No guarantees: This is a community project, not affiliated with WSL or EnviDat. Availability depends on the upstream EnviDat API.

For the full security posture (egress allow-list, redirect handling, accepted risks) see SECURITY.md.


MCP Protocol Version

This server speaks two protocol eras over the same endpoint. The client's first request on a connection decides which one applies; a later claim from the other era is refused.

EraRevisionWho reaches it
initialize handshake2024-11-05 … 2025-11-25What today's clients speak. The server answers with the revision asked for, or with the 2025-11-25 ceiling when the request asks for something newer.
Per-request envelope2026-07-28A request carrying the 2026-07-28 _meta envelope opens a modern connection.

Both revisions are pinned in tests/test_protocol_version.py and asserted against the installed SDK, so a Dependabot bump of mcp cannot move either one silently. This server builds no ASGI app to send an initialize through, so the gate asserts the SDK constants rather than a measured response — the weaker form, named rather than left unsaid.

SUPPORTED_MCP_PROTOCOL_VERSION in server.py names the modern era; a mismatch against the SDK logs a warning at startup. A warning is not a gate — that is what the test file is for.

Note that the SDK's LATEST_PROTOCOL_VERSION is an alias for the modern era, not for the handshake era — pinning against it alone would leave the era that current clients actually negotiate free to drift.

Update policy. When the gate fails, do not edit the constant blindly: read the spec changelog between the two revisions, verify the server still behaves, then move the constant, this section, README.de.md and CHANGELOG.md together.


What the server uses from 2026-07-28

Pinning a revision is not the same as speaking it. Until now this server pinned 2026-07-28 and used the shape of the era before it; the table above was true and the wire was older than it sounded.

Two channels per tool result. The revision gives a tool result content for the reader and structuredContent for the application, with outputSchema as the contract between them. Every tool now fills both: the same human-readable Markdown as before in content, and the data behind it — typed, schema-backed — in structuredContent.

This is not a new interface. The fields are exactly the payload that response_format="json" has always produced. That option is the predecessor of structuredContent: it exists only because, before 2026-07-28, there was one channel, so the machine-readable version had to travel as a JSON string inside the reader's channel. response_format still works and still controls only the text block.

What it replaces is worse than nothing. A signature of -> str makes the SDK publish an outputSchema of {"result": string} and repeat the Markdown block underneath it. Measured on wsl_search against the recorded fixture: 2058 characters of text, 2058 characters of structuredContent.result, character-identical. An outputSchema is a promise; that one promised structure and delivered prose under a key called result.

serverInfo carries its six fields. It carried two, one of them empty. version was the expensive one: the number is kept in step across pyproject.toml, server.json and both README badges by scripts/check_version_sync.py — and reached every place except the one a client reads. It now comes from the package metadata, so no literal enters src/.

Tool titles moved to title. They sat in annotations.title, the slot from before this revision. A client that follows the schema and reads tool.title got None and displayed the slug.

Deliberately not used: icons on server, tools and resources, and the task-augmented call flow (execution). Both are optional, and neither has anything real to point at here — this repository ships no icon asset, and every call is a short CKAN query that finishes well inside a request. Declaring either would be a claim without a thing behind it.

tests/test_structured_output.py holds all of the above against a live ClientSession, with a negative control that shows what the SDK does when a server does not do this — so the day the default changes, the assertions say so instead of quietly passing.

Testing

bash
# Unit tests — offline, no network access, all CKAN responses mocked via respxPYTHONPATH=src pytest -m "not live"
# Live integration tests — actual HTTP calls to envidat.chPYTHONPATH=src pytest -m live
# Lintingruff check src/ruff format --check src/

CI runs the offline suite on every PR. The live suite runs only on main pushes and manual workflow_dispatch triggers, so build status is not coupled to upstream availability.


Changelog

See CHANGELOG.md


Contributing

See CONTRIBUTING.md


Security

See SECURITY.md (Deutsch) for the security posture and how to report a vulnerability.


License

MIT License — see LICENSE

Data on EnviDat is published under various open licenses (Creative Commons, CC0) — see individual dataset metadata.


Author

Hayal Oezkan · malkreide


Credits & Related Projects

Installation

Run via uv's uvx — no clone or manual install needed. Add to your MCP client config (mcpServers for Claude Desktop, Cursor and Windsurf; use a top-level servers key for VS Code in .vscode/mcp.json):

json
{  "mcpServers": {    "wsl-envidat-mcp": {      "command": "uvx",      "args": [        "wsl-envidat-mcp"      ]    }  }}

來源:README.md,提交 4c370e9

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

3
  1. v0.3.1最新Sep 20, 2026
  2. v0.3.0Sep 20, 2026
  3. v0.2.5Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分