netdisk-organizer-mcp
README.md
# netdisk-organizer-mcp
> **官方是地基,本 MCP 是二楼。**
百度官方已把"碰网盘"做成了标准 MCP 数据层(`baidu-netdisk`,SSE: `https://mcp-pan.baidu.com/sse`)。
本项目**不重新实现任何网盘协议**,只在官方数据层之上叠加三层整理智能:
- **语义层**:`pan_scan` / `pan_events` / `pan_ask` —— 事件聚类 + 跨目录认领孤儿照片,补官方 `file_keyword_search` 答不了"去年暑假度假的照片在哪"的缺口
- **安全层**:不提供 delete tool;`pan_move` 内置 `protect_patterns` 拦截(珍藏/合同/发票直接拒绝);journal 自动留痕 + `pan_undo` 可回滚
- **个性化层**:`pan_profile` + 可移植的 `profiles/` 偏好文件,各用户各改各的,互不干扰
---
## 目录
- [快速开始](#1-快速开始)
- [架构](#2-架构)
- [环境要求](#3-环境要求)
- [安装](#4-安装)
- [配置](#5-配置)
- [工具清单(21 个)](#6-工具清单21-个)
- [个性化](#7-个性化)
- [安全模型](#8-安全模型)
- [获取 Access Token](#9-获取-access-token)
- [项目结构](#10-项目结构)
- [开发与测试](#11-开发与测试)
- [License](#12-license)
---
## 1. 快速开始
```bash
# 1. 安装
git clone <your-repository-url> # 替换为你的仓库地址
cd netdisk-organizer-mcp
pip install -e .
# 2. 配置 token(见「获取 Access Token」)
export BAIDU_NETDISK_ACCESS_TOKEN="你的AccessToken"
export NETDISK_BACKEND="official" # 默认值,可省略
# 3. 启动 MCP server(stdio)
python server.py
```
然后在你的 MCP 客户端(WorkBuddy / Trae / Claude / Cursor 等)里注册连接器,即可开始使用。
---
## 2. 架构
```
┌─────────────────────────────────────────────────────────────┐
│ 你的 agent(WorkBuddy / Trae / 任何标准 MCP 客户端) │
└───────────────┬─────────────────────────────────────────────┘
│ stdio MCP
┌───────────────▼─────────────────────────────────────────────┐
│ netdisk-organizer-mcp (本仓库 · 二楼 · 整理智能) │
│ pan_scan/events/ask/stat/issues · pan_move/undo/history │
│ pan_profile · pan_mkdir/save/quota/semantic │
└───────────────┬─────────────────────────────────────────────┘
│ 委托(OfficialDataClient / BaiduBackend)
┌───────────────▼─────────────────────────────────────────────┐
│ 官方数据层(地基 · 百度维护 · 标准 MCP) │
│ file_list / file_move / upload_by_url / get_quota / │
│ file_semantics_search / make_dir ... │
└─────────────────────────────────────────────────────────────┘
```
**边界原则**:本仓库只做"整理",绝不复刻"增删改查"。任何纯数据 I/O 都委托给官方数据层。
| 模块 | 职责 |
|---|---|
| `server.py` | MCP stdio server 入口,工具路由 |
| `index.py` | 语义层:扫描 → 打标 → 事件聚类 → 结构化检索 |
| `ops.py` | 安全层:move / undo / history,journal 留痕 |
| `io_ops.py` | 数据层薄封装:委托官方 file_* 工具 |
| `backend.py` | 后端抽象:OfficialDataClient / BaiduBackend / LocalBackend |
| `profiles/` | 可移植整理偏好(JSON),加载 + 严格校验 |
---
## 3. 环境要求
| 依赖 | 版本 |
|---|---|
| Python | ≥ 3.12 |
| `mcp` | ≥ 1.0.0 |
| `httpx` | ≥ 0.27.0 |
| `anyio` | ≥ 4.0.0 |
| `python-dotenv` | ≥ 1.0.0 |
sdk 兜底后端(`NETDISK_BACKEND=sdk`)额外需要:`urllib3` / `certifi` / `six` / `python-dateutil`。
---
## 4. 安装
```bash
git clone <your-repository-url>
cd netdisk-organizer-mcp
pip install -e . # 或 uv sync
# 若用 sdk 兜底后端(NETDISK_BACKEND=sdk):
pip install -e ".[sdk]"
```
---
## 5. 配置
本 server 是**标准 MCP stdio server**,`mcpServers` 的 JSON schema 所有客户端通用 —— 差异只在配置文件存放路径(各客户端约定),不在本项目的分叉。
```json
{
"mcpServers": {
"netdisk-organizer": {
"command": "python",
"args": ["/absolute/path/to/netdisk-organizer-mcp/server.py"],
"env": {
"BAIDU_NETDISK_ACCESS_TOKEN": "你的AccessToken",
"NETDISK_BACKEND": "official",
"NETDISK_DATA_MCP_URL": "https://mcp-pan.baidu.com/sse"
}
}
}
}
```
| 客户端 | 配置文件位置 |
|---|---|
| **WorkBuddy** | 设置 → 连接器 → 添加自定义连接器(stdio 模式) |
| **Trae** | 项目根 `.trae/mcp.json` 或 `~/.trae/mcp.json` |
| **Claude** | `.mcp.json` |
| **Cursor** | `~/.cursor/mcp.json` |
| 其他标准 MCP 客户端 | 同一段 JSON,仅文件路径不同 |
> 若用 `uv` 管理:把 `command` 改为 `uv`,`args` 改为 `["--directory","/absolute/path/to/netdisk-organizer-mcp","run","python","server.py"]`。
### 环境变量
| 变量 | 取值 | 说明 |
|---|---|---|
| `NETDISK_BACKEND` | `official`(默认)/ `sdk` | official=连官方数据层;sdk=vendored BaiduBackend 兜底 |
| `NETDISK_DATA_MCP_URL` | URL | 官方数据层端点,默认 `https://mcp-pan.baidu.com/sse` |
| `BAIDU_NETDISK_ACCESS_TOKEN` | token | `official` 模式必填;个人用户 OAuth 令牌,非应用凭证 |
| `NETDISK_SDK_PATH` | 目录 | 仅 sdk 模式可指定自定义 SDK 位置 |
| `NETDISK_PROFILE` | 名称/路径 | 指定整理偏好(见第 7 节),缺省用内置 `default` |
无 token 又传 `backend_root` → `LocalBackend`(本地测试 / mock,无需账号)。
---
## 6. 工具清单(21 个)
### 语义层(6 · 独有护城河,官方零覆盖)
| 工具 | 作用 | 改写官方 |
|---|---|---|
| `pan_scan` | 扫描网盘/目录建语义索引(事件聚类+标签传播) | 否 |
| `pan_scan_status` | 查看索引状态(已扫文件数/最后扫描时间/覆盖) | 否 |
| `pan_events` | 列出识别出的事件(旅行/节日/纪念/集中拍摄) | 否 |
| `pan_ask` | 结构化检索(时间窗+类别+标签+关键词) | 否 |
| `pan_stat` | 全盘体检报告(类别/来源/风险分级) | 否 |
| `pan_issues` | 扫描已索引数据返回发现(孤儿/垃圾/重复/命名混乱/大文件) | 否 |
### 安全层(3 · 独有护城河)
| 工具 | 作用 | 改写官方 |
|---|---|---|
| `pan_move` | 移动文件(内置 `protect_patterns` 拦截) | ✅ 包官方 `file_move` |
| `pan_undo` | 回滚指定批次的 move(LIFO) | 否 |
| `pan_history` | 查看可回滚的操作历史(按批次聚合) | 否 |
### 个性化层(1 · 独有护城河)
| 工具 | 作用 | 改写官方 |
|---|---|---|
| `pan_profile` | 读取当前生效的整理偏好(只读) | 否 |
### 数据层薄封装(11 · 官方对等,零逻辑复刻)
| 工具 | 作用 | 改写官方 |
|---|---|---|
| `pan_mkdir` | 建整理用目标目录 | 委托 `make_dir` |
| `pan_save` | 转存外链资源进收件箱 | 委托 `upload_by_url` |
| `pan_quota` | 读取容量使用 | 委托 `get_quota` |
| `pan_semantic` | 透传官方语义检索 | 委托 `file_semantics_search` |
| `pan_search_keyword` | 按文件名关键词搜索 | 委托 `file_keyword_search` |
| `pan_meta` | 获取文件详情(按 fs_id,最多 10) | 委托 `file_meta` |
| `pan_upload_text` | 把一段文本直接写成网盘文件 | 委托 `file_upload_by_content` |
| `pan_copy` | 复制文件(`ondup=newcopy` 防覆盖) | 委托 `file_copy` |
| `pan_share_link` | 创建文件分享链接 | 委托 `file_sharelink_set` |
| `pan_user` | 获取已鉴权用户信息(头像/会员/UID) | 委托 `user_info` |
| `pan_del` | 删除/移入回收站 | 委托 `file_del`(⚠️ 见下) |
> **`pan_del` 使用警示**:官方 SSE 数据层**未暴露删除**(仅 vendored `sdk` 后端可用),且删除风险系数高。作者立场:**不把它作为默认分发能力** —— 清理请走隔离目录 `/_待清理_/`(profile 的 `quarantine_dir`)+ 用户手动删除;`pan_del` 仅保留后端完整性,使用需自担风险,且 `pan_undo` 不支持回滚删除(回收站无恢复 API)。
> 官方 16 个数据工具已覆盖 15 个;唯一刻意不提供的是 `file_upload_stdio`(本地文件直传,web 场景用不到)。
### 使用示例
| 用户意图 | 工具调用 |
|---|---|
| 扫描我的网盘 | `pan_scan` |
| 2025年夏季时间段的照片在哪 | agent 解析为 `{years:[2025], months:[7,8], category:"照片", scene:"旅行"}` 调 `pan_ask` |
| 把截图归档到 /整理后/截图/ | `pan_move`(每个 move 自动写 journal) |
| 刚才那批撤回 | `pan_undo(batch=...)` |
| 转存这个链接 | `pan_save({url, to_folder})` |
---
## 7. 个性化
整理偏好是**纯 JSON**,放在 `profiles/`:
- `profiles/default.profile.json` —— 内置默认(保护规则 + 隔离目录 + 软偏好)
- `profiles/schema.json` —— JSON Schema,加载时严格校验(配置非法宁可失败,不带病动用户文件)
自定义:复制 `default.profile.json` 改名,运行时设 `NETDISK_PROFILE=我的.profile.json`。
可改项:额外 `protect_patterns`(永不移动的路径/关键词)、`never_touch`(前缀黑名单)、`quarantine_dir`(清理隔离区)、`preferences`(软偏好,如默认按事件聚类)。
> **内置保护规则不可被 profile 关闭** —— 这是铁律,防止误配把重要文件挪走。
---
## 8. 安全模型
1. **永不删除**:不暴露 delete tool,清理只能 move 到隔离目录
2. **move 内置保护**:`protect_patterns` / `never_touch` 命中直接拒绝(珍藏/纪念/毕业/合同/发票/身份证/微信备份…)
3. **journal 自动留痕**:每次 move 记录,undo 一键回滚(LIFO)
4. **凭证不入库**:token 走 env / `.env`(`.gitignore` 屏蔽),绝不提交
5. **防提示注入**:不提供读取文件内容的工具,文件名当不可信数据
---
## 9. 获取 Access Token
MCP 配置里要的是**「用户」令牌**(代表某百度账号授权访问其网盘),不是开放平台的「应用」凭证(AppKey/SecretKey 不能直接当 token 用)。
个人使用:用你自己的 AppKey + SecretKey 走一次 OAuth,把**你自己的网盘**授权给应用。
```bash
pip install requests
python tools/get_baidu_token.py --app-key 你的AppKey --app-secret 你的SecretKey
# 打开打印的验证 URL,登录百度账号授权 → 脚本自动拿到 access_token / refresh_token
```
token 约 30 天有效;过期用 `--refresh` 续期。(个人应用最多授权 10 个账号,自用绰绰有余。)
> ⚠️ 脚本会**在终端打印** access_token / refresh_token。请勿把终端输出截图发给他人,token 等同于你的网盘访问权限。
---
## 10. 项目结构
```
netdisk-organizer-mcp/
├── server.py # MCP stdio server 入口,工具路由
├── index.py # 语义层:扫描/事件聚类/检索/体检
├── ops.py # 安全层:move/undo/history + journal
├── io_ops.py # 数据层薄封装(委托官方)
├── backend.py # 后端抽象(Official/Baidu/Local)
├── tools/
│ └── get_baidu_token.py # OAuth 设备码取 token 脚本
├── profiles/
│ ├── __init__.py # profile 加载器 + 严格校验
│ ├── default.profile.json # 内置默认偏好
│ └── schema.json # JSON Schema
├── openapi_client/ # vendored 官方 SDK(sdk 兜底模式用)
├── pyproject.toml
├── .env.example # 环境变量模板
└── .gitignore
```
---
## 11. 开发与测试
```bash
pip install -e ".[dev]"
python -m pytest -q
```
> **说明**:当前分享版为精简裁剪,**未包含测试套件与 CI 配置**。若需完整开发环境,请基于 `backend.py` 的 `FakeDataClient` 注入点自行补充单元测试(可离线验证代理逻辑,无需真实 token / 网络)。
---
## 12. License
[MIT](LICENSE)
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues