Skip to main content
Glama

Part of the Swiss Public Data MCP Portfolio

swisstopo-mcp

Version License: MIT Python 3.11+ MCP No Auth Required CI

MCP server for Swiss federal geodata -- maps, elevation, geocoding, cadastral extracts, and downloadable datasets via Swisstopo APIs

Deutsche Version


Overview

swisstopo-mcp gives AI assistants access to Switzerland's official geodata infrastructure through 13 tools across 6 API families, all without authentication:

Source

Data

API

Swisstopo REST API

500+ geodata layers (buildings, boundaries, land use)

REST/JSON

Geocoding

Official addresses, place names, postal codes

REST/JSON

Height Service

Elevation above sea level, elevation profiles

REST/JSON

STAC Catalog

Orthophotos, elevation models, 3D buildings

STAC 0.9

WMTS

National maps, aerial images, zoning maps

URL builder

OEREB Cadastre

Public-law restrictions, parcels

REST/JSON (cantonal)

Anchor demo query: "What land-use restrictions apply to the parcel at Musterstrasse 5, Zurich? Show me the location on a map." β†’ More use cases by audience β†’


Features

  • πŸ—ΊοΈ 13 tools across 6 API families (REST, Geocoding, Height, STAC, WMTS, OEREB)

  • πŸ” Geocode Swiss addresses and reverse-geocode coordinates

  • πŸ”οΈ Query elevation and compute elevation profiles

  • πŸ“¦ Discover and download geodatasets (orthophotos, 3D buildings, historical maps)

  • πŸ—οΈ Identify map features at coordinates across 500+ Swisstopo layers

  • πŸ”— Generate shareable map.geo.admin.ch links

  • πŸ“‹ Look up cadastral property IDs (EGRID) and retrieve OEREB extracts

  • πŸ”“ No API key required for 11 of 13 tools

  • ☁️ Dual transport -- stdio (Claude Desktop) + Streamable HTTP (cloud)


Prerequisites

  • Python 3.11+

  • uv (recommended) or pip


Installation

# Clone the repository
git clone https://github.com/malkreide/swisstopo-mcp.git
cd swisstopo-mcp

# Install
pip install -e .
# or with uv:
uv pip install -e .

Or with uvx (no permanent installation):

uvx swisstopo-mcp

Quickstart

# stdio (for Claude Desktop)
python -m swisstopo_mcp.server

# Streamable HTTP (port 8000)
python -m swisstopo_mcp.server --http --port 8000

Try it immediately in Claude Desktop:

"Where is Bahnhofstrasse 1, Zurich? Give me the coordinates." "What is the elevation at the Uetliberg summit?" "What buildings are at coordinates 2683500, 1247500 (LV95)?"


Configuration

Claude Desktop

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

{
  "mcpServers": {
    "swisstopo": {
      "command": "python",
      "args": ["-m", "swisstopo_mcp.server"]
    }
  }
}

Or with uvx:

{
  "mcpServers": {
    "swisstopo": {
      "command": "uvx",
      "args": ["swisstopo-mcp"]
    }
  }
}

Config file locations:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Cloud Deployment (SSE for browser access)

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

Render.com (recommended):

  1. Push/fork the repository to GitHub

  2. On render.com: New Web Service -> connect GitHub repo

  3. Set start command: python -m swisstopo_mcp.server --http --port 8000

  4. In claude.ai under Settings -> MCP Servers, add: https://your-app.onrender.com/sse


Available Tools

REST API (Layer & Feature Queries)

Tool

Description

swisstopo_search_layers

Search the Swisstopo layer catalog (500+ layers) by keyword

swisstopo_identify_features

Find map features at a specific coordinate (spatial query)

swisstopo_find_features

Search features by attribute value within a layer (e.g. buildings by EGID)

swisstopo_get_feature

Retrieve full attributes and geometry for a feature by ID

Geocoding

Tool

Description

swisstopo_geocode

Convert Swiss addresses, place names, or postal codes to coordinates

swisstopo_reverse_geocode

