Skip to main content
Glama
Lavoiedavidw

Charlotte-Mecklenburg MCP Server

by Lavoiedavidw

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)

https://gis.charlottenc.gov/arcgis/rest/services

Mecklenburg County on-prem ArcGIS Server

County data (parcels, tax foreclosures)

https://meckags.mecklenburgcountync.gov/server/rest/services

City of Charlotte ArcGIS Online (AGOL) org

Solid waste routes, bike lanes, ADA infrastructure, CATS transit, watersheds, tree canopy

https://services.arcgis.com/9Nl857LBlQVyzq54/arcgis/rest/services

Mecklenburg County ArcGIS Online (AGOL) org

Capital Improvement Projects, brownfields, battery/HHW recycling sites

https://services.arcgis.com/BWD3gDuaqc7SQmy7/arcgis/rest/services

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: civic-library-mcp

Install

git clone <this repo> charlotte-mcp
cd charlotte-mcp
uv sync

Register 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-mcp

Use from ChatGPT (remote connector)

ChatGPT cannot run local MCP servers — it only supports remote custom connectors (a public HTTPS endpoint, added in Developer Mode). A hosted instance of this server runs at:

https://pcygic2am3.us-east-1.awsapprunner.com/mcp

To connect it (requires ChatGPT Plus/Pro; custom connectors are read-only on those plans, which is all this server needs):

  1. On chatgpt.com, open Settings → Apps & Connectors → Advanced settings and enable Developer mode.

  2. Add a custom connector: name Charlotte City Data, MCP server URL https://pcygic2am3.us-east-1.awsapprunner.com/mcp, authentication none.

  3. Start a new chat, enable the connector from the tools menu, and test with "When is trash pickup at 2437 Remount Rd?" (expected answer: Thursday).

Non-technical users: paste the block below into a new ChatGPT chat and it will walk you through the steps above interactively.

You're going to help me connect a custom connector called "Charlotte City Data" — a read-only tool that answers questions about Charlotte, NC using the city's official open data. Source: https://github.com/Lavoiedavidw/Charlotte-City-MCP Please walk me through, one step at a time, waiting for my confirmation between each: (1) confirm I'm signed in to ChatGPT Plus or Pro on chatgpt.com in a web browser; (2) guide me to Settings → Apps & Connectors → Advanced settings and help me turn on Developer mode; (3) guide me to add a custom connector named "Charlotte City Data" with MCP server URL https://pcygic2am3.us-east-1.awsapprunner.com/mcp and no authentication; (4) have me start a new chat, enable the connector from the tools menu, and test it with "When is trash pickup at 2437 Remount Rd?" — the answer should be Thursday. Afterward, give me five examples of useful things I can ask it about any Charlotte address.

Remote hosting (AWS)

The same server serves streamable HTTP for remote MCP clients:

uv run charlotte-mcp --transport http --host 0.0.0.0 --port 8080

The hosted instance is defined as two CloudFormation stacks in infra/:

  • infra/build.yaml — ECR repository + a CodeBuild project that builds the Dockerfile directly from this public GitHub repo (no GitHub↔AWS OAuth connection needed) and pushes :latest.

  • infra/service.yaml — an App Runner service (0.25 vCPU / 0.5 GB, ≈$3–5/mo at light usage) serving the image with auto-deploy on new pushes. Deploy it after the first CodeBuild run, since App Runner requires the image to exist.

One transport gotcha, fixed in server.py: FastMCP enables localhost-only DNS rebinding protection at construction time, which makes a public deployment reject its own hostname with HTTP 421. The entrypoint disables that protection when binding to a non-loopback --host.

Tools

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

geocode

core

Geocode a free-form address to lat/lon via the Esri World geocoder

list_datasets

datasets

Search the ~1,875-entry endpoint registry by keyword/source

lookup_parcel

property

Look up a parcel by address, point, PID, or NC-PIN (ParcelStatus)

get_zoning

property

Get zoning code and rezone date for a parcel (Parcel_Zoning_Lookup)

search_tax_foreclosures

property

Search county tax foreclosures by neighborhood/zip/status (TaxForeclosures)

get_trash_schedule

sanitation

Garbage/recycling/yard-waste day, provider, route, and GREEN/ORANGE recycling week

crime_near

safety

CMPD patrol + domestic-violence calls-for-service near a point (NPA-aggregate)

violent_crime_near

safety

CMPD violent-offense counts (homicide/rape/robbery/assault) near a point (NPA-aggregate)

homicides_near

safety

Point-level homicide incidents near a point, with weapon/clearance detail

service_requests_near

safety

311 service requests near a point

get_planning_area

planning

Named community planning area containing a location

rezonings_near

planning

Approved rezonings (since 2016) near a point

area_plans_at

planning

Area plan(s) covering a location

bike_lanes_near

transport

Bike lane segments near a point (street, lane type, width, year built)

ada_features_near

transport

ADA curb ramps, accessible parking, and pedestrian signals near a point

cip_projects_near

transport

County Capital Improvement (stormwater) projects near a point

cats_projects_near

transport

CATS transit capital projects (stations + corridors) near a point

brownfields_near

environment

Recorded NC Brownfields Program sites near a point

watershed_at

environment

Named watershed/basin containing a location

tree_canopy_at

environment

Tree canopy / vegetation / impervious-surface stats for a location

battery_recycling_sites_near

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/AddressLocator geocoder 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; geocode and every tool's address resolution go through Esri's World geocoder instead.

  • ParcelStatus (county on-prem) rejects outFields=* — the layer's query operation returns an HTTP 200 with an ArcGIS {"error": {"code": 400, ...}} body whenever outFields=* or resultRecordCount is present, regardless of the where/point/envelope filter. lookup_parcel always passes an explicit field list and never a page-size hint to work around it. This is isolated to this layer.

  • TaxForeclosures.status is null on every row in the current dataset (629 total rows checked). The status filter is still exposed by search_tax_foreclosures as documented — it just won't match anything until the county populates that column. cde_symbology_val and bpo_status are the actually-populated status-like fields.

  • CMPD_Calls_for_Service and ViolentCrimeData are aggregate-only tables, not incident-level data — no geometry, no per-incident rows, just monthly counts by Neighborhood Profile Area (NPA). crime_near and violent_crime_near proxy "near this point" by sampling nearby NPAs from the spatial ServiceRequests311 layer, then filtering the aggregate tables to those NPAs — a best-effort approximation, not a true point-in-polygon match. homicides_near and service_requests_near, by contrast, query real point-level layers directly.

  • ArcGIS distance + units=esriSRUnit_Meter buffer overshoot, on some AGOL layers. During development the environment tool pack found Brownfields and Battery_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's brownfields_near and battery_recycling_sites_near work 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 of safety.py and transport.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 of Brownfields/Battery_Recycling_Sites — see the "Task 8 distance-buffer regression check" note in PLAN.md for 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 pack

Tests are marked live because they hit real network services; expect occasional transient failures from upstream ArcGIS endpoints rather than code bugs.

Available Tools

21 tools
ada_features_nearA

Find ADA pedestrian infrastructure near an address or coordinate.

Covers curb ramps, on-street accessible parking spaces, and accessible pedestrian signals from the city's ADA self-evaluation dataset.

Args: address: Free-form address. Provide this OR lat/lon. lat: Latitude, used with lon instead of address. lon: Longitude, used with lat instead of address. radius_m: Search radius in meters (default 400). feature_type: Which ADA feature types to return: "all" (default), "ramps", "parking", or "signals".

Returns: Dict with the resolved location, lists under "ramps", "parking", and/or "signals" (only the requested types are populated), and a "summary" sentence.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
addressNo
radius_mNo
feature_typeNoall

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the burden. It discloses the output structure (resolved location, lists under 'ramps', 'parking', 'signals', and a 'summary' sentence) and the address/lat-lon exclusivity. Yet it omits behavioral edge cases such as no-results behavior, invalid address handling, or rate limits, leaving some gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured: a one-sentence summary, a coverage note, a clearly labeled Args section, and a Returns section. Every sentence contributes meaningful information without redundancy, and key details are front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only search tool, the description is largely complete: it covers purpose, parameters, and return format. The return structure is explicitly described because no output schema exists. Minor omissions include error handling and geocoding caveats, but these do not significantly hinder usability.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description's 'Args' section fully compensates. It explains each parameter's meaning and constraints: address is free-form and mutually exclusive with lat/lon, radius_m has a default of 400 meters, and feature_type enumerates its allowed values. This adds semantic depth beyond raw names and types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific action: 'Find ADA pedestrian infrastructure near an address or coordinate.' It names the exact resource (ADA infrastructure) and lists covering curb ramps, accessible parking, and accessible signals, which clearly distinguishes it from sibling tools like crime_near or bike_lanes_near.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description communicates when to use the tool: when ADA pedestrian infrastructure near a location is needed. It provides clear usage context by explaining address vs. lat/lon ('Provide this OR lat/lon') and the feature_type option. However, it does not explicitly name alternatives or state when not to use this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

area_plans_atA

Find adopted area/small-area plan boundaries containing a point.

Provide either address (free-form string) or both lat and lon. Runs a point-in-polygon query against the city's Area_Plan_Boundaries layer; a point can fall inside more than one adopted plan boundary (overlapping study areas), so all matches are returned.

Args: address: Free-form address, e.g. "2437 Remount Rd, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given.

Returns: Dict with area_plans (list of dicts with plan_name, plan_type, district, adopt_date, adopt_year, acres, hyperlink), count, lat, lon, resolved_address, and a summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
addressNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It transparently explains that it runs a point-in-polygon query, that overlapping boundaries can yield multiple matches, and that all matches are returned. It also lists return fields. It does not mention error conditions or data freshness, but for a read-only query tool, this is strong disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured: a lead sentence stating purpose, a sentence about input alternatives, a behavior explanation, and a structured Args/Returns section. Every sentence contributes useful information without redundancy or fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers input constraints, query behavior, overlapping boundary handling, and return fields. Since an output schema exists, it needn't detail return values, but it does anyway. It lacks explicit error handling or permission info, but for a point-query tool with this level of explanation, it is nearly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description fully compensates by documenting each parameter: address is a free-form string, lat and lon are used together if address is not given. This clarifies the relationship among parameters and their intended usage, going well beyond the schema's simple nullability.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence clearly states the verb and resource: 'Find adopted area/small-area plan boundaries containing a point.' This distinguishes it from sibling tools by focusing specifically on plan boundaries and using a point query. The mention of overlapping boundaries adds specificity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides clear context for when to use the tool: when you need to identify which area plans cover a point. It also gives input alternatives (address vs. lat/lon). However, it does not explicitly name alternatives or exclusion scenarios, so it lacks the direct 'when-not-to-use' guidance of a top-tier description.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

battery_recycling_sites_nearA

Find battery/household-hazardous-waste recycling drop-off sites near a location.

Queries the Mecklenburg County recycling drop-off centers point layer (batteries are one of several accepted materials at these sites; there is no battery-specific kiosk layer published). Provide either address or both lat/lon.

Args: address: Free-form address, e.g. "2437 Remount Rd, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given. radius_m: Search radius in meters (default 8000m, ~5 miles — sites are sparse, only 5 exist countywide).

Returns: Dict with sites (list of name/address/hours/description/ distance_m), count, lat, lon, resolved_address, and summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
addressNo
radius_mNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses important behavioral traits: the data source is the county recycling drop-off layer, the results are not battery-specific kiosks but multi-material sites, and only five sites exist countywide, justifying the large default radius. This goes well beyond the schema's structured information.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and appropriately sized: a crisp one-line summary, a brief limitation note, then organized Args and Returns sections. Each sentence contributes necessary information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is complete in context: it explains the conditional input requirements, the data limitations, the default behavior, and what the return dictionary contains. Since an output schema exists, the explicit Returns summary is a helpful supplement, and the conditional logic is fully addressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description compensates by explaining every parameter: address is free-form, lat/lon are used together when address is absent, and radius_m has a default with a reason. This adds meaning that the bare schema properties completely lack.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'Find battery/household-hazardous-waste recycling drop-off sites near a location.' It also differentiates from sibling tools by clarifying this queries the Mecklenburg County recycling drop-off centers point layer and that there is no battery-specific kiosk layer, making the tool's exact scope clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly states when to use the tool: provide either an address or both lat/lon. It also gives practical context by explaining the default radius and the sparsity of sites. However, it does not explicitly mention a sibling alternative or when not to use this tool, though the caveat that batteries are only one of several accepted materials serves as a partial exclusion.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bike_lanes_nearA

Find bike lanes near an address or coordinate.

Args: address: Free-form address, e.g. "600 E 4th St, Charlotte, NC". Provide this OR lat/lon. lat: Latitude, used with lon instead of address. lon: Longitude, used with lat instead of address. radius_m: Search radius in meters (default 800).

Returns: Dict with the resolved location, a list of bike lane segments (street, lane type, side of street, width, year built, notes), and a "summary" sentence.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
addressNo
radius_mNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of describing behavior. It discloses the default radius, the option to supply coordinates or an address, and the return structure including a resolved location and summary sentence. While it does not explicitly label the tool as read-only, the 'Find' wording makes that clear, and the detailed return description adds useful behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with separate Args and Returns sections, and the opening sentence immediately states the purpose. Every sentence adds value, explaining parameters or expected output without unnecessary fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that there are no annotations and no output schema, the description is remarkably complete. It covers all four parameters, explains the input alternatives, and describes the return structure with specific segment fields. This is sufficient for an agent to invoke the tool and interpret the result appropriately.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does so thoroughly by explaining each parameter: address, lat/lon, and radius_m with its default value. It also clarifies the OR relationship between address and lat/lon, which is not obvious from the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description begins with a specific verb and resource: 'Find bike lanes near an address or coordinate.' This clearly identifies the tool's function and differentiates it from the many sibling 'near' tools by focusing on bike lanes as the subject. The location input options are also stated upfront.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context: it is for finding bike lanes near a user-specified location, and it explains how to provide that location (either address or lat/lon). It does not explicitly mention alternatives or when-not-to-use, but the context is unambiguous and sufficient for an agent to select this tool for bike lane queries.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brownfields_nearA

Find recorded brownfield sites within a radius of a location.

Queries the Mecklenburg County recorded brownfields point layer (NC Brownfields Program). Provide either address or both lat/lon.

Args: address: Free-form address, e.g. "2437 Remount Rd, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given. radius_m: Search radius in meters (default 1600m, ~1 mile).

Returns: Dict with brownfields (list of name/status/address/city/acreage/ distance_m), count, lat, lon, resolved_address, and summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
addressNo
radius_mNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It explains that the tool queries a recorded points layer, the input modes, and the return structure including resolved_address and summary. It does not cover potential error cases or rate limits, but for a straightforward read-only query this is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a summary sentence, a context sentence, an Args block, and a Returns block. Every sentence adds value; there is no fluff. The docstring format makes it easy to parse quickly, and the most important information (purpose) is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Although the output schema is marked as present, the description's Returns section fully enumerates the response fields, making the tool self-contained. It covers geocoding implications via resolved_address, radius default, and the county scope. For a tool with 4 parameters and a clear purpose, this description is complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does so thoroughly: each parameter (address, lat, lon, radius_m) is explained with examples and defaults. The crucial constraint that address is mutually exclusive with lat/lon is clearly stated, adding substantial meaning beyond the flat schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence 'Find recorded brownfield sites within a radius of a location' uses a specific verb ('Find'), a clear resource ('recorded brownfield sites'), and a scope ('within a radius'), which fully distinguishes it from the many other 'near' sibling tools. It also specifies the geographic context (Mecklenburg County), leaving no ambiguity about what the tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit usage instructions: 'Provide either ``address`` or both ``lat``/``lon``.' This clearly explains how to invoke the tool, but does not explicitly mention when to choose this tool over alternatives like crime_near or homicides_near. Since the resource type is obvious from the name and purpose, this is a minor gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cats_projects_nearA

Find CATS (Charlotte Area Transit System) capital projects near an address or coordinate.

Queries both the point layer (e.g. stations) and the line layer (e.g. transit corridors/tracks) and merges the results.

Args: address: Free-form address. Provide this OR lat/lon. lat: Latitude, used with lon instead of address. lon: Longitude, used with lat instead of address. radius_m: Search radius in meters (default 1600).

Returns: Dict with the resolved location, a list of CATS projects (name, description, funding status, geometry type), and a "summary".

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
addressNo
radius_mNo

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of disclosing behavior. It does add useful interim behavior: 'Queries both the point layer ... and the line layer ... and merges the results,' and it describes the return dict. However, it does not mention potential error conditions, geocoding dependency for addresses, result ordering, or limits. For a read-only search tool, this is acceptable but not comprehensive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, followed by a concise layer-merging detail and a compact Args list. The format is a bit longer than strictly necessary but every sentence earns its place; the Args contributions clarify parameter semantics not present in the schema. No unnecessary fluff or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of an output schema and annotations, the description compensates by explicitly listing the return fields (resolved location, project list, summary) and the two-layer behavior. It covers the primary usage modes and parameters. It lacks edge-case handling (e.g., what happens with no results or invalid coordinates), but for a relatively simple spatial search tool, this is nearly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Even though the schema coverage is 0%, the description's Args section fully explains each parameter. It states that address is used instead of lat/lon, clarifies the mutual exclusivity ('Provide this OR lat/lon'), and gives the default for radius_m. This adds significant semantic meaning beyond the bare schema types and defaults, making parameter usage unambiguous.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Find CATS (Charlotte Area Transit System) capital projects near an address or coordinate,' which clearly names the specific resource (CATS capital projects) and the action (find near location). It also explicitly notes that it queries both point and line layers, further distinguishing it from sibling tools like cip_projects_near or crime_near. This is a specific verb+resource+scope statement.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use the tool (for CATS projects near a location) and explains the address-or-coordinate input modes, but it does not explicitly contrast it with alternatives such as cip_projects_near or mention any exclusions. Usage context is clear enough for an agent to select it for transit-related proximity searches, but direct guidance against using other tools is absent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cip_projects_nearA

Find Mecklenburg County Capital Improvement Projects (stormwater) near an address or coordinate.

Covers Charlotte-Mecklenburg Storm Water Services projects: drainage improvements, stream & wetland restoration, and pollutant removal — both active and completed.

Args: address: Free-form address. Provide this OR lat/lon. lat: Latitude, used with lon instead of address. lon: Longitude, used with lat instead of address. radius_m: Search radius in meters (default 1600).

