Urban street network analysis via MCP and CLI
Project description
Desirepath
Urban street network analysis as an MCP server and CLI.
An LLM or CLI tool can ask: route between two points, find missing links, measure circuity, compute isochrones, compare cities, render interactive maps. Desirepath is a typed MCP interface over OSMnx and Momepy, with 20 tools and 9 resources.
Install
Requires Python 3.12+ and uv.
git clone https://github.com/yourname/desirepath
cd desirepath
uv sync
Quickstart
# Check environment
uv run desirepath doctor
# Network stats for any place
uv run desirepath stats "Piedmont, California, USA"
# Compare two cities
uv run desirepath compare "Amsterdam, Netherlands" "Houston, Texas, USA"
# Start the MCP server
uv run desirepath serve --place "Amsterdam, Netherlands" --name amsterdam
Sample stats output:
{
"n": 388,
"m": 916,
"edge_length_avg": 106.4,
"streets_per_node_avg": 2.887,
"circuity_avg": 1.065
}
Connect to Claude
Claude Code: add to .mcp.json at the project root:
{
"mcpServers": {
"desirepath": {
"command": "uv",
"args": ["run", "desirepath", "serve"],
"cwd": "/path/to/desirepath",
"type": "stdio"
}
}
}
Claude Desktop: add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"desirepath": {
"command": "uv",
"args": [
"run", "--project", "/path/to/desirepath",
"desirepath", "serve",
"--graphml", "/path/to/my_city.graphml",
"--name", "my_city"
]
}
}
}
Claude Desktop's sandbox blocks Overpass at runtime. Download a graph first with desirepath serve --place ..., call save_graph to write it to disk, then use --graphml on subsequent starts.
MCPJam Inspector: renders map_graph, map_route, and map_isochrone as inline Leaflet maps:
npx @mcpjam/inspector@latest --config mcpjam.json --server desirepath
Tools
All routing coordinates are in lng, lat order.
Graph
| Tool | What it does |
|---|---|
load_graph |
Load from place name, lat/lng radius, GraphML file, or .osm.pbf |
save_graph |
Write graph to GraphML for fast reload |
set_active_graph |
Switch which graph other tools operate on |
drop_graph |
Remove a graph from memory |
subgraph |
Extract a bbox or radius subgraph from a loaded graph |
Routing
| Tool | What it does |
|---|---|
find_nearest |
Snap a coordinate to the nearest node or edge |
route |
Shortest path by distance or travel time; k>1 returns alternatives |
isochrone |
Reachable area within a travel-time budget |
Stats
| Tool | What it does |
|---|---|
betweenness_centrality |
Top 10 nodes by flow centrality (O(VE); call subgraph first on large networks) |
articulation_points |
Nodes whose removal disconnects the graph |
missing_links |
Euclidean-close node pairs with high network detour ratios |
network_resilience |
Component size after sequential removal of top-centrality nodes |
circuity_distribution |
Per-edge circuity histogram; top 10 most circuitous segments |
Basic stats, orientation entropy, street hierarchy, and degree distribution are resources, not tools. Read them at graph://{name}/stats and graph://{name}/street-hierarchy without a tool call.
Morphology
morphology(metrics=[...]) computes any combination of:
linearity: edge straightness (0 to 1)sinuosity: inverse of linearity; top 10 most winding streetsconnectivity: meshedness coefficient; near 1 = grid, near 0 = treeclustering: squares clustering coefficient (how grid-like at the local scale)intersection_types: dead-end / 3-way / 4-way-plus fractions
Features
get_features(source, tags) fetches OSM features from Overpass by point, bbox, or place name. Times out after 25 seconds; use specific tag values.
Enrichment
enrich_graph(speeds, travel_times, bearings, grades) adds computed attributes to graph edges in a single call.
Map
| Tool | What it does |
|---|---|
map_graph |
Interactive Leaflet map of the network |
map_route |
Network map with a route overlay |
map_isochrone |
Network map with a reachable-area overlay |
Renders inline in MCPJam Inspector. Saves HTML to ~/Downloads/ on other hosts.
Compare
compare_graphs produces a side-by-side JSON summary of two loaded graphs.
Optional tools
| Extra | Install | Tools added |
|---|---|---|
[loaders] |
uv add "desirepath[loaders]" |
load_graph(source='pbf') for large .osm.pbf files |
[access] |
uv add "desirepath[access]" |
accessibility_to_pois: pandana-based POI distance for every node |
[spatial] |
uv add "desirepath[spatial]" |
spatial_autocorrelation (Moran's I), network_constrained_clustering |
[transit] |
uv add "desirepath[transit]" |
load_graph_from_gtfs: GTFS feed to transit stop graph |
[all] |
uv add "desirepath[all]" |
all of the above |
Optional tools register automatically when their dependency is installed. Run uv run desirepath doctor to see what is present.
Resources
Resources are read directly by the agent without a tool call.
| URI | Content |
|---|---|
graph://graphs |
All loaded graphs with counts |
graph://metadata |
Active graph: counts, bbox, CRS, attributes |
graph://{name}/metadata |
Same for a named graph |
graph://{name}/stats |
Basic stats, orientation entropy, dead-end count |
graph://{name}/street-hierarchy |
Edge counts and lengths by highway tag |
graph://{name}/nodes/{node_id} |
Single node attributes |
graph://{name}/edges/{u}/{v}/{key} |
Single edge attributes (geometry excluded) |
graph://{name}/edge-attributes |
List of edge attribute names |
graph://{name}/edge-attributes/{attr} |
Unique values for an attribute |
Programmatic use
import osmnx as ox
from desirepath import mount
G = ox.graph_from_place("Piedmont, California, USA", network_type="drive")
G = ox.add_edge_speeds(G)
G = ox.add_edge_travel_times(G)
server = mount(G, name="piedmont")
server.run()
mount(G) accepts any nx.MultiDiGraph and returns a FastMCP server. Use server.run_http_async() for HTTP transport.
Attribution
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file desirepath-0.1.0.tar.gz.
File metadata
- Download URL: desirepath-0.1.0.tar.gz
- Upload date:
- Size: 192.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0599b2e02ba590a66ee4e396a4be9abf0180504253fede4370d535cd8880e45c
|
|
| MD5 |
8187a190e62d589eb74443fc6498489e
|
|
| BLAKE2b-256 |
a01e0c27800043b980ac27e9711ed7a6b185f00182b4226fa6456e37ace0fd34
|
Provenance
The following attestation bundles were made for desirepath-0.1.0.tar.gz:
Publisher:
publish.yml on msradam/desirepath
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
desirepath-0.1.0.tar.gz -
Subject digest:
0599b2e02ba590a66ee4e396a4be9abf0180504253fede4370d535cd8880e45c - Sigstore transparency entry: 1859607992
- Sigstore integration time:
-
Permalink:
msradam/desirepath@fc8650491ce683ff5330b584e04c602797b4531f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/msradam
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fc8650491ce683ff5330b584e04c602797b4531f -
Trigger Event:
release
-
Statement type:
File details
Details for the file desirepath-0.1.0-py3-none-any.whl.
File metadata
- Download URL: desirepath-0.1.0-py3-none-any.whl
- Upload date:
- Size: 35.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
91a8669fb76781ace5f3e400ec767b435bb98ff83fab848ab9644b5b658f8929
|
|
| MD5 |
1612bed30ff0ebda0c1235fe44cd5f18
|
|
| BLAKE2b-256 |
54eac5897aaf1e21ec54743f33ad550bac559560b29c7b1ef12245e83262a4c9
|
Provenance
The following attestation bundles were made for desirepath-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on msradam/desirepath
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
desirepath-0.1.0-py3-none-any.whl -
Subject digest:
91a8669fb76781ace5f3e400ec767b435bb98ff83fab848ab9644b5b658f8929 - Sigstore transparency entry: 1859608006
- Sigstore integration time:
-
Permalink:
msradam/desirepath@fc8650491ce683ff5330b584e04c602797b4531f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/msradam
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fc8650491ce683ff5330b584e04c602797b4531f -
Trigger Event:
release
-
Statement type: