Metadata-Version: 2.4
Name: dhcckb-ancient-map
Version: 0.3.1
Summary: 古籍空间可视化 MCP 工具（fastmcp 2.x / LLM JSON 容错修复）— 接收古籍文本结构化抽取结果，自动修复 LLM 非标准 JSON 格式，通过三级级联地名解析补全坐标，生成交互式 HTML 可视化地图。
License-Expression: MIT
Keywords: ancient-text,chgis,digital-humanities,json-repair,llm,mcp,spatial-visualization
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: GIS
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.10
Requires-Dist: fastmcp<3.0,>=2.0
Requires-Dist: json-repair>=0.30.0
Provides-Extra: all
Requires-Dist: psutil>=5.0; extra == 'all'
Description-Content-Type: text/markdown

# 古籍空间可视化 MCP Server（fastmcp 2.x v0.2.0）

`dhcckb-ancient-map` 是一个 stdio 模式的 MCP Server（Python ≥ 3.10，依赖 `fastmcp>=2.0,<3.0`），接收古籍文本的结构化抽取结果（地点、空间关系、人物轨迹），通过**三级级联地名解析**自动补全坐标，生成自包含的交互式 HTML 可视化地图。

支持 Cherry Studio、Claude Desktop 等 MCP 客户端导入使用。

## 修订说明（v0.1.1 → v0.2.0）

本次修订目标：**从 mcp SDK 底层 API（`@server.list_tools()` / `@server.call_tool()`）迁移到 fastmcp 2.x 高层框架**，使用 `@mcp.tool()` 装饰器注册工具，Pydantic 模型定义输入 Schema。

### 核心变更

| 变更项 | 说明 |
|--------|------|
| **fastmcp 2.x 迁移** | 从 `mcp>=0.9.0` 迁移到 `fastmcp>=2.0,<3.0`，使用 `FastMCP` 实例和 `@mcp.tool()` 装饰器 |
| **Pydantic 模型** | Location、Relation、Agent、NaturalFeature、VisualizationData 等 Pydantic 模型定义工具输入 Schema |
| **简化传输层** | fastmcp 内置 stdio 传输管理、信号处理和异常捕获，移除手动 asyncio loop / transport 监听等 boilerplate |
| **工具注册** | 5 个 tool 直接从函数签名 + Pydantic 模型自动生成 JSON Schema |
| **向后兼容** | 工具名称、输入 JSON 结构和输出格式与 v0.1.1 完全兼容 |

### v0.1.1 遗产特性（全部保留）

| 特性 | 说明 |
|------|------|
| **全局异常捕获** | fastmcp 内置 + tool handler 统一 try-catch 保护 |
| **health_check 工具** | 返回 server 状态、运行时间、已注册 tool 列表和数量 |
| **diagnostics 工具** | 返回 Python 版本、平台信息、内存使用、依赖版本号、脱敏环境变量 |
| **structured JSON 日志** | 统一 JSON 行格式输出到 stderr |
| **[MCP:READY] 信号** | 初始化完成后向 stderr 写入 READY 信号行 |

### 验收标准

- ✅ Server 启动后 `list-tools` 调用 100% 成功（连续 10 次无错误）
- ✅ 5 个 tool 通过 `@mcp.tool()` 正确注册，fastmcp 自动生成 JSON Schema
- ✅ 任一 tool 实现抛出异常时，Server 进程不退出，返回结构化错误响应
- ✅ `health_check` tool 可供宿主在调用链前探测 Server 就绪状态
- ✅ 日志输出包含启动阶段、tools 注册、请求追踪等关键信息

## 功能概览

| 工具 | 说明 |
|------|------|
| `extract_and_visualize` | 接收完整结构化 JSON → 数据验证 → 坐标补全 → 生成 HTML |
| `generate_map` | 接收已验证数据（坐标齐全）→ 跳过解析直接渲染 HTML |
| `query_place` | 单独查询地名坐标，返回解析来源和年代范围 |
| `health_check` | 🆕 健康检查：返回 server 状态、运行时间、已注册 tool 列表和数量 |
| `diagnostics` | 🆕 诊断信息：返回 Python 版本、内存使用、依赖版本、脱敏环境变量 |

## 安装

```bash
uvx dhcckb-ancient-map
```

或在 MCP 客户端配置中添加：

```json
{
  "mcpServers": {
    "dhcckb-ancient-map": {
      "type": "stdio",
      "command": "uvx",
      "args": ["dhcckb-ancient-map"]
    }
  }
}
```

## 输入数据格式

```json
{
  "locations": [
    {
      "id": "loc1",
      "name": "长安",
      "type": "concrete",
      "coordinates": [108.94, 34.26],
      "year": -208,
      "description": "西汉都城"
    },
    {
      "id": "loc2",
      "name": "洛阳",
      "type": "concrete",
      "year": 200,
      "description": "东汉都城"
    }
  ],
  "relations": [
    {
      "from": "loc1",
      "to": "loc2",
      "type": "path",
      "trigger": "自长安至洛阳",
      "description": "东西交通"
    }
  ],
  "agents": [
    {
      "name": "司马迁",
      "color": "#d63031",
      "trajectory": ["loc1", "loc2"]
    }
  ],
  "natural_features": [
    {
      "feature_type": "mountain",
      "coordinates": [110.08, 34.49],
      "hint": "华山"
    }
  ],
  "mode": "auto",
  "title": "《史记》空间关系图",
  "source_text": "太史公自叙……"
}
```

