关于 geonames-mcp-server
geonames-mcp-server 为开发者和地理位置研究提供 GeoNames 地名及地理参考数据。工具涵盖地点搜索、行政层级、反向地理编码、邮政编码和国家信息。
主要功能
- 01按地理条件搜索地点
- 02获取地点详细记录
- 03浏览上级与下级层级
- 04对坐标进行反向地理编码
- 05查找邮政编码和国家信息
适用场景
- 01查找某国或边界框内的地点
- 02识别坐标对应的行政区域
- 03探索地点的上级或下级区域
- 04查询邮政编码或国家详情
MCP 相关
通过 STDIO 或 Streamable HTTP 向 MCP 客户端提供八种 GeoNames 工具,也提供公开托管的 MCP 服务。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://geonames.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-geonames https://geonames.caseyjhand.com/mcp{"mcpServers":{"cyanheads-geonames":{"type":"http","url":"https://geonames.caseyjhand.com/mcp"}}}在 Cursor 中打开{"servers":{"cyanheads-geonames":{"type":"http","url":"https://geonames.caseyjhand.com/mcp"}}}在 VS Code 中打开{"mcpServers":{"cyanheads-geonames":{"type":"http","url":"https://geonames.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-geonames":{"serverUrl":"https://geonames.caseyjhand.com/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
8| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| limit | integer | 否 | 要返回的最大条目数,范围为 1 到 100。默认值为 10。 |
| match | enum | 否 | 查询的匹配方式。name_required(默认值)要求地点名称中至少包含一个查询词,其他词可匹配国家/地区或行政区名称;any_field 允许每个词匹配这些字段中的任意字段;exact_name 要求完整名称完全匹配,也包括别名和历史名称;name_prefix 匹配以查询词开头的名称。必须提供 query。不区分大小写。name_required | any_field | exact_name | name_prefix |
| query | string | 否 | 要搜索的地点名称,例如 Springfield 或 "Berlin, Germany",最多 200 个字符。match 设置比较方式。省略此项可仅按过滤条件搜索,此时 countries、featureClasses、featureCodes 或 boundingBox 中至少需要提供一项(仅提供 cities 不够)。 |
| cities | enum | 否 | 仅保留人口至少为 1,000(cities1000)、5,000(cities5000)或 15,000(cities15000)的居住地(类别 P),以及行政区驻地:即 GeoNames 的城市级别。与 featureClasses 或 featureCodes 同时使用时,只列出类别 P 或类别 P 的代码(例如 PPLC)。不区分大小写。cities1000 | cities5000 | cities15000 |
| offset | integer | 否 | 分页时,在首个返回条目之前跳过的条目数,范围为 0 到 5000。默认值为 0。 |
| orderBy | enum | 否 | 结果排序方式:relevance(GeoNames 默认值)或 population(按人口从高到低)。不区分大小写。relevance | population |
| countries | array | 否 | ISO 3166-1 国家/地区代码,最多 10 个,可用列表或逗号分隔的字符串表示:alpha-2(US、GB、DE)、alpha-3(USA、GBR、DEU)或三位数字代码(840、826、276);每个代码都会以 alpha-2 形式发送给 GeoNames。不区分大小写;接受 UK 作为 GB。 |
| boundingBox | object | 否 | 仅保留此边界框内的地点。边界框不能跨越 180° 经线;此类区域需拆分为两次搜索。 |
| boundingBox.east | number | 是 | 东侧经度边界,单位为十进制度,范围为 -180 到 180。 |
| boundingBox.west | number | 是 | 西側经度边界,单位为十进制度,范围为 -180 到 180;小于 east。 |
| boundingBox.north | number | 是 | 北纬边界,十进制度,范围为 -90 至 90。 |
| boundingBox.south | number | 是 | 南纬边界,十进制度,范围为 -90 至 90;低于北纬边界。 |
| featureCodes | array | 否 | GeoNames 要素代码(PPLC 首都、ADM1 州、MT 山、AIRP 机场),最多 20 个,可用列表或逗号分隔的字符串。区分大小写;类前缀(P.PPLC)会被移除。每个代码都隐含其类别;同时指定 featureClasses 时,两份列表取交集,因此 featureClasses 必须恰好列出这些代码对应的类别。geonames_list_reference 的 topic feature_codes 列出所有代码。 |
| featureClasses | array | 否 | GeoNames 要素类别:A 行政区划、H 水域、L 区域、P 居民地、R 道路、S 地点和建筑物、T 地形、U 海底、V 植被。可用列表或逗号分隔的字符串;不区分大小写。同时指定 featureCodes 时,两份列表取交集:请准确列出这些代码对应的类别,或仅传入 featureCodes。 |
| geonamesUsername | string | 否 | 你自己的 GeoNames 用户名,这样调用会消耗该账户的免费额度,而不是服务器的额度。省略此参数则使用服务器账户。该账户必须在 geonames.org 账户页面启用免费 Web 服务。 |
详细介绍
@cyanheads/geonames-mcp-server
通过 MCP 搜索 GeoNames 地点、遍历行政层级、反向地理编码、获取邮政编码和国家信息。支持 STDIO 或 Streamable HTTP。
概述
GeoNames 地名数据库收录了全球 1,300 多万个地点,并将它们按行政层级从大洲到街区关联成树形结构。可搜索地点、读取完整记录、遍历行政层级、对坐标进行反向地理编码、查询邮政编码并读取国家信息。
工具
| 工具 | 描述 |
|---|---|
geonames_search_places | 按名称、国家、行政区划代码、要素类别或代码、人口等级和边界框搜索地点 |
geonames_get_place | 获取单个 geonameId 的完整记录:行政区划链、时区、海拔、别名、邮政编码和外部标识符 |
geonames_get_hierarchy | 获取从地球和大洲到该地理要素的父级层级链 |
geonames_get_children | 获取该地理要素在行政、旅游或属地树中的直接子级 |
geonames_reverse_geocode | 获取坐标所在的国家和行政区划(或海洋),以及最近的地点或地理要素,并可选择获取时区 |
geonames_find_postal_codes | 按邮政编码、地点名称或坐标附近查找邮政编码 |
geonames_get_countries | 获取国家信息:ISO 和 FIPS 代码、geonameId、首都、人口、面积、语言、货币和邮政编码格式 |
geonames_list_reference | 获取要素类别、要素代码以及提供邮政编码数据的国家 |
功能参考
geonames_search_places 工具
query(最多 200 个字符)按match进行匹配:name_required(默认)、any_field、exact_name或name_prefix;筛选条件包括countries(最多 10 个,使用 ISO alpha-2、alpha-3 或数字代码)、adminCode1–adminCode4、featureClasses、featureCodes(最多 20 个)、cities(cities1000/cities5000/cities15000)和boundingBox。调用时必须提供query或countries、featureClasses、featureCodes、boundingBox之一- 列出的国家也会返回 GeoNames 文件中归属于该国的领地(
GB还会返回 IM、GG、JE 和 GS),每个地点的countryCode都是其自身的代码;如果页面上有countries未列出的国家,通知中会注明 adminCode1–adminCode4按 GeoNames 行政区划代码搜索行政区,geonames_get_place和geonames_reverse_geocode会在adminLevels中返回该代码(countries: ["US"], adminCode1: "TX", featureCodes: ["AIRP"]可列出德克萨斯州机场)。代码不区分大小写,前导零也计入代码(02,而非2);它们不是 ISO 3166-2 代码或邮政编码(巴伐利亚的代码是02,而非BY)。每次搜索必须指定一个国家,级别 2–4 还必须提供adminCode1limit为 1–1,000(默认 10),每次调用最多返回 100 条;有更多结果时会发出通知;offset为 0–5000,orderBy为relevance或population(省略时使用 GeoNames 自身的顺序);返回totalCount、effectiveQuery和nextOffsetfeatureClasses、featureCodes和cities(仅限类别 P)会相互取交集:同时设置两个列表时,每个代码的类别必须在列表中,且每个列出的类别都必须有对应代码;与cities同时使用时,仅可指定类别 P 及其代码。其他组合会以feature_filter_mismatch失败- 在发出任何请求前,若出现
query_or_filter_required、query_required、unknown_country_code、unknown_feature_code、admin_code_unscoped、feature_filter_mismatch或invalid_bounding_box,调用会失败
geonames_get_place 工具
- 提供一个
geonameId;未知 ID 会返回found: false和guidance - 返回 1–5 级
adminLevels(代码、名称、geonameId)、时区(1 月 1 日和 7 月 1 日的 UTC 偏移量)、边界框、记录海拔和 DEM 海拔、人口、Wikipedia URL、alternateNames、postalCodes、links和identifiers(IATA、ICAO、FAA、Transport Canada、UN/LOCODE、Wikidata) nameLanguages(最多 20 个标签;zh也会匹配zh-CN)仅筛选alternateNames
geonames_get_hierarchy 工具
- 提供一个
geonameId;chain从地球及其大洲开始,经过国家和行政区划,直至该地理要素,并跳过其不隶属的级别 - 每个级别都包含
geonameId、要素类别和代码、国家及一级行政区代码、坐标和人口;未知 ID 会返回found: false
geonames_get_children 工具
hierarchy:administrative(默认)、tourism(岛屿、海岸及其市镇;几乎都在西班牙)或dependency(一国的属地)。子级大多为行政区划(类别 A)和人口聚居地(类别 P);大洲和海岸属于类别 L,岛屿属于类别 T- 如果该地理要素没有
tourism或dependency树,GeoNames 会针对这两种请求返回行政子级。工具会比较两个列表;如果相同,则设置sameAsAdministrative并发出通知;即使是实际的树结构,两者也可能相同,因此仍会保留这些行 - 每个父级最多获取 1,000 个子级,并缓存结果,因此
nameContains、limit(1–1,000,默认 100,每次调用最多 500 条;有更多结果时会发出通知)和offset不会额外消耗额度;GeoNames 列出的结果更多时会发出通知 - 未知 ID 会返回
found: false;叶节点会返回空的children列表,并附带通知
geonames_reverse_geocode 工具
lat/lng可解析为country和adminLevels(最多到 ADM5,每级均包含geonameId,以及存在时的 ISO 3166-2 行政区划代码);若位于近海,则解析为oceancoastalBufferKm(0–50,默认值为 0)会在点位不属于任何国家时,匹配该距离内最近的国家,适用于港口、码头和海岸线点位;缓冲匹配会携带country.distanceInKm,而附近地点和时区查询仍使用精确点位nearby会列出最近的有人居住地点(nearbyLimit为 0–1,000,默认值为 5;每次调用最多返回 50 个,半径内还有更多地点时会显示提示;radiusKm最大为 300,默认值为 20;可选的cities等级);若设置了featureClasses/featureCodes,则会列出该类型的最近地理要素;nearbyKind会说明类型。featureClasses和featureCodes的筛选条件取交集- 发起任何请求前,若存在筛选条件冲突则会失败,并返回
conflicting_filters(cities与地理要素筛选条件同时使用)、unknown_feature_code或feature_filter_mismatch(代码所属类别未列出,或列出的类别没有对应代码) includeTimezone会添加 IANA 标识符、UTC 时差、本地时间、日出和日落(仅近海位置会报告时差;两项日期均按标准时差报告)
geonames_find_postal_codes 工具
mode:code(需要postalCode)、place_name(需要placeName)或nearby(需要lat和lng;radiusKm最大为 30,默认值为 10);缺少必填字段,或在nearby模式下设置countries或大于 0 的offset,都会以mode_fields_mismatch失败countries筛选条件适用于code和place_name,可使用 ISO alpha-2、alpha-3 或数字代码(共 250 个国家代码,另含已废弃的AN、CS和YU;其他代码,例如EL或ZZZ,会以unknown_country_code失败)- 列出的国家还会返回 GeoNames 归属该国的领土文件(
GB还会返回 IM、JE 和 GG),每个邮政编码均使用其自身的countryCode;提示会列出页面上未包含在countries中的国家 limit为 1–1,000(默认值为 10),每次调用最多返回 100 条;若仍有更多结果,会显示提示;code和place_name支持分页,offset为 0–5000,若 5000 以内仍有更多行,则返回nextOffset;GeoNames 不提供总数,因此truncated表示是否还有更多行,而不是其数量- 覆盖 122 个国家;爱尔兰仅返回 Eircode 路由键,马耳他仅返回字母前缀
geonames_get_countries 工具
- 可按 ISO alpha-2、alpha-3 或数字代码筛选,最多指定 250 个
countries;也可按continent、nameContains筛选,或不设筛选条件以获取全部 250 个国家;limit为 1–1,000(默认值为 50),每次调用最多返回 250 条,并支持offset - 每行包含 ISO 和 FIPS 代码、
geonameId(可作为geonames_get_children的起始点)、首都、人口、面积、大洲、语言、货币、邮政编码格式及本土边界框;未知代码会列入notFound
geonames_list_reference 工具
topic:feature_classes(9 项)、feature_codes(684 项,可按featureClass筛选)或postal_countries(122 项,包含各国的邮政编码范围和数量);将featureClass与其他主题搭配使用会以filter_not_applicable失败nameContains、limit为 1–1,000(默认值为 100,每次调用最多返回 700 条,足以涵盖所有主题),以及offset;地理要素类别和代码已打包,不消耗额度
功能
基于 @cyanheads/mcp-ts-core 构建:支持 stdio 和 Streamable HTTP 传输、可插拔身份验证(none / jwt / oauth)、可切换存储(in-memory、filesystem、Supabase、Cloudflare KV/R2/D1)、结构化日志记录,以及可选的 OpenTelemetry 跟踪。
GeoNames 专属功能:
- 数据来自 GeoNames,采用 CC BY 4.0 许可:传递结果时必须注明 GeoNames。此服务独立于 GeoNames。
- 每个账户每小时限制 1,000 次请求;超出配额后会进入冷却期,且仅影响该账户
- 响应在不同调用方之间共享缓存:搜索缓存 1 小时,时区不缓存,其他所有查询缓存 24 小时。命中缓存不会消耗配额
- 宽松的输入格式:支持 alpha-3 和数字国家代码、用
UK表示GB,以及用FL表示LI。服务还接受其公开的 schema 未列出的格式(以逗号连接的列表字符串、枚举值和代码的其他大小写形式、P.PPLC类别前缀、GeoNames.org URL 或表示geonameId的 JSON 整数、邮政编码中的多余空格、用username表示geonamesUsername),但工具描述只提供规范格式,因为会验证参数的客户端会拒绝其他格式
适合 Agent 的输出:
- 类型化失败原因会区分调用方账户(
caller_account_rejected)和运营方账户(server_account_rejected)、已耗尽的配额(quota_exhausted,其data.window为hour、day、week或local),以及被 GeoNames 拒绝的值(upstream_rejected_parameter) - 未知 ID 会返回
found: false和guidance,而不是错误;空白或不完整的分页结果会附带notice,指出下一个offset或应放宽的筛选条件 - 对于 GeoNames 用来表示“无”的占位值(
population: 0、空管理区名称、geonameId: 0),会直接丢弃,不会当作事实报告
已知限制:
- 共享部署会共享配额。 所有未使用自有用户名的调用方共享服务端账户每小时 1,000 次的配额。一阵反向地理编码请求(每次最多消耗 7 个配额)就可能耗尽配额,而且 GeoNames 不会说明配额何时重置。
- 免费层级的搜索和邮政编码搜索最多可查到
offset5000,每页最多 100 行,因此最多可访问结果集中的第 5,100 行。附近邮政编码查询不支持分页。 - 每个父项最多返回 1,000 个子项。
- 邮政编码数据涵盖 122 个国家。 爱尔兰和马耳他只返回代码前缀。美国的附近查询会将第一行放在查询点,而不是 ZIP 代码质心处。
- 附近查询半径上限为 300 km(地点和地理要素)和 30 km(邮政编码),这是 GeoNames 免费层级的限制。
- 边界框不能跨越 180° 经线。 此类区域需拆分成两次搜索。
- 沿海点在未设置缓冲距离时可能会解析到海洋。 默认情况下,只有包含该点的国家才会匹配,因此,刚好位于海港或海岸线轮廓之外的点会返回海洋,而附近地点则位于陆地上。设置
coastalBufferKm(最高 50),即可匹配最近的国家;在海峡中,两岸任一侧都有可能匹配。 - 微型国家和飞地可能会解析到周边国家。 位于梵蒂冈城内的点会返回意大利。
- 最近的有人居住地点中可能包含城区和历史地点。 在人口稠密的城市中,最近的结果通常是
PPLX城区或PPLH前行政区;每行的featureCode会标明类型,cities则会将结果限制在超过指定人口级别的地点。 - 近海时区只提供时差。 海上没有 IANA ID、本地时间、日出或日落信息,两个日期的时差也都是标准时差(公海不实行夏令时)。
exact_name会匹配别名和历史名称,因此结果的name可能与查询内容不同:查询“Springfield”可能会返回密苏里州的 Plattsburg 或 Palmyra。- 数据由社区编辑,并按“原样”提供。 许多地理要素没有记录人口或海拔。
入门指南
公共托管实例
可使用公共实例:https://geonames.caseyjhand.com/mcp,无需安装。通过 Streamable HTTP 将任意 MCP 客户端指向该实例:
{
"mcpServers": {
"geonames-mcp-server": {
"type": "streamable-http",
"url": "https://geonames.caseyjhand.com/mcp"
}
}
}
如果调用未传入 geonamesUsername,则会使用托管实例的 GeoNames 账户,该账户每小时 1,000 个额度由所有此类调用者共享。传入你自己的 geonamesUsername,即可使用自己账户的额度。
自托管 / 本地
将以下内容添加到 MCP 客户端配置文件中,并用你的 GeoNames 用户名替换占位符。
{
"mcpServers": {
"geonames-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/geonames-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"GEONAMES_USERNAME": "your_geonames_username"
}
}
}
}
或者使用 npx(无需 Bun):
{
"mcpServers": {
"geonames-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/geonames-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"GEONAMES_USERNAME": "your_geonames_username"
}
}
}
}
或者使用 Docker:
{
"mcpServers": {
"geonames-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"-e", "GEONAMES_USERNAME=your_geonames_username",
"ghcr.io/cyanheads/geonames-mcp-server:latest"
]
}
}
}
如需使用 Streamable HTTP,请设置传输方式并启动服务:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 GEONAMES_USERNAME=your_geonames_username bun run start:http
# Server listens at http://localhost:3010/mcp
前提条件
- Bun v1.4.0 或更高版本(或 Node.js v24+)。
- 一个免费的 GeoNames 账户,并在其账户页面启用免费 Web 服务。在启用前,GeoNames 会拒绝该账户发出的调用。
安装
- 克隆仓库:
git clone https://github.com/cyanheads/geonames-mcp-server.git
- 进入目录:
cd geonames-mcp-server
- 安装依赖:
bun install
- 配置环境:
cp .env.example .env
# edit .env and set GEONAMES_USERNAME
配置
每次 GeoNames 调用都会消耗 GeoNames 账户的额度。GEONAMES_USERNAME 是服务端账户:一个免费 GeoNames 账户,且已在账户页面启用免费 Web 服务。每个工具也都接受 geonamesUsername,因此,共享部署的调用者可以使用自己的账户,而不是服务端账户。两者都未设置时,调用会以 username_required 失败;只有 geonames_list_reference 中内置的 feature_classes 和 feature_codes 主题无需账户即可使用。
免费账户每小时有 1,000 个额度,每天有 10,000 个额度。缓存查询不会消耗额度。
| 工具 | 每次调用的额度 |
|---|---|
geonames_search_places、geonames_get_place、geonames_get_hierarchy | 1 |
geonames_get_children | 1;当父级的行政列表未缓存时,tourism 或 dependency 为 2 |
geonames_find_postal_codes | 1(code、place_name;若未命中且传入 countries,则除非邮政覆盖列表已缓存,否则额外消耗 1);2(nearby) |
geonames_reverse_geocode | 包含性查询为 1(无论是否设置 coastalBufferKm);查找最近的有人居住地点额外消耗 3,查找最近的地理要素额外消耗 4;若没有国家包含该点或位于缓冲区内,则查询海洋额外消耗 1;查询时区额外消耗 1 |
geonames_get_countries | 每天 1;国家表会被缓存 |
geonames_list_reference | feature_classes 和 feature_codes 为 0;postal_countries 每天 1 |
| 变量 | 描述 | 默认值 |
|---|---|---|
GEONAMES_USERNAME | 当调用未传入 geonamesUsername 时使用的 GeoNames 账户。在 geonames.org 免费注册;在账户页面启用免费 Web 服务。 | 无 |
MCP_TRANSPORT_TYPE | 传输方式:stdio 或 http。 | stdio |
MCP_HTTP_PORT | HTTP 服务端口。 | 3010 |
MCP_SESSION_MODE | HTTP 会话模式:stateless、stateful 或 auto。.env.example 和 Docker 镜像设为 stateless。 | auto |
MCP_AUTH_MODE | 身份验证:none、jwt 或 oauth。 | none |
MCP_LOG_LEVEL | 日志级别(debug、info、warning、error 等)。 | info |
LOGS_DIR | 日志文件目录(仅限 Node.js)。 | <app-root>/logs |
LOG_TOOL_FAILURE_PAYLOADS | 记录每次失败的工具调用参数和结果,并按键名进行脱敏:GeoNames 用户名在 geonamesUsername、username 或任何包含 user 或 account 字样的相似键下都会被移除。 | false |
STORAGE_PROVIDER_TYPE | 存储后端:in-memory、filesystem、supabase、cloudflare-kv/r2/d1。 | in-memory |
OTEL_ENABLED | 启用 OpenTelemetry。 | false |
完整的可选覆盖项列表请参阅 .env.example。
运行服务
本地开发
-
构建并运行生产版本:
# One-time build bun run rebuild # Run the built server bun run start:http # or bun run start:stdio -
运行检查和测试:
bun run devcheck # Lints, formats, type-checks, and more bun run test # Runs the test suite
项目结构
| 目录 | 用途 |
|---|---|
src/index.ts | createApp() 入口:服务说明、工具注册、GeoNames 服务的设置与拆除。 |
src/config | 使用 Zod 解析和验证 GEONAMES_USERNAME。 |
src/mcp-server/tools | 八个工具定义(*.tool.ts)及其共用的输入(shared-inputs.ts)。 |
src/services/geonames | GeoNames 服务:获取边界、状态映射、重试、按账户控制请求间隔、响应缓存、解析器,以及打包的要素代码表和国家代码表。 |
src/utils | 用于清理 format() 输出及 enrichment 页脚内容中由 GeoNames 编写或回显调用方内容的内联文本。 |
tests/ | 单元测试和集成测试,结构与 src/ 对应。 |
docs/design.md | 设计说明:工具接口、凭证模型、上游行为。 |
开发指南
开发指南和架构规则请参阅 CLAUDE.md。简而言之:
- 处理函数抛出异常,框架负责捕获——工具逻辑中不使用
try/catch - 使用
ctx.log记录日志,使用ctx.state存储数据 - 在
src/mcp-server/tools/definitions/index.ts中注册新工具 - 封装外部 API 调用:验证原始数据 → 规范化为领域类型 → 返回输出架构;绝不捏造缺失字段
贡献
欢迎提交问题。提交前请运行检查和测试:
bun run devcheck
bun run test
许可证
本项目采用 Apache 2.0 许可证。详情请参阅 LICENSE 文件。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。