GeoOntology
БесплатноНе проверенA geographic ontology layer MCP server that exposes hierarchical relations, topological adjacency, toponym disambiguation, spatial operations, and geo-constrain
Описание
A geographic ontology layer MCP server that exposes hierarchical relations, topological adjacency, toponym disambiguation, spatial operations, and geo-constraint verification, enabling LLMs to reason with geographic structures instead of raw SQL.
README
地理本体层 MCP 服务器——让 LLM 用地理结构推理,而非裸 SQL。
为什么需要这个项目
现有 PostGIS MCP 服务器只暴露原始 SQL 查询能力。LLM 拿到的是行和列,不是"南京属于江苏"或"苏州与上海相邻"这样的地理结构知识。
GeoOntology-MCP 暴露的是地理本体层——层级关系、拓扑邻接、语义消歧、空间运算、属性对比,以及核心创新:地理约束校验。LLM 生成地理断言后,MCP 可以校验真伪并返回结构化纠错,驱动 LLM 自我修正。
LLM: "苏州与上海不相邻"
→ check_adjacency("320500", "310000")
← { valid: false, correction: "苏州市 与 上海市 相邻,共享边界 42.3km",
evidence: { shared_boundary_length_km: 42.3 } }
LLM: "我修正之前的说法,苏州与上海实际上是相邻的……"
架构
LLM Client ──MCP Protocol──► GeoOntology-MCP (TypeScript)
│
┌─────────┴─────────┐
│ Ontology Engine │
│ - 层级遍历 (KG) │
│ - 拓扑查询 (PostGIS)│
│ - 约束校验 (两层) │
│ - 空间运算 (PostGIS)│
│ - 路径搜索 (BFS) │
└─────────┬─────────┘
│
┌─────────────┴─────────────┐
│ │
Knowledge Graph (内存) PostGIS (持久化)
- 46,413 节点 - boundary geometries
- 44,956 BELONGS_TO 边 - admin_adjacency (预计算)
- 地名/拼音/英文索引 - admin_containment (预计算)
- admin_attributes (属性数据)
数据策略:知识图谱 JSON 在启动时加载到内存,处理所有层级关系和地名消歧(纯图遍历,O(depth));邻接关系通过 PostGIS ST_Touches 预计算后存入 admin_adjacency 表,查询时 O(1)。
工具一览(10 个)
查询类
| 工具 | 参数 | 说明 |
|---|---|---|
resolve_place |
name, context? |
地名消歧,支持中文、拼音、英文。返回候选列表(ID、层级位置、坐标),按相关性排序取 top-5 |
get_ancestors |
id |
向上遍历层级链(县→市→省),返回从直接父到顶级的有序数组 |
get_neighbors |
id |
查询同层级邻接区域,含共享边界长度 |
describe_region |
id, include_geometry?, geometry_tolerance_km? |
区域全景:层级位置、邻居、面积、类型、子区数量,可选返回简化 GeoJSON |
校验类(核心差异化)
| 工具 | 参数 | 说明 |
|---|---|---|
check_containment |
child_id, parent_id |
验证包含关系,KG 层级检查 + PostGIS 空间回退 |
check_adjacency |
id_a, id_b |
验证邻接关系,预计算表 + 实时空间回退 |
空间运算类
| 工具 | 参数 | 说明 |
|---|---|---|
find_path |
id_a, id_b, max_hops? |
BFS 搜索两区域间的邻接路径(如 江苏→浙江) |
measure_distance |
id_a, id_b |
两区域质心间距离 (km) |
find_within |
id, radius_km |
查找半径内的同层级区域 |
属性对比类
| 工具 | 参数 | 说明 |
|---|---|---|
compare_regions |
ids[], metric |
多区域属性排名对比(人口/GDP/面积) |
校验返回格式
校验通过:
{
"valid": true,
"claim": "南京市 属于 江苏省",
"explanation": "层级关系确认: 南京市(city) → 江苏省(province)"
}
校验失败 + 纠错:
{
"valid": false,
"claim": "南京市 属于 浙江省",
"explanation": "南京市 不属于 浙江省,实际属于 江苏省(province)",
"correction": "实际归属: 南京市 属于 江苏省(province)",
"evidence": {
"actual_parent_id": "320000",
"actual_parent_name": "江苏省",
"actual_parent_level": "province"
}
}
这种结构化返回使 LLM 能理解错误原因并自我修正——这就是地理约束驱动的推理精炼环。
地名消歧(多语言)
resolve_place 支持三级匹配:
- 中文精确/模糊匹配 — "南京"、"南京市"、"江宁"
- 拼音匹配 — "nanjing"、"jss"(首字母)、"jiangsusheng"
- 英文别名匹配 — "Nanjing"、"Jiangsu"、"Canton"
拼音索引使用 pinyin-pro 库在启动时构建,英文别名覆盖所有省和主要地级市(~60 个)。
Skills
GeoRiddle(地理谜题推理)
skills/geo-riddle/SKILL.md 定义地理谜题推理工作流。LLM 解谜时自动调用 MCP 工具逐步缩小候选范围:
谜题: "我是江苏省面积最小的与安徽接壤的地级市"
→ get_children("320000") → 获取江苏所有地级市
→ describe_region(每个市) → 获取面积
→ check_adjacency(每个市, "340000") → 筛选与安徽相邻的
→ 综合约束得出答案: 南京市
5 道示例谜题(1-5 分难度),每道附带完整 solution trace。
GeoFactCheck(地理断言校验)
skills/geo-fact-check/SKILL.md 定义 LLM 输出中的地理断言自动扫描与校验:
- 扫描 — 识别包含/邻接/否定断言模式
- 提取 — 解析为 (subject, relation, object) 三元组
- 校验 — 调用
check_containment/check_adjacency - 报告 — verified / falsified / unverifiable 三类
支持中英文断言模式:
| 模式 | 示例 | 三元组 |
|---|---|---|
| X属于Y | "南京属于江苏" | (南京, BELONGS_TO, 江苏) |
| X与Y相邻 | "江苏与浙江相邻" | (江苏, ADJACENT_TO, 浙江) |
| X不属于Y | "南京不属于浙江" | (南京, NOT_BELONGS_TO, 浙江) |
MCP Resources
mapping_knowledge/mapping_resources/ 目录下的 JSON 文件自动注册为 MCP Resource,LLM 可按需读取制图知识:
projection-advice.json— 中国地图投影选择指南(Albers / Lambert / Web Mercator)admin-level-guide.json— 行政区划层级体系及编码规则
添加新 JSON 文件即可扩展,无需代码改动。
校验机制(双层)
- 层级检查(KG 内存遍历):遍历
parentOf链,O(depth) ≈ 最多 4 次查找。无需数据库查询。 - 空间回退(PostGIS
ST_Contains/ST_Touches):当 ID 不在 KG 中或需要空间验证时使用。单次查询约 16-23ms。
前置条件
- Node.js 18+
- PostgreSQL + PostGIS 扩展
- 本地 PostGIS 数据库包含中国行政区划表(
province,city,county,village) - 知识图谱 JSON 文件(
admin_knowledge_graph.json)
数据库表结构
项目连接的 PostGIS 数据表:
| 表名 | 名称列 | 区划码列 | 几何列 |
|---|---|---|---|
province |
省 |
省级码 |
geom |
city |
地名 |
区划码 |
geom |
county |
地名 |
区划码 |
geom |
village |
name |
area_code |
geom |
预计算表(npm run materialize 创建):
| 表名 | 说明 |
|---|---|
admin_adjacency |
邻接关系(70 + 963 + 8134 对) |
admin_containment |
包含关系闭包(预留) |
admin_attributes |
区域属性(人口/GDP/面积) |
安装与运行
# 安装依赖
npm install
# 首次运行:预计算邻接表(约 30 秒)
npm run materialize
# 导入属性数据(人口/GDP/面积)
npx tsx scripts/materialize-attributes.ts
# 启动 MCP 服务器
npm run dev
启动后输出:
Loading knowledge graph...
Loaded 46413 nodes, 44956 edges
Connecting to PostGIS...
PostGIS connected
Registered 2 mapping resources
GeoOntology-MCP server running
配置
环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
KG_PATH |
(required) | 知识图谱 JSON 路径 |
MAPPING_RESOURCES_DIR |
mapping_knowledge/mapping_resources |
制图知识资源目录 |
PGHOST |
127.0.0.1 |
PostgreSQL 主机 |
PGPORT |
5432 |
PostgreSQL 端口 |
PGDATABASE |
(required) | 数据库名 |
PGUSER |
(required) | 数据库用户 |
PGPASSWORD |
(required) | 数据库密码 |
Claude Desktop / Claude Code 配置
{
"mcpServers": {
"geo-ontology": {
"command": "npx",
"args": ["tsx", "/path/to/GeoOntology-MCP/src/index.ts"],
"env": {
"KG_PATH": "/path/to/admin_knowledge_graph.json",
"PGHOST": "127.0.0.1",
"PGPORT": "5432",
"PGDATABASE": "your_database",
"PGUSER": "your_user",
"PGPASSWORD": "your_password"
}
}
}
}
使用示例
典型工作流:先消歧,再查询,最后校验
→ resolve_place(name="南京")
← [{ id: "320100", name: "南京市", level: "city", parentName: "江苏省", score: 104 }]
→ get_ancestors(id="320100")
← [{ id: "320000", name: "江苏省", level: "province", type: "省" }]
→ check_containment(child_id="320102", parent_id="320000")
← { valid: true, claim: "玄武区 属于 江苏省",
explanation: "层级关系确认: 玄武区(county) → 南京市(city) → 江苏省(province)" }
拼音/英文搜索
→ resolve_place(name="Nanjing")
← [{ id: "320100", name: "南京市", level: "city", score: 90 }]
→ resolve_place(name="jss")
← [{ id: "320000", name: "江苏省", level: "province", score: 40 }]
路径搜索
→ find_path(id_a="320000", id_b="330000")
← { found: true, path: ["320000", "330000"], pathNames: ["江苏省", "浙江省"],
hops: 1, totalBoundaryKm: 152.7 }
距离与范围查询
→ measure_distance(id_a="320100", id_b="330100")
← { idA: "320100", nameA: "南京市", idB: "330100", nameB: "杭州市",
distanceKm: 267.4, method: "centroid-to-centroid" }
→ find_within(id="320100", radius_km=200)
← [{ id: "330100", name: "杭州市", distanceKm: 267.4, ... }, ...]
属性对比
→ compare_regions(ids=["110000", "310000", "320000"], metric="population")
← { metric: "population", regions: [
{ id: "320000", name: "江苏省", value: 85054000, rank: 1 },
{ id: "110000", name: "北京市", value: 21893095, rank: 2 },
{ id: "310000", name: "上海市", value: 24870895, rank: 3 }
] }
几何数据
→ describe_region(id="110000", include_geometry=true, geometry_tolerance_km=0.5)
← { id: "110000", name: "北京市", ..., geometry: { type: "Polygon", coordinates: [...] },
geometryToleranceKm: 0.5 }
项目结构
src/
index.ts # MCP 服务器入口
data-source/
interface.ts # GeoDataSource 接口 + 所有类型定义
postgis-adapter.ts # PostGIS 实现(核心适配器)
column-map.ts # 表名/列名映射 + inferLevel()
knowledge-graph/
types.ts # KG 节点/边类型(含拼音/别名字段)
loader.ts # KG JSON 加载 + 拼音索引 + 别名合并
english-aliases.ts # 省市英文名映射 (~60个)
ontology/
hierarchy.ts # 层级遍历(getAncestors, getChildren)
resolver.ts # 地名消歧(中文/拼音/英文四级匹配)
verifier.ts # 包含关系校验(KG 层级检查)
pathfinder.ts # BFS 路径搜索(纯函数)
tools/
registration.ts # 10 个工具注册到 McpServer
resources/
registration.ts # MCP Resource 注册(mapping_knowledge)
scripts/
materialize-adjacency.ts # 邻接预计算脚本
materialize-attributes.ts # 属性数据导入脚本
skills/
geo-riddle/SKILL.md # GeoRiddle 谜题推理 skill
geo-fact-check/SKILL.md # GeoFactCheck 断言校验 skill
mapping_knowledge/
mapping_resources/ # MCP Resource JSON 文件
projection-advice.json # 投影选择指南
admin-level-guide.json # 行政区划编码规则
data/
admin-attributes.csv # 省级属性数据(人口/GDP/面积)
tests/
knowledge-graph.test.ts # KG 加载器测试
hierarchy.test.ts # 层级遍历测试
resolver.test.ts # 地名消歧测试
verifier.test.ts # 校验逻辑测试
column-map.test.ts # 列映射测试
pinyin-resolver.test.ts # 拼音消歧测试
path.test.ts # BFS 路径搜索测试
fixtures/
sample-kg.json # 测试用样本 KG
可插拔数据源
所有工具通过 GeoDataSource 接口访问数据,PostGIS 只是默认实现:
interface GeoDataSource {
connect(): Promise<void>;
close(): Promise<void>;
getRegionInfo(id: string): Promise<RegionInfo | null>;
getAncestors(id: string): Promise<HierarchyNode[]>;
getChildren(id: string): Promise<HierarchyNode[]>;
getNeighbors(id: string): Promise<AdjacencyResult[]>;
checkContainment(childId: string, parentId: string): Promise<VerificationResult>;
checkAdjacency(idA: string, idB: string): Promise<VerificationResult>;
resolvePlace(name: string, context?: string): Promise<PlaceCandidate[]>;
findPath(idA: string, idB: string, maxHops?: number): Promise<PathResult>;
getRegionGeometry(id: string, toleranceKm?: number): Promise<RegionGeometry | null>;
measureDistance(idA: string, idB: string): Promise<DistanceResult | null>;
findWithin(id: string, radiusKm: number): Promise<WithinResult[]>;
getAttributes(id: string): Promise<RegionAttributes | null>;
compareRegions(ids: string[], metric: 'population' | 'gdp' | 'areaSqKm'): Promise<CompareResult>;
}
测试
npm test
50 个单元测试覆盖:KG 加载器、层级遍历、地名消歧(中文+拼音)、校验逻辑、列映射、BFS 路径搜索。测试使用 tests/fixtures/sample-kg.json 样本数据,无需连接数据库。
技术栈
- TypeScript + ESM (
@modelcontextprotocol/sdk) - pg — PostgreSQL/PostGIS 客户端
- pinyin-pro — 拼音转换
- zod — 工具参数校验
- Vitest — 单元测试
License
MIT
Установка GeoOntology
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/kevics1/GeoOntology-MCPFAQ
GeoOntology MCP бесплатный?
Да, GeoOntology MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для GeoOntology?
Нет, GeoOntology работает без API-ключей и переменных окружения.
GeoOntology — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить GeoOntology в Claude Desktop, Claude Code или Cursor?
Открой GeoOntology на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
wenb1n-dev/SmartDB_MCP
A universal database MCP server supporting simultaneous connections to multiple databases. It provides tools for database operations, health analysis, SQL optim
автор: wenb1n-devPostgres Server
This server enables interaction with PostgreSQL databases through the Model Context Protocol, optimized for the AWS Bedrock AgentCore Runtime. It provides tools
автор: madhurprashPostgres
Query your database in natural language
автор: AnthropicPostgreSQL
Read-only database access with schema inspection.
автор: modelcontextprotocolCompare GeoOntology with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории data
