新闻详情

新闻详情

首页 / 资讯中心 / 详情

notebooklm-py 远程 MCP 文件传输设计全解:signed-URL 旁路与 ADR-0024 的实现细节

发布时间:2026/9/13 7:50:49来源:尧图网络
notebooklm-py 远程 MCP 文件传输设计全解:signed-URL 旁路与 ADR-0024 的实现细节
notebooklm-py 远程 MCP 文件传输设计全解signed-URL 旁路与 ADR-0024 的实现细节【免费下载链接】notebooklm-pyUnofficial Python API and agentic skill for Google Gemini Notebook. Full programmatic access to NotebookLMs features—including capabilities the web UI doesnt expose—via Python, CLI, and AI agents like Claude Code, Codex, and OpenClaw.项目地址: https://gitcode.com/GitHub_Trending/no/notebooklm-py本篇基于 ADR-0024docs/adr/0024-mcp-remote-file-transfer.md及其配套实现完整拆解 notebooklm-py 如何让source_add上传本地文件与studio_download下载播客/视频/PDF 等工件在远程 HTTP 传输claude.ai connector下正常工作。读完你能掌握MCP 生态缺少原生文件传输原语时如何设计签名 URL 旁路、无状态 HMAC 令牌如何编码操作参数、单用single-usejti 追踪如何封住令牌重放以及整条链路的安全边界与运维配置方式。为什么字节不能走 MCP 通道notebooklm-py 的 MCP 服务器可以通过--transport http暴露为远程 HTTP 服务供 claude.ai connector 通过 Cloudflare/Tailscale 隧道访问远程传输与自托管 OAuth 分别由 ADR #1645、#1647 先行确立。但此时仍有两个工具停留在stdio 心智模型——假设服务器的文件系统就是用户的文件系统source_add的source_typefile接受path参数它是服务器主机上的路径见 source_add 工具studio_download的path参数指向服务器主机上的输出文件见 下载工具。在 claude.ai connector 下服务器位于隧道后方的容器里用户提供的path指向一个用户看不见的文件系统而服务器写出的文件也落在用户够不到的地方。上传一份本地 PDF和下载我的播客因此在远程 connector 上双双失效尽管它们在 stdio 下工作正常。ADR-0024 的调研还确认了 MCP 协议本身帮不上忙上传没有原生原语。官方 File Uploads Working Group 章程2026-04-23Anthropic指出服务器今天只能退化为用文字说明请求 base64 字符串或本地路径提议中的声明式文件输入描述符SEP-2356仍是 Draft不可落地且章程本身就把预签名上传 URL列为候选方案。也就是说signed-URL 旁路是当前生态公认的最佳实践不是重复发明。下载有一个原生原语但不够用。Resources BlobResourceContents在 claude.ai connector 上确实支持二进制资源但自定义 connector 的工具结果上限约150,000 字符base64 后约 110 KB 二进制——而 NotebookLM 的播客、视频、幻灯片、PDF 工件远大于此原生路径对真实载荷不可用。结论二进制必须走出MCP JSON-RPC 通道——上下文窗口留给控制消息不留给大块数据。仓库后续也补了一个窄路径当 agent 已经持有字节、且浏览器与agent_uploadPOST 都走不通时source_add提供bytes_base64参数在通道内传递 ≤10,000 字符的 base64约 7 KB见 _fileupload.py 中的_MAX_UPLOAD_B64_CHARS常量——请求体积上限正是这个数值这么小的原因更大的文件仍要走本 ADR 定义的签名 URL 流程。总体决策挂载在同一个 FastMCP http app 上的签名 URL 旁路ADR-0024 的决策是MCP 工具负责签发短期签名 URL用户的浏览器直接对隧道做字节传输。没有字节经过 MCP/claude.ai。具体是三条后扩展为四条FastMCPcustom_routeGET /files/dl/{token} - 流式下载工件 Starlette FileResponse GET /files/ul/{token} - 极简上传页 文件选择器 fetch POST POST|PUT /files/ul/{token} - 流式读原始 body - 添加 sourcePOST服务浏览器fetchPUT服务代码执行沙箱的curl——同一个处理器同时覆盖两条投递路径人打开链接在浏览器里上传或 Claude 的代码执行沙箱把它已经持有的文件 curl 到预签名 URL。实现落在三个文件_filelink.py令牌签发/校验、jti 追踪_fileroutes.py/files/*路由处理器_uploadwidget.py实验性应用内上传 widgetADR-0027 扩展复用同一条/files/ul路由。下载流程http 传输下的 studio_download工具把签名链接作为resource_link内容项返回claude.ai 会渲染成可点击链接同时携带结构化载荷{status: download_ready, url: base/files/dl/token, expires_at: …}——而不是往服务器路径写文件。为什么不直接用原生BlobResourceContents正是上面说的 ~150 KB connector 上限排除了它。浏览器 GET → 处理器校验令牌调用既有下载核心_app.download的build_download_plan/execute_download把工件落到私有临时目录返回带BackgroundTask清理的FileResponse与 REST 服务器 server/routes/artifacts.py 的模式一致。从源码看download_route 还做了几件 ADR 文字背后更细的事并发下载上限_MAX_CONCURRENT_DOWNLOADS 4防止泄漏令牌驱动 N 路并行流 N 份临时磁盘占用 N 倍上游抓取放大超限直接 429槽位由_SlotHeldFileResponseFileResponse子类在流结束或客户端断开时才释放并清理临时目录保证慢速/挂起的流仍然计入限额、槽位永不泄漏工件输出路径必须断言位于临时目录内否则拒绝服务。下载工具侧的download_ready构造 会附带filename、mime_type、size_bytes等自描述元数据且与路由实际使用的Content-Type来自同一套中央解析函数保证宣称的与流出的不漂移。上传流程http 传输下的 source_add typefile工具返回{status: upload_required, url: base/files/ul/token, expires_at: …}而不是读取服务器路径。_broker_upload 的实际返回比 ADR 文字更丰富它区分两条一等执行路径——human_upload用短链/u/shortid抗移动端聊天里长令牌被截断/自动纠错破坏与agent_uploadraw-body POST附带可直接复制的 curl 示例和agent_instructions回退规则另带mime_locked标志签了 mime 时请求头 Content-Type 即被忽略。浏览器 GET → 返回单屏 HTML 页文件选择器 fetch脚本见 _UPLOAD_PAGE。页面把文件作为原始请求体上传fetch(url ?filename encodeURIComponent(file.name), {method:POST, headers:{Content-Type: file.type || application/octet-stream}, body: file})——不是multipart 表单。原因在 ADR 中讲得很透原始 body 省略了文件名而 NotebookLM 上传要求真实的 basename扩展名无扩展名会 400见 _web/sources/upload.py所以页面把浏览器选中的file.name作为查询参数、MIME 作为Content-Type传递处理器用request.stream()逐块写入权限0o600的临时文件文件名取自清洗后的?filename带滚动字节上限真正的 DoS 防御之前先做Content-Length早拒413之后运行中立的source_add核心source_typefile在finally中删除临时文件含流中断开的情形返回 HTML added (id…) 页。刻意不用form enctypemultipart/form-data/request.form()还因为python-multipart只在serverextra 里、不在mcpextra 里更因为 multipart 会先把整个 body 落盘、然后才能做逐块大小检查——那个磁盘耗尽漏洞在 REST 路由上要靠应用层 Content-Length 中间件弥补而 FastMCP 自定义路由并不继承该中间件。Agent 用await_upload轮询进程内完成记录返回{source_id, file:{name,size,mime,sha256}}或source_list确认。值得注意的两个实现细节源码在 upload_route上传上限MAX_UPLOAD_BYTES 200 * 1024 * 1024与 REST 路由一致滚动上限才是权威防御Content-Length只是对声明超限的 body 做早拒——chunked 或未如实声明的长度能绕过它agent 提供的title/mime走签名令牌签过名、不可篡改而filename令牌签发时用户还没选文件令牌无从知道由浏览器/沙箱作为清洗后的?filename到达用作临时文件的 basename扩展名。此外还支持可选的?sha256hex完整性声明服务端流式计算收到的字节摘要不匹配就在添加 source之前以干净的 400 拒绝可重试坏值非 64 位小写 hex也先被拦成 400 而非 500。无状态令牌参数编码进令牌处理器不持有状态签名令牌编码操作参数所以/files/*处理器不保留任何服务端状态下载令牌载荷{op:dl, nb, atype, fmt?, aid?, exp, jti}上传令牌载荷{op:ul, nb, title?, mime?, exp, jti}把title/mime放进上传令牌使source_add typefile的参数能在浏览器往返中存活且不可被篡改。令牌线上格式见 FileLinkSignerbase64url(json(payload)) . base64url(HMAC-SHA256(key, body))只依赖标准库hmac/hashlib/base64/json/secrets没有新增第三方依赖itsdangerous未安装。verify的校验顺序在源码里刻得很死先做令牌长度上限检查_MAX_TOKEN_LEN 4096任何 decode/HMAC 工作之前防止异常长的路径段驱动解码/分配成本再重新补齐 base64url、用hmac.compare_digest常数时间比较 MAC伪造令牌在 MAC 通过前不会到达 JSON 解析器最后才查exp和op——上传链接不能重放到下载路由反之亦然。失败统一抛FileLinkError路由一律返回扁平 403探测者学不到为什么失败上传路由所有拒绝共用同一句文案。没有 ref-registry也没有后台清扫任务。唯一的进程内状态是ul的单用追踪器ConsumedJtiStore见下节一个临时、有界、内联清扫的进程内已消费jti集合与签名密钥同生共死。dl保持完全无状态TTL 内多用途。认证模型HMAC 签名令牌是/files/*的唯一且充分的认证打开签名 URL 的浏览器无法携带 MCP bearer/OAuth 凭证所以旁路必须自证。ADR 对 fastmcp 3.2.0 的核实结论与 FastMCP 挂载路由的方式 一致auth.get_middleware()作为全局中间件挂载——它认证填充请求作用域但不拒绝未认证请求BearerAuthBackend.authenticate返回None而非抛错MultiAuth/McpBearerAuthProvider继承这一不拒绝基线RequireAuthMiddleware只包裹MCP 路由streamable-http 传输自定义路由被未包裹地追加可以不经bearer 门禁到达。因此HMAC 签名令牌就是/files/*唯一且充分的认证而这是正确的浏览器没有 bearer。仓库里有一个回归测试钉住这个 FastMCP 行为——一旦升级开始对自定义路由强制鉴权测试会大声失败。另一个容易被忽略的问题自定义路由处理器收到的是 StarletteRequest而不是 MCPContext用不了工具的get_client(ctx)。解决方案是经request.app.state.fastmcp_serverFastMCP 会把它设在 Starlette app 上→._lifespan_resultlifespan 产出的AppState拿到进程唯一 client并以._lifespan_result_set守卫_lifespan_result是 FastMCP 私有属性所以同样有回归测试钉住这条访问路径。处理器签名必须是(request)——(request, token)会直接弄崩 Starlette 的request_response。配置签名密钥、公共 URL 与不崩启动从源码_build_file_transfer看配置解析规则是密钥服务器启动时生成临时secrets.token_bytes(32)。令牌 TTL 短上传15 分钟、下载30 分钟见 UPLOAD_TTL / DOWNLOAD_TTL重启使存量链接失效是可接受的且省去一个要管理的秘密——无需任何配置项。公共 base URL环境变量NOTEBOOKLM_MCP_PUBLIC_URL回退到NOTEBOOKLM_MCP_OAUTH_BASE_URLOAuth 流程本就已要求的公共 https 隧道地址。两者都经共享的 _validate_bare_https_origin 校验为裸 https originhttps scheme、无 path/query/fragment与 OAuth base URL 用同一个检查防止/mcp后缀或非 https 值产生坏链/不安全链。不崩启动文件传输是可选能力。只设 bearer、没设公共 URL 的远程部署仍然合法聊天等一切正常——服务器不会SystemExit_build_file_transfer直接返回None两个文件工具在调用时干净地报错 remote file transfer is not configured; set NOTEBOOKLM_MCP_PUBLIC_URL。早期草案提议启动时SystemExit被两次评审都点名否决那会弄坏从不用文件传输的纯 bearer 远程服务器。传输分支create_server增加一个可选的 file-transfer 配置signer 校验过的公共 base URL只在 http 分支构造并挂在AppState上配置存在时两个工具发 URL不存在时stdio或 http 未配公共 URLstdio 保持既有的 path 行为不变、http 则报未配置。stdio 路径不受任何影响。运维上最简单的结论如果你已经为 claude.ai OAuth 配了NOTEBOOKLM_MCP_OAUTH_BASE_URL文件传输就已经开着见 docs/mcp-guide.md 与 docs/configuration.md。安全侧还有一个值得注意的权衡令牌签过名但未加密泄漏的 URL 会让读到日志的人 base64 解码出 notebook id / 工件类型 / 标题。这是被接受的——单租户自己的低敏感元数据HMAC 的职责是防伪造而非防披露加密需要不透明服务端状态会毁掉无状态设计。令牌随 URL 路径走会被隧道访问日志、浏览器历史、Referer捕获所以 HTML 页统一发Referrer-Policy: no-referrer、Cache-Control: no-store并加X-Frame-Options: DENY与严格 CSP见 _HTML_SECURITY_HEADERS所有插值一律 HTML 转义。残留风险TTL 内的令牌重放——ul单用dl接受FileLinkSigner.verify检查长度上限、HMAC、exp、op一个通过这些检查的令牌在过期前每次都能通过。泄漏不是理论问题令牌在 URL 路径里会被 claude.ai、浏览器历史、隧道日志、Referer捕获且两种操作的爆炸半径不同泄漏的ul令牌是内容无关的写原语载荷只有{nb, title?, mime?}上传字节就是原始请求体——持有链接的人可以把任意内容≤200 MiB作为 source 写进属主的 notebook是内容/提示注入向量不只是同文件重放泄漏的dl令牌可在 30 分钟 TTL 内反复重取该类型工件的最新版本。令牌钉的是{nb, atype, fmt?, aid?}而非字节快照重放会流出发放时下载核心解析到的东西。ADR-0024 的更新决策#17462026-07-02 多模型 MCP 差距评审把ul严重度重新加权为写/内容注入原语后ul单用dl多用途。ul— 强制单用。每个令牌携带随机jti128 位由sign()注入并被 MAC 覆盖。/files/ulPOST 路由在落盘之前通过 ConsumedJtiStore.try_begin原子认领jti只在source_add成功后commit烧毁失败/中止/429 的上传在路由finally中rollback认领链接可重试保留大文件重试窗口——200 MiB 上传在差链路上要 ~13 分钟逼近 15 分钟 TTL所以只在成功时记账。效果顺序重放日志泄漏的现实情形在发生一次成功使用后即被 403 拒绝且不触碰任何落盘原子认领还拒绝了并发重复 POST先于落盘把 #1746 之前 N 个并发 × 200 MiB 临时盘 的窗口坍缩为一个窄竞态且被_MAX_CONCURRENT_UPLOADS 4再兜一层单用追踪器是临时、有界8192、内联清扫的进程内集合与签名密钥同死——重启即全灭密钥轮换本就使所有令牌失效所以没有引入 ref-registry也没有后台清扫任务无状态设计依然成立。dl— TTL 内重放被接受多用途。jti存在但对下载不强制执行因为GET /files/dl/{token}是直流的Range/断点续传客户端会合法地重发 GET带Range:的断线重连——单用会把续传 403 掉、弄坏大工件下载。dl本身也更轻重读同一工件不是写原语并已被四层约束30 分钟短 TTL、每进程临时签名密钥重启全灭、单租户范围无跨租户升级、HMAC 完整性重放需要一个合法签发的令牌再加_MAX_CONCURRENT_DOWNLOADS 4并发上限封住扇出。原 ADR 列过三条会翻转权衡的条件多租户、TTL 变长、有重放事故报告均只针对dldl的 Range/续传约束是它保持多用途的常设理由。边界为什么 REST 服务器不在范围内REST 服务器server/extra原生就支持二进制文件传输POST /v1/notebooks/{id}/sources/filemultipart 上传server/routes/sources.py和POST /v1/notebooks/{id}/artifacts/downloadFileResponseserver/routes/artifacts.py。REST 客户端是带 bearer 令牌、直接流式传字节的程序化 HTTP 客户端两个逼出本设计的约束都不存在。所以 ADR-0024 是刻意MCP-only不是遗漏。ADR 同时否决了三个替代方案字节走 MCP 结果base64尺寸上限 claude.ai 不会把文件存下来有状态上传 broker ref 注册表 TTL 清扫令牌既已编码参数它就是多余代码加一个后台任务直接复用 FastAPI 的server/路由那是另一个部署独立 ASGI app、FastAPIDepends旁路必须长在 MCP app 上——共享的是逻辑不是 FastAPI 管道。测试如何钉住这些行为相关单测集中在 tests/unit/mcp/test_fileroutes.py覆盖面与 ADR 的承诺一一对应无 bearer 下好令牌正常流字节、坏令牌/跨操作令牌 403、并发上限 429 与槽位释放、mkdtemp失败的干净 500、服务路径必须留在临时目录内、上传页安全头、短链 302/404、CORS 预检、客户端 sha256 声明的匹配/不匹配/坏值三分支、文件名清洗含..与按字节截断保留扩展名、Content-Length 超限 413 不落临时文件、jti完成记录供await_upload轮询等。另有回归测试专门钉住自定义路由不经 bearer 门禁与app.state.fastmcp_server._lifespan_result访问路径这两个 FastMCP 行为确保升级不静默破坏旁路。小结ADR-0024 给出的方案可以浓缩为四条设计不变式字节永远不走 JSON-RPC——MCP 通道只传控制消息签名 URL字节走隧道直连这与 MCP 生态正在收敛的方向SEP-2356/SEP-2631 的预签名 URL 侧通道前向兼容届时现有/files/*端点直接成为规格协商的预签名目标迁移主要只是把 UX 移进客户端原生文件选择器令牌即状态——操作参数notebook、工件类型、title/mime、过期、jti全部编码进 HMAC 签名令牌处理器零持久状态唯一进程内状态jti 集合临时、有界、内联清扫、随进程死亡写比读严——ul单用防内容注入写原语、dl多用途保 Range 续传TTL 分别 15/30 分钟临时密钥重启全灭可选能力不崩启动——未配公共 URL 时调用期干净报错stdio 行为零改动。对操作者而言需要记住的实际事项很少为 http 传输设置NOTEBOOKLM_MCP_PUBLIC_URL裸 https origin无/mcp后缀否则回退到NOTEBOOKLM_MCP_OAUTH_BASE_URL若想让 Claude 的代码执行沙箱PUT文件需在 claude.ai 开启 Code Execution 并把服务器域加入 Settings → Capabilities → additional allowed domains浏览器上传路径则无此要求、是通用回退链接在服务器重启后一律失效上传上限 200 MiB单文件超小≤10,000 base64 字符 ≈ 7 KB的场景可直接用bytes_base64跳过签名 URL。【免费下载链接】notebooklm-pyUnofficial Python API and agentic skill for Google Gemini Notebook. Full programmatic access to NotebookLMs features—including capabilities the web UI doesnt expose—via Python, CLI, and AI agents like Claude Code, Codex, and OpenClaw.项目地址: https://gitcode.com/GitHub_Trending/no/notebooklm-py创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