Find the nearest address for given coordinates

Height Service

Tool

Description

swisstopo_get_height

Get elevation above sea level (m a.s.l.) at a coordinate

swisstopo_elevation_profile

Compute an elevation profile along a line

STAC Catalog (Geodata Downloads)

Tool

Description

swisstopo_search_geodata

Search the STAC catalog for downloadable geodatasets

swisstopo_get_collection

Get details and download links for a STAC collection

WMTS (Map URLs)

Tool

Description

swisstopo_map_url

Generate a map.geo.admin.ch URL for browser display

OEREB Cadastre

Tool

Description

swisstopo_get_egrid

Resolve a cadastral property ID (EGRID) from coordinates

swisstopo_get_oereb_extract

Retrieve public-law land-use restrictions (OEREB) for a parcel

Example Use Cases

Query

Tool

"Where is Bahnhofstrasse 1, Zurich?"

swisstopo_geocode

"What is the elevation at the Uetliberg summit?"

swisstopo_get_height

"What buildings are at coordinates 2683500, 1247500?"

swisstopo_identify_features

"Find orthophoto datasets for download"

swisstopo_search_geodata

"Show me a map of Bern at zoom level 10"

swisstopo_map_url

"What restrictions apply to parcel at Musterstrasse 5?"

swisstopo_get_egrid + swisstopo_get_oereb_extract


Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Claude / AI   │────▢│  swisstopo-mcp               │────▢│  Swisstopo REST API      β”‚
β”‚   (MCP Host)    │◀────│  (MCP Server)                │◀────│  api3.geo.admin.ch       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚                              β”‚     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                        β”‚  13 Tools                    │────▢│  Geocoding               β”‚
                        β”‚  Stdio | Streamable HTTP     │◀────│  api3.geo.admin.ch       β”‚
                        β”‚                              β”‚     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                        β”‚  No authentication required  │────▢│  STAC Catalog            β”‚
                        β”‚  (11 of 13 tools)            │◀────│  data.geo.admin.ch       β”‚
                        β”‚                              β”‚     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                        β”‚                              │────▢│  OEREB Cadastre          β”‚
                        β”‚                              │◀────│  (cantonal endpoints)    β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Project Structure

swisstopo-mcp/
β”œβ”€β”€ src/swisstopo_mcp/
β”‚   β”œβ”€β”€ __init__.py              # Package version
β”‚   β”œβ”€β”€ server.py                # MCP server wiring (tool registrations)
β”‚   β”œβ”€β”€ api_client.py            # Shared HTTP client (httpx + error handling)
β”‚   β”œβ”€β”€ geocoding.py             # swisstopo_geocode, swisstopo_reverse_geocode
β”‚   β”œβ”€β”€ rest_api.py              # swisstopo_search_layers, identify, find, get_feature
β”‚   β”œβ”€β”€ height.py                # swisstopo_get_height, swisstopo_elevation_profile
β”‚   β”œβ”€β”€ stac.py                  # swisstopo_search_geodata, swisstopo_get_collection
β”‚   β”œβ”€β”€ wmts.py                  # swisstopo_map_url
β”‚   └── oereb.py                 # swisstopo_get_egrid, swisstopo_get_oereb_extract
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ test_api_client.py
β”‚   β”œβ”€β”€ test_geocoding.py
β”‚   β”œβ”€β”€ test_height.py
β”‚   β”œβ”€β”€ test_oereb.py
β”‚   β”œβ”€β”€ test_rest_api.py
β”‚   β”œβ”€β”€ test_stac.py
β”‚   └── test_wmts.py
β”œβ”€β”€ .github/workflows/ci.yml     # GitHub Actions (Python 3.11/3.12/3.13)
β”œβ”€β”€ pyproject.toml
β”œβ”€β”€ CHANGELOG.md
β”œβ”€β”€ CONTRIBUTING.md
β”œβ”€β”€ LICENSE
β”œβ”€β”€ README.md                    # This file (English)
└── README.de.md                 # German version

Security & Compliance

Phase

