Metadata-Version: 2.4
Name: russel-travel-safety-mcp-2026
Version: 0.2.4
Summary: Allowlist-only MCP server and Qwen travel-advice aggregator
License: MIT
Requires-Python: >=3.11
Requires-Dist: httpx<1,>=0.28
Requires-Dist: mcp<2,>=1.27
Description-Content-Type: text/markdown

# Travel Safety MCP

一个仅访问固定官方来源的旅行安全 MCP 服务。Agent 只能传入国家、别名和日期，不能传入任意 URL。

## 工具

- `get_current_time`
- `search_china_consular_alert_url`：极简版，只输入国家/地区，返回最新匹配的中国领事服务网安全提醒 URL
- `search_china_consular_alert_urls`：只在中国领事服务网“安全提醒”栏目页内查找指定国家/地区的详情页 URL
- `search_four_travel_advisories`：输入一次国家名称，后台并行调用千问联网检索 Agent 四次并合并结果
- `search_basic_advisories`
- `search_health_events`
- `search_disaster_events`
- `search_conflict_events`

## 中国领事服务网站内 URL 查找

当百炼全网搜索无法稳定召回 `cs.mfa.gov.cn` 原始详情页时，优先使用：

```json
{
  "country": "日本"
}
```

如果需要候选列表和别名匹配，再使用复数版：

```json
{
  "country": "日本",
  "aliases": ["日本国"],
  "max_results": 5,
  "max_pages": 1
}
```

返回示例：

```json
{
  "country": "日本",
  "aliases": ["日本", "日本国"],
  "candidates": [
    {
      "title": "提醒中国公民近期避免前往日本",
      "date": "2026-03-26",
      "url": "https://cs.mfa.gov.cn/gyls/lsgz/lsyj/202603/t20260326_11881693.shtml",
      "matched_term": "日本",
      "source_index_url": "https://cs.mfa.gov.cn/gyls/lsgz/lsyj/"
    }
  ],
  "selected": {
    "title": "提醒中国公民近期避免前往日本",
    "date": "2026-03-26",
    "url": "https://cs.mfa.gov.cn/gyls/lsgz/lsyj/202603/t20260326_11881693.shtml",
    "matched_term": "日本",
    "source_index_url": "https://cs.mfa.gov.cn/gyls/lsgz/lsyj/"
  },
  "errors": []
}
```

百炼工作流中，下一步“读取详情页”节点引用 `selected.url`。

## 千问四站聚合工具

`search_four_travel_advisories` 的最小输入只有国家名称：

```json
{
  "country": "日本"
}
```

可选传入时间 MCP 返回的日期和英文国名：

```json
{
  "country": "日本",
  "current_date": "2026-07-07",
  "country_en": "Japan"
}
```

服务会在后台并行执行中国领事服务网、澳大利亚 Smartraveller、英国
Foreign Travel Advice、美国 Travel.State.Gov 四次定向检索，只向 Agent 返回
一次合并 JSON。非目标域名 URL 会被拒绝；每个候选 URL 还必须实际访问成功，
并通过页面标题或国家正文匹配。千问未召回或返回假 URL 时，服务自动从对应官网
目录发现并读取真实链接。只有 `status=FOUND_VERIFIED` 的页面可以用于回答，
事实依据以 `official_excerpt` 为准。

运行前配置环境变量：

```bash
export DASHSCOPE_API_KEY="sk-你的百炼APIKey"
export QWEN_WEB_SEARCH_AGENT_ID="aid-你的联网检索应用ID"
export QWEN_WEB_SEARCH_AGENT_VERSION="release"
```

可选配置：

```bash
export QWEN_WEB_SEARCH_TIMEOUT_SECONDS="180"
export QWEN_WEB_SEARCH_MAX_RETRIES="1"
```

密钥只能通过环境变量或阿里云密钥管理注入，不要写入代码、提示词或发布包。

所有检索工具都会返回来源状态。`error` 表示访问失败，`no_match` 表示当前页面没有找到国家匹配，Agent 不得把这两种状态描述为“没有风险”。

## 安全边界

- 起始网页固定在 `config.py` 中。
- 只允许 HTTPS 443 和精确匹配的白名单域名。
- 每一次重定向都会重新检查域名。
- 拒绝解析到私网、环回、链路本地等非公网地址的域名。
- HTTP 客户端不读取系统代理配置。
- 单个响应最多 2 MB，最多跟随 5 次白名单内重定向。
- 工具不接受 URL 参数。

代码白名单可以控制 MCP 自己发出的请求。生产环境仍建议通过 VPC 出站代理或云防火墙实施“默认拒绝、按域名放行”的网络策略。

## 本地运行

需要 Python 3.11 以上和 `uv`：

```bash
uv sync
uv run travel-safety-mcp
```

运行测试：

```bash
uv run python -m unittest discover -s tests -v
```

## 发布到 PyPI

百炼的 `uvx` 脚本部署需要从公开 PyPI 安装包。当前发布包名为 `russel-travel-safety-mcp-2026`，命令名为 `travel-safety-mcp`。

```bash
uv build
uv publish
```

不要在代码或发布包中保存 PyPI Token、百炼 API Key 或其他密钥。

## 百炼脚本部署

在 `MCP 管理 -> 创建 MCP 服务 -> 使用脚本部署` 中选择：

- 安装方式：`uvx`
- 部署方式：基础模式
- 地域：北京或最接近业务的地域

使用下面的包名和版本：

```json
{
  "mcpServers": {
    "travel-safety": {
      "command": "uvx",
      "args": [
        "--from",
        "russel-travel-safety-mcp-2026==0.2.4",
        "travel-safety-mcp"
      ]
    }
  }
}
```

## Agent 提示词片段

```text
每次国家查询必须先调用 get_current_time，时区固定为 Asia/Shanghai。
随后使用中文国名和英文国名调用相应检索工具。
近一年和近两年的起止日期必须根据 get_current_time 的 date 计算。
只允许使用本 MCP 返回的 pages 内容。
status 为 error 或 no_match 时，不得推测或补写；应说明指定网站未获取到相关信息。
不同基本网站风险描述冲突时，采用最高风险描述。
```

## 当前限制

第一版通过各官方网站的固定索引页发现国家相关链接。网站改版、JavaScript 渲染、验证码或反自动化策略都可能导致单一来源返回 `error` 或 `no_match`。后续应为失败率较高的网站增加专用适配器，而不是放开通用搜索或任意 URL 抓取。