Returns: Dict with the resolved location, a list of CIP projects (name, status, phase, type, fiscal-year-complete), and a "summary".

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
addressNo
radius_mNo

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses the scope of projects (stormwater, active/completed) and the return structure ('resolved location, a list of CIP projects...and a summary'), which is useful. However, it does not mention potential errors, rate limits, or confirm read-only behavior, leaving some gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and appropriately concise: a clear opening sentence, a supportive scope sentence, a neatly formatted Args list, and a Returns section. No redundant text; every part contributes to understanding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only geospatial query tool with 4 parameters and no output schema, the description covers the necessary input and output essentials. It could elaborate on coordinate format or error handling, but it is largely complete for this simple tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description explicitly defines all four parameters in the Args section, including the relationship between address, lat/lon, and the radius_m default. This fully compensates for the schema's lack of descriptions, providing clear semantic meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: 'Find Mecklenburg County Capital Improvement Projects (stormwater) near an address or coordinate.' It uses a specific verb ('Find') and resource ('CIP projects') with geographic and thematic context, distinguishing it from siblings like crime_near or homicides_near.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context by explaining the two input modes ('Provide this OR lat/lon') and the default radius. It does not explicitly mention alternatives or when not to use the tool, but the instructions for address vs. coordinate input are a practical usage guideline.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

crime_nearA

CMPD calls-for-service (patrol + domestic violence) near a point.

Provide either address (free-form string) or both lat and lon. CMPD_Calls_for_Service has no incident-level geometry — it is a monthly-aggregate table keyed by Neighborhood Profile Area (NPA). This tool resolves the NPA(s) near the point via nearby 311 request density (see module docstring), then sums CALL_COUNT by CALL_DESCRIPTION ("CMPD Patrol Calls For Service" / "CMPD DV Calls For Service") for months within days of now.

Args: address: Free-form address, e.g. "600 E 4th St, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given. radius_m: Radius in meters used to resolve nearby NPAs (default 800). days: Only include months within this many days of now (default 90). limit: Maximum number of raw NPA/month/category records to return (default 50); the breakdown totals cover all matching months, not just the returned records.

Returns: Dict with nearby_npas (NPA ids used), records (raw NPA/month/ category rows, capped at limit), breakdown (call description -> total count), total_calls, radius_m, days, lat, lon, resolved_address, and a summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
daysNo
limitNo
addressNo
radius_mNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly. It discloses the data aggregation methodology, the NPA resolution via 311 request density, and the exact computation (sums CALL_COUNT by CALL_DESCRIPTION) — information that goes far beyond a simple read operation and gives the user a clear mental model of behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every sentence earns its place: a one-line summary, a necessary methodological caveat, a concise Args list with defaults, and a Returns summary. It is well-structured and front-loaded with the most essential fact first.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has 6 parameters, no required ones, and an output schema, but the description still provides complete context: it explains the data's nature, the resolution strategy, parameter meanings, and return fields. Even without the output schema, an agent would know what to expect. No gaps remain.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, yet the description explains every parameter in Args, including defaults and special behaviors (e.g., 'the breakdown totals cover all matching months, not just the returned records' for limit). This fully compensates for the schema's lack of descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first line states the exact purpose: 'CMPD calls-for-service (patrol + domestic violence) near a point.' This clearly distinguishes it from sibling tools like homicides_near or service_requests_near by specifying the dataset and the spatial query nature.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit input guidance: 'Provide either address or both lat and lon.' It also explains the underlying data limitation (no incident-level geometry, monthly aggregate by NPA) which tells the user when this tool is appropriate. However, it does not explicitly mention when not to use it or name alternatives, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

geocodeA

Geocode a free-form address to lat/lon using the Esri World geocoder.

Args: address: Free-form address string, e.g. "2437 Remount Rd, Charlotte, NC".

Returns: Dict with matched address, lat, lon, match score, and a summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
addressYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It discloses the underlying geocoder (Esri World), the output structure (matched address, lat, lon, match score, and a summary), and gives an example. It does not mention error handling or edge cases, but for a read-only lookup tool, this is adequate transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and well-structured: a one-sentence purpose, followed by Args and Returns sections. Every sentence serves a purpose, and the main functionality is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool is a simple one-parameter geocoder with no annotations or output schema, the description is complete: it explains what the tool does, the input format, and the return structure. No additional information is needed for an agent to select and invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides only a title for the single 'address' parameter (0% description coverage). The description compensates fully with an 'Args' section explaining it is a free-form address string and provides a concrete example ('2437 Remount Rd, Charlotte, NC'), adding meaningful value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool geocodes a free-form address to lat/lon using the Esri World geocoder, specifying both the action and the resource. This distinguishes it from sibling tools which are all data lookups (e.g., lookup_parcel, crime_near) rather than address-to-coordinate conversion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage through its purpose statement ('Geocode a free-form address to lat/lon'), and the example shows a typical input. However, it does not explicitly state when to prefer this over alternatives or provide any exclusions, so guidance is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_planning_areaA

Look up the community planning area (and CCW planning region) at a point.

Provide either address (free-form string) or both lat and lon. Runs a point-in-polygon query against the city's Community_Planning_Areas layer (one of Charlotte's 15 named community planning areas, e.g. "West Inner", "Uptown") and the Center_Corridor_Wedge layer (finer "Center/Corridor/Wedge" planning region, e.g. "West Corridor").

Args: address: Free-form address, e.g. "2437 Remount Rd, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given.