This server is in Phase 1 β€” Read-only wrapper. All 13 tools are readOnlyHint: true / destructiveHint: false; there are no write or send capabilities. See docs/roadmap.md for later phases.

Lethal Trifecta assessment

Capability

Status

Rationale

Access to private data

❌ No

Public Open Data only (federal/cantonal geodata)

Exposure to untrusted content

⚠️ Limited

Reads only from a fixed allow-list of trusted geo.admin / OEREB hosts

External communication (write/send)

❌ No

Read-only; no mail/webhook/write tools

Trifecta score: at most 1 of 3 β€” safe by design.

Egress

Outbound requests are restricted to an explicit code-layer allow-list and redirects are disabled β€” see docs/network-egress.md.

Container deployment

For containerised HTTP deployments, a hardened Dockerfile and Kubernetes manifests (non-root, read-only root filesystem, dropped capabilities, egress NetworkPolicy) are provided β€” see docs/deployment.md.

MCP Protocol Version

The MCP protocol version is negotiated by the mcp SDK, which is pinned to the 1.x major in pyproject.toml so an update cannot silently change the negotiated version. SDK bumps are proposed monthly via Dependabot and tracked in CHANGELOG.md.

Sessions & Authentication

The server is unauthenticated by design β€” it serves only public open data. Over HTTP, session IDs are managed entirely by the FastMCP framework; there is no per-user state, so there is nothing user-specific to bind a session to. If an authenticated deployment is ever introduced, session IDs must be bound to the validated user identity (audit finding SEC-009).

Error handling

  • Execution errors (upstream failure, invalid value) are returned as a ToolResponse with is_error: true and a user-friendly summary; raw exception text is never leaked to the client (it is logged to stderr instead).

  • Protocol errors (unknown tool, malformed/invalid arguments) are emitted by the MCP SDK as JSON-RPC errors with standard codes (e.g. -32602 invalid params). Input validation happens at the Pydantic boundary (SEC-018).

MCP Primitives

This server intentionally exposes Tools only (no Resources or Prompts): it is a Phase-1 read-only wrapper, and every result is a live, parameterised API query rather than a static addressable document. Resources/Prompts may be added in a later phase if stable URI schemes emerge.

Tool workflows

Most tools return a thought-complete result in a single call. Two domains use a short, documented discovery chain (each tool's description states the next step):

  • Feature query: swisstopo_search_layers (find layer IDs) β†’ swisstopo_identify_features / swisstopo_find_features β†’ swisstopo_get_feature (full detail).

  • Cadastre: swisstopo_geocode β†’ swisstopo_get_egrid β†’ swisstopo_get_oereb_extract.

  • Downloads: swisstopo_search_geodata β†’ swisstopo_get_collection.


Response Format

Every tool returns a structured ToolResponse (FastMCP emits it as structured content with an output schema, plus a JSON text block):

Field

Meaning

summary

Human-readable Markdown summary

results

Machine-readable structured records

count

Number of results

match_type

exact / fuzzy / none (search-style tools)

source / license

Data attribution (OGD-CH, CC/OGD terms)

provenance / retrieved_at

How and when the data was obtained

is_error

true for handled errors


Known Limitations

  • OEREB tools require a canton parameter; not all cantons expose the same API format

  • STAC catalog uses Swisstopo's v0.9 endpoint; some collections may lack complete metadata

  • Geocoding covers Swiss addresses only (no Liechtenstein)

  • Rate limits are enforced by Swisstopo; high-frequency usage may be throttled


Testing

# Unit tests (no network required)
pytest tests/ -m "not live"

# Integration tests (live API calls)
pytest tests/ -m "live"

Changelog

See CHANGELOG.md


Contributing

See CONTRIBUTING.md


License

MIT License -- see LICENSE

Data provided by swisstopo under Open Government Data terms.


Author

Hayal Oezkan Β· malkreide


Install Server
A
license - permissive license
A
quality
B
maintenance

Maintenance

–Maintainers
–Response time
–Release cycle
1Releases (12mo)

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/malkreide/swisstopo-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server