Charlotte-Mecklenburg MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Charlotte-Mecklenburg MCP ServerWhat's the zoning for 300 South Davidson St?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Charlotte-Mecklenburg MCP Server
An MCP (Model Context Protocol) server that exposes Charlotte, NC and Mecklenburg County open data as tools for an LLM agent. Ask about trash pickup, parcels and zoning, crime and 311 requests, planning areas and rezonings, bike lanes and ADA infrastructure, or environmental data (watersheds, tree canopy, brownfields) at any address in the city/county, and the server geocodes the address and queries the relevant live ArcGIS layer for you.
Core motion behind almost every tool: geocode an address → spatial or attribute query against an ArcGIS REST layer → structured result + a human-readable summary.
Data sources
Everything is queried live, at call time, from public ArcGIS REST endpoints — there
is no local copy of the underlying data (a small local registry of endpoint
metadata, not the data itself, lives in data/registry.json; see "Endpoint
discovery" below). Four backends are in play:
Source | What it is | Base URL |
City of Charlotte on-prem ArcGIS Server | City departmental data (CMPD, sanitation, 311, zoning) |
|
Mecklenburg County on-prem ArcGIS Server | County data (parcels, tax foreclosures) |
|
City of Charlotte ArcGIS Online (AGOL) org | Solid waste routes, bike lanes, ADA infrastructure, CATS transit, watersheds, tree canopy |
|
Mecklenburg County ArcGIS Online (AGOL) org | Capital Improvement Projects, brownfields, battery/HHW recycling sites |
|
All endpoints are public and require no authentication/token. Geocoding uses
Esri's public World geocoder (https://geocode.arcgis.com/...), also token-free for
non-stored results.
An offline registry of ~1,875 discovered service/layer entries across all four
sources (crawled via scripts/build_registry.py) backs the list_datasets tool, so
an agent can search for "what layer has X" before calling a specific tool.
Related MCP server: Dilix MCP
Install
git clone <this repo> charlotte-mcp
cd charlotte-mcp
uv syncRegister with Claude Code:
claude mcp add charlotte -- uv --directory /Users/dwlavoie/charlotte-mcp run charlotte-mcp(Substitute your actual clone path for /Users/dwlavoie/charlotte-mcp.) The server
runs over stdio — no ports, no API keys, no config needed.
You can also run it directly for local testing:
uv run charlotte-mcpTools
21 tools total: 1 geocoder, 1 dataset-discovery tool, and 19 domain tools across six
tool packs. Every location-based tool accepts either address: str or
lat: float, lon: float and returns a dict with a summary field.
Tool | Pack | Description |
| core | Geocode a free-form address to lat/lon via the Esri World geocoder |
| datasets | Search the ~1,875-entry endpoint registry by keyword/source |
| property | Look up a parcel by address, point, PID, or NC-PIN ( |
| property | Get zoning code and rezone date for a parcel ( |
| property | Search county tax foreclosures by neighborhood/zip/status ( |
| sanitation | Garbage/recycling/yard-waste day, provider, route, and GREEN/ORANGE recycling week |
| safety | CMPD patrol + domestic-violence calls-for-service near a point (NPA-aggregate) |
| safety | CMPD violent-offense counts (homicide/rape/robbery/assault) near a point (NPA-aggregate) |
| safety | Point-level homicide incidents near a point, with weapon/clearance detail |
| safety | 311 service requests near a point |
| planning | Named community planning area containing a location |
| planning | Approved rezonings (since 2016) near a point |
| planning | Area plan(s) covering a location |
| transport | Bike lane segments near a point (street, lane type, width, year built) |
| transport | ADA curb ramps, accessible parking, and pedestrian signals near a point |
| transport | County Capital Improvement (stormwater) projects near a point |
| transport | CATS transit capital projects (stations + corridors) near a point |
| environment | Recorded NC Brownfields Program sites near a point |
| environment | Named watershed/basin containing a location |
| environment | Tree canopy / vegetation / impervious-surface stats for a location |
| environment | Household hazardous waste / battery recycling drop-off sites near a point |
Example prompts
"When is trash pickup at 2437 Remount Rd?"
"What's the zoning for 2437 Remount Rd, and has it been rezoned recently?"
"Are there any tax foreclosures in zip code 28208?"
"What watershed is 2437 Remount Rd in, and what's the tree canopy like there?"
"Any 311 requests or CMPD calls for service near 600 E 4th St in the last 90 days?"
"Find bike lanes and ADA curb ramps within 400 meters of 600 E 4th St."
"What capital improvement or CATS transit projects are planned near uptown?"
"Search the dataset registry for anything related to 'waste'."
See docs/demo.md for a full worked transcript of the trash-pickup question.
Known data quirks
City
SWS/AddressLocatorgeocoder is broken — it returns roughly(0, 0)in its native spatial reference (wkid 2264) instead of a real match. The server does not use it;geocodeand every tool's address resolution go through Esri's World geocoder instead.ParcelStatus(county on-prem) rejectsoutFields=*— the layer'squeryoperation returns an HTTP 200 with an ArcGIS{"error": {"code": 400, ...}}body wheneveroutFields=*orresultRecordCountis present, regardless of the where/point/envelope filter.lookup_parcelalways passes an explicit field list and never a page-size hint to work around it. This is isolated to this layer.TaxForeclosures.statusis null on every row in the current dataset (629 total rows checked). Thestatusfilter is still exposed bysearch_tax_foreclosuresas documented — it just won't match anything until the county populates that column.cde_symbology_valandbpo_statusare the actually-populated status-like fields.CMPD_Calls_for_ServiceandViolentCrimeDataare aggregate-only tables, not incident-level data — no geometry, no per-incident rows, just monthly counts by Neighborhood Profile Area (NPA).crime_nearandviolent_crime_nearproxy "near this point" by sampling nearby NPAs from the spatialServiceRequests311layer, then filtering the aggregate tables to those NPAs — a best-effort approximation, not a true point-in-polygon match.homicides_nearandservice_requests_near, by contrast, query real point-level layers directly.ArcGIS
distance+units=esriSRUnit_Meterbuffer overshoot, on some AGOL layers. During development the environment tool pack foundBrownfieldsandBattery_Recycling_Sites(both hosted on layers with a native NC State Plane feet spatial reference) returning features far outside the requested meter radius — consistent with the server silently treating the requested distance as the layer's native unit (feet) instead of converting from meters, a roughly 3.28x overshoot.environment.py'sbrownfields_nearandbattery_recycling_sites_nearwork around this by fetching the full (small: 170 and 5 records respectively) layer once and filtering with a client-side haversine calculation instead of relying on the server-side buffer. A follow-up audit of every other radius-based tool (all ofsafety.pyandtransport.py, plus a re-probe of the two originally-flagged layers) found the meter buffer behaving correctly everywhere else, including on a fresh re-test ofBrownfields/Battery_Recycling_Sites— see the "Task 8 distance-buffer regression check" note inPLAN.mdfor the full methodology and a caution for future maintainers about re-verifying before trusting (or removing a workaround for) the buffer on any new layer.
Development
uv run pytest -m live # live smoke tests against real endpoints, one file per tool packTests are marked live because they hit real network services; expect occasional
transient failures from upstream ArcGIS endpoints rather than code bugs.
This server cannot be installed
Maintenance
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
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/Lavoiedavidw/Charlotte-City-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server