The same county parcel data behind our tools, in three forms you can call from code: a TypeScript npm package for your own programs, an MCP server for Claude, Cursor, and other AI clients, and a hosted REST API that turns a US address into the owner of record. The SDK is MIT-licensed and needs no account. The MCP server's discovery tools need no key either. The hosted lookup API runs on a free key; theenrich_address action and bulk enrichment are on paid plans (from $19/mo) or pay-as-you-go.
@urbankitstudio/atlas v0.5.3. TypeScript, ESM + CJS, zero runtime deps.
JSON-RPC 2.0, MCP spec 2025-06-18. Four tools via npm, six on the hosted endpoint, no key.
155 counties across 50 states, each with verified REST endpoints and searchable fields.
A typed wrapper around the atlas, bundled offline so your code makes no runtime network call to resolve a county. Look up an endpoint by slug or FIPS, read its searchable fields, and build deep-links into the parcel-lookup tool. Works in Node 18+ and every modern bundler.
npm i @urbankitstudio/atlas
Every function below ships in v0.5.3. findCountyByFips and findCounty return undefined on a miss rather than throwing, so you can branch on the result.
import { findCountyByFips, listStates, atlas } from "@urbankitstudio/atlas";
// 1. Resolve a 5-digit county FIPS to its parcel endpoint.
const kane = findCountyByFips("17089"); // Kane County, IL
if (kane) {
const endpoint = kane.endpoints[0];
console.log(endpoint.url); // the live ArcGIS REST URL
console.log(endpoint.searchFields); // [{ name: "PIN", searchable: true }, ...]
}
// 2. Discovery: which states are indexed, and how many counties each.
const populated = listStates().filter((s) => s.populated);
console.log(populated.length, "states");
// 3. Coverage totals are on the bundled atlas root.
console.log(atlas.totals); // { states, counties, endpoints }
// Unknown / malformed input returns undefined. It never throws.listStates, findState, findCounty, findCountyByFips, listCountiesByState, buildParcelLookupDeepLink.
Dual ESM/CJS builds, full .d.ts types, sideEffects: false, zero runtime dependencies.
The parcel atlas is available as a published npm MCP server you can run in any MCP-capable client with one command:
It exposes four tools: list_counties, find_county, get_parcel_endpoint, and build_owner_query. The server is public and read-only. Your client pays its own LLM-token cost; there is no key to manage.
Open claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/; Windows: %APPDATA%\Claude\) and merge in this block, then restart Claude Desktop.
{
"mcpServers": {
"urbankit-atlas": {
"command": "npx",
"args": ["-y", "@urbankitstudio/mcp-atlas"]
}
}
}Clients that connect by URL instead of spawning a subprocess can point at the remote HTTP endpoint: https://urbankitstudio.com/api/mcp. It exposes six public discovery tools plus two key-gated actions: enrich_address returns owner, APN, and mailing fields for one address, and radius_ownersreturns every owner parcel inside a radius. enrich_address runs on paid plans or pay-as-you-go and uses one unit when data is released; radius_owners is paid-plans-only and uses one unit per parcel row returned, with a caller-set cap and a count_only preview.
The full MCP server page has the per-tool reference, an example conversation, a curl walkthrough, and setup notes for Cursor and other clients.
The SDK and MCP server hand you the verified county endpoint to query. If you would rather send a US street address and get the owner back directly, the hosted /api/atlas/lookup endpoint is the property owner lookup API on top of the same 155-county atlas. One authenticated GET resolves the address to its county, the parcel endpoint, and the owner / APN / mailing fields that endpoint exposes, the address-to-owner API behind the parcel-lookup tool, and a practical skip-trace API alternative when the owner of record is all you need.
curl "https://urbankitstudio.com/api/atlas/lookup\ ?address=100 N Lake St, Aurora, IL" \ -H "Authorization: Bearer uk_live_..."
{
"ok": true,
"matched": true,
"geocode": {
"matchedAddress": "100 N LAKE ST, AURORA, IL, 60506",
"countyName": "Kane",
"stateAbbrev": "IL",
"countyFips": "17089"
},
"atlas_indexed": true,
"county": {
"county_name": "Kane",
"county_fips": "17089",
"endpoints": [
{
"url": "https://.../MapServer/0",
"searchable_fields": [
{ "name": "PIN", "label": "Parcel number (APN)" },
{ "name": "OWNER_NAME", "label": "Owner of record" },
{ "name": "SITE_ADDR", "label": "Site address" }
],
"sample_query": ".../query?where=PIN='...'&outFields=*&f=json",
"endpoint_status": "ok"
}
]
}
}The whole public API is described in /openapi.json (OpenAPI 3.1): all four endpoints, the bearer scheme, the rate-limit headers, and the error shape. Point Postman, an SDK generator or an agent at it rather than reading this page and transcribing it by hand.
It covers /api/atlas/lookup, /api/atlas/county, /api/atlas/radius and /api/atlas/bulk. A test fails the build if an endpoint ships without being documented there, so the contract cannot quietly fall behind the API it describes.
Anonymous calls work up to 10 a day so you can try the response shape; a free key raises that to 500 a day, and the paid plans add bulk address-to-owner enrichment for whole lists. Owner data comes from each county's own public ArcGIS layer. When a county does not publish owner names, the response says so rather than guessing.
package.json.Both surfaces read the same source: the County Parcel REST API Atlas, a hand-verified index of public ArcGIS endpoints. No hidden database sits behind them. The JSON files are the source of truth, and you can browse the whole set by state.
The browsable index of 155 indexed counties, by state, with each endpoint's searchable fields.
BrowsePer-tool reference, JSON-RPC examples, and client setup for the six-tool server.
Read the docsThe site, the atlas data files, the SDK, and the MCP edge function all live in one open repo.
Open repo