STM32F407硬件JPEG编码+4G透传实战指南 2026/9/13 8:38:53

STM32F407硬件JPEG编码+4G透传实战指南

简介:本资源是一套面向嵌入式物联网开发者的STM32F407单片机实战项目例程,聚焦于EC20-4G模块与OV2640摄像头的协同应用,解决边缘端图像采集、JPEG编码及串口实时输出的核心问题,适用于高校电子类课程设计、毕业设计及初/中级工程师…

阅读更多 →
AI如何解决科研论文写作与发表难题 2026/9/13 8:38:53

AI如何解决科研论文写作与发表难题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Windows 10与Linux双系统安装全攻略:从UEFI、GRUB引导到分区修复 2026/9/13 8:38:53

Windows 10与Linux双系统安装全攻略:从UEFI、GRUB引导到分区修复

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
408数据结构算法模板:科学整理与高效实战指南 2026/9/13 8:38:53

408数据结构算法模板:科学整理与高效实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
如何不用 SDK 直接调用 Dub REST API 手动上报 lead 与 sale 事件 2026/9/13 8:38:53

如何不用 SDK 直接调用 Dub REST API 手动上报 lead 与 sale 事件

如何不用 SDK 直接调用 Dub REST API 手动上报 lead 与 sale 事件 【免费下载链接】dub The modern link attribution platform. Loved by world-class marketing teams like Framer, Perplexity, Superhuman, Twilio, Buffer and more. 项目地址: https://gitcode.com/GitHu…

阅读更多 →
CogVideoX文生视频本地推理教程:单卡3行命令出5秒成片 2026/9/13 8:35:53

CogVideoX文生视频本地推理教程:单卡3行命令出5秒成片

CogVideoX文生视频本地推理教程:单卡3行命令出5秒成片 【免费下载链接】CogVideo text and image to video generation: CogVideoX (2024) and CogVideo (ICLR 2023) 项目地址: https://gitcode.com/GitHub_Trending/co/CogVideo 把 A girl riding a bike 敲…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