### 字段说明

- **locations**: `type` 为 `concrete` 时 `coordinates` 可选（不提供则自动调用 API 查询），`abstract` 时无坐标仅有拓扑关系。
- **relations**: `from`/`to` 引用 `locations` 的 `id`，`type` 支持 `path`/`contain`/`direction`/`adjacent`/`distance`。
- **agents**: `trajectory` 是 `locations.id` 的有序序列。
- **natural_features**: 山脉、河流、森林等自然地理要素，作为背景装饰层渲染。
- **mode**: `auto`（自动选择）/ `gis`（GIS 地图）/ `topo`（拓扑图）/ `mixed`（混合叠加）。

## 三级级联地名解析

1. **内置坐标表**（`data/ancient_places.json`，63 个核心地名，人工校验）—— 命中则跳过 API
2. **CHGIS TGAZ API**（`http://tgaz.fudan.edu.cn/tgaz/placename`，免认证，覆盖前 222 年~1911 年）—— 带 `yr` 年份过滤
3. **GeoNames API**（`http://api.geonames.org/searchJSON`）—— 中文地名自动转拼音搜索，补充山川河流

## 渲染特性

- **三段式页面布局**：原典文本区 → 地名列表区 → 交互式地图区
- **古风配色**：宣纸暖色背景（`#f5f0e8`）、传统色系标注
- **标签防重叠**：8 个候选方向碰撞检测，选冲突最少方向放置，偏移时画引线
- **SVG 缩放平移**：鼠标滚轮以光标为中心缩放、拖拽平移、双击重置
- **自然地理装饰**：山脉（山形 SVG path）、河流（波浪线）、森林（树形符号），opacity=0.5 在关系线/轨迹下层渲染
- **动态缩放策略**：坐标范围小时按比例加 padding（range×0.5），范围大时加固定 padding
- **力导向布局**：存在 abstract 地点时自动切换拓扑图（纯 JS 实现，无 D3.js 依赖）
- **自包含 HTML**：所有 CSS/JS 内嵌，无外部 CDN 依赖，离线可用，适合长期存档

## 已知限制

### CHGIS API
- **城市内部小地名不准**：坊、里、曲、巷等小地名 API 解析普遍不准（实测《李娃传》长安坊名全部错误），需手动赋坐标。
- **朝代歧义**：同名地名存在朝代歧义，必须传 `yr` 参数做时间过滤。
- **山川类地名支持有限**：自然地名（山、河、湖）CHGIS 覆盖不完整，需用 GeoNames 补充。

### GeoNames API
- **拼音匹配不精确**：依赖中文→拼音转换，部分地名匹配不精确，可能返回错误结果。
- **古代地名覆盖不足**：GeoNames 主要收录现代地名，古代地名查询效果有限。

### 坐标解析
- 三级级联均无法解析的地名，坐标将设为 `[0, 0]`，需手动补充。
- 建议优先在 `data/ancient_places.json` 中补充常用地名坐标。

## 项目结构

```
dhcckb-ancient-map/
├── src/dhcckb_ancient_map/
│   ├── __init__.py
│   ├── server.py          # MCP Server 入口，注册 5 个 Tool（加固版）
│   ├── extractor.py       # 数据验证与增强
│   ├── geo_resolver.py    # 三级级联地名解析
│   ├── renderer.py        # HTML 渲染引擎
│   └── logger.py          # 🆕 结构化 JSON 日志模块
├── data/
│   └── ancient_places.json # 63 个核心地名坐标表
├── tests/
│   └── test_server.py     # 🆕 集成测试（启动→list-tools→各 tool 调用）
├── pyproject.toml
├── mcp-manifest.json
└── README.md
```

## 集成测试

```bash
# 运行集成测试（需要 uv 和 Python ≥ 3.10）
cd tests
python test_server.py
```

测试覆盖：
- Server 启动并检测 [MCP:READY] 信号
- `list-tools` 返回 5 个 tool
- `health_check` 返回 healthy 状态
- `diagnostics` 返回运行时信息
- `query_place` 参数校验
- `extract_and_visualize` / `generate_map` 数据校验

## 日志格式

所有日志以单行 JSON 格式输出到 stderr：

```json
{"timestamp": "2026-07-28T12:00:00.000Z", "level": "INFO", "logger": "dhcckb-ancient-map", "message": "server_ready", "extra": {"tools_count": 5}}
```

[MCP:READY] 信号行：

```json
{"timestamp": "2026-07-28T12:00:00.000Z", "level": "INFO", "logger": "dhcckb-ancient-map", "message": "[MCP:READY] Server is ready to accept connections", "extra": {"tools_count": 5, "uptime_ms": 123}}
```

## 许可

MIT License
