Skip to main content
Glama
tansuasici

country-state-city

by tansuasici

Country State City


About

Country State City provides a versioned dataset of 250 countries and territories, 4,963 administrative areas, 147,739 populated-place records, and 922 Türkiye districts as an NPM package, an MCP server for AI assistants, and an interactive web app.

Related MCP server: OpenStreetMap MCP Server

Features

  • Versioned location data — 250 countries and territories, 4,963 administrative areas, and 147,739 places

  • Immutable public identity — Namespaced csc:country|state|city|district:{id} values, source-ID collision gates, and version-pair migration downloads

  • Normalized display labels — CLDR-style country names and separated administrative categories across subdivision and place records without changing canonical source names

  • Reproducible artifacts — one canonical country/state/city source generates optimized data, browser shards, and package copies with byte-level CI drift checks

  • Multiple Formats — JSON, CSV, XML, YAML output

  • MCP Server — Connect to Claude Desktop and AI assistants

  • TypeScript — Full type definitions included

  • Dual Entry Points — Separate browser (ESM) and Node.js (CJS/ESM) builds

  • Search — Filter countries, states, and cities by name

  • Ranked location search — Canonical names, aliases, transliterations, typo tolerance, match reasons, and stable IDs

  • Nearest-centre lookup — Lazy spatial indexes, batch queries, antimeridian handling, distance, and confidence metadata

  • Timezone utilities — Observe IANA timezone offsets for a specific instant instead of relying on stale stored offsets

  • Explicit Türkiye districts — 922 current districts with province parents, legacy aliases, open source IDs, and centre-coordinate review status

  • Optional boundary layers — Versioned Türkiye admin-1/admin-2 GeoJSON downloads and a lazy overview TopoJSON export

  • Auditable quality — Machine-readable coverage, provenance, normalization, package-budget, and migration reports

  • Interactive Playground — Test the API at the live demo

Quick Start

npm install @tansuasici/country-state-city
import { CountryStateCity, toPublicId } from '@tansuasici/country-state-city';

const countries = CountryStateCity.getAllCountries();
const turkey = CountryStateCity.getCountryByIso2('TR');
const states = CountryStateCity.getStatesByCountryId(225);
const cities = CountryStateCity.getCitiesByStateId(2170);
const districts = CountryStateCity.getDistrictsByCountryCode('TR');
const currentAdmin1 = CountryStateCity.getAdministrativeAreas({ level: 1 });
const settlements = CountryStateCity.getSettlements({ countryCode: 'TR' });
const stableCityId = toPublicId('city', cities[0].id);
const stableDistrictId = toPublicId('district', districts[0].id);

// Search
const results = CountryStateCity.searchLocations('İstanbull', {
  countryCode: 'TR',
  entityTypes: ['state'],
});

// Optional Türkiye boundary asset — not loaded with the core API
const { default: turkeyOverview } = await import(
  '@tansuasici/country-state-city/data/boundaries/tr/overview.json',
  { with: { type: 'json' } }
);

// Different formats
const csv = CountryStateCity.getAllCountries('csv');
const xml = CountryStateCity.getStatesByCountryId(231, 'xml');
const yaml = CountryStateCity.getCitiesByStateId(1416, 'yaml');

Hosted REST and GraphQL API

The optional hosted API exposes the same canonical data snapshot under /api/v1 and includes the immutable data version and source attribution in every response.

curl 'https://countrystatecity.tansuasici.com/api/v1/countries?limit=3&fields=id,name,iso2' \
  -H 'x-api-key: YOUR_API_KEY'

REST supports search, pagination, field selection, ETag caching, and per-key rate limits. Read-only GraphQL is available at /api/graphql; the OpenAPI contract and operating policy live at /api/openapi.json and /api/policy.json. See the hosted API documentation and interactive playground.

Offline nearest-centre lookup uses a lazy 3D KD-tree, handles the antimeridian, and returns distance, confidence, and the immutable data version:

const nearest = CountryStateCity.nearestCenters(
  { latitude: 40.9811, longitude: 29.0651 },
  { entityTypes: ['country', 'state', 'city'], countryCode: 'TR' }
);

// Ranked multilingual/alias search with canonical identity and match reason
const matches = CountryStateCity.searchLocations('München', {
  countryCode: 'DE',
  entityTypes: ['city'],
});

