Skip to main content
Glama
ajwann

Charlotte Open Data MCP Server

by ajwann

Charlotte Open Data MCP Server

An MCP server that lets an LLM answer Charlotte residents' everyday questions with official public data from the City of Charlotte Open Data Portalhttps://data.charlottenc.gov.

The portal lives at data.charlottenc.gov. It is an ArcGIS Hub site; its ~380 datasets are ArcGIS REST layers run by the City of Charlotte and Mecklenburg County. No API key is required.

What's on the portal

A survey of the catalog (/api/feed/dcat-us/1.1.json) shows these main themes:

Theme

Examples

Public safety

CMPD incidents (870k+ since 2017, updated daily), homicides, traffic stops, fire incident reports, crashes

City services

311 service requests (3.4M), solid-waste collection routes, code enforcement cases, street closures

Planning & zoning

Zoning, rezoning petitions, historic districts, 2040 policy map, floodplains, parcels

Transportation

CATS bus routes and stops, LYNX light rail, park-and-ride, bike lanes, sidewalks, greenways

Places

Libraries, schools, parks, fire/police stations, pharmacies, grocery stores, EV chargers, day care

Government

Capital projects, budget, employee salaries, council and commissioner districts

Demographics

Census block groups/tracts, Quality of Life neighborhood profiles

Related MCP server: mcp-arcgis-raleigh

Tools

The tools are chosen for the questions residents actually ask. Every tool is read-only, and every location parameter accepts either an address ("600 E 4th St, Charlotte") or "latitude,longitude".

My address

Tool

Answers questions like

get_address_profile

"Who is my council member?" "What police division and fire station serve me?" "What's my zoning? Am I in a flood zone or historic district?"

get_trash_and_recycling_schedule

"What day is trash pickup? Is this a recycling week (GREEN/ORANGE)?"

lookup_address

"Is this a valid address? What's its parcel ID and municipality?"

Safety

Tool

Answers questions like

get_crime_near

"Any car break-ins near my apartment this month?"

summarize_crime

"How have robberies in Charlotte changed since 2019?" "Which division has the most burglaries?"

get_traffic_crashes_near

"Is the intersection by my kid's school dangerous?"

City services and neighborhood change

Tool

Answers questions like

get_311_requests_near

"Has anyone already reported this pothole or streetlight?"

get_code_enforcement_cases

"Does the house I'm renting have open housing-code violations?"

get_street_closures

"Are any roads closed on my commute?"

get_capital_projects_near

"What's being built near me, when is it done, and who do I contact?"

get_pending_rezonings

"Is anyone trying to rezone land near my neighborhood?"

Places and transit

Tool

Answers questions like

find_nearby_places

Nearest library, school, park, greenway, pharmacy, grocery store, EV charger, light rail station, bus stop, public Wi-Fi… (18 categories)

get_bus_route

"How often does the 9 run on Sunday evenings?"

Government transparency

Tool

Answers questions like

get_city_budget

"How much does the city budget for Police?"

get_city_salary_stats

"What do Charlotte firefighters earn on average?" (aggregates only, no names)

Anything else in the catalog

Tool

Purpose

search_datasets

Keyword search over the whole portal

describe_dataset

Fields, types, and record count for a layer

query_dataset

SQL-filtered records from any layer, optionally near a location

summarize_dataset

Server-side counts/sums grouped by fields

Setup

Requires Python 3.14 (developed on 3.14.7).

~/.pyenv/versions/3.14.7/bin/python -m venv .venv
.venv/bin/python -m pip install -e . --group dev

Use with Claude Code

claude mcp add charlotte-open-data -- /absolute/path/to/meck-311-mcp/.venv/bin/charlotte-open-data-mcp

Use with Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "charlotte-open-data": {
      "command": "/absolute/path/to/meck-311-mcp/.venv/bin/charlotte-open-data-mcp"
    }
  }
}

Other transports and debugging

.venv/bin/charlotte-open-data-mcp --transport streamable-http --port 8000   # http://127.0.0.1:8000/mcp
npx @modelcontextprotocol/inspector .venv/bin/charlotte-open-data-mcp       # interactive inspector

Development

.venv/bin/pytest                 # unit + in-memory MCP tests; no network access
.venv/bin/ruff format --check . && .venv/bin/ruff check .
.venv/bin/mypy

Layout:

  • src/charlotte_mcp/arcgis.py: async ArcGIS REST / Hub client (timeouts, bounded retries, host allowlist)

  • src/charlotte_mcp/address.py: address matching against the county Master Address layer

  • src/charlotte_mcp/catalog.py: the curated layers behind the purpose-built tools

  • src/charlotte_mcp/server.py: the MCP tools

Data notes and limitations

  • Geocoding uses Mecklenburg County's Master Address layer, so only addresses inside the county resolve. Coordinates outside the county are rejected.

  • Freshness varies by dataset: CMPD incidents, 311 requests, and code enforcement are current within days; the Budget Report dataset currently runs FY2018–FY2023. Tools report what the portal publishes.

  • CMPD locations are generalized by the department for privacy.

  • 311 data records when requests were received, not when they were resolved.

  • Timestamps are ISO 8601 in Charlotte local time with the UTC offset (e.g. 2026-09-06T00:00:00-04:00). The underlying services store UTC.

  • Budget amounts include large negative lines (e.g. "00 Non Department", Charlotte Water), so get_city_budget reports both the net total and the sum of positive lines.

  • Statistics limits: some city map services ignore resultRecordCount on aggregate queries, so the client enforces row limits itself.

  • Live bus arrivals are not on the portal; pair this server with a CATS real-time source. Bus stop IDs from find_nearby_places match CATS stop IDs.

  • The generic tools only reach hosts that serve portal datasets (gis.charlottenc.gov, meckgis.mecklenburgcountync.gov, services.arcgis.com, gis.ci.charlotte.nc.us).

  • Mecklenburg County's server rejects default Python user agents, so the client sends its own.

Ideas for more tools

  • Neighborhood Quality of Life indicators by NPA (income, age, housing, amenities)

  • Charlotte Fire incident reports by address block

  • CMPD officer traffic-stop statistics

  • Sidewalk and bike network gaps near an address

  • Tree canopy and land surface temperature by neighborhood