Returns: Dict with planning_area (name + equity-index fields, or None if no polygon covers the point), planning_region (CCW name + location type, or None), lat, lon, resolved_address, and a human-readable summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
addressNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure. It explicitly states that it runs a point-in-polygon query, returns None if no polygon covers the point, and describes the resolved_address and summary fields. This goes beyond the input schema to explain what happens during execution and what the user can expect in return.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and appropriately sized. It opens with a clear one-sentence summary, followed by an Args section and a Returns section. Every sentence contributes useful information, with no filler or repetition of schema details. The layout is easily scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has an output schema, but the description still explains the return fields (planning_area, planning_region, lat, lon, resolved_address, summary) and provides context about the layers (e.g., 'one of Charlotte's 15 named community planning areas'). This makes the tool fully self-contained for an agent to invoke correctly without external knowledge.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. The Args section adds meaning to each parameter: address is a free-form string with an example, lat and lon are used together when address is not given. This fully clarifies the schema fields, which only provide types and defaults without descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Look up the community planning area (and CCW planning region) at a point.' It uses a specific verb and resource, names the exact layers queried, and distinguishes itself from sibling tools like lookup_parcel and get_zoning by specifying its unique point-in-polygon query against Community_Planning_Areas and Center_Corridor_Wedge.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context: 'Provide either address (free-form string) or both lat and lon.' It explains the input alternatives and the underlying query mechanism. However, it does not explicitly mention when not to use this tool or name alternatives, though the specificity of the purpose makes usage inferable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_trash_scheduleA

Look up garbage, recycling, and yard waste collection schedule.

Provide either address (free-form string) or both lat and lon. Queries the City of Charlotte Solid Waste Collection polygon layer via point-in-polygon and returns per-stream day, provider, route, and (for recycling) the GREEN/ORANGE alternating week parsed from the route note.

Args: address: Free-form address, e.g. "2437 Remount Rd, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given.

Returns: Dict with garbage, recycling, yard_waste sub-dicts (each with day, provider, route, route_note, and for recycling recycling_week), plus lat, lon, resolved_address, and a human-readable summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
addressNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full transparency burden. It explains the underlying method (point-in-polygon query against the City of Charlotte Solid Waste polygon layer) and the output structure (per-stream day, provider, route, recycling week). It does not mention error handling or edge cases, but this is a solid disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with Args and Returns sections. Every sentence adds value: describing the query method, parameter options, and return fields. It is appropriately sized for the tool's complexity without extraneous information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has an output schema and the description already explains the return dict, parameters, and data source, the description is complete for an agent to select and invoke the tool correctly. No significant gaps are present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage, but the description fully compensates. Each parameter (address, lat, lon) is clearly defined, including examples and the relationship between them (address vs lat/lon). This is exactly what parameter semantics should provide.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Look up garbage, recycling, and yard waste collection schedule.' It clearly distinguishes this from sibling tools (crime, zoning, projects, etc.) and even specifies the City of Charlotte context in the second sentence.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit usage instructions: 'Provide either address or both lat and lon,' with details on how each parameter is used. It does not explicitly name alternative tools, but given the unique focus on trash schedules, the usage context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_zoningA

Get zoning classification for a parcel from Parcel_Zoning_Lookup.

Resolves a parcel (by address, lat/lon, or a known pid) against ParcelStatus first if a pid isn't supplied directly, then looks up its zoning record.

Args: address: Free-form address, e.g. "2437 Remount Rd, Charlotte, NC". lat: Latitude in decimal degrees (WGS84). Requires lon. lon: Longitude in decimal degrees (WGS84). Requires lat. pid: Mecklenburg County parcel ID, if already known.

Returns: Dict with zoning (dict of zoning attributes or None), resolved pid, and a summary string.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
pidNo
addressNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It transparently explains that the tool first resolves the parcel against ParcelStatus if pid is not supplied, then performs the zoning lookup. It also warns that zoning may be None and mentions dependencies like 'Requires lon' for lat. This gives a solid understanding of the tool's internal behavior, though it stops short of detailing error handling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and appropriately sized. It front-loads the purpose, then explains the resolution process, followed by a concise Args section and Returns section. Every sentence adds value without unnecessary fluff or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is contextually complete for a tool with 4 optional parameters, no annotations, and no output schema. It explains the return format (dict with zoning, pid, summary), covers all parameters, and describes the lookup workflow. This gives an agent everything needed to invoke it correctly and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Given that the input schema has 0% description coverage, the description fully compensates by explaining each parameter in detail: address example, coordinate system for lat/lon, the dependency between lat and lon, and the meaning of pid. This goes well beyond the schema's bare type definitions, providing essential usage semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Get zoning classification for a parcel from Parcel_Zoning_Lookup.' This clearly identifies the tool's function and distinct purpose compared to siblings like lookup_parcel or get_planning_area. It also explains the resolution process, further clarifying its role.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context by explaining the three accepted input methods (address, lat/lon, or pid) and the resolution workflow. It does not explicitly state when not to use this tool or name alternative tools, but the context is clear enough for an agent to decide to use it when a zoning classification is needed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

homicides_nearA

Homicide incidents near a point, from the point-level CMPD_Homicide layer.

Provide either address (free-form string) or both lat and lon. Unlike the aggregate crime tables, CMPD_Homicide is a real point Feature Layer (public lat/lon per victim, since 2015), so this runs a genuine point+radius spatial query with a DATE_REPORTED where-clause. Homicides are rare, so defaults are wider (1600m / 365 days) than the other "near" tools; relax further for sparse areas.

Args: address: Free-form address, e.g. "600 E 4th St, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given. radius_m: Search radius in meters (default 1600). days: Only include homicides reported within this many days of now (default 365). limit: Maximum number of homicides to return (default 50).

Returns: Dict with homicides (list of dicts with crime_report_id, location, weapon, clearance_status, circumstances, ipv, npa, council_district, patrol_division, date_reported, clearance_date), count, breakdown (weapon -> count), radius_m, days, lat, lon, resolved_address, and summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
daysNo
limitNo
addressNo
radius_mNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does well by disclosing that this is a genuine point+radius spatial query with a DATE_REPORTED where-clause, and that data is public per victim since 2015. It does not mention potential rate limits or error cases, but the disclosed spatial/behavioral details are substantial.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than average but every sentence earns its place: it explains the layer's nature, the query approach, why defaults are wider, and provides structured Args/Returns sections. It is well-organized, front-loaded with purpose, and free of fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (point query with two alternative input modes, spatial and temporal filters), the description is complete. It covers inputs, defaults, output structure, and notable behavioral differences. The explicit Returns section and mention of breakdown/weapon counts satisfy what the agent needs to know.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does so thoroughly with an Args section explaining each parameter, including defaults, the address example, and the lat/lon pairing requirement. This adds meaning far beyond the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource: 'Homicide incidents near a point, from the point-level CMPD_Homicide layer.' It clearly distinguishes itself from aggregate crime tables by noting 'CMPD_Homicide is a real point Feature Layer', which differentiates it from sibling tools like crime_near and violent_crime_near.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context: 'Provide either address (free-form string) or both lat and lon' and explains why defaults are wider ('Homicides are rare'). It implicitly contrasts with aggregate crime tables, but does not name explicit alternative tools or state when not to use this tool, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_datasetsA

Search the Charlotte/Mecklenburg ArcGIS endpoint registry.

Use this to discover which layer to query before calling a spatial/attribute tool -- e.g. search "waste" to find the solid waste collection routes layer, or "parcel" for parcel/zoning data.

Args: keyword: Case-insensitive substring matched against service name, layer name, and field names/aliases. Omit to browse. source: Optional filter to one of "city-onprem", "county-onprem", "city-agol", "county-agol". limit: Maximum number of results to return (default 25).

Returns: Dict with a "results" list (service, service_type, layer_name, url, geometry_type, field_count, broken) and a "summary" line.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
sourceNo
keywordNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description details search semantics (case-insensitive substring across service/layer/field names), source filters, and return structure including the 'broken' field. Since no annotations are provided, this thorough explanation covers the behavior well, but it could explicitly state read-only or note pagination/error behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a one-sentence purpose, a usage note with examples, and labeled Args/Returns sections. Every sentence contributes information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a discovery tool with three optional parameters and a structured output, the description covers all necessary semantics, workflow context, and return shape. It's self-sufficient even without the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema coverage, the description fully compensates by explaining each parameter: keyword's substring matching and omission behavior, source's allowed values, and limit's default. This adds meaning beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'Search' and names the resource 'Charlotte/Mecklenburg ArcGIS endpoint registry'. It clearly distinguishes itself from sibling spatial/attribute tools by positioning itself as a precursor step to discover the correct layer.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides explicit guidance to use this tool 'before calling a spatial/attribute tool', with concrete examples. This establishes proper workflow context, though it doesn't name specific alternative tools or include 'when not to use' exclusion.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lookup_parcelA

Look up Mecklenburg County parcel(s) from the ParcelStatus layer.

Provide exactly one way to locate the parcel: an address (will be geocoded), explicit lat/lon, a pid (8-digit parcel ID), or an nc_pin (NC state parcel identification number).

Args: address: Free-form address, e.g. "2437 Remount Rd, Charlotte, NC". lat: Latitude in decimal degrees (WGS84). Requires lon. lon: Longitude in decimal degrees (WGS84). Requires lat. pid: Mecklenburg County parcel ID (e.g. "06705133"). nc_pin: NC state parcel identification number (e.g. "4534836016").

Returns: Dict with parcels (list of parcel attribute dicts), count, and a summary string.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
pidNo
nc_pinNo
addressNo

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the behavioral burden. It discloses that address input 'will be geocoded', that lat/lon must be used together, and specifies the return shape: 'Dict with parcels (list of parcel attribute dicts), count, and a summary string.' This exceeds a minimal lookup description, though it omits edge-case behavior such as error handling or ambiguous match resolution.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and then organized into Args and Returns sections. Every sentence is informative, with no filler or repetition. It is appropriately sized for a tool with five optional parameters.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations and no output schema, the description covers the essential aspects: purpose, all parameter semantics, mutual-exclusion rule, geocoding behavior, and return structure. Minor gaps exist (e.g., no mention of failure modes or what happens if multiple parcels match), but overall it is complete enough for an agent to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides only names, types, and defaults with 0% description coverage. The description fully compensates with per-parameter details: free-form address examples, WGS84 coordinate system, the lat/lon mutual requirement, 8-digit PID format, and example values for pid and nc_pin. This adds substantial meaning beyond the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Look up Mecklenburg County parcel(s) from the ParcelStatus layer.' It clearly distinguishes itself from siblings by focusing on parcel lookup via multiple identifiers (address, lat/lon, pid, nc_pin), which differentiates it from geocoding and proximity tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit usage guidance: 'Provide exactly one way to locate the parcel' and lists the four mutually exclusive input methods with their required counterparts (e.g., lat requires lon). It does not explicitly name alternative sibling tools or state when not to use this tool, but the context is clear and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rezonings_nearA

Find approved rezoning petitions near a point.

Provide either address (free-form string) or both lat and lon. Queries the city's Approved_Rezonings_since_2016__by_CCW point layer within radius_m meters, filtered to Decision = 'App' (the layer also carries deferred/withdrawn petitions despite its name), most recently approved first.

Args: address: Free-form address, e.g. "2437 Remount Rd, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given. radius_m: Search radius in meters (default 1600, roughly 1 mile). limit: Maximum number of rezonings to return (default 25).

Returns: Dict with rezonings (list of dicts with petition, petitioner, from_zone, to_zone, type, received_date, approved_date, decision, ccw_region, acres, petition_acres), count, radius_m, lat, lon, resolved_address, and a summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
limitNo
addressNo
radius_mNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description fully carries the transparency burden. It explicitly discloses the layer name, the Decision='App' filter, the surprising fact that the layer also contains deferred/withdrawn petitions despite its name, and the sort order (most recently approved first). This is rich behavioral detail beyond a simple 'find' statement.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with a one-sentence summary, followed by well-structured Args and Returns sections. Every sentence adds value, including the example address and the caveat about deferred/withdrawn petitions, with no redundant or filler content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Even though an output schema exists, the description goes beyond it by enumerating the exact fields returned in each rezoning dict and the top-level response keys. It covers the alternate input modes, defaults, and layer filtering nuances, making it fully self-contained for an agent to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero descriptions (0% coverage), so the description must compensate. It provides thorough per-parameter meaning: address is a free-form string with an example, lat/lon are used together only when address is absent, radius_m defaults to 1600 meters (~1 mile), and limit defaults to 25. This fully clarifies the ambiguous optional parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb ('Find') and specific resource ('approved rezoning petitions near a point'), immediately distinguishing itself from sibling 'near' tools by focusing on approved rezonings and explicitly filtering to Decision='App'. It also names the exact underlying layer, leaving no ambiguity about the tool's scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context by explaining the two location input modes (address vs. lat/lon), the radius default with an approximate mile equivalent, and the limit default. However, it does not mention alternative tools or state when not to use this tool, so it lacks explicit exclusion guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_tax_foreclosuresA

Search active Mecklenburg County tax foreclosures.

All filters are optional and combined with AND; omit all to list foreclosures broadly (results are still capped by limit). nhood matches as a case-insensitive substring; zip and status match exactly (case-insensitive). Note: as of 2026-07-12 the status field is null on essentially every row in this dataset, so filtering by it will often return zero rows even when other filters would match — this is a data-population gap in the source, not a client bug.

Args: zip: 5-digit ZIP code, e.g. "28208". nhood: Neighborhood/subdivision name substring, e.g. "WESTCHESTER". status: Foreclosure status value, if populated for the record. limit: Max rows to return (default: all matches).

Returns: Dict with foreclosures (list of property dicts), count, and a summary string.

ParametersJSON Schema
NameRequiredDescriptionDefault
zipNo
limitNo
nhoodNo
statusNo

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It fully discloses matching semantics (case-insensitive substring for nhood, exact for zip/status), the limiting behavior via 'limit', and a known data-quality issue (status nulls) with reassurance that it's not a client bug. This is exemplary transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured: a one-sentence purpose, brief operational notes, a caveat, a concise Args list, and a Returns line. Every sentence adds value; there is no fluff or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (4 optional filter params, no output schema, no annotations), the description is complete: it explains matching semantics, default behavior, data caveats, and return value shape. An agent has enough to invoke it correctly and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides zero description coverage, but the description includes an Args section that defines each parameter with type examples, default behavior, and matching rules. This fully compensates for the schema's lack of semantic information.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Search active Mecklenburg County tax foreclosures,' using a specific verb and resource, clearly indicating the tool's purpose. The scope ('active', county-specific) distinguishes it from sibling parcel/lookup tools like lookup_parcel.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states that all filters are optional and combined with AND, and explains the default behavior when omitting all filters. It also provides a concrete note about the status field data gap and its impact on filtering, though it does not explicitly name alternative tools or when to choose them.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

service_requests_nearA

311 service requests near a point, from the point-level ServiceRequests311 layer.

Provide either address (free-form string) or both lat and lon. Runs a point+radius spatial query, most recent first. Note: this layer has no open/closed "status" field — the closest available signal is INTERNAL_FIELD_OBSERVATION (a Y/N flag for whether the request originated from an internal field observation rather than a resident report), surfaced as field_observation below.

Args: address: Free-form address, e.g. "600 E 4th St, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given. radius_m: Search radius in meters (default 800). days: If given, only include requests received within this many days of now (default None: no date filter). limit: Maximum number of requests to return (default 50).

Returns: Dict with requests (list of dicts with request_type, title, department, division, received_date, field_observation, address, npa, council_district), count, breakdown (request_type -> count), radius_m, days, lat, lon, resolved_address, and summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
daysNo
limitNo
addressNo
radius_mNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full disclosure burden. It effectively discloses the lack of an open/closed status field, the internal field observation proxy, the 'most recent first' ordering, and the point+radius query mechanism. It does not cover edge cases like the precedence if both address and lat/lon are provided, and there is no mention of permissions or rate limits, but for a read-only query tool the disclosed behaviors are significant.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise yet complete, leading with a one-sentence summary of the tool's purpose, then clearly separating Args and Returns. Every sentence adds value: the note about the missing status field, the parameter explanations, and the output structure are all essential. No filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (6 optional parameters with conditional requirements), no annotations, and no schema-level descriptions, the description provides a thorough overview. It explains the input alternatives, the return payload fields, and the subtle field semantics. The presence of an output schema reduces the need to dive deeper into exact return types, but the description still covers the key behavioral context. The description is complete enough for an agent to select and use this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides almost no descriptions (0% coverage), so the description must fully compensate. It does: 'address' is explained as a free-form string with an example, 'lat'/'lon' are described as a pair used when address is not given, 'radius_m' has a default and meaning, 'days' is explained, and 'limit' is explained. This goes far beyond the schema's raw types and defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with '311 service requests near a point, from the point-level ServiceRequests311 layer,' which clearly states a specific verb, resource, and scope. It distinguishes itself from sibling 'near' tools by clearly targeting 311 service requests and noting the spatial query type.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context on how to invoke the tool: the address vs lat/lon alternatives, the radius, days filter, and limit. It also notes the absence of a status field, which guides result interpretation. However, it does not explicitly name alternative tools or state when not to use this tool, so it misses the full 'explicit exclusions/alternatives' bar.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

tree_canopy_atA

Get tree canopy stats for the area containing a location.

Point-in-polygon query against the joint City of Charlotte / TreesCharlotte 2022 tree canopy assessment layer, which stacks multiple geography levels (Neighborhood Profile Area, Council District, Jurisdiction, County, ...) for the same point. The finest available level is returned as primary (Neighborhood Profile Area preferred, per plan); all matched levels are included under by_geography for context. Provide either address or both lat/lon.

Args: address: Free-form address, e.g. "2437 Remount Rd, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given.

Returns: Dict with primary (geography/value/canopy_percent/canopy_acres/ vegetation_percent/impervious_percent), by_geography (all matched levels), lat, lon, resolved_address, and summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
addressNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses the multi-geography stacking, the selection of finest level as 'primary', the inclusion of all matched levels under 'by_geography', and the preference for Neighborhood Profile Area. It also specifies input modes and return structure, providing substantial behavioral detail beyond the bare schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with a concise summary, followed by focused Args and Returns sections. It is somewhat lengthy due to the detailed return field list, but each section serves a purpose and the structure aids readability. Earns a high score, though not perfectly minimal.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with three parameters, no annotations, and a known output schema, the description fully covers input constraints, output structure, data source, and selection logic. It provides enough context for an agent to select and invoke the tool correctly without ambiguity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides no descriptions (0% coverage), but the description compensates with an Args section explaining 'address' as free-form, and 'lat'/'lon' as used together if address is absent. This adds meaning beyond the nullable/default schema properties, clarifying the mutual exclusivity and usage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Get tree canopy stats for the area containing a location.' It clearly states the point-in-polygon query against a named layer, distinguishing it from sibling tools that handle other data types like watershed or area plans.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear input guidance ('Provide either address or both lat/lon') but does not explicitly discuss when to prefer this tool over alternatives or when not to use it. Usage context is implied by the data source description, but no exclusions or sibling comparisons are made.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

violent_crime_nearA

CMPD violent-crime offense counts (Homicide/Rape/Robbery/Assault/...) near a point.

Provide either address (free-form string) or both lat and lon. Same shape/limitation as crime_near: ViolentCrimeData is a monthly-aggregate table keyed by Neighborhood Profile Area, not incident-level points, so nearby NPAs are resolved via 311 density (see module docstring) and OFFENSE_COUNT is summed by OFFENSE_DESCRIPTION for months within days of now.

Args: address: Free-form address, e.g. "600 E 4th St, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given. radius_m: Radius in meters used to resolve nearby NPAs (default 800). days: Only include months within this many days of now (default 180). limit: Maximum number of raw NPA/month/offense records to return (default 50); the breakdown totals cover all matching months.

Returns: Dict with nearby_npas, records (capped at limit), breakdown (offense description -> total count), total_offenses, radius_m, days, lat, lon, resolved_address, and a summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
daysNo
limitNo
addressNo
radius_mNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full responsibility for behavioral disclosure. It thoroughly explains the aggregated nature of the data, the resolution mechanism via 311 density, the summation logic, and the output structure. This gives users a clear understanding of the tool's limitations and behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a clear opening summary, an Args section, and a Returns section. It is front-loaded with the primary purpose. Each sentence adds substantive detail, and the formatting makes it easy to scan. No wasteful repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers all essential aspects: the tool's purpose, input modes, data caveats, parameter roles, and return keys. Despite the existence of an output schema, the description adds valuable context about data aggregation and resolution that a schema cannot convey. It is sufficiently complete for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must fully compensate. It does so by providing detailed explanations for every parameter: address (with example), lat/lon (with conditional usage), radius_m, days, and limit (including its effect on records vs breakdown). This exceeds the schema's minimal property names and defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: 'CMPD violent-crime offense counts (Homicide/Rape/Robbery/Assault/...) near a point.' This specifies the verb (counts), resource (violent-crime offenses), and scope (near a point), effectively distinguishing it from siblings like crime_near and homicides_near.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context, explaining the input modes ('Provide either address or both lat and lon') and the data limitations. It references the sibling tool crime_near, but does not explicitly state when to use this tool versus alternatives such as crime_near or homicides_near, so it stops short of a perfect score.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

watershed_atA

Look up the named watershed/basin containing a location.

Point-in-polygon query against the City of Charlotte "Watershed Basins" layer, which covers all of Mecklenburg County. Provide either address or both lat/lon.

Args: address: Free-form address, e.g. "2437 Remount Rd, Charlotte, NC". lat: Latitude, used with lon if address is not given. lon: Longitude, used with lat if address is not given.

Returns: Dict with watershed (name/tile_name/basin_index), lat, lon, resolved_address, and summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNo
lonNo
addressNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It clearly states this is a read-only lookup ('Look up', 'Point-in-polygon query') and describes the exact input alternatives and return fields. It does not mention error conditions or rate limits, but for a simple lookup tool the disclosure is strong.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a one-sentence summary, a concise mechanism explanation, then Args and Returns sections. Every part adds value without redundancy. The front-loaded summary quickly tells the agent what the tool does.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the full workflow: what the tool finds, which layer it queries, the geographic coverage, how to provide inputs, and what the return dict contains. Given the low parameter count and presence of an output schema, this is complete and ready for an agent to use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description fully compensates by explaining each parameter's role and the mutually exclusive relationship: 'Provide either ``address`` or both ``lat``/``lon``.' It also specifies address format with an example and clarifies that lat/lon are used only if address is not given.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb phrase 'Look up the named watershed/basin containing a location' and identifies the exact data layer ('City of Charlotte "Watershed Basins" layer'). It clearly distinguishes this from sibling 'at' tools like area_plans_at or tree_canopy_at by naming the resource and the point-in-polygon mechanism.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit usage context: 'Provide either ``address`` or both ``lat``/``lon``.' It also states the geographic coverage ('covers all of Mecklenburg County'), which helps the agent decide if the tool is appropriate. It does not explicitly list alternative tools, but the context is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 21 tool updatesv0.1.0
    • First observedada_features_near
    • First observedarea_plans_at
    • First observedbattery_recycling_sites_near
    • First observedbike_lanes_near
    • First observedbrownfields_near
    • First observedcats_projects_near
    • First observedcip_projects_near
    • First observedcrime_near
    • First observedgeocode
    • First observedget_planning_area
    • First observedget_trash_schedule
    • First observedget_zoning
    • First observedhomicides_near
    • First observedlist_datasets
    • First observedlookup_parcel
    • First observedrezonings_near
    • First observedsearch_tax_foreclosures
    • First observedservice_requests_near
    • First observedtree_canopy_at
    • First observedviolent_crime_near
    • First observedwatershed_at

TDQS

A4.3/5.0

Scored across 21 tools

Disambiguation4/5

Most tools target distinct datasets (parcels, zoning, crime, planning, transportation), but the crime tools (crime_near, violent_crime_near, homicides_near) and planning tools (area_plans_at, get_planning_area) overlap in purpose and could cause misselection. Descriptions are detailed enough to resolve ambiguity.

Naming Consistency4/5

Names mostly follow a predictable pattern: [subject]_near for radius searches, [subject]_at for point-in-polygon lookups, and verb_noun (get_, lookup_, search_) for direct lookups. Minor deviations exist (geocode, get_planning_area vs area_plans_at) but the mixed conventions are still readable and consistent within their categories.

Tool Count4/5

21 tools is slightly heavy but justified by the wide scope of municipal data (geocoding, parcels, zoning, crime, transit, environment). Each tool covers a distinct dataset, so the count feels appropriate for the server's purpose.

Completeness4/5

The tool surface covers a broad range of civic data with read-only queries, and list_datasets helps discover additional layers. Minor gaps exist (e.g., no generic query tool for arbitrary layers, no parks or building permits) but agents can work around these for most core workflows.

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Open-source MCP server providing real estate regulatory intelligence (zoning, permits, entitlements, deal scoring) for US properties, enabling AI agents to access 10 callable tools.
    12
    5 npm
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    An MCP server that gives LLM agents typed, cached access to civic open-data portals via Socrata (SODA 2.1 + Discovery API), enabling search, query, profiling, sampling, and CSV export of datasets.
    6
    MIT