Metadata-Version: 2.4
Name: a02-career-data-mcp
Version: 0.2.1
Summary: A02 职业数据 MCP Server：招聘数据（聚合数据）/ 学习资源（GitHub）/ 职业趋势（快照）/ 职业百科（百度百科），三级降级链，来源全程可溯
License-Expression: MIT
Keywords: mcp,career,education,a02
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: mcp<2.0.0,>=1.9.0
Requires-Dist: pydantic>=2.0

# a02-career-data-mcp · 职业数据 MCP Server

> A02 项目（面向未来工作的 AI 职业导航与终身学习伙伴系统）的**真实数据接入层**。
> 把三类数据源封装成标准 MCP 工具，供蚂蚁百宝箱智能体 / 工作流通过插件节点调用。
> 本服务是 E8「MCP 对接说明」的核心取证素材。

## 一句话定位

| 工具 | 数据类型 | 数据来源 | 是否需要 Key |
|---|---|---|---|
| `fetch_company_jobs` | 招聘数据 | 聚合数据「企业招聘信息查询」**真实 API** | 需 `JUHE_KEY`（缺则降级快照） |
| `search_learning_resources` | 学习资源 | GitHub Search API **真实 API** | 不需要（可选 `GITHUB_TOKEN` 提额） |
| `fetch_career_stats` | 职业数据 | 本地快照（源自公开行业报告综述） | 不需要 |
| `fetch_career_wiki` | 职业百科 | 百度百科词条卡片接口 **真实 API** | 不需要 |
| `list_data_sources` | 数据源自检 | — | 不需要 |

## 核心设计（答辩可讲）

1. **统一返回骨架**：`{status, data, source, degraded, notice, latency_ms}`
   与 `a02-mock-career-mcp` 同构 —— 下游 N5 代码节点的归一化逻辑**零改动**即可复用。
2. **三级数据来源，永不静默降级**：
   `real`（实时 API）→ `snapshot`（本地快照，带 `as_of` 时效）→ `last_resort`（内置最小兜底）。
   每次返回都在 `source` 声明真实来源，`notice` 说明降级原因 —— **绝不编造数据**。
3. **配置集中 + 快速失败**：所有密钥来自环境变量；缺 key 不崩溃，该工具自动降级为快照。
4. **纯标准库 HTTP**（`urllib`），不引入 `requests`，减小安装面；超时 + 网络错误重试 1 次。
5. **stdio 协议红线**：日志一律走 stderr，**绝不 print 到 stdout**（会污染 MCP 协议流）。

## 快速开始

```bash
# 1) 安装依赖（在 mcp/career-data/ 目录下）
pip install -r requirements.txt

# 2) 配置密钥（可选，不配也能跑，招聘工具会降级为快照）
#    .env 会被自动读取；平台/系统已注入的同名环境变量优先
cp .env.example .env      # 然后填入 JUHE_KEY

# 3) 查看生效配置（排查「为什么降级了」）
python -m career_data_mcp.server --show-config

# 4) 离线自检（不联网，验证骨架与降级链）
python -m career_data_mcp.server --selftest

# 5) 真机探测（需网络，真实调用 GitHub / 聚合数据）
python -m career_data_mcp.server --live-test

# 6) 离线单测（46 例）
python -m unittest discover -s tests -v

# 7) MCP 全链路联调（握手 / 列工具 / 调用）
python test_client.py                                  # stdio，默认
MCP_TRANSPORT=streamable-http python test_client.py    # 自部署 HTTP 形态
```

## 启动服务

```bash
# 本地 HTTP（自部署路线，默认 http://0.0.0.0:8000/mcp）
python -m career_data_mcp.server

# stdio（百宝箱一键部署 / PyPI console-script 形态）
MCP_TRANSPORT=stdio python -m career_data_mcp.server
# 或装包后直接用入口：
career-data-mcp
```

## 环境变量

| 变量 | 默认 | 说明 |
|---|---|---|
| `JUHE_KEY` | 空 | 聚合数据 APPKey。不填 → `fetch_company_jobs` 降级快照 |
| `GITHUB_TOKEN` | 空 | **留空即可**。未认证搜索限 10 次/分钟（`core` 是 60 次/小时，`search` 单独计） |
| `CACHE_TTL` | `300` | 结果缓存秒数；相同请求在 TTL 内复用，命中时 notice 会声明。`0` = 关闭 |
| `MCP_TRANSPORT` | `streamable-http` | `streamable-http` \| `sse` \| `stdio` |
| `MCP_HOST` / `MCP_PORT` | `0.0.0.0` / `8000` | 仅 HTTP 形态生效 |
| `HTTP_TIMEOUT` | `8` | 单次外部请求超时秒数 |

> 配置来源：**自动读取包根 `.env`**（纯 stdlib 实现），**平台/系统已注入的同名环境变量优先** —— 因此云托管侧的 `env` 配置永远能覆盖本地 `.env`。用 `--show-config` 可随时确认生效值。

## ⚠️ 打包红线

**依赖必须钉死 `mcp>=1.9.0,<2.0.0`** —— `mcp` 2.x 把 `FastMCP` 改名为 `MCPServer`、API 不兼容（本项目实测踩坑）。
`pyproject.toml` 已钉死，改依赖前请先回归 `test_client.py`。

## 平台配置（百宝箱插件节点）

```json
{"mcpServers":{"career-data":{"command":"uvx","args":["--from","a02-career-data-mcp","career-data-mcp"],"env":{"JUHE_KEY":"<你的聚合数据KEY>"}}}}
```

> `uvx` 后面跟的是**可执行文件名**（`career-data-mcp`），包名必须用 `--from` 指定 —— 这是 uvx 的参数位规则，写错会报错。

完整接入步骤、发布流程与合规说明见 **`docs/30-职业数据MCP服务接入指南-A02.md`**。

## 目录结构

```
mcp/career-data/
├── career_data_mcp/
│   ├── __init__.py
│   ├── server.py                     # 四个 MCP 工具 + 三级降级链
│   └── data/
│       ├── career_stats_snapshot.json       # 职业数据快照（源自 kb2_trends）
│       ├── career_wiki_snapshot.json        # 职业百科快照（8 个职业，百度百科冻结）
│       └── learning_resources_snapshot.json # 学习资源快照（站点级链接）
├── tests/test_server.py              # 46 例离线单测
├── test_client.py                    # MCP 协议全链路联调
├── pyproject.toml
├── requirements.txt
└── .env.example
```

## 合规红线

- 所有响应均带 `source` 声明；快照与演示数据**不冒充**实时数据。
- 演示数据一律带「演示」标注。
- **不编造 URL** —— `detail_url` / `url` 一律原样来自接口返回。
- 真实密钥只存在于 `.env` / 环境变量，**绝不入库**。