Available Tools

19 tools
describe_datasetDescribe a dataset's fieldsA
Read-onlyIdempotent

Show a dataset layer's description, record count, and fields.

Call this before query_dataset or summarize_dataset to learn field names and types.

ParametersJSON Schema
NameRequiredDescriptionDefault
layer_urlYesArcGIS layer URL from search_datasets, ending in /MapServer/<n> or /FeatureServer/<n>.

Output Schema

ParametersJSON Schema
NameRequiredDescription
nameYes
fieldsYes
layer_urlYes
descriptionYes
record_countYes
geometry_typeYes
supports_statisticsYes
max_records_per_queryYes

TDQS

A3.9/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the description does not need to cover safety. It adds that the tool returns description, record count, and fields, which is useful behavioral detail beyond annotations. However, it does not disclose potential rate limits, authentication requirements, or 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 two sentences, front-loaded with the tool's core purpose, followed immediately by the when-to-use guideline. Every sentence earns its place, with no filler.

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 that an output schema exists, the description need not explain return values. It covers purpose and usage context adequately, but could be more complete by mentioning that the tool is read-only or that it works with ArcGIS layers (implied by 'dataset layer') or by noting any constraints. For a simple read-only metadata tool, this is largely complete.

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

Parameters4/5

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

The schema has 100% description coverage for the single 'layer_url' parameter, so the baseline is 3. The description implies that the parameter identifies a dataset layer but adds no additional semantics beyond what the schema already provides, such as valid URL formats or constraints. A slight bump to 4 is warranted because the description's mention of 'dataset layer' reinforces the expected input context.

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

Purpose4/5

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

