fnos-mcp
# fnos-mcp
将 [fnos-skill](https://github.com/Muwei-TA/fnos-skill) 的 `trim-cli` 封装为 [MCP](https://modelcontextprotocol.io) 服务器(基于 [FastMCP](https://gofastmcp.com)),让任何 MCP 客户端(Claude Desktop、Knot、Cursor 等)都能用自然语言管理飞牛 fnOS NAS。
## 功能覆盖
219 个 MCP 工具,覆盖 trim-cli 除 media 外的完整能力面:
| 模块 | 工具示例 |
| --- | --- |
| 认证 | `login`(OAuth 2.0 + PKCE)、`submit_auth_code`、`logout`、`whoami` |
| 系统 | `system_info`、`system_hardware`、`system_volumes`、`system_power_plan`、`system_details`(18 项聚合)、`system_timezone_list` |
| 文件 | `file_list`、`file_search`、`file_copy`、`file_upload`、`file_write_text`、`file_compress`、`file_extract`、`file_chown`、`file_acl_get/set`、`file_share_*`、`file_team_*`、`file_fav_*`、`file_trash_*` |
| 相册 | `photos_search`(AI 语义搜图)、`photos_detail`、`photos_preview_url` |
| 应用中心 | `app_list`、`app_store_search/list`、`app_install`、`app_install_fpk`、`app_update`、`app_task_status`、`app_task_action`、`app_config_*`、`app_openapi_*`、`app_guide_*` |
| Docker | `docker_containers`、`docker_images`、`docker_image_pull/inspect`、`docker_container_create/inspect/top/stats/update`、`docker_compose_ls/create/build/start/stop/delete/containers`、`docker_request` |
| 下载 | `download_list`、`download_add_uri`、`download_add_path`、`download_action`、`download_stats`、`download_request` |
| 日志 | `logger_list`、`logger_modules`、`logger_export`、`logger_clear`、`logger_archive_query/set`、`logger_debuglog`、`diagnostic_export` |
| 监控 | `monitor_cpu`、`monitor_memory`、`monitor_network`、`monitor_disk`、`monitor_gpu`、`monitor_npu`、`monitor_battery`、`monitor_fan`、`monitor_proc_info/services`、`monitor_metrics` |
| 网络 | `network_ssh_status`、`network_ssh_switch` |
| 电源 | `power_reboot`、`power_poweroff` |
| 存储 | `storage_overview`、`storage_disks`、`storage_free_disks`、`storage_removable`、`storage_disk_info/health/smart`、`storage_mount/umount` |
| 用户 | `user_list`、`user_info`、`user_add/mod/del`、`user_set_admin`、`user_unfreeze`、`user_frozen_list`、`user_groups`、`user_group_*`(增删改/成员管理) |
| 百度网盘 | `baidu_list`、`baidu_search`、`baidu_info`、`baidu_upload/download`、`baidu_move/copy`、`baidu_share_save`、`baidu_task_*`、`baidu_sync_*` |
| 原始 API | `raw_request`、`photos_raw_request`(兜底) |
## 安装
```bash
git clone https://github.com/Muwei-TA/fnos-mcp.git
cd fnos-mcp
python3 -m venv .venv
.venv/bin/pip install -e .
```
要求 Python ≥ 3.10。`vendor/trim-cli/` 已内置六平台二进制(Linux x64/arm64、macOS x64/arm64、Windows x64/arm64),开箱即用,无需单独安装 trim-cli。
## 配置 MCP 客户端
stdio 方式(推荐,适用于 Claude Desktop / Knot 等):
```json
{
"mcpServers": {
"fnos": {
"command": "/path/to/fnos-mcp/.venv/bin/python",
"args": ["-m", "fnos_mcp.server"]
}
}
}
```
HTTP 方式(先启动服务端 `fnos-mcp --transport http --port 8000`,客户端连 `http://127.0.0.1:8000/mcp`)。
## 首次登录(OAuth 2.0 + PKCE)
MCP 客户端中对话式完成:
1. 让客户端调用 `login`,参数给 `host`(如 `fnos.muwei.xyz`)和 `port`/`scheme`
2. 工具返回授权 URL,在浏览器打开、登录 fnOS 并确认授权
3. 把页面显示的一次性 code 告诉客户端,由 `submit_auth_code` 完成交换
也可以先在本机命令行手动登录(session 存在 `~/.config/trim-cli/`,MCP 服务共用):
```bash
vendor/trim-cli/trim-cli-linux-x64 --profile default --host <host> --port 443 --scheme https login
```
说明:
- 登录仅支持 OAuth 2.0 授权码 + PKCE,不处理账号密码
- 远程明文 HTTP 需 `allow_insecure_http=True`;自签 HTTPS 需 `tls_insecure=True`
- 会话 token 自动刷新;连续 401 时需重新登录
## 文件写入与 Compose 的坑(真机实测)
- `file_write_text` 会在服务端临时目录里以目标文件名建文件再上传,远端文件名与 `path` 一致
- `file_check_upload` 的 `overwrite` 默认是 `skip`(非破坏性):目标已存在时返回 `{"result":"succ","skip":1}`,原文件不动
- ⚠️ `file_check_upload(overwrite="replace")` 会**立刻把同名目标文件截断成 0 字节**,内容丢失且回收站里也没有。别用它"试探会不会冲突",要覆盖直接调 `file_upload`
- ⚠️ 预检在目标不存在时会留下 0 字节的 `<名字>.~#0` 占位文件。**不要用 `file_delete` 删它**:fnOS 的 rm 把 `X.~#0` 当作 X 的别名,会把同名目标文件一起删掉。占位文件会被后续 `file_upload` 覆盖,留着无害
- 创建 compose 项目:先把 yaml 写进项目目录,再 `docker_compose_create`,最后 `docker_compose_build` 才真正 `compose up -d`。`docker_compose_start` 只执行 `docker compose start`,新项目还没容器时必然失败。项目目录不能嵌套在自带 compose 文件的目录下(如 `/vol1/1000/docker` 自身有 `docker-compose.yml`),否则 errno `0x03200107`
## 已知问题(219 工具全量实测,fnOS 1.2.0800)
已在 0.4.2 修掉的 MCP 封装层 bug:
- `raw_request` 之前拼成 `raw <method> <request>`,而 CLI 只有 `raw <REQ>`,导致**任何调用都报 unexpected argument**;现在改为 `raw <REQ> [--json] --yes`
- `network_ssh_status` 之前调 `network ssh switch` 不带参数(CLI 要求必须给 `--enable`/`--disable`),**永远失败**;现在走原始端点 `appcgi.network.ssh.status`
- `file_usage` 的 `<VOL>` 只接受整数,之前文档写"1 或 /vol1",传 `vol1` 直接 `invalid digit`;现在统一抽取数字部分
- 失败结果之前以 `isError=false` + "命令失败(exit N)" 文本返回,客户端无法判断成败;现在抛 `ToolError`,正确置 `isError=true`
仍然存在(上游 trim-cli / fnOS API 限制,非本仓库能修):
- `file_delete` 是**硬删除**:文件不进 `.@#local/trash`,`file_trash_list` 查不到,`file_trash_restore` 返回 Restored 但文件不回来
- `file_search`、`file_usage` 调用时上游返回 `failed to call HTTP proxy .../ogh/ac/...`,功能不可用
- `app_*` 系列必须传 `app_list` 里的 `appName`(如 `fn-codeserver`),传 `name`(如 `code-server`)报 installed app not found
- `docker_container_create` 的 `cmd` 会被 trim-cli 按空格重新切分,`["sh","-c","sleep 300"]` 变成 `["sh","-c","sleep","300"]`;带空格的命令请走 `docker_request(containerCreate)`
- `docker_container_stats` 只认 64 位容器 ID,传容器名会静默返回 `{"result":"succ"}` 空壳
- `monitor_battery`(无电池)、`baidu_*`(网盘应用未运行,502)、`system_details` 部分子项(非官方硬件)会报错,属环境限制
## 安全设计
- 写操作命令一律显式传 `--yes`,避免 CLI 交互确认卡死 MCP 进程
- 危险操作(`power_reboot`、`file_trash_clear`、`file_team_trash_clear`、`logger_clear`、`user_del`、`docker_container_rm` 等)在工具描述中明确标注,由客户端侧决定是否二次确认
- 不封装 `media` 命令(fnos-skill 明确排除 Media API)
- 不封装 storage 池级破坏性操作(`create/stop/add-disk/remove-disk/replace-disk/extend/resize/format/eject`),需要时由管理员在 NAS 端操作;`user_change-password`(改密会作废 session)也未暴露
- `login` 使用 15 秒超时提取授权 URL 后返回,不阻塞 MCP 进程
## 项目结构
```
fnos-mcp/
├── fnos_mcp/
│ ├── cli.py # trim-cli 二进制引导与执行层
│ └── server.py # FastMCP 服务器与 219 个工具定义
├── vendor/trim-cli/ # 六平台 trim-cli 二进制(来自 fnos-skill fa21571)
├── pyproject.toml
└── README.md
```
## 致谢
- [fnos-skill](https://github.com/Muwei-TA/fnos-skill) 提供 trim-cli 与全部 fnOS API 能力
- [FastMCP](https://github.com/PrefectHQ/fastmcp) 提供 MCP 服务器框架
## License
MIT
TDQS
Scored across 219 tools
Many tools map to distinct resources, but overlap is frequent: app_task_cancel vs app_install_cancel/app_update_cancel/app_download_cancel/app_task_action, docker_request vs specific Docker tools, raw_request vs everything, and multiple file_share_* variants. Descriptions are detailed, but an agent still faces unclear boundaries on when to use generic fallbacks versus specific tools.
Nearly all tools use a consistent domain_action snake_case convention (file_list, docker_container_action, user_group_add), making names predictable. Minor deviations exist (login, logout, whoami, status_overview, raw_request) but do not seriously hinder readability.
219 tools is extreme for any server, far beyond the 50+ threshold for a severe mismatch; even a broad NAS OS surface does not justify this many, especially with numerous cancel/action variants and catch-all request tools. This volume will overwhelm an agent's selection process.
Coverage spans file operations, users/groups, apps, Docker, storage, network, monitoring, downloads, Baidu Netdisk, logs, and diagnostics, with a raw_request fallback for uncovered endpoints. Gaps remain around pool/volume creation, RAID/backup/snapshot, and network configuration, but core NAS lifecycle operations are broadly represented.