For polygon containment, import a compatible GeoJSON boundary and use PolygonLookupIndex; current versioned coverage is Türkiye admin-1/admin-2. Nearest centres are not treated as proof of administrative containment.

MCP Integration

Use location data directly in Claude Desktop and other MCP-compatible AI assistants.

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "country-state-city": {
      "command": "npx",
      "args": ["-y", "@tansuasici/country-state-city"]
    }
  }
}

11 Toolssearch_countries, get_country, get_countries_by_region, get_states, search_states, get_cities, search_cities, get_stats, get_regions, get_timezones, get_currencies

6 Resources://countries, ://countries/{iso2}, ://countries/{iso2}/states, ://states/{id}/cities, ://stats, ://snapshot

The exact production identity policy and version-pair migration index are published as package exports:

import identityPolicy from '@tansuasici/country-state-city/data/identity-policy.json';
import migrationIndex from '@tansuasici/country-state-city/data/migrations/index.json';
import coveragePolicy from '@tansuasici/country-state-city/data/coverage-policy.json';
import coverageReport from '@tansuasici/country-state-city/data/coverage-report.json';
import stateCoordinatePolicy from '@tansuasici/country-state-city/data/geography/state-coordinate-policy.json';
import schemaNormalizationPolicy from '@tansuasici/country-state-city/data/schema-normalization-policy.json';

API Reference

Country Methods

CountryStateCity.getAllCountries(format?: 'json' | 'csv' | 'xml' | 'yaml');
CountryStateCity.getCountryById(id: number);
CountryStateCity.getCountryByIso2(iso2: string);
CountryStateCity.getCountryByIso3(iso3: string);
CountryStateCity.searchCountries(query: string);
CountryStateCity.getCountriesByRegion(region: string);
CountryStateCity.getCountriesBySubregion(subregion: string);
CountryStateCity.getCountryTranslation(countryCode, locale);
CountryStateCity.getCoverageReport();
CountryStateCity.getCountryCoverage(countryCode: string);

State Methods

CountryStateCity.getAllStates(format?: 'json' | 'csv' | 'xml' | 'yaml');
CountryStateCity.getStateById(id: number);
CountryStateCity.getStatesByCountryId(countryId: number, format?: string);
CountryStateCity.getStatesByCountryCode(countryCode: string, format?: string);
CountryStateCity.searchStates(query: string, countryId?: number);

City Methods

CountryStateCity.getAllCities(format?: 'json' | 'csv' | 'xml' | 'yaml');
CountryStateCity.getCityById(id: number);
CountryStateCity.getCitiesByStateId(stateId: number, format?: string);
CountryStateCity.getCitiesByCountryId(countryId: number, format?: string);
CountryStateCity.searchCities(query: string, stateId?: number, countryId?: number);

Canonical Entity Methods

The legacy state/city methods retain the imported collections. For comparable administrative levels and a clean settlement layer, use:

CountryStateCity.getAdministrativeAreas({
  countryCode?: string,
  level?: number, // defaults to 1
  lifecycleStatus?: 'current' | 'historical' | 'review-required' | 'all',
  sourceLayer?: 'state' | 'city' | 'all', // defaults to state
});
CountryStateCity.getSettlements({
  countryCode?: string,
  stateId?: number,
  lifecycleStatus?: 'current' | 'historical' | 'review-required' | 'all',
});

Every state/city row has explicit entity, level, parent, place type, lifecycle, validity, confidence, and policy-source fields. The migration contract and country mappings are exported as data/entity-level-policy.json.

District Methods

The district layer currently covers Türkiye. Legacy city records remain available for backward compatibility; use these methods when the administrative district grain is required.

CountryStateCity.getAllDistricts(format?: 'json' | 'csv' | 'xml' | 'yaml');
CountryStateCity.getDistrictById(id: number);
CountryStateCity.getDistrictByPublicId(publicId: string);
CountryStateCity.getDistrictsByStateId(stateId: number, format?: string);
CountryStateCity.getDistrictsByCountryCode(countryCode: string);
CountryStateCity.searchDistricts(query: string, stateId?: number);

