Skip to main content
Glama

urban-mcp

PyPI Python CI License: MIT DOI

A Model Context Protocol (MCP) server for urban planning, mobility and spatial statistics. It gives AI agents (Claude Desktop, Claude Code and any other MCP client) 24 tools for accessibility (2SFCA, gravity, 15-minute city, PTAL), multi-criteria siting (AHP, TOPSIS, MCLP), space syntax, landscape metrics, seismic screening, slope-aware routing and isochrones, and spatial statistics (Moran's I, LISA, Getis-Ord Gi*, GWR, Huff).

The methods come from three published, tested SDKs; this package is a thin, validated MCP layer over them:

SDK

Import

Used for

planx-sdk

planx

accessibility, PTAL, MCDA, MCLP, space syntax, landscape metrics, Spacemate, seismic chain

zero2route3d-sdk

zero2route3d

slope/energy-aware routing, isochrones, hiking time, ramp audit, OSM streets

geoai2analytics-sdk

geoai2analytics

Moran's I, LISA, Gi*, GWR, Huff model

Generic GIS MCP servers (e.g. gis-mcp, mcp-geo) cover geometry operations and file I/O; urban-mcp focuses on planning indicators and spatial statistics and returns analysis-ready summaries.


Installation

pip install urban-mcp          # Python >= 3.10
urban-mcp --list-tools         # check the install

Or run it without installing, with uv:

uvx urban-mcp --list-tools

Dependencies: mcp (official Python SDK, 2.x), planx-sdk, zero2route3d-sdk, geoai2analytics-sdk and NumPy/SciPy. No GDAL, GeoPandas or Shapely is needed.

Related MCP server: arcpy-mcp-server

Connecting a client

Claude Code

claude mcp add urban-mcp -- uvx urban-mcp
# with file output and OpenStreetMap downloads enabled:
claude mcp add urban-mcp -- uvx urban-mcp --output-dir ./urban_outputs --allow-network

Claude Desktop

Add to claude_desktop_config.json (Settings > Developer > Edit Config):

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

With a pip install, use "command": "urban-mcp", "args": [] instead. To let the server save results, add "--output-dir", "/path/to/folder" to args.

Other clients / HTTP

Any MCP client that launches a stdio server can run urban-mcp. For a network service use streamable HTTP (bound to localhost by default):

urban-mcp --transport streamable-http --host 127.0.0.1 --port 8000   # endpoint: /mcp

Options

Option

Environment variable

Default

Meaning

--output-dir DIR

URBAN_MCP_OUTPUT_DIR

none

the only folder save_geojson may write to; without it, writing is disabled

--allow-network

URBAN_MCP_ALLOW_NETWORK=1

off

enables fetch_osm_street_network

--max-output-features N

URBAN_MCP_MAX_OUTPUT_FEATURES

500

features kept in a GeoJSON result (the rest is dropped and flagged truncated)

--max-input-features N

URBAN_MCP_MAX_INPUT_FEATURES

2000

largest layer accepted by the quadratic tools

--transport

stdio

stdio or streamable-http

--list-tools [--json]

print the tools and exit


Tools

Tool

What it does

SDK function

accessibility_2sfca

2SFCA / E2SFCA supply-per-head of demand points to facilities, with Gini

planx.spatial.enhanced_2sfca, spatial_equity_gini

accessibility_gravity

Hansen gravity accessibility

planx.spatial.gravity_accessibility

accessibility_2sfca_matrix

2SFCA on your own travel-time matrix

planx.engine.accessibility.two_step_fca

fifteen_minute_city_score

0-100 score, per-category coverage, missing categories per origin

planx.spatial.calculate_15m_city_score

ptal_score

TfL PTAL index and band for a site

planx.engine.ptal.accessibility_index, band

ahp_weights

AHP weights and consistency ratio

planx.suitability.ahp_weights

topsis_ranking

TOPSIS ranking (given, AHP or equal weights)

planx.suitability.topsis_method

facility_siting_mclp

Maximal covering location (greedy), with existing facilities

planx.suitability.greedy_mclp

space_syntax_segment_analysis

Angular integration (NAIN) and choice (NACH) per street segment

planx.engine.graphs.build_segment_graph, planx.engine.syntax.segment_angular_analysis

landscape_metrics

FRAGSTATS-style class and landscape metrics of a land-cover grid

planx.engine.landscape.metrics

spacemate_density

FSI/GSI/OSR/L and density typology per block

planx.urban_morphology.spacemate_density_matrix

seismic_damage_screening

ASB2014 PGA, Hazus damage states and casualties per building (screening)

planx.engine.gmpe.predict, fragility.*, impact.casualties

route_3d

Slope/energy-aware route for a mobility profile

zero2route3d.solve_3d_route

isochrones_3d

Slope-aware isochrone polygons

zero2route3d.solve_3d_isochrones

hiking_time

DIN 33466, Naismith-Langmuir and Tobler walking times

zero2route3d.estimate_hiking_time

wheelchair_ramp_audit

ADA ramp slope / rise / landing audit of a 3D path

zero2route3d.audit_wheelchair_ramp_compliance

list_mobility_profiles

The 15 mobility profiles (adult, senior, wheelchair, bicycle ...)

zero2route3d.PROFILES

global_moran_i

Global Moran's I with permutation test

geoai2analytics.global_moran

local_moran_lisa

LISA clusters and outliers (FDR-corrected)

geoai2analytics.local_moran

hotspot_gi_star

Getis-Ord Gi* hot/cold spots with 99/95/90 % bins

geoai2analytics.local_getis_ord_gi_star

gwr_regression

Geographically weighted regression, local coefficients and R2

geoai2analytics.GWR

huff_market_share

Huff retail model: probabilities and market shares

geoai2analytics.huff_model

save_geojson

Save a FeatureCollection into --output-dir (off by default)

(urban-mcp)

fetch_osm_street_network

OSM streets in a bbox via Overpass (off by default)

zero2route3d.NetworkSourceManager.fetch_osm_network_bbox

Inputs are GeoJSON FeatureCollections (points; polygons are reduced to their area-weighted centroid), plain arrays and numbers, each described in the tool's JSON schema. Coordinates may be WGS84 lon/lat or projected metres: coordinate_system="auto" treats a layer as lon/lat when every coordinate lies within +-180/+-90 and projects it to a local plane in metres. Pass coordinate_system="projected" for projected data with small coordinate values (e.g. a local grid in metres near the origin). Routing tools need lon/lat.

Outputs are JSON objects with the SDK function used, a summary (counts, min/mean/max, class counts, top items) and, where it makes sense, a GeoJSON result that pairs each input geometry with the computed properties. Results are capped at --max-output-features and marked truncated: true with total_features.

Distances in the point-based tools (2SFCA, gravity, 15-minute city, MCLP, Huff) are straight-line. Use route_3d / isochrones_3d, or pass a network travel-time matrix to accessibility_2sfca_matrix, for network distances.

Resources and prompts

Resource

Content

urban://tools

Markdown catalogue of all tools and the SDK functions behind them

urban://methods

Index of method notes

urban://methods/{method}

Formula, interpretation and references: 2sfca, gravity, 15-minute-city, ptal, ahp, topsis, mclp, space-syntax, landscape-metrics, spacemate, seismic-screening, routing-3d, hiking-time, ramp-audit, morans-i, lisa, gi-star, gwr, huff

urban://samples/{name}

Small WGS84 sample layers: street-network, neighbourhoods, clinics

urban://about

Package versions and the active safety configuration

Prompt

Arguments

Workflow

fifteen_minute_city_audit

area_name, amenity_categories, max_walk_m

15-minute score, 2SFCA equity, profile isochrones, optional siting

hot_spot_analysis

layer_description, value_field, weights

Moran's I, sensitivity to weights, LISA and Gi*

site_selection_mcda

facility_type, criteria

AHP weights with consistency check, TOPSIS ranking, robustness

Example conversations

You: Here are our neighbourhood centroids with population and the GP clinics with doctor counts (two GeoJSON files). Who is underserved within 1.5 km?

Assistant calls accessibility_2sfca(demand_points=..., supply_points=..., demand_field="population", supply_field="doctors", cutoff_m=1500) and answers: "Median access is 0.42 doctors per 1 000 residents; 3 of 41 neighbourhoods (6 900 people) have no clinic within 1.5 km - all on the eastern edge. The population-weighted Gini is 0.38."

You: Is the rent level clustered? Use the census tracts layer.

Assistant runs the hot_spot_analysis prompt: global_moran_i (I = 0.41, p = 0.001), then local_moran_lisa and hotspot_gi_star, and reports 12 high-high tracts around the waterfront and 9 low-low tracts in the north, noting the FDR correction.

You: How much harder is the walk from the station to the hospital for a wheelchair user?

Assistant calls route_3d twice (profile="adult" and profile="wheelchair") on the street network and compares: "The direct route climbs 40 m over a steep hill street; the wheelchair route avoids it, 0.44 km longer (12.5 vs 8.1 min) and ADA-compliant."

You: We have 120 candidate parcels; pick 5 shelter sites that cover most residents within 500 m.

Assistant calls facility_siting_mclp(k=5, max_distance_m=500, ...), lists the five parcels with marginal coverage, and offers save_geojson to export them for QGIS.

Python use

The tool handlers are plain functions and can be called without MCP:

from urban_mcp.tools.accessibility import ptal_score

print(ptal_score([
    {"stop_id": "s1", "walk_minutes": 4,
     "routes": [{"route_id": "B1", "mode": "bus", "frequency_per_hour": 6},
                {"route_id": "B2", "mode": "bus", "frequency_per_hour": 12}]},
    {"stop_id": "s2", "walk_minutes": 10,
     "routes": [{"route_id": "R1", "mode": "rail", "frequency_per_hour": 4}]},
])["ptal_band"])   # 2

urban_mcp.server.build_server(ServerConfig(...)) returns the configured MCPServer, for embedding or in-process testing with mcp.Client.

Security notes

  • No arbitrary code execution. Tools only accept data (GeoJSON, arrays, numbers, enums) validated against JSON schemas and again in the handler; nothing is evaluated or imported from user input, and no tool reads files by path.

  • File writes are opt-in and confined. Only save_geojson writes, only when the server was started with --output-dir, only plain file names inside that folder (no paths, no ..), and it never overwrites unless overwrite=true. Note: zero2route3d-sdk creates an empty zero2route3d_cache folder in the system temp directory when it parses a network; nothing else is written there by the routing tools.

  • No network by default. Only fetch_osm_street_network goes online, only with --allow-network, with a bounded bbox (about 5 x 5 km) and 12 s timeouts; its cache goes to --output-dir/osm_cache or a temporary folder that is deleted afterwards. The routing tools never fetch elevation online (fetch_online_dem=False).

  • Bounded work. Input layers for the quadratic tools are capped (--max-input-features, 4 million matrix cells, 1 500 features for GWR), outputs are truncated, and long computations run in a worker thread so the server stays responsive.

  • Errors are tool errors. Invalid input returns an MCP tool result with isError: true and a message that says what to fix; the server does not crash.

  • HTTP transport binds to 127.0.0.1 by default and has no authentication; put it behind an authenticating proxy before exposing it.

  • Model outputs are screening results. The seismic tool in particular uses uncalibrated design-level mapping (see urban://methods/seismic-screening).

Development

git clone https://github.com/YusufEminoglu/urban_mcp_sdk
cd urban_mcp_sdk
pip install -e ".[dev]"
python -m pytest --cov=urban_mcp     # handler tests + in-process MCP client round trips
python -m ruff check . && python -m ruff format --check src tests
python -m mypy src

Citation

@software{eminoglu_urban_mcp,
  author  = {Eminoğlu, Yusuf},
  title   = {urban-mcp},
  year    = {2026},
  version = {0.1.1},
  doi     = {10.5281/zenodo.24063350},
  url     = {https://doi.org/10.5281/zenodo.24063350}
}

See CITATION.cff. Please also cite the underlying SDKs and the original method papers listed in the urban://methods/* resources.

License

MIT (c) Yusuf Eminoğlu. OpenStreetMap data fetched by the OSM tool is (c) OpenStreetMap contributors, ODbL 1.0.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    Enables AI agents to become geospatially intelligent assistants with tools for location search, smart routing, round trip planning, reverse geocoding, isochrone analysis, route visualization, geofence management, and interactive map display.
    8
    17 npm
    7
    Apache 2.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to perform geospatial analysis, spatial data processing, vector and raster operations, coordinate transformations, spatial statistics, mapping, and access to climate, satellite, and other geospatial data through MCP-compatible clients.
    MIT