Worcester GIS MCP
Enables querying and exploring the City of Worcester's open data portal (ArcGIS Hub) through natural language, including dataset search, type filtering, schema inspection, spatial point-in-polygon queries, and geocoding.
README
OpenContext
<p align="center"> <img src="docs/opencontext_logo.png" alt="OpenContext Logo" width="400"> </p>
San Diego City GIS MCP — a City of San Diego fork of OpenContext (forked from the Worcester GIS fork). It serves the City's ArcGIS Server REST services directory (webmaps.sandiego.gov/arcgis/rest/services, ArcGIS Enterprise 11.5) through the built-in arcgis plugin.
It is a sibling to the San Diego regional (SANDAG/SanGIS) and Worcester servers: identical tool names and signatures, so it composes with them at the MCP client with zero new orchestration. The regional server covers county-wide layers; this one covers City-authored layers (MHPA, Base Zones, Community Plan Land Use, and ~700 more).
How discovery works (no Hub here)
webmaps.sandiego.gov is a bare services directory — there is no ArcGIS Hub / Open Data catalog in front of it, so the Hub-search discovery used by the Worcester fork does not apply. Instead:
scripts/crawl_catalog.pywalks the directory offline: folders → MapServer/FeatureServer services → each service's/layers?f=json, capturing layer id, name, geometry type, description, extent, andmaxRecordCount.- The result is serialized to
plugins/arcgis/catalog.json— a versioned, diffable deploy artifact (~718 layers from 329 services at last crawl). - The running server loads that manifest at startup — instant, no live crawl, no cold-start penalty.
search_datasetsdoes substring/fuzzy/acronym matching over it. - Services that require an ArcGIS account (HTTP 401/403 or ArcGIS error codes 498/499) are skipped during the crawl and recorded in the manifest's
skippedlist — 15 folders on this host at last crawl (AMPGIS, GetItDone, TED, …).
To refresh the catalog: python scripts/crawl_catalog.py, review the diff, commit, redeploy.
Dataset IDs
A dataset id is the layer's services-directory path:
{folder}/{service}/{MapServer|FeatureServer}/{layerId}
Known-good public layers (all in the anonymous Planning/PLN_LongRangePlanning MapServer):
| Layer | dataset_id | Notes |
|---|---|---|
| Multi-Habitat Planning Area (MHPA) | Planning/PLN_LongRangePlanning/MapServer/7 |
Polygon. Key fields: HABPRES (int, % targeted preservation), INHABPRES, SUBAREA, ACRES |
| Base Zones (official City zoning) | Planning/PLN_LongRangePlanning/MapServer/27 |
Polygon. Zone codes like RS-1-7, CC-3-5 |
| Community Plan Land Use | Planning/PLN_LongRangePlanning/MapServer/24 |
Polygon |
These are curated as featured_datasets in config.yaml (aliases + notes boost search; edits take effect on deploy without re-crawling).
The WGS84 contract
The layers are authored in EPSG:2230 (NAD83 State Plane California Zone VI, US survey feet). Every query this server sends sets inSR=4326 and outSR=4326, so all tools take and return WGS84 lon/lat — same as the sibling servers. Without inSR, WGS84 coordinates would be interpreted as State Plane feet and silently return zero rows.
Pagination is metadata-driven: each layer's maxRecordCount comes from the catalog (it varies by layer), and query_data pages with resultOffset/resultRecordCount when needed.
Connect to the server
Add it as a custom connector in Claude (same steps on Claude.ai and Claude Desktop):
-
Settings → Connectors (or Customize → Connectors on claude.ai)
-
Add custom connector
-
Name it e.g.
San Diego City GISand paste the URL:https://sandiego-city-gis.codeforanchorage.org/mcp
Quick health check from a terminal:
curl -sS -X POST https://sandiego-city-gis.codeforanchorage.org/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"ping"}'
# → {"jsonrpc":"2.0","id":1,"result":{"status":"ok"}}
Tools exposed
| Tool | Purpose |
|---|---|
arcgis__search_datasets |
Discover layers by keyword (e.g. "MHPA", "zoning"). Matches names, service/folder names, descriptions, acronyms. Optional type filter: MapServer/FeatureServer or a geometry (Polygon, Point, Polyline) |
arcgis__get_dataset |
Fetch a layer's metadata: geometry type, record cap, extent, layer URL |
arcgis__get_layer_schema |
List a layer's fields (name, type, alias, coded values), optionally filtered by keyword |
arcgis__get_distinct_values |
List the distinct values in a field (with optional like / where) to confirm exact codes |
arcgis__query_data |
Query features (supports where, out_fields, order_by, limit). Output leads with a TOTAL MATCHING count, so "how many X?" needs no paging. Auto-paginates past per-layer record caps |
arcgis__spatial_query_point |
Point-in-polygon: which polygon(s) contain a point — by lon/lat (WGS84) or a street address |
arcgis__geocode_address |
Convert a street address to lon/lat (US Census geocoder, biased to San Diego) |
arcgis__get_aggregations |
Facet counts of the catalog by folder, service, service_type, or geometry_type |
Raw JSON-RPC example:
curl -sS -X POST https://sandiego-city-gis.codeforanchorage.org/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"arcgis__search_datasets",
"arguments":{"q":"MHPA","limit":5}}}'
Verified end-to-end
The definition-of-done check is a WGS84 point-in-polygon on MHPA at the Tijuana River Valley (32.5539, -117.0846) — a point that returns null on the regional server's County MSCP_CN layer but sits inside a City MHPA preserve:
// arcgis__spatial_query_point
{
"item_id": "Planning/PLN_LongRangePlanning/MapServer/7",
"lon": -117.0846,
"lat": 32.5539,
"out_fields": "HABPRES,INHABPRES,SUBAREA,ACRES"
}
returns the containing preserve polygon:
Record 1:
HABPRES: 100
INHABPRES: Yes
SUBAREA: 113
ACRES: 2734.79
scripts/smoke_prod.py runs this plus 12 more checks (search resolution for "MHPA" and "zoning", schema, TOTAL MATCHING counts, geocode → zoning chain at City Hall) against any deployment:
python scripts/smoke_prod.py # production
python scripts/smoke_prod.py http://localhost:8000/mcp # local
Local development
uv sync # or: pip install -r requirements.txt
python scripts/crawl_catalog.py # (re)build plugins/arcgis/catalog.json
python scripts/local_server.py # serves http://localhost:8000/mcp
python -m pytest tests/ -q # tests
See CLAUDE.md and docs/ for architecture, deployment, and plugin development.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。