从旧版 PCS 到 MCP:百度网盘 API 这些年到底变了什么


最近翻旧代码,又碰到百度网盘 API。这个东西挺有年代感的:网上还能搜到很多 2020 年前后的脚本,里面一堆 PCS、xpan/file、分片上传、MD5、access_token

问题是,这些脚本现在直接跑,经常会卡在奇怪的地方。不是 OAuth 过不去,就是上传流程对不上;好不容易能列目录了,文件操作又开始返回看不懂的错误码。

刚好看到官方出了 baidu-netdisk/mcp,把百度网盘封装成 MCP Server。它提供文件列表、文件详情、上传、复制、删除、移动、重命名、搜索、分享链接、用户信息、容量查询这些工具。也就是说,现在不用每次都自己拼 REST 请求了,可以把网盘当成一组工具来用。

所以这篇就简单记一下:旧脚本为什么容易坏,MCP 这层到底帮我们省了什么,以及如果要把旧代码救回来,我会怎么改。

旧脚本为什么容易坏

以前很多脚本大概都是这个套路:

  1. 申请应用,拿 access_token
  2. xpan/file 或更早的 PCS 接口列目录
  3. 上传时自己算 MD5,自己走 precreate、分片上传、create
  4. copy/move/delete/rename 也都自己拼接口
  5. 搜索、分享、配额这些功能后面再补

这个写法当年没啥问题。脚本嘛,能跑就行。但几年过去以后,问题就来了:

  • 有些旧 PCS 接口不太适合新应用了。
  • 鉴权比以前严格,复制一个 token 长期跑不稳。
  • 上传不是简单 POST 文件,分片、预上传、block list、创建文件一步都不能少。
  • 路径编码很容易出事,中文路径尤其烦。
  • 返回字段越来越业务化,fs_id / fsidpathisdir、缩略图、摘要这些字段在不同接口里不完全一样。
  • 搜索也不只是文件名关键词了,现在还有语义搜索。

最麻烦的是,旧脚本坏起来通常不是坏一个点,而是一整条链都老了。你修好列目录,上传又挂;上传能跑了,路径编码又不对;路径对了,重名文件怎么处理又跟以前不一样。

MCP 更像一层工具封装

baidu-netdisk/mcp 里的工具大概可以分成几类:

类别MCP 工具做什么
文件信息file_listfile_doc_listfile_image_listfile_video_listfile_meta列目录、按类型列文件、查文件详情
文件管理make_dirfile_copyfile_delfile_movefile_rename创建目录和基本文件操作
上传file_upload_stdiofile_upload_by_url、文本上传本地文件、URL、文本内容上传
搜索file_keyword_searchfile_semantics_search关键词搜索和语义搜索
分享file_sharelink_set创建分享链接
用户user_infoget_quota用户信息和容量

我觉得这个方向挺合理。以前你要知道哪个接口负责预上传,哪个接口负责创建文件,哪个参数控制重名策略。现在你只要说“列目录”“上传文件”“搜索文件”,底下那些细节先交给工具处理。

当然 MCP 也不是魔法。路径还是路径,冲突策略还是冲突策略,上传也还是上传。它只是把这些麻烦集中到工具层,不用散在业务代码里到处处理。

修旧代码时我会先做 adapter

如果有一份旧脚本,我不会一上来就逐行换 URL。那样很容易变成考古,而且改完还是一堆接口细节到处飞。

我会先把旧代码里真正需要的动作抽出来,比如:

async function listDir(path) {}
async function uploadFile(localPath, remotePath) {}
async function mkdir(path) {}
async function rename(path, newName) {}
async function remove(path) {}

然后改成一层 adapter:

const netdisk = {
  async listDir(dir = '/') {
    return callTool('file_list', { dir });
  },

  async uploadFile(local_file_path, remote_path) {
    return callTool('file_upload_stdio', {
      local_file_path,
      remote_path,
    });
  },

  async mkdir(path) {
    return callTool('make_dir', {
      path,
      rtype: 1,
    });
  },

  async rename(path, newname) {
    return callTool('file_rename', {
      async: 1,
      ondup: 'newcopy',
      filelist: [{ path, newname }],
    });
  },
};

这样旧业务逻辑可以先不动。以后 MCP 参数变了,或者你要换 SDK,也主要改 adapter,不用全项目到处搜百度网盘接口。

路径编码最容易坑