The description states a clear verb and resource ('Show a dataset layer's description, record count, and fields'), which is specific and distinguishes it from operational siblings like query_dataset and summarize_dataset. However, it does not explicitly differentiate from search_datasets, which also deals with datasets.

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 explicitly tells the agent to 'Call this before query_dataset or summarize_dataset to learn field names and types,' providing clear usage context and naming two alternatives. It does not say when not to use it or mention other related tools like search_datasets.

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

find_nearby_placesFind nearby public placesA
Read-onlyIdempotent

Nearest public places of one type, sorted by straight-line distance.

Categories include libraries, public schools, parks, greenways, fire and police stations, post offices, pharmacies, grocery stores, medical facilities, child care, EV chargers, park-and-ride lots, light rail stations, bus stops, YMCAs, places of worship, and public Wi-Fi. Bus stop IDs can be used with CATS real-time arrival services.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum places to return.
categoryYes
locationYesA street address in Mecklenburg County, e.g. '600 E 4th St, Charlotte, NC 28202', or coordinates as 'latitude,longitude', e.g. '35.2271,-80.8431'.
radius_milesNoRadius in miles.

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesYes
placesYes
categoryYes
locationYes
radius_milesYes
total_within_radiusYes

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, openWorld, and non-destructive, so the safety profile is covered. The description adds genuinely useful behavior beyond them: results are ranked by straight-line distance (not routed travel distance), only one category may be queried per call, and bus stop IDs are reusable with CATS real-time services. It does not mention result caps beyond the schema's limit, but that is minor given annotations.

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 key fact — nearest places of one type, ranked by straight-line distance — is front-loaded in the opening sentence. The long category list is somewhat redundant with the schema enum and consumes most of the text, but it reads cleanly and nothing is confusing.

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?

With annotations covering the safety profile and an output schema covering the return shape, the description supplies what remains: the distance metric used for ranking, the one-category-per-call constraint, and the downstream bus-stop ID use. An agent has enough to call this correctly without further guessing.

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

Parameters3/5

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

Schema coverage is 75%, so the schema already documents limit, location, and radius_miles; the description's category enumeration merely restates the enum rather than adding meaning. The one piece of added parameter context is that bus stop IDs returned can be fed to CATS real-time arrivals, which the schema does not say. Baseline 3 is appropriate.

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

Purpose4/5

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

The first sentence gives a specific verb-plus-resource ('nearest public places of one type') plus a defining constraint ('sorted by straight-line distance'), which separates it from the *_near siblings that target crime, crashes, or capital projects. It stops short of naming any sibling explicitly, so an agent must infer the distinction from the category list.

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?

Usage is only implied: the category list and the note that bus stop IDs work with CATS real-time arrivals hint at when this tool fits. There is no explicit statement of when to prefer this over get_crime_near, get_traffic_crashes_near, or lookup_address, and no prerequisites or exclusions are given.

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

get_311_requests_near311 service requests near a locationA
Read-onlyIdempotent

311 service requests reported near a location, with counts by request type.

Shows whether a problem (pothole, missed pickup, dumping, streetlight) was already reported.

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNoHow many days back to look.
limitNoMaximum number of records to return.
locationYesA street address in Mecklenburg County, e.g. '600 E 4th St, Charlotte, NC 28202', or coordinates as 'latitude,longitude', e.g. '35.2271,-80.8431'.
radius_milesNoRadius in miles.
request_typeNoOptional type filter, e.g. 'pothole', 'missed recycling', 'graffiti', 'streetlight', 'dumping'.

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNo
sinceNoEarliest date included (local time).
recordsYes
locationNo
breakdownNoCounts of all matching records per value.
breakdown_byNo
radius_milesNo
total_matchingYesRecords matching the filters; may exceed returned.

TDQS

A3.6/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so the safety profile is covered. The description adds that results are aggregated "with counts by request type," which is useful, but it says nothing about radius defaults, limits, or data freshness that would go beyond the schema.

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?

Two short sentences, no filler, and the core purpose is front-loaded in the first clause. Every sentence earns its place.

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?

With an output schema present, return values need not be explained, and the counts-by-type statement covers the shape of the result. A proximity query with fully described params is well covered, though it omits the geographic service area constraint (Mecklenburg County) present in the schema.

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

Parameters3/5

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

Schema description coverage is 100%, so every parameter (days, limit, location, radius_miles, request_type) is already documented in the schema, including example addresses and type filters. The description adds no syntax, format, or defaulting meaning beyond that, so the baseline 3 applies.

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

Purpose4/5

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

States a specific verb (reported), resource (311 service requests), and scope (near a location, with counts by request type). The resource is clearly distinct from siblings like get_crime_near and get_traffic_crashes_near, though the description never explicitly names a sibling to route against.

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?

"Shows whether a problem (pothole, missed pickup, dumping, streetlight) was already reported" implies a use case — checking for duplicate/existing reports — but there is no explicit when-to-use, when-not-to-use, or alternative-tool guidance relative to the many other '*_near' siblings.

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

get_address_profileAddress profile: representatives, services, zoningA
Read-onlyIdempotent

Everything that serves or governs a location, in one call.

Returns city council district and representative, county commissioner, CMPD patrol division, first-due fire station, trash/recycling/yard-waste days, zoning, FEMA flood zone, historic district, ZIP code, and tax parcel ID.

ParametersJSON Schema
NameRequiredDescriptionDefault
locationYesA street address in Mecklenburg County, e.g. '600 E 4th St, Charlotte, NC 28202', or coordinates as 'latitude,longitude', e.g. '35.2271,-80.8431'.

Output Schema

ParametersJSON Schema
NameRequiredDescription
zoningYes
locationYes
zip_codeYes
unavailableYesSections that could not be retrieved because a source service failed.
city_councilYesNone when the point is outside Charlotte's council districts.
fire_stationYesFirst-due Charlotte Fire station.
jurisdictionYes
tax_parcel_idYes
fema_flood_zoneYesFEMA flood zone if inside a mapped FEMA floodplain, otherwise None.
police_divisionYes
historic_districtYes
county_commissionerYes
trash_and_recyclingYesCity of Charlotte residential collection; None if not on a city route.

TDQS

A4.1/5.0
Behavior3/5

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

Annotations already cover the behavior profile (readOnly, idempotent, open-world, non-destructive), and the description's 'in one call' phrasing adds useful context that many sub-queries are executed internally. It doesn't disclose the geographic constraint (Mecklenburg County) on behavior or describe output richness beyond enumerating fields.

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?

Two sentences: a front-loaded summary followed by a compact enumerated list. Every clause earns its place, and the summary line is placed first for fast scanning.

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?

An output schema exists, so return-value explanation is not required. For a single-input, read-only aggregate lookup, the description plus annotations plus output schema give the agent everything needed to invoke it correctly and understand its scope.

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

Parameters4/5

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

Schema coverage is 100% and the schema clearly describes accepting either a street address or 'latitude,longitude' coordinates with examples. The description adds no additional parameter detail, but with a fully documented single parameter the baseline is 3–4; the schema does the work.

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, distinctive framing — 'Everything that serves or governs a location, in one call' — and then enumerates the concrete data returned (council district, CMPD division, trash days, zoning, FEMA flood zone, tax parcel ID). This is a clearly defined aggregate-lookup tool that is readily distinguished from siblings like lookup_address or get_trash_and_recycling_schedule.

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 by framing itself as an 'in one call' aggregate, hinting that it should be preferred over several narrow sibling tools. However, it never states when NOT to use it, e.g. that lookup_address is lighter-weight for a bare address, or that the more specific sibling tools give fresher/dedicated data. Implied context only.

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

get_bus_routeCATS bus route frequenciesA
Read-onlyIdempotent

CATS bus routes with scheduled frequency (minutes between buses) by time of day.

For stops near an address use find_nearby_places with category 'bus_stop'.

ParametersJSON Schema
NameRequiredDescriptionDefault
routeNoRoute number (e.g. '9') or part of its name; omit to list all routes.

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNo
sinceNoEarliest date included (local time).
recordsYes
locationNo
breakdownNoCounts of all matching records per value.
breakdown_byNo
radius_milesNo
total_matchingYesRecords matching the filters; may exceed returned.

TDQS

A4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is fully covered. The description adds only content framing (frequency expressed as minutes between buses, varying by time of day), which is useful but modest and partly overlaps the output schema.

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?

Two short sentences, zero filler. The resource and return content lead, and the disambiguation pointer follows, so the most important information is 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?

An output schema exists, so the description need not enumerate return fields, and the annotations carry the safety profile. What remains is that an agent gets no hint about coverage/scope (all CATS routes? live vs. scheduled?) or whether the route argument is case/punctuation sensitive, but the essentials are present.

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

Parameters3/5

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

The single parameter is already fully documented in the schema, including the 'route number or part of name, omit to list all' semantics and an example. The description adds nothing beyond that, so the baseline of 3 for 100% schema coverage applies.

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?

Names the specific resource (CATS bus routes) and the specific content returned (scheduled frequency in minutes between buses, broken down by time of day), which is far more informative than the title alone. It also distinguishes itself from find_nearby_places, which an agent might otherwise reach for when asked about buses.

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?

Explicitly routes the agent elsewhere when the real need is stops near an address: 'use find_nearby_places with category bus_stop'. That is a concrete alternative-plus-condition, but no reciprocal guidance on when this tool (vs. e.g. get_traffic_crashes_near or get_street_closures) is the right pick, so it stops short of full when/when-not coverage.

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

get_capital_projects_nearCity capital projects near a locationB
Read-onlyIdempotent

City capital projects (roads, sidewalks, parks, facilities) near a location.

Includes phase, schedule, budget, and the project manager's contact information.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of records to return.
phaseNoany
locationYesA street address in Mecklenburg County, e.g. '600 E 4th St, Charlotte, NC 28202', or coordinates as 'latitude,longitude', e.g. '35.2271,-80.8431'.
radius_milesNoRadius in miles.

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNo
sinceNoEarliest date included (local time).
recordsYes
locationNo
breakdownNoCounts of all matching records per value.
breakdown_byNo
radius_milesNo
total_matchingYesRecords matching the filters; may exceed returned.

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered by structured data. The description adds what the records contain (phase, schedule, budget, PM contact), which is useful content context, but says nothing about ordering, spatial matching behavior, or result truncation. With annotations carrying the safety burden, a 3 is appropriate.

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?

Two tight sentences, front-loaded with the resource and scope, then a useful content summary. No filler or repetition. Slightly under-specified rather than verbose, which is a minor deduction at most.

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

Completeness3/5

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

An output schema exists, so return-value explanation is not required, and annotations cover the safety profile. What remains missing is spatial semantics: how radius_miles interacts with location, whether results are ranked by distance, and when this tool should be chosen over its near-location siblings.

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

Parameters3/5

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

Schema coverage is 75%, with location, limit and radius_miles documented in-schema and phase left undocumented. The description adds no parameter-level detail such as units, default radius behavior, or how 'near' is defined relative to radius_miles. Baseline 3 is correct since the schema handles most of the parameter burden.

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

Purpose4/5

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

States a specific verb (get) and resource (capital projects) plus a spatial scope (near a location). It enumerates what counts as a capital project (roads, sidewalks, parks, facilities), which disambiguates the resource. It doesn't explicitly distinguish itself from spatial siblings like get_311_requests_near or get_street_closures, but the resource is clear enough.

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

Usage Guidelines2/5

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

No when-to-use statement and no alternatives named. The description never tells the agent when to prefer this over get_street_closures or get_pending_rezonings, even though several siblings share the 'near a location' spatial pattern. Usage is only implied by the resource name.

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

get_city_budgetCity budget by department or fundB
Read-onlyIdempotent

City of Charlotte budget totals for a fiscal year by department, fund, or expense type.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
group_byNodepartment
departmentNoOptional filter, e.g. 'Police'.
fiscal_yearNoe.g. 'FY2023'; defaults to the latest published.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowsYes
notesYes
group_byYes
fiscal_yearYes
net_total_amountYesSum of all lines, including negative ones.
department_filterYes
positive_total_amountYesSum of lines with positive amounts.
available_fiscal_yearsYes

TDQS

B3.3/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds only that results are budget totals scoped to a single fiscal year; it says nothing about pagination despite a limit parameter, so it adds limited value beyond structured data.

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?

A single, front-loaded sentence with no filler. Every word carries scope information and nothing is redundant.

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

Completeness3/5

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

An output schema exists, so return values need not be explained, and annotations cover safety. But for a parameterized aggregation tool, the undocumented limit/pagination behavior and the absence of any usage context leave it only minimally complete.

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

Parameters3/5

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

At 50% schema coverage, the description usefully maps the group_by enum concepts ('by department, fund, or expense type') to real aggregation dimensions. However, the limit parameter is unexplained in both schema and description, so the description only partially compensates for the coverage gap.

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

Purpose4/5

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

States a specific verb and resource with scope: 'City of Charlotte budget totals for a fiscal year by department, fund, or expense type.' This distinguishes it from data siblings like get_city_salary_stats. It does not explicitly name an alternative, but the resource is unambiguous.

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

Usage Guidelines2/5

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

The description offers no when-to-use guidance, no prerequisites, and no alternatives among the many sibling data tools (query_dataset, get_city_salary_stats). Usage must be inferred entirely from the resource name.

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

get_city_salary_statsCity employee pay statisticsA
Read-onlyIdempotent

Pay statistics for City of Charlotte employees: head count and annual pay rates.

Aggregated by department or job title for one quarter (the latest by default); individual employees are not listed.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearNo
limitNo
quarterNo
group_byNodepartment
job_titleNoPartial match, e.g. 'Fire Fighter' or 'Captain'.
departmentNoPartial match on abbreviated department names, e.g. 'CFD' (Fire), 'CMPD' (Police), 'CDOT', 'CATS', 'Charlotte Water'.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowsYes
yearYes
notesYes
filtersYes
overallYes
quarterYes
group_byYes

TDQS

A3.7/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so safety is covered. The description adds genuinely new behavioral facts beyond that: results are pre-aggregated, default to the latest quarter, and individual employees are explicitly not listed (a privacy/scope constraint). Rate limits or auth requirements are still unstated.

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?

Two short sentences, front-loaded with what the tool returns, and no filler. The parenthetical defaults are efficiently embedded rather than spread across extra sentences.

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?

With an output schema present, return values need no explanation, and the annotations carry the safety profile. The remaining gap is the under-documented limit and year parameters and the unspecified interaction between department and job_title filters, which an agent would need before refining a query.

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

Parameters3/5

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

Schema description coverage is only 33% (just job_title and department), so the description must compensate. It partially does: it names the group_by alternatives and states quarter defaults to the latest. It adds nothing on year, limit (default 25, max 100), or how department and job_title interact when both are supplied.

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

Purpose4/5

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

Names a specific resource and the exact outputs (head count, annual pay rates) plus the aggregation granularity (department or job title, one quarter), so an agent knows precisely what it gets back. It does not distinguish itself from sibling data tools like query_dataset or search_datasets that could plausibly return the same underlying data.

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?

Usage is only implied: 'aggregated by department or job title for one quarter (the latest by default)' tells the agent the tool's shape but never states when to pick this over query_dataset/describe_dataset or what conditions make it inapplicable. No explicit when/when-not guidance is given.

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

get_code_enforcement_casesCode enforcement cases near an addressB
Read-onlyIdempotent

Housing and neighborhood code enforcement cases at or near an address.

Covers nuisance (junk, overgrown lots), minimum housing, zoning, graffiti, and parking violations. Useful for renters, buyers, and neighbors.

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNoCases opened in this many days.
limitNoMaximum number of records to return.
statusNoany
locationYesA street address in Mecklenburg County, e.g. '600 E 4th St, Charlotte, NC 28202', or coordinates as 'latitude,longitude', e.g. '35.2271,-80.8431'.
case_typeNoany
radius_milesNoRadius in miles; 0.05 is about one parcel.

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNo
sinceNoEarliest date included (local time).
recordsYes
locationNo
breakdownNoCounts of all matching records per value.
breakdown_byNo
radius_milesNo
total_matchingYesRecords matching the filters; may exceed returned.

TDQS

B3.4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered. The description adds real value by enumerating the violation categories it surfaces, but it says nothing about result shape, ordering, or the geographic scope limits implied by the 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?

Three short sentences, front-loaded with the core purpose before the category list and audience. The audience line is mild filler, but nothing is bloated or buried.

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

Completeness3/5

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

With an output schema present, return format need not be described, and the description adequately conveys domain and categories. However, for a 6-parameter geo-query tool it omits any guidance on status/case_type usage and gives no hint about result ordering or proximity behavior beyond what the schema states.

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

Parameters3/5

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

Schema coverage is 67%: days, limit, location and radius_miles are documented in-schema, while status and case_type are not. The description partially compensates by listing violation types that map to the case_type enum, but it adds no meaning for status, days, or the proximity semantics of radius_miles.

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

Purpose4/5

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

The description states a specific verb+resource ('Housing and neighborhood code enforcement cases at or near an address') and enumerates the covered categories (nuisance, minimum housing, zoning, graffiti, parking). It clearly separates this from siblings like get_crime_near or get_311_requests_near by naming the domain, though it never explicitly says what it is not.

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?

Usage is only implied via the audience note ('Useful for renters, buyers, and neighbors'), which hints at intent but gives no when-to-use condition, no exclusions, and no comparison to adjacent tools such as get_311_requests_near or get_crime_near. An agent must infer the routing itself.

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

get_crime_nearPolice incidents near a locationA
Read-onlyIdempotent

CMPD police incident reports near a location: counts by offense and the latest reports.

Answers "is there much crime near 123 Main St?" or "any car break-ins near me lately?".

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNoHow many days back to look.
limitNoMaximum number of records to return.
offenseNoOptional offense filter, e.g. 'burglary', 'motor vehicle theft', 'assault', 'vandalism'.
locationYesA street address in Mecklenburg County, e.g. '600 E 4th St, Charlotte, NC 28202', or coordinates as 'latitude,longitude', e.g. '35.2271,-80.8431'.
radius_milesNoRadius in miles.

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNo
sinceNoEarliest date included (local time).
recordsYes
locationNo
breakdownNoCounts of all matching records per value.
breakdown_byNo
radius_milesNo
total_matchingYesRecords matching the filters; may exceed returned.

TDQS

A3.6/5.0
Behavior3/5

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

The annotations already declare readOnly/idempotent/destructive=false/openWorld, so the safety profile is fully covered. The description adds that results combine aggregate offense counts with the most recent reports and identifies the data source (CMPD), but says nothing about data latency, rate limits, or geographic coverage limits beyond what the schema states.

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?

Two tightly written sentences: the first front-loads what the tool returns, the second supplies natural-language query examples. Zero filler, and the most decision-relevant information (proximity-based incident data) comes first.

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?

With a rich annotation set, 100% schema coverage, and an existing output schema, the description need not explain return values or safety. It is nearly complete, with the only material gap being the absent contrast against summarize_crime, which an agent must resolve on its own.

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

Parameters3/5

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

Schema description coverage is 100%, so every parameter (days, limit, offense, location, radius_miles) is already documented in-schema with defaults, bounds and examples. The description adds only indirect hints (e.g. 'car break-ins' maps loosely to the offense filter, 'lately' to days), so a baseline 3 is appropriate.

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

Purpose4/5

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

States a specific verb+resource (retrieves CMPD police incident reports near a location) and even specifies the return shape: counts by offense plus the latest individual reports. The proximity scope ('near a location') implicitly separates it from the aggregate sibling summarize_crime, but it never names or contrasts that sibling explicitly.

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 two example questions ('is there much crime near 123 Main St?', 'any car break-ins near me lately?') give concrete usage context and hint at the days/offense parameters. However, there is no explicit when-not-to-use guidance and no routing between this tool and summarize_crime or the other *_near siblings, leaving the agent to infer the boundary from phrasing alone.

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

get_pending_rezoningsPending rezoning petitionsB
Read-onlyIdempotent

Rezoning petitions currently in process, citywide or near a location.

Shows the petitioner, existing and requested zoning, acreage, and a link to the petition.

ParametersJSON Schema
NameRequiredDescriptionDefault
nearNoOptional street address or 'latitude,longitude'; when given, only records within radius_miles of it are returned.
limitNoMaximum number of records to return.
radius_milesNoUsed with near.

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNo
sinceNoEarliest date included (local time).
recordsYes
locationNo
breakdownNoCounts of all matching records per value.
breakdown_byNo
radius_milesNo
total_matchingYesRecords matching the filters; may exceed returned.

TDQS

B3.4/5.0
Behavior3/5

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

Annotations already cover readOnly, idempotent, non-destructive, open-world, so the safety and behavior profile is set. Description adds that records are 'currently in process' (a filter trait) but does not disclose pagination behavior, ordering, or what the petition link resolves to. Modest value beyond annotations.

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?

Two short lines front-loaded with the core scope, no wasted words. Could be slightly tighter by merging the field list, but structure is efficient.

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

Completeness3/5

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

With an output schema present, return values needn't be explained, and the description's listing of returned fields is somewhat redundant with it. For a read-only spatial-filter tool, the description avoids the key gaps (pagination, ordering) but nothing here is critical. Adequate but with clear gaps.

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

Parameters3/5

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

Schema description coverage is 100%, so near, limit, and radius_miles are fully documented in the schema. The description's phrase 'citywide or near a location' loosely echoes the near parameter but adds no syntax or format detail (e.g., address vs lat,long) beyond what the schema already provides. Baseline 3 is appropriate.

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

Purpose4/5

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

Clear verb+resource: lists rezoning petitions currently in process. Adds scope detail (citywide or near a location) and the fields returned (petitioner, zoning, acreage, link). Distinguishes resource from siblings like get_capital_projects_near or get_311_requests_near, but doesn't explicitly compare against them.

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?

Implies usage ('currently in process, citywide or near a location') but gives no explicit when-to-use, exclusions, or alternatives among siblings. An agent can infer a spatial/citywide filter, but routing guidance is thin.

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

get_street_closuresStreet closures and detoursA
Read-onlyIdempotent

Street and lane closures and detours published by CDOT, citywide or near a location.

ParametersJSON Schema
NameRequiredDescriptionDefault
nearNoOptional street address or 'latitude,longitude'; when given, only records within radius_miles of it are returned.
limitNoMaximum number of records to return.
active_onlyNo
radius_milesNoUsed with near.

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNo
sinceNoEarliest date included (local time).
recordsYes
locationNo
breakdownNoCounts of all matching records per value.
breakdown_byNo
radius_milesNo
total_matchingYesRecords matching the filters; may exceed returned.

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already declare this a read-only, idempotent, non-destructive, open-world read, so safety is covered. The description usefully adds data provenance (published by CDOT), but it omits a real behavioral trait: active_only defaults to true, so by default only currently active closures are returned – a filter an agent must know about.

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?

A single front-loaded sentence with no filler; the resource and its scope are stated immediately. Nothing in it is redundant with the schema or annotations.

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

Completeness3/5

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

With an output schema present, return values need no explanation, and the annotations cover the safety profile. However, for a 4-parameter tool with a default-on active_only filter and a spatial radius mode, the description is thin on how the parameters interact and when to use each mode.

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

Parameters3/5

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

Schema coverage is 75% and the 'near' parameter is well documented in the schema itself. The description adds nothing beyond restating the citywide-vs-near duality, and active_only has no description in either the schema or the description, leaving that parameter's effect unexplained.

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

Purpose4/5

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

Names the specific resource (street and lane closures and detours), the publisher (CDOT), and the two query scopes (citywide or near a location). An agent can tell what it returns, though it never contrasts itself with nearby siblings like get_traffic_crashes_near or get_capital_projects_near.

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 phrase 'citywide or near a location' implies the two modes of use and hints that 'near' is the spatial selector, but there is no explicit when-to-use guidance, no mention of when 'near' should be omitted, and no routing to alternatives for adjacent data.

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

get_traffic_crashes_nearTraffic crashes near a locationA
Read-onlyIdempotent

Reported traffic crashes near a location, with counts by severity.

Useful for "is this intersection dangerous?" or traffic-calming requests.

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNoHow many days back to look.
limitNoMaximum number of records to return.
locationYesA street address in Mecklenburg County, e.g. '600 E 4th St, Charlotte, NC 28202', or coordinates as 'latitude,longitude', e.g. '35.2271,-80.8431'.
radius_milesNoRadius in miles.

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNo
sinceNoEarliest date included (local time).
recordsYes
locationNo
breakdownNoCounts of all matching records per value.
breakdown_byNo
radius_milesNo
total_matchingYesRecords matching the filters; may exceed returned.

TDQS

A3.8/5.0
Behavior3/5

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

Annotations already declare this is a read-only, idempotent, non-destructive open-world query, so the safety profile is covered. The description adds that results include counts grouped by severity, but says nothing about data recency, rate limits, coverage gaps, or what happens when no crashes match.

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?

Two short sentences with zero filler; the core capability and the motivating use cases are front-loaded in that order. Nothing redundant with the title or schema.

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?

An output schema exists, so return-value detail is unnecessary, and the description supplies purpose plus task context for a four-parameter spatial query. It could do slightly more to orient the agent among the many '*_near' siblings, but it is sufficient to call the tool correctly.

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

Parameters3/5

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

Schema description coverage is 100% and each of the four parameters (days, limit, location, radius_miles) is documented in the schema, including the address/coordinate format for location. The description adds no parameter-level meaning beyond that, so the baseline of 3 applies.

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

Purpose4/5

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

States a specific verb ('get'), resource ('traffic crashes'), and spatial scope ('near a location'), plus the output shape ('counts by severity'). It is clearly distinguishable from siblings like get_crime_near or get_311_requests_near by resource, though it never names an alternative explicitly.

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?

Provides concrete usage context with the example questions 'is this intersection dangerous?' and 'traffic-calming requests', which tell the agent what kind of tasks this tool serves. It stops short of stating when NOT to use it or pointing to sibling tools for adjacent datasets.

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

get_trash_and_recycling_scheduleTrash and recycling scheduleB
Read-onlyIdempotent

Garbage, recycling, and yard-waste collection days for an address in Charlotte.

ParametersJSON Schema
NameRequiredDescriptionDefault
locationYesA street address in Mecklenburg County, e.g. '600 E 4th St, Charlotte, NC 28202', or coordinates as 'latitude,longitude', e.g. '35.2271,-80.8431'.

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesYes
locationYes
scheduleYes

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so the safety profile is fully covered. The description's only added behavioral context is geographic scope ('in Charlotte'), which is worth noting since the schema's parameter description says Mecklenburg County — a slightly broader area. No mention of data freshness or holiday-shifted pickups.

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?

A single tight sentence with the resource front-loaded and zero filler. It reads as a noun phrase rather than a verb-led statement of what the tool returns, but nothing is wasted.

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 one-parameter read tool with a full annotation set and an output schema, the essentials are covered: purpose, input form, and geographic scope. The remaining gap is the Charlotte vs. Mecklenburg County scope ambiguity and the absence of any sibling routing.

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

Parameters3/5

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

Schema description coverage is 100% and the parameter description already gives address and 'latitude,longitude' examples, so the schema does the heavy lifting. The description only says 'an address' and omits the coordinate form the schema explicitly supports, adding no meaning beyond the schema.

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

Purpose4/5

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

The description names a specific resource — garbage, recycling, and yard-waste collection days — scoped to an address in Charlotte, so an agent knows exactly what data comes back. It does not, however, distinguish itself from sibling address tools such as lookup_address or get_address_profile, leaving the agent to infer the difference from the name alone.

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

Usage Guidelines2/5

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

There is no when-to-use guidance, no prerequisites, and no mention of alternatives among the many address-oriented siblings. The agent gets a topic but no routing logic.

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

lookup_addressLook up a Mecklenburg County addressB
Read-onlyIdempotent

Find an address in Mecklenburg County's official master address list.

Returns matches with coordinates, tax parcel ID, municipality, and ZIP code.

ParametersJSON Schema
NameRequiredDescriptionDefault
addressYese.g. '600 E 4th St, Charlotte'.
max_resultsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNo
queryYes
candidatesYes

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already declare readOnly, idempotent, openWorld, and non-destructive behavior, so the safety profile is covered. The description adds that results are drawn from an 'official master address list' and a partial list of returned fields, but says nothing about matching behavior, tolerance for partial/incomplete addresses, or ambiguity handling — relevant for a geocoder against an open-world dataset.

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?

Two short sentences, front-loaded with the core purpose and followed by useful return-content context. No filler, no repetition of the title.

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?

An output schema exists, so return values need not be enumerated, and rich annotations cover the safety profile. The description is adequate for a simple two-parameter read tool, though the missing guidance on matching semantics and the undocumented max_results leave a small gap.

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

Parameters2/5

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

Schema description coverage is only 50%: 'address' has an example, but 'max_results' has no description anywhere. The tool description does not mention either parameter, so it fails to compensate for the undocumented max_results parameter (cap of 10, default 5).

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

Purpose4/5

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

The description names a specific verb and resource ('Find an address in Mecklenburg County's official master address list'), which is far more concrete than a tautology. It does not, however, distinguish this tool from the sibling 'get_address_profile', which an agent would reasonably assume also resolves an address. Clear purpose, but no explicit sibling differentiation.

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

Usage Guidelines2/5

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

There is no guidance on when to use this lookup versus alternatives such as get_address_profile or find_nearby_places, nor any statement of prerequisites (e.g., whether the input must be a full street address). Usage is only implied by the tool name.

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

query_datasetQuery any datasetB
Read-onlyIdempotent

Fetch records from any portal dataset layer with a SQL filter, optionally near a place.

ParametersJSON Schema
NameRequiredDescriptionDefault
nearNoOptional street address or 'latitude,longitude'; when given, only records within radius_miles of it are returned.
limitNoMaximum number of records to return.
whereNoSQL where clause over the layer's fields (see describe_dataset), e.g. "ZIP = '28205'" or "DATE_REPORTED >= TIMESTAMP '2026-01-01 00:00:00'". Use '1=1' for everything.1=1
fieldsNoFields to return; omit for all.
order_byNoe.g. 'DATE_REPORTED DESC'.
layer_urlYesArcGIS layer URL from search_datasets, ending in /MapServer/<n> or /FeatureServer/<n>.
radius_milesNoUsed with near.

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNo
sinceNoEarliest date included (local time).
recordsYes
locationNo
breakdownNoCounts of all matching records per value.
breakdown_byNo
radius_milesNo
total_matchingYesRecords matching the filters; may exceed returned.

TDQS

B3.3/5.0
Behavior3/5

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

Annotations already declare readOnly, idempotent, openWorld, and non-destructive, so the safety profile is covered. The description adds the geospatial behavior ('optionally near a place') and the SQL-filter capability, but says nothing about result caps, projection cost, or error behavior on bad layer_urls.

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?

One tight sentence with the primary action and the two optional capabilities front-loaded and zero filler. Nothing is redundant or padded.

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

Completeness3/5

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

The output schema covers return values and the annotations cover safety, which lightens the description's load. However, for a high-fan-out generic tool facing many specialized siblings, the missing guidance on routing between this and the get_*_near tools leaves a real gap.

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

Parameters3/5

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

Schema description coverage is 100%, so every parameter including where, near, radius_miles, limit, and layer_url is already documented in the schema. The description only gestures at the SQL filter and proximity options without adding syntax or format detail, so baseline 3 applies.

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

Purpose4/5

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

States a specific verb (Fetch) and resource (records from any portal dataset layer) and names the two filtering modes (SQL filter, optional proximity). It is clearly the generic record-retrieval tool, but it never explicitly distinguishes itself from the specialized get_*_near siblings or from the other dataset tools (describe_dataset, summarize_dataset), which the schema itself cross-references.

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

Usage Guidelines2/5

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

There is no when-to-use or when-not guidance. Given a fleet of purpose-built siblings (get_crime_near, get_street_closures, get_traffic_crashes_near, etc.), the description should say whether this generic query is preferred, a fallback, or a substitute — it does not.

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

search_datasetsSearch Charlotte open datasetsA
Read-onlyIdempotent

Search the Charlotte Open Data Portal catalog (about 380 datasets) by keyword.

Use this to find data the purpose-built tools don't cover. Pass a result's layer_url to describe_dataset, query_dataset, or summarize_dataset.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum datasets to return.
queryYesKeywords, e.g. 'sidewalks', 'tree canopy', 'speed humps', 'census'.

Output Schema

ParametersJSON Schema
NameRequiredDescription
queryYes
datasetsYes
total_matchingYes

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered. The description adds useful non-annotation context: the catalog's approximate size and the fact that results are meant to be handed off via layer_url to three downstream tools. It does not discuss result counts or pagination behavior, but the presence of an output schema reduces that burden.

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?

Two sentences, zero filler. The core action and scope come first, then the fallback role and the handoff workflow. Every clause earns its place.

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 a rich annotation set, a 100%-documented 2-parameter schema, and an existing output schema, the description supplies exactly the missing pieces: why this tool exists alongside the purpose-built ones and how its results are consumed downstream. Nothing an agent needs to select or invoke it correctly is absent.

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

Parameters3/5

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

Schema coverage is 100%, so both parameters (query, limit) are fully documented in the schema, including keyword examples and the 1-25 bound on limit. The description adds no syntax, format, or matching-semantics detail beyond what the schema already provides, so the baseline of 3 applies.

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?

States a specific verb (search) and resource (Charlotte Open Data Portal catalog), plus concrete scope (~380 datasets) and mechanism (by keyword). It is clearly distinguishable from the purpose-built siblings like get_crime_near or get_city_budget, which it explicitly positions itself against.

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

Usage Guidelines5/5

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

Explicitly states when to use it ('find data the purpose-built tools don't cover') and names the follow-up alternatives (describe_dataset, query_dataset, summarize_dataset) along with the exact field (layer_url) that bridges them. This is a complete routing instruction with no inference required.

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

summarize_crimeCitywide crime statisticsA
Read-onlyIdempotent

Citywide CMPD incident counts grouped by offense, division, year, or neighborhood.

Use group_by='year' with an offense filter for trends, e.g. robberies per year since 2017.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearNoCalendar year.
limitNoMaximum number of records to return.
offenseNoe.g. 'robbery'.
group_byNooffense
patrol_divisionNoe.g. 'Central', 'Providence'.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowsYes
notesNo
sourceYes
filtersYesThe SQL where clause that was applied.
group_byYes
locationNo
statisticYes
radius_milesNo

TDQS

A3.7/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, and openWorldHint=true, so the safety profile is fully covered by structured data. The description adds the aggregation semantics (grouped counts) which is useful, but it does not disclose return shape, pagination behavior, or default ordering. With annotations carrying the behavioral load, a 3 is appropriate.

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?

Two tight sentences with zero filler. The grouping dimensions are front-loaded, and the usage example is presented compactly as a follow-on cue. Every clause earns its place.

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?

An output schema exists, so the description need not explain return values, and annotations cover safety. The description is largely complete for a 5-param, no-required aggregation tool. The one gap is not naming the sibling it overlaps with (get_crime_near), which would help an agent choose correctly.

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

Parameters4/5

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

Schema description coverage is 80%, so the schema already documents most parameters (year, limit, offense, patrol_division) including examples. The description adds value by explicitly tying group_by='year' to the offense filter as a combined pattern (trend analysis), which is semantic meaning not present in the schema's enum alone. It does not cover 'place_type' or 'clearance_status' but those are self-explanatory enums.

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

Purpose4/5

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

The description states a specific verb (summarize) and resource (citywide CMPD incident counts) with the grouping dimensions enumerated. However, it does not distinguish itself from the sibling get_crime_near, which also deals with crime data. The agent can tell this is an aggregation/count tool, but the boundary against the 'near' variant is left implicit.

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 gives one concrete usage pattern ('group_by=year with an offense filter for trends'), which is helpful implied guidance. But it does not state when to use summarize_crime over get_crime_near or the generic summarize_dataset, and no exclusions or prerequisites are given.

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

summarize_datasetAggregate any datasetA
Read-onlyIdempotent

Count or aggregate any portal dataset server-side, grouped by up to three fields.

Answers questions like "how many 311 requests of each type were made in ZIP 28205?". Rows are sorted by the statistic, largest first, in a column named stat_value.

ParametersJSON Schema
NameRequiredDescriptionDefault
nearNoOptional street address or 'latitude,longitude'; when given, only records within radius_miles of it are returned.
limitNoMaximum groups to return.
whereNo1=1
group_byYesFields to group by.
layer_urlYesArcGIS layer URL from search_datasets, ending in /MapServer/<n> or /FeatureServer/<n>.
radius_milesNoUsed with near.
statistic_typeNocount
statistic_fieldNoNumeric field to aggregate; required unless counting.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowsYes
notesNo
sourceYes
filtersYesThe SQL where clause that was applied.
group_byYes
locationNo
statisticYes
radius_milesNo

TDQS

A3.7/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, non-destructive and open-world, so safety is covered. The description adds operational context beyond that: aggregation runs server-side, grouping is capped at three fields, and results are sorted by the statistic descending in a stat_value column. It does not mention limits or pagination behavior, but the added context is real.

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?

Three short sentences with the core capability front-loaded, an illustrative example, and the output convention last. No filler or redundant restatement of the name.

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

Completeness3/5

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

For an 8-parameter aggregation tool the description covers purpose and result shape (an output schema exists, so return values needn't be explained), but it leaves filtering (where, near) and statistic selection undocumented and never positions itself against query_dataset or the domain-specific summarize_* siblings.

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

Parameters3/5

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

Schema coverage is 75%, so most parameters are documented structurally, but the description does not compensate for the gaps: where, near/radius_miles, statistic_type, and statistic_field are never explained in prose. The 'grouped by up to three fields' phrase merely restates the schema's maxItems: 3 on group_by.

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

Purpose4/5

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

States a specific verb (count/aggregate) and resource (any portal dataset) with scope qualifiers: server-side, grouped by up to three fields. An agent can distinguish it from row-returning siblings like query_dataset, but no sibling is named explicitly.

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 concrete example question ('how many 311 requests of each type were made in ZIP 28205?') implies the class of questions this tool answers, which is useful implied usage. However, there is no explicit when-to-use/when-not guidance and no mention of when to prefer query_dataset or a dedicated sibling like summarize_crime.

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. 19 tool updatesv0.1.0
    • First observeddescribe_dataset
    • First observedfind_nearby_places
    • First observedget_311_requests_near
    • First observedget_address_profile
    • First observedget_bus_route
    • First observedget_capital_projects_near
    • First observedget_city_budget
    • First observedget_city_salary_stats
    • First observedget_code_enforcement_cases
    • First observedget_crime_near
    • First observedget_pending_rezonings
    • First observedget_street_closures
    • First observedget_traffic_crashes_near
    • First observedget_trash_and_recycling_schedule
    • First observedlookup_address
    • First observedquery_dataset
    • First observedsearch_datasets
    • First observedsummarize_crime
    • First observedsummarize_dataset

TDQS

A3.7/5.0

Scored across 19 tools

Disambiguation4/5

Most tools map to distinct data domains (311, crime, crashes, budget, etc.), but get_address_profile duplicates several specialized capabilities—especially trash/recycling schedule—and the generic query_dataset/summarize_dataset can answer questions also covered by purpose-built tools. Descriptions provide guidance (e.g., search_datasets says to use purpose-built tools first), so misselection risk is moderate but present.

Naming Consistency5/5

All 19 tools use snake_case with a verb-first pattern (get_, lookup_, summarize_, find_, search_, describe_, query_), and resource names are clear and predictable. Minor verb variety (get vs lookup vs find) is semantically appropriate and does not break consistency.

Tool Count4/5

19 tools is on the higher side but justified by the breadth of Charlotte open data (address, transit, safety, budget, etc.) plus a generic dataset access layer. Each tool targets a distinct data type, though the composite address profile and generic trio create some redundancy.

Completeness4/5

The surface covers major city data domains and the generic search/describe/query/summarize tools allow access to any of ~380 portal datasets, so agents can answer most questions without dead ends. Minor gaps include real-time transit arrivals and a dedicated bus stop tool (handled indirectly via find_nearby_places), but overall coverage is strong.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides access to Cincinnati open data via the Socrata SODA API, allowing users to query datasets using natural language or direct tool calls.
    3 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables searching and querying Durham, North Carolina open geospatial data from ArcGIS Feature/Map Services, including parcels, zoning, and public safety datasets via natural language or direct tool calls.
    3 npm
    MIT