Swiss Housing Mcp

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

Swiss Register of Buildings and Dwellings (GWR/RegBL): EGID/EWID lookup, geocoding, housing stats

概覽

AI 產生的概覽

針對瑞士聯邦建築物與住宅登記冊(GWR/RegBL)的唯讀 MCP 伺服器,支援 EGID/EWID 查詢、地址地理編碼與市政住宅統計。

可以做什麼
  • 依聯邦 EGID 查詢單一建築物,並列出其住宅的房間數、面積與樓層
  • 將任何瑞士地址地理編碼為 EGID/EDID 及 LV95 座標
  • 依市政統計某年以來的新建住宅數量(含 4 房以上占比),並檢視規劃、核准與興建中的案件
  • 彙整某市政的住宅存量與房型面積組成,或依矩形範圍列出建築物以進行分區分析
  • 以官方德/法/義代碼表解讀 GWR 屬性代碼,並查看快取新鮮度
適用情境
當助理需要以聯邦識別碼串接的瑞士建築物或住宅資料時適用,例如某市政的住宅供給問題、供規劃用的興建中案件指標,或把其他瑞士資料連結到 EGID。它屬於登記冊層,而非統計或市場指數來源。
執行需求
本機 Python 3.10+ 程序,通常透過 uvx 從 PyPI 執行。不需要 API 金鑰或帳號。需要連線至公開的州級資料傾印與 geo.admin.ch。每個快取的州傾印約占 130 MB 磁碟;快取目錄與 24 小時有效期可透過 SWISS_HOUSING_CACHE 與 SWISS_HOUSING_DUMP_TTL_HOURS 設定。
安裝前請注意
唯讀且無需驗證,公開資料摘錄不含個人資料。它會把較大的州級傾印(ZH 約 121 MB)下載到本機磁碟並查詢瑞士公開端點,因此請求會離開本機。座標為建築物參考點而非輪廓多邊形,部分老建築缺少建造年份。

安裝

在 SourceWeft 中

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

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

其他 MCP 客戶端

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

README

swiss-housing-mcp

Part of the Swiss Public Data MCP Portfolio — open-source MCP servers connecting AI agents to Swiss public data. Private project, independent of any employer or institutional affiliation.

[Version] [License: MIT] [Python] [MCP]

MCP server for the Swiss Federal Register of Buildings and Dwellings (GWR/RegBL) — buildings, dwellings, and the construction pipeline

🇩🇪 Deutsche Version


🎯 Anchor Demo Query

«How many dwellings were newly built in the City of Zurich since 2020, how many with 4+ rooms — and how many are currently under construction?»

Verified against the live dump on 2026-07-24: 16'164 new dwellings since 2020 (27.4% with 4+ rooms — the family-housing proxy), and 7'287 dwellings currently under construction. Dwellings under construction today are households in 1–3 years: the early indicator for school-space planning.

Demo

[Demo: Claude using new_construction and construction_pipeline]


Overview

The GWR/RegBL is to buildings what Zefix is to companies: not one data source among many, but the federal register whose identifiers (EGID for buildings, EWID for dwellings) serve as join keys across Swiss administrative data. This server exposes the register's public extract through MCP tools — building lookups, address geocoding, per-municipality construction statistics, sub-municipal bounding-box analysis, and the planning/construction pipeline.

address_to_egid is the plug that makes other data sources EGID-capable: address in, federal identifier and LV95 coordinates out.

Architecture decision

This server uses Architecture B (Hybrid: Dump-first, API-fallback).

Rationale (verified live on 2026-07-24):

  • The public cantonal dump (public.madd.bfs.admin.ch/{canton}.zip) is refreshed daily (~05:30 CET) and ships a ready-made data.sqlite with tables building (399'830 rows for ZH), entrance, dwelling (894'631 rows for ZH), and code. No CSV parsing, no auth.
  • api3.geo.admin.ch (find / identify / SearchServer) works reliably without authentication for single-entity lookups and geocoding, but does not scale to area-wide aggregations (result limits).
  • A MADD REST endpoint probed at /api/buildings/{egid} returned 404; it is excluded until path and auth status are clarified — no blocker, since all Phase-1 tools work without it.

Consequences:

  • Cantonal dumps are cached on disk with a 24 h TTL (configurable via SWISS_HOUSING_DUMP_TTL_HOURS).
  • Aggregations and spatial queries run as read-only SQL against the cached SQLite; single lookups and geocoding hit the live API.
  • Every response carries source (attribution) and provenance (daily_dump | live_api | cached).

Live probe findings (2026-07-24)

EndpointHTTPStatusNote
api3.geo.admin.ch …/find (EGID lookup)200✅ worksfull attribute set, no auth
api3.geo.admin.ch …/identify (coordinates)200✅ works77 attributes incl. EGID/EWID
…/SearchServer (address → EGID)200✅ worksfeatureId = {EGID}_{EDID}; axis swap: y=east, x=north
public.madd.bfs.admin.ch/zh.zip200✅ works121 MB, daily refresh, contains data.sqlite
madd.bfs.admin.ch/api/buildings/{egid}404❌ excludedpath/auth unclear
Invalid EGID on find200⚠️ soft errorempty results array — not an HTTP error

