UrbanKit County Parcel Atlas
One line: It is a lookup/reference server for county parcel GIS endpoints — it tells you which counties are covered and hands you ready-to-run ArcGIS REST query URLs, but never fetches or returns parcel data itself.
list_counties— browse coverage, optionally filtered by state abbreviation or full name; answers "is this county covered and what can I search there?" (no URLs or field names).find_county— fuzzy-resolve a vague, partial, misspelled, "County State" or 5-digit FIPS reference; returns every match with its full record (endpoints, searchable fields, owner field, sample query, license).get_parcel_endpoint— for an exact state + county, return the ArcGIS REST service URL, layer index, searchable field names, owner field (or why no owner query is offered), a ready sample?where=…&f=jsonquery, and the UrbanKit deep-link.build_owner_query— turn a state + county + owner name into a runnable URL using the county's verified owner/taxpayer field viaUPPER(field) LIKE UPPER('%NAME%'), with scope predicates for shared statewide layers.No execution — every tool returns URLs/information only; you run the fetch yourself. City datasets (
get_city_datasets) appear in the README but are absent from this schema, andlist_countieshere claims "~155 counties" where the README claims 515 — the schema looks out of date relative to the README.
Provides tools to query US county parcel data from ArcGIS REST endpoints, including listing covered counties, finding county endpoints, and constructing owner queries.
@urbankitstudio/mcp-atlas
Query the parcel ArcGIS REST endpoints of 515 counties across 51 US states (50 states plus DC), 509 endpoints total, for owner, APN and address lookup via the Model Context Protocol (MCP).
An MCP server that gives AI assistants direct access to UrbanKit Studio's atlas of manually verified county parcel GIS services. Ask Claude or Cursor to find the ArcGIS REST endpoint for any covered county, get the exact owner-search query URL, and look up parcel data — without needing to know anything about ArcGIS REST API conventions.
Coverage: 515 counties across 51 US states (50 states plus DC), 509 endpoints, 509 of them live (atlas 0.7.2). 481 of the counties have an endpoint; for the other 34 the atlas records why not (see "A county we cannot serve" below).
Quick start
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"mcp-atlas": {
"command": "npx",
"args": ["-y", "@urbankitstudio/mcp-atlas"]
}
}
}Cursor
Add to .cursor/mcp.json in your project root (or ~/.cursor/mcp.json globally):
{
"mcpServers": {
"mcp-atlas": {
"command": "npx",
"args": ["-y", "@urbankitstudio/mcp-atlas"]
}
}
}Install globally (optional)
npm install -g @urbankitstudio/mcp-atlasThen use mcp-atlas as the command instead of npx -y @urbankitstudio/mcp-atlas.
Related MCP server: Property Intelligence MCP Server
Tools
The first four tools are one county pipeline, and what separates them is how
precisely you can already name the county. The fifth, get_city_datasets, is
separate: it answers about a city, not a county.
You have | Use | You get |
A state, or nothing |
| Which counties are covered, and whether owner search works there. No URLs. |
A vague, misspelled or FIPS reference |
| Every county that reference matches, named, each with its record |
An exact state and county |
| That one county's endpoint URL, layer, fields and sample query |
A county and an owner's name |
| A runnable URL that searches for that name |
A city, and optionally a street |
| That city's code-violation, building-permit and zoning-case datasets, each with a runnable query URL |
find_county and get_parcel_endpoint return the same per-county record. They
differ in how you address the county: find_county accepts an uncertain
reference and may come back with several candidates, get_parcel_endpoint
takes an exact pair and answers about one. If you already know the county, skip
find_county.
This server never executes a query and returns no parcel records. It tells you the URL to fetch; fetching it is yours to do.
A county we cannot serve
find_county, get_parcel_endpoint and build_owner_query give one answer for
a county with no endpoint to hand back, the same text the hosted UrbanKit MCP
server, its REST API and the uks CLI give. It comes from
coverageAnswer() in @urbankitstudio/atlas 0.6.38:
The atlas has no record (a misspelling lands here too): "This county is not in the UrbanKit atlas", with a prompt to check the spelling first.
The atlas records the county and it publishes nothing we can serve (Shelby TN, whose terms bar public display; Columbia PA, whose layer has parcel numbers only): the reason in one sentence, the date we last checked, the date of the next check when one is set, the county's own office and, where the county sells the data, its own product.
Both end with a free request for the county: a ready body for request_county
on the hosted MCP server or POST https://urbankitstudio.com/api/atlas/request.
Requesting does not promise we add the county. list_counties still lists only
the counties we serve.
list_counties
Browse coverage. Answers "is this county covered?" and "what can I search there?" — one line per county, with no endpoint URLs or field names.
Parameter | Type | Required | Description |
| string | No | Two-letter abbreviation ( |
Example prompt: "List all covered counties in Illinois"
Example output:
ST | County | Slug | Coverage
--------------------------------------------------------------------
IL | Kane | kane-county | owner+APN
IL | Cook | cook-county | APN only
IL | DuPage | dupage-county | owner+APN
...What each Coverage label promises:
Label | Meaning |
|
|
| A reviewed record says the county serves no usable owner name |
| A reviewed record says owner names are withheld: by a statute, by the county's terms, or while we ask the county |
| No endpoint answers attribute searches; parcels are reached by geometry, which also returns owner fields |
| An owner column exists but the county marks it unsearchable by name; a parcel-id or location query returns it |
| An owner column exists, but the layer's confidential-owner flag is malformed, so no owner query is offered |
| No endpoint documents an owner column |
find_county
Resolves a reference you cannot state exactly. Fuzzy-matches a partial or misspelled name, a "County State" phrase, or a 5-digit FIPS code against every covered county, and names each county it matched so an ambiguous reference comes back as a list to choose from. Each match carries that county's record: endpoint URLs, searchable field names, owner field, sample query, license.
Parameter | Type | Required | Description |
| string | Yes | County name ( |
Example prompt: "Find the parcel endpoint for Kane County Illinois"
get_parcel_endpoint
The default lookup once the county is known. Returns the full ArcGIS REST URL,
layer index, searchable fields, owner field (or why no owner query is offered),
the county's Scope: predicate when the layer is shared statewide or
regionally, a generic sample ?where=…&f=json query and the UrbanKit deep-link
for one county. For a named owner, use
build_owner_query rather than editing the sample query by hand. On a layer
that flags confidential owners it prints the Confidential flag: exclusion
to AND into any query of your own, and prints its own sample owner query in
place of the atlas's, so the one sample shown carries this server's clauses.
Parameter | Type | Required | Description |
| string | Yes | Two-letter abbreviation or full name |
| string | Yes | County name ( |
Example prompt: "Give me the ArcGIS REST endpoint for Cook County Illinois"
build_owner_query
The only tool that searches for a named owner. Fills a person or company name
into the county's verified owner/taxpayer field as
UPPER(field) LIKE UPPER('%NAME%'), a case-insensitive partial match, and
returns a URL you can fetch or open. On a shared statewide or regional layer
(Connecticut's regional composites, for example) the county's scope predicate
is ANDed in front, as
(scope) AND UPPER(field) LIKE …, so only that county's rows come back.
Some layers publish an owner whose record must not be shown, and flag it in a
column beside the owner: Texas Tax Code §25.025 lets peace officers, judges,
family-violence victims and others keep their home address confidential, and
Harris and Collin mark those accounts (Ector carries a forward guess). On such
a layer the query excludes flagged rows, as
(…) AND UPPER(CAST(flag AS VARCHAR(255))) NOT LIKE '%Y%', a contains test
for every flag value (Harris packs one flag per ownership slot, YNNNNNNNNN).
SQL UPPER matches the atlas's uppercase rule on ASCII only, so each of the 17
non-ASCII characters whose uppercase holds an ASCII letter (ß, a dotless i,
the fi ligatures, ẙ and the like) gets a clause of its own when it shares a
letter with a value: CAST(flag AS VARCHAR(255)) NOT LIKE '%ẙ%' drops a cell
holding one. Those clauses still lean on the county's database (an UPPER that
maps a-z to A-Z, a LIKE that reads past an embedded NUL, no cell cut off at the
255-character cast, one encoding for cell and literal), so the query ends with a
clause that does not: flag IN (…), the exact raw cells the atlas lists as safe
(confidentialFlag.safeValues: Harris's blank and N runs, each 10 characters;
Collin F; Ector 0). A row stays only when the database itself says its cell
equals one of those values, under its own comparison rules, so a NUL, a cut-off
cell or a value nobody has reviewed drops out. A backend that ignores trailing
spaces or case also keeps the same safe value padded differently or in another
case; none of those holds a flag value. A flag without safe values, or with one that holds a marker, offers no
owner query. On 2026-10-26 the IN clause kept exactly the rows the contains
clauses keep on all three layers (Harris 1,541,671, Collin 435,783, Ector
77,042), and those lists were each layer's complete distinct values.
A value longer than one character is a contains test too, which deliberately
excludes more than the atlas's trimmed-equality rule: for SEALED, the cells
SEALED and UNSEALED drop out as well. The cast lets one form serve a text
or an integer column, and UPPER on both sides compares the flag without regard
to case. A row with no flag recorded (NULL) counts as flagged and drops
out. The flag column comes back with each row; never show or pass on a row
whose flag is set.
An endpoint is refused, with the reason, rather than handed a query that finds nothing, hangs, or serves confidential owners:
a reviewed record says the county publishes no usable owner name;
the layer serves no attribute search at all (query it by location instead);
the owner column is not searchable by name (use a parcel-id or location query);
the layer carries a confidential-owner flag that is present but incomplete (no column, no values, or a value that is not ASCII letters and digits only), so no exclusion can be built.
A refusal that points to a location, parcel-id or address read also prints the
layer's Confidential flag: line, and on a flagged layer its advice follows
the flag. With a well-formed flag, the read must request the flag column in
outFields and keep a row only when its flag cell is exactly one of the safe
values and contains no flag value, dropping every other row (a missing or NULL
cell included); a layer with no attribute search takes no where clause, so that
filtering is the reader's, and its Confidential flag: line gives that row
rule in place of "AND this into every query". With an incomplete flag, the refusal advises no
read at all: do not read owner fields on that layer. find_county and
get_parcel_endpoint carry the same advice in their Confidential flag: line,
and their Owner line says why no owner query is offered.
Every free-text argument of every tool refuses control characters (CR, LF, TAB, NUL and the rest of U+0000 to U+001F, U+007F, and the C1 controls U+0080 to U+009F), the line and paragraph separators U+2028 and U+2029, and the whole Unicode Bidi_Control set (U+061C, U+200E, U+200F, U+202A to U+202E and U+2066 to U+2069), so an argument echoed into an answer cannot start a line of its own there or reorder how the text around it displays. Other invisible characters, such as U+200B, U+FEFF and the soft hyphen U+00AD, still pass. A validation error on a tool argument never repeats the value it refused (the MCP SDK's own error for an unknown tool name does quote that name).
Parameter | Type | Required | Description |
| string | Yes | Two-letter abbreviation or full name |
| string | Yes | County name |
| string | Yes | Owner/taxpayer name (partial match) |
Example prompt: "Build an ArcGIS query for properties owned by 'Smith' in Kane County IL"
Example output:
County: Kane, Illinois
Owner field: TaxName
WHERE clause: UPPER(TaxName) LIKE UPPER('%SMITH%')
Query URL:
https://gistech.countyofkane.org/arcgis/rest/services/KanePINList/MapServer/0/query
?where=UPPER(TaxName)%20LIKE%20UPPER('%25SMITH%25')
&outFields=PIN,TaxName,SiteAddress,SiteCity,MailingAddress
&returnGeometry=false&f=json&resultRecordCount=25get_city_datasets
City code-violation, building-permit and zoning-case datasets. Give a city
slug (fort-worth) or name (Fort Worth, Fort Worth, TX), optionally a
kind and a street line, and it returns each verified dataset for that city:
the endpoint and provider (Socrata, ArcGIS, CKAN or CARTO), the column the
address is matched on, the date field, any filter that is part of the dataset's
definition, coverage and freshness notes, and, when you pass a street, a ready
query_url to run against the city's own server. Omit city to list every
covered city.
Parameter | Type | Required | Description |
| string (max 80) | No | City slug or name; omit to list covered cities |
| string (max 40) | No | Two-letter code or state name, for a name used in two states |
|
| No | Return only that kind of dataset |
| string (max 120) | No | Street line only, such as |
A name shared by two cities comes back as
found: false, ambiguous: truewith the candidates; repeat withstate. A city outside the registry comes back asfound: falsewith the covered cities in its state, or in its county when the reference names one.query_urlisnullfor a point lookup (a polygon docket or a current-zoning map); the dataset'squery_templatethen carries the request with a{LON},{LAT}placeholder to fill in.Scope is the city's limits, not the county. These tables hold no owner data: for a parcel's owner, use the county tools above.
Like the county tools, this one fetches nothing. It answers from the atlas package and hands you URLs to run yourself. Socrata throttles anonymous callers, so send your own
X-App-Tokenheader for volume.It is the same tool the hosted UrbanKit MCP serves, with the same advertised inputs and response keys. The stdio server holds arguments to that schema strictly:
kindmust beviolations,permitsorzoningin lower case.
Example prompt: "Where do I pull open building permits for 600 Commerce St, Dallas?"
Example output (abridged):
{
"found": true,
"city": { "slug": "dallas", "name": "Dallas", "state_abbrev": "TX", "county_slug": "dallas-county" },
"street": "600 Commerce St",
"datasets": [
{
"kind": "permits",
"provider": "socrata",
"endpoint": "https://www.dallasopendata.com/resource/e7gq-4sah.json",
"address_field": "street_address",
"street_used": "600 Commerce St",
"query_url": "https://www.dallasopendata.com/resource/e7gq-4sah.json?$where=upper(street_address)%20like%20upper('%25600%20Commerce%20St%25')&$limit=30"
}
]
}Example conversation
User: I'm doing due diligence on properties in Kane County, Illinois. Can you find all parcels owned by "Blackstone"?
Claude (using mcp-atlas):
Calls
get_parcel_endpoint→ gets thegistech.countyofkane.orgURL and confirms the owner field isTaxNameCalls
build_owner_querywithowner_name=Blackstone→ returns a ready fetch URLOptionally fetches the URL and formats the parcel results
Atlas coverage
The atlas is maintained by UrbanKit Studio. All endpoints are manually verified. Counties with an owner/taxpayer field support full name-based lookups; PIN-only counties support APN/parcel-number queries.
Full coverage map: https://urbankitstudio.com/parcel-atlas
Data
Atlas data is embedded in the package (no network calls at startup). The underlying @urbankitstudio/atlas SDK is also published separately for programmatic use.
What Socket flags, and how much of it is ours
Socket's supply-chain scanner rates this package in the mid-70s. Clicking through shows a long alert list. Each alert, checked rather than waved away:
Alert | Whose | What it is |
| Not ours | No |
| Not ours | Transitive dependencies last published 2017–2021. |
| Not ours | A dependency published as |
| Ours, by design |
|
| Ours | An MCP server talks to a client over stdio and reads its own config. A server without these could not do the job. |
| Ours | Download count and a |
Vulnerability and license both come back at 100, quality at 99. The number the badge shows is the supply-chain sub-score, and its single largest deduction is download count, a popularity measure wearing a security badge's clothes. Judge the list above, not the digit.
The four access alerts are what let the server read its own config and talk to a client over stdio, nothing more. It still never executes a query or returns a parcel record.
License
MIT — © 2026 UrbanKit Studio LLC
Available Tools
4 toolsbuild_owner_queryBuild ArcGIS owner name query URLA
Constructs the exact ArcGIS REST query URL using that county's verified owner/taxpayer field. Returns a URL you can open in a browser or fetch directly. The query uses UPPER(field) LIKE UPPER('%NAME%') — case-insensitive partial match.
| Name | Required | Description | Default |
|---|---|---|---|
| state | Yes | Two-letter state abbreviation (e.g. 'IL') or full state name | |
| county | Yes | County name (e.g. 'Kane' or 'Kane County') | |
| owner_name | Yes | Owner/taxpayer name to search for (partial match, case-insensitive) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It clearly discloses the query uses UPPER and LIKE for case-insensitive partial matching, and references a 'verified owner/taxpayer field' per county. This is sufficient to understand the tool's internal operation and side-effect-free nature.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences: first states the action and result, second details the query mechanism. Every word is purposeful with no redundancy or extraneous information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description adequately covers what the tool does, how it works, and what it returns. It leverages the context of county-specific fields. For a URL builder with three well-documented parameters and no output schema, it is nearly complete; minor omission is potential limitations (e.g., URL length, ArcGIS version compatibility).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
All three parameters have 100% schema coverage, but the description adds value by explaining the SQL-like query pattern (UPPER... LIKE) applied to owner_name, which goes beyond the schema's 'partial match, case-insensitive' description. This enhances understanding of how the parameter is used.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('constructs') and identifies the resource ('ArcGIS REST query URL'), clearly stating it builds the exact URL for owner name queries. It distinguishes from sibling tools (find_county, get_parcel_endpoint, list_counties) by focusing on URL construction for owner queries.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains the tool returns a URL for browser or direct fetch, implying its use for querying by owner name. It also details the query pattern (case-insensitive partial match), giving guidance on behavior. However, it lacks explicit when-not-to-use or alternatives, though the context of siblings provides some differentiation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_countyFind a county by name or FIPSA
Fuzzy-matches a county by name (e.g. 'Kane', 'Cook County', 'Cook County IL') or by 5-digit FIPS code. Returns endpoint URLs, searchable field names, owner field, sample query URL, and license info.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | County name, 'County Name State' (e.g. 'Kane IL'), or 5-digit FIPS code |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions that the tool performs fuzzy matching and returns specific data, which is transparent about its output. However, it does not disclose whether the tool is read-only, whether it requires authentication, or any other behavioral traits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, well-structured sentence that efficiently conveys the purpose, input format, and return value. No unnecessary words or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple lookup tool with one parameter and no output schema, the description is sufficiently complete. It explains the input and output clearly. However, it could be more complete by mentioning any prerequisites or common errors.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema coverage is 100%, so the schema documents the parameter 'query' with a description. The tool description adds value by providing examples and clarifying the fuzzy-matching behavior, which goes beyond the schema's static description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states that the tool performs fuzzy matching to find a county by name or FIPS code, and lists the specific information returned (endpoint URLs, fields, etc.). It distinguishes itself from siblings like list_counties by focusing on lookup rather than listing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides usage examples and input formats (e.g., 'Kane IL', FIPS code), which helps the agent understand when and how to use it. However, it does not explicitly state when not to use it or compare to alternatives like list_counties.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_parcel_endpointGet parcel ArcGIS REST endpointA
Returns the full ArcGIS REST service URL, layer index, searchable field names, owner field, a ready sample ?where=…&f=json query, and the UrbanKit deep-link for a specific county.
| Name | Required | Description | Default |
|---|---|---|---|
| state | Yes | Two-letter state abbreviation (e.g. 'IL') or full state name | |
| county | Yes | County name (e.g. 'Kane' or 'Kane County') |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description must carry the burden. It lists what is returned but does not explicitly state that the tool is read-only or disclose any side effects, performance characteristics, or requirements. The description is adequate but not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that efficiently enumerates all key outputs without redundancy. It is front-loaded and every element provides value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the lack of an output schema, the description adequately lists all expected return values. It could be strengthened by noting input validation or error handling, but is complete enough for a simple lookup tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% coverage with descriptions for both state and county. The description does not add additional meaning beyond what the schema provides, meeting the baseline for high coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the specific outputs: ArcGIS REST service URL, layer index, searchable field names, owner field, sample query, and UrbanKit deep-link for a county. It distinguishes from siblings like build_owner_query and find_county by focusing on endpoint retrieval.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage when a parcel endpoint for a specific county is needed, but does not explicitly state when not to use it or mention alternatives. Siblings (build_owner_query, find_county) suggest a workflow, but no direct guidance is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_countiesList covered countiesA
Returns all counties in the UrbanKit Atlas that have a verified ArcGIS REST parcel endpoint. Pass a state abbreviation (e.g. 'IL') or state name (e.g. 'Illinois') to filter by state. Omit state to list all ~155 counties.
| Name | Required | Description | Default |
|---|---|---|---|
| state | No | Optional: two-letter state abbreviation (e.g. 'IL') or full state name (e.g. 'Illinois') |
TDQS
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 discloses that only counties with verified endpoints are returned, and mentions the approximate count (155). No side effects or auth requirements are needed for a read-only list tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences: first declares the main function, second explains the optional filter. No redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given one optional parameter, no output schema, and no annotations, the description covers the tool's purpose, filtering, and scope. It could mention the return format (e.g., list of county names or IDs) but the core functionality is clear.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%. The description adds value by clarifying that the 'state' parameter accepts both abbreviations and full names, and that omission lists all. This goes slightly beyond the schema's own description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool returns all counties in the UrbanKit Atlas with verified ArcGIS REST parcel endpoints. It uses a specific verb ('Returns') and distinguishes from siblings like 'find_county' and 'get_parcel_endpoint'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage instructions: pass a state abbreviation or name to filter, or omit to list all ~155 counties. It does not compare to sibling tools but implies when to use state filtering.
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.
4 tool updates
v0.1.0- First observed
build_owner_query - First observed
find_county - First observed
get_parcel_endpoint - First observed
list_counties
TDQS
Scored across 4 tools
find_county and get_parcel_endpoint overlap heavily: both return endpoint URLs, searchable fields, owner fields, and sample query URLs. list_counties and find_county also both identify counties, so the tool boundaries are not clearly distinct.
All tool names follow a consistent verb_noun snake_case pattern: list_counties, find_county, get_parcel_endpoint, build_owner_query. The action-object structure is predictable and easy to scan.
Four tools is a reasonable size for a focused endpoint-discovery and query-construction service. However, the functional overlap between find_county and get_parcel_endpoint makes one of them nearly redundant.
The core workflow is covered: list available counties, resolve a county, get endpoint details, and build an owner query. Minor gaps remain, such as no direct execution of the built query and no builder for address- or PIN-based parcel searches, but these are arguably out of scope.
Maintenance
Related MCP Connectors
US parcel boundaries and assessor data: lookup by APN, point, radius or polygon.
US parcel records plus utilities, power, grid, environmental and logistics data by address or point.
US parcels and building permits from public sources. No owner data. Pay per record or monthly plan.
US parcels, owners, sales, zoning rules, building permits and zoning cases.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceRead-only MCP server providing direct, credentialed access to parcel data via Regrid and county ArcGIS sources, with tools for querying by point, owner, size, and county.-
- FlicenseNot gradedqualityDmaintenanceProvides free property and parcel intelligence using official US government data APIs, county assessor records, and live listings, with tools for hazard risk checks, affordability calculations, and parcel ranking.-
- FlicenseNot gradedqualityCmaintenanceEnables querying public ArcGIS REST services for county/state parcel data, GIS layer identification, and USGS elevation without API keys.-
- AlicenseNot gradedqualityCmaintenanceProvides access to comprehensive US property data, including automated valuations, tax history, comparable sales, and ownership details, enabling real estate analysis and market insights.140 npmMIT