csc:district:* IDs belong to CountryStateCity. Türkiye's public validation source does not publish an authoritative district code, so the dataset keeps officialDistrictCode: null instead of inventing one.

Utility Methods

CountryStateCity.getStats();
CountryStateCity.getCoverageReport();
CountryStateCity.getCountryCoverage(countryCode: string);
CountryStateCity.getAllRegions();
CountryStateCity.getAllSubregions();
CountryStateCity.getAllTimezones();
CountryStateCity.getTimezoneOffset(zoneName, at?);
CountryStateCity.getAllCurrencies();
CountryStateCity.searchLocations(query, options?);
CountryStateCity.nearestCenters(point, options?);
CountryStateCity.nearestCentersBatch(points, options?);
CountryStateCity.exportData(dataType, format, options?);

nearestCenters() compares a coordinate with representative centre points. It does not prove that a point is inside an administrative area. For containment, supply compatible GeoJSON to PolygonLookupIndex or locatePointInPolygons(). Versioned polygon coverage currently includes Türkiye admin-1/admin-2 only.

Direct Data Exports

Use package exports instead of repository-relative paths:

import countries from '@tansuasici/country-state-city/data/countries.json' with { type: 'json' };
import states from '@tansuasici/country-state-city/data/states.json' with { type: 'json' };
import compactCities from '@tansuasici/country-state-city/data/cities.optimized.json' with { type: 'json' };
import turkeyDistricts from '@tansuasici/country-state-city/data/districts/tr.json' with { type: 'json' };

The compact city keys are i (ID), n (name), s (state ID), c (country ID), la/lo (coordinates), and optional w (Wikidata QID). Use the class API when full City objects are preferred.

TypeScript

import { CountryStateCity } from '@tansuasici/country-state-city';
import type {
  Country,
  State,
  City,
  District,
  DataFormat,
  FormatOptions,
} from '@tansuasici/country-state-city';

Migrating to v3

Version 3 keeps the familiar country/state/city methods while tightening the data contract and adding canonical administrative, search, district, timezone, and spatial APIs.

  • @tansuasici/country-state-city/data/cities.json was removed. Use the class API or data/cities.optimized.json.

  • Country and state coordinates can be null when no trustworthy value is available.

  • Country translations are normalized to typed locale keys and values can be null when a translation is unavailable.

  • State and city records now include explicit entity classification, administrative level, lifecycle, parent, and source fields.

  • Centre-based reverse geocoding and polygon containment are deliberately separate APIs.

Review nullable fields when upgrading TypeScript consumers and prefer immutable csc:* public IDs for persisted references.

Development

# Install dependencies
npm install

# Start dev server
npm run dev

# Build NPM package
npm run build:lib

# Build MCP server
npm run build:mcp

# Run tests
npm test

# Validate the pinned data source and patch manifests
npm run test:data-sync

# Validate immutable public IDs and versioned migration contracts
npm run test:identity

# Check whether a newer upstream release exists
npm run data:check-freshness

# Build and validate a reproducible candidate dataset (does not modify production data)
npm run data:sync -- --check --verify-reproducible

# Regenerate non-destructive subdivision display names and types
npm run data:display-metadata

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for guidelines.

License

The data is derived from Countries States Cities Database. Attribution is required. Machine-readable source and version details are in data/provenance.json.


A
license - permissive license
Not graded
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
2moRelease cycle
2Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    A geospatial MCP server that provides tools for geocoding, routing, elevation profiles, and spatial analysis. It enables AI agents to process GIS file formats like GeoJSON and Shapefiles while performing complex coordinate transformations and distance calculations.
    4
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    A comprehensive MCP server providing 30 tools for geocoding, routing, and OpenStreetMap data analysis. It enables AI assistants to search for locations, calculate travel routes, and perform quality assurance checks on map data.
    30
    3
    MIT

View all related MCP servers

Related MCP Connectors

  • MCP server for Japan geodata: cadastral lot numbers (chiban) and reverse geocoding, for AI agents.

  • Free GeoNames MCP: countries, cities, POIs, distance & nearby. Remote HTTP + agent token signup.

  • MCP server for Mireye Earth — federal-source-cited geospatial data for any MCP-aware agent.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tansuasici/CountryStateCity'

If you have feedback or need assistance with the MCP directory API, please join our Discord server