Features

  • lookup_building(egid) — single building by federal identifier (live API)
  • address_to_egid(address) — geocode any Swiss address to EGID/EDID + LV95
  • lookup_dwellings(egid) — all dwellings of a building with rooms, area, floor
  • new_construction(municipality_bfs, since_year) — yearly new construction incl. 4+ room family-housing share
  • construction_pipeline(municipality_bfs) — projected / approved / under construction
  • buildings_in_bbox(e_min, n_min, e_max, n_max) — sub-municipal analysis (e.g. school districts)
  • municipality_housing_stats(municipality_bfs) — housing stock and room-size mix
  • explain_code(attribute, code) — decode GWR codes via the official DE/FR/IT code table
  • dump_status() — cache freshness, graceful-degradation entry point

Prerequisites

  • Python 3.10+
  • ~130 MB disk per cached cantonal dump (ZH)
  • No API keys — Phase 1 is authentication-free

Installation

bash
uvx swiss-housing-mcp        # once published on PyPI
# or from sourcepip install -e .

Usage / Quickstart

Claude Desktop (claude_desktop_config.json):

json
{  "mcpServers": {    "swiss-housing": {      "command": "uvx",      "args": ["swiss-housing-mcp"]    }  }}

Cloud (Render/Railway):

bash
SWISS_HOUSING_TRANSPORT=streamable-http PORT=8000 swiss-housing-mcp

Configuration

VariableDefaultPurpose
SWISS_HOUSING_TRANSPORTstdiostdio | streamable-http | sse
SWISS_HOUSING_CACHE~/.cache/swiss-housing-mcpDump cache directory
SWISS_HOUSING_DUMP_TTL_HOURS24Dump freshness window

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 eras are measured, not inferred: tests/test_modern_era.py drives real requests of each era through this server's own ASGI app — the one __main__.py serves under SWISS_HOUSING_TRANSPORT=streamable-http — and reads the negotiated revision off the response body. Alongside it, tests/test_protocol_version.py pins both revisions against the installed SDK, so a Dependabot bump of mcp breaks the build before anyone reads the measurement.

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.

Identity on the modern era. The 2026-07-28 era has no initialize handshake: a connection is a single request carrying a _meta envelope. So server/discover is the only channel through which a modern client learns anything about this server, and the serverInfo block the SDK stamps into every result is the only place its identity appears. This server therefore declares version, title, description, websiteUrl and instructions. description and websiteUrl are read from the package metadata rather than repeated as literals — the SDK fills none of them in, and an unversioned server announces an empty version on every single response.

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.

Testing

bash
PYTHONPATH=src pytest tests/ -m "not live"   # CI-safePYTHONPATH=src pytest tests/ -m live         # against real upstream

Project Structure

swiss-housing-mcp/├── src/swiss_housing_mcp/│   ├── server.py      # FastMCP tools (9)│   ├── gwr.py         # Dump store + geo.admin.ch client + retry│   ├── models.py      # Pydantic v2 envelopes (source + provenance)│   └── __main__.py    # Dual-transport entry point├── tests/             # respx-mocked + @pytest.mark.live└── .github/workflows/ # CI + OIDC PyPI publish

Known Limitations

  • The public extract omits person-related and some sensitive attributes of the full GWR; official data deliveries to authorities go through the BFS/MADD channel.
  • Coordinates are building reference points (LV95), not footprint polygons — polygon joins (e.g. exact school-district boundaries) need external geometries; buildings_in_bbox covers the rectangular approximation.
  • GBAUJ (construction year) is missing for a share of older buildings; period codes (GBAUP) exist as fallback but are not yet exposed.
  • Municipality→canton resolution is seeded for common cases; pass canton explicitly for others.
  • Housing-market indices (IMPI, construction price index, vacancy rate) deliberately live in swiss-statistics-mcp — this server is the register layer, not the statistics layer.

Changelog

See CHANGELOG.md

Contributing

Contributions are welcome — see CONTRIBUTING.md (Deutsch).

Security

Read-only, no PII, no authentication — a public federal register accessed through a fixed set of endpoints. See SECURITY.md (Deutsch) for the full posture and how to report a vulnerability.

License

MIT License — see LICENSE. Data: GWR/RegBL, Swiss Federal Statistical Office (BFS), open government data with attribution.

Author

Hayal Oezkan · github.com/malkreide

Credits & Related Projects

來源:README.md,提交 cece646

工具

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

版本歷史

2
  1. v0.2.0最新Sep 20, 2026
  2. v0.1.0Sep 16, 2026

評分

已滿足適用檢查項的 50%

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

  • 近 30 天內可連通25 分

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

  • 已宣告認證方式10 分

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

  • 已列出工具15 分

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

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