百度网盘路径一直有个老坑:路径要以 / 开头,中文路径还要注意 URL Encode。有些地方还会提到斜杠怎么编码。

最常见就是两种错:

// 错误:没处理中文
const dir = '/我的资源/课程';

// 也可能错误:编码了两次
const dir = encodeURIComponent(encodeURIComponent('/我的资源/课程'));

我的习惯是:业务层不要到处 encodeURIComponent。业务层就用正常路径,真正发请求的时候再统一处理。如果是 MCP 工具,就先按它 README 里的参数约定来;如果是自己打 REST API,就在 adapter 里集中编码。

function normalizeRemotePath(path) {
  if (!path.startsWith('/')) {
    throw new Error(`remote path must start with /: ${path}`);
  }

  return path.replace(/\/+/g, '/');
}

这个函数只做路径规范化,不做编码。编码和规范化最好分开,不然旧代码越改越绕。

上传别再硬拼旧流程

旧上传代码是最容易坏的。以前很多脚本会自己做:

  1. 算每个 block 的 MD5
  2. precreate
  3. superfile2 分片上传
  4. create

这套流程不是不能写,但很脆。接口细节一变,权限策略一变,错误码一变,就要重新查文档。

MCP 里有 file_upload_stdio。如果只是让自动化脚本把文件传上去,我会优先用它。除非你真的需要进度条、断点续传、秒传判断,否则没必要在脚本里维护一套上传 SDK。

迁移早期也别急着把上传结果包装得太漂亮。原始响应先留着,排错的时候很有用。

文件操作要写清楚冲突策略

复制、移动、删除、重命名这些操作,看起来简单,但最怕默认行为不清楚。

比如重命名或移动时,最好明确写 ondup

{
  "async": 1,
  "ondup": "newcopy",
  "filelist": [
    {
      "path": "/test/old.docx",
      "dest": "/test/archive",
      "newname": "old.docx"
    }
  ]
}

我一般会默认用 newcopy。自动化脚本误覆盖网盘文件真的很烦,宁愿多出一个副本,也别悄悄把原文件盖了。真要覆盖,再显式传 overwrite

删除也是一样。不要让 remove(path) 这种函数太黑盒,至少要知道它调的是哪个工具、是不是批量、失败时有没有原始响应。

搜索不只是文件名了

以前搜网盘,基本就是关键词搜文件名。现在 MCP 里有 file_keyword_search,也有 file_semantics_search

这两个东西最好别混在一起。关键词搜索适合“我知道文件大概叫什么”;语义搜索适合“我记得内容大概是什么,但不记得文件名”。

可以简单做个兼容:

async function search(query, mode = 'keyword') {
  if (mode === 'semantic') {
    return callTool('file_semantics_search', { query });
  }

  return callTool('file_keyword_search', {
    dir: '/',
    keyword: query,
  });
}

旧应用默认还是走关键词比较稳。等真的需要按内容找文件,再把语义搜索暴露出去。

我会怎么迁移

如果手里有一份 2020 年左右的百度网盘脚本,我大概会按这个顺序改:

  1. 把散落的 API URL 收到一个 netdisk adapter
  2. 把列目录、查详情、创建目录、上传、删除、移动、重命名、搜索拆成独立方法
  3. 路径统一校验,编码只在请求边界做
  4. 上传优先换成 file_upload_stdio 或官方封装
  5. 文件操作显式设置冲突策略
  6. 原始响应先留着,不要一开始就把错误包装没了

这类 API 不是特别难,主要是边界条件多。路径、权限、分页、文件类型、冲突策略、异步任务,哪个没处理好都可能让脚本看起来“差一点就能跑”。

小结

百度网盘 API 这几年的变化,不只是接口地址变了,而是调用方式变了。以前是脚本自己拼 HTTP 请求,现在更适合把网盘能力封装成工具来调用。baidu-netdisk/mcp 就是这个方向。

如果只是让 Agent 或自动化脚本管理网盘文件,MCP 这层会比旧 PCS 脚本舒服很多。旧代码要修的也不是某一个 URL,而是把路径、上传、文件操作、搜索这些能力从旧接口里拆出来。

这样以后接口再变,也不至于全项目一起陪着塌。

另外,我做了两个配套工具练练手:pan.n3m.org 可以用来浏览百度网盘,bduss.n3m.org 可以用来获取 BDUSS。