Metadata-Version: 2.4
Name: futurepath-mcp
Version: 0.1.0
Summary: 职途智航职业数据 MCP Server —— 真实数据接入层（GitHub 学习资源 + 百度百科岗位百科 + TBox 数据仓库自有数据）
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: mcp<2.0.0,>=1.9.0

# futurepath-mcp · 职途智航职业数据 MCP Server

职途智航（面向未来工作的 AI 职业导航与终身学习伙伴系统）的**真实数据接入层**。把真实外部数据与自有的 TBox 数据仓库数据封装成标准 MCP 工具，供蚂蚁百宝箱智能体 / 工作流通过插件节点调用。

## 一句话定位

| 组 | 工具 | 数据类型 | 来源 | 需 Key |
|---|---|---|---|---|
| A | `search_learning_resources` | 学习资源 | GitHub Search API（真实） | 否（可选 GITHUB_TOKEN 提额） |
| A | `fetch_career_info` | 岗位/职业百科 | 百度百科词条卡片接口（真实） | 否 |
| B | `get_user_long_term_memory` | 用户长期记忆 | TBox 数据仓库「百宝箱长期记忆-0514」 | 需 TBOX_TOKEN |
| B | `get_user_career_assets` | 用户职业资产 | TBox 数据仓库 `user_assets` | 需 TBOX_TOKEN |
| B | `get_user_resume` | 用户简历 | TBox 数据仓库 `user_resumes` | 需 TBOX_TOKEN |
| — | `list_data_sources` | 数据源自检 | — | 否 |

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

- **统一返回骨架**：`{status, data, source, degraded, notice, latency_ms}` —— 下游归一化逻辑零改动即可复用。
- **三级降级，永不静默**：`real`（实时 API）→ `snapshot`（本地快照，带 `as_of` 时效）→ `last_resort`（内置最小兜底）；每次返回都声明真实来源、说明降级原因，**绝不编造数据**。用户自有数据（B 组）不降级为假数据，读取失败只返回空并声明。
- **配置集中 + 快速失败**：密钥全走环境变量；缺 `TBOX_TOKEN` 不崩溃，B 组工具自动返回空并声明。
- **纯标准库 HTTP（urllib）**：不引入 requests，减小安装面；超时 + 网络错误处理。
- **stdio 协议红线**：日志一律走 stderr，绝不 print 到 stdout（避免污染 MCP 协议流）。

## 快速开始

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

# 2) 配置（可选，不配也能跑，B 组工具会返回空并声明）
cp .env.example .env      # 填入 TBOX_TOKEN

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

# 4) 离线自检（不联网，验证骨架、快照、降级链、解析逻辑）
python -m futurepath_mcp.server --selftest

# 5) 真机探测（需网络，真实调用 GitHub / 百度百科 / TBox）
python -m futurepath_mcp.server --live-test

# 6) 离线单测
python -m unittest discover -s tests -t . -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 futurepath_mcp.server

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

## 部署到百宝箱

**路线一：自部署 MCP（免发 PyPI，演示/联调推荐）**

1. 本地起 server：`python -m futurepath_mcp.server`（streamable-http @ `http://0.0.0.0:8000/mcp`）。
2. 用 cpolar / ngrok 把 8000 端口公网化。
3. 百宝箱控制台 → 新增 MCP Server → 选「自部署 MCP」→ 填公网 URL（如 `https://xxxx.cpolar.cn/mcp`）。

**路线二：百宝箱一键部署（需把包发布到 PyPI）**

前置：`futurepath-mcp` 已发布到 PyPI（`uv publish`）。之后在百宝箱面板选「百宝箱一键部署 MCP」+ uvx 安装，填：

```json
{
  "mcpServers": {
    "futurepath-mcp": {
      "command": "uvx",
      "args": ["--from", "futurepath-mcp", "futurepath-mcp"],
      "env": { "TBOX_TOKEN": "<你的TBOX_TOKEN>" }
    }
  }
}
```

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

## 环境变量

| 变量 | 默认 | 说明 |
|---|---|---|
| `TBOX_TOKEN` | 空 | 百宝箱数据仓库访问令牌。不填 → B 组工具返回空并声明 |
| `TBOX_API_BASE` | `https://open.tbox.alipay.com` | 百宝箱 API 地址 |
| `GITHUB_TOKEN` | 空 | 留空即可；未认证 search 限 10 次/分钟，触发限流自动降级快照 |
| `HTTP_TIMEOUT` | 8 | 单次外部请求超时秒数 |
| `MCP_TRANSPORT` | `streamable-http` | `streamable-http` \| `sse` \| `stdio` |
| `MCP_HOST` / `MCP_PORT` | `0.0.0.0` / `8000` | 仅 HTTP 形态生效 |

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

## 目录结构

```
mcp/futurepath-mcp/
├── futurepath_mcp/
│   ├── __init__.py
│   ├── config.py          # 配置加载（环境变量优先 + .env）
│   ├── tbox_client.py     # TBox 数据仓库读取客户端（纯 urllib）
│   ├── sources.py         # GitHub / 百度百科 + 三级降级链
│   ├── shaping.py         # 统一返回骨架 + 数据塑形（纯函数）
│   ├── server.py          # FastMCP + 6 个工具 + 诊断命令
│   └── data/
│       ├── career_info_snapshot.json        # 岗位百科快照（8 个职业）
│       └── learning_resources_snapshot.json # 学习资源快照（站点级链接）
├── tests/test_server.py   # 离线单测
├── test_client.py         # MCP 协议全链路联调
├── pyproject.toml
├── requirements.txt
└── .env.example
```

## ⚠️ 打包红线

- 依赖必须钉死 `mcp>=1.9.0,<2.0.0` —— mcp 2.x 把 `FastMCP` 改名为 `MCPServer`、API 不兼容。改依赖前先回归 `test_client.py`。
- `data/*.json` 已在 `pyproject.toml` 的 `package-data` 里声明，打包进 wheel 才能让 uvx 运行时读到快照。

## 合规红线

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