Puter MCP Connector 实战指南:用 Cloudflare Workers 把个人 Puter 账号接入任意 MCP 客户端
【免费下载链接】puter🌐 The Internet Computer! Free, Open-Source, and Self-Hostable.项目地址: https://gitcode.com/GitHub_Trending/pu/puter
Puter MCP Connector(puter-mcp)是 Puter 仓库中位于 src/mcp-connector 的一个独立子项目:它以 Cloudflare Workers 为运行载体,把 Puter 账号的文件系统、静态网站托管、服务端 Workers、KV 存储、应用注册能力以 MCP(Model Context Protocol)工具的形式暴露给 Claude、Cursor 等任意 MCP 客户端。读完本文,你将掌握它的架构原理(如何在 Worker 中「零凭据」地以每个调用者身份运行真实 puter.js)、全部 45 个工具的参数语义、本地开发/生产部署/自托管接入的完整流程,以及 OAuth 免拷贝 Token 接入与 curl 冒烟测试方法。
概述:无共享凭据的「个人 Puter 网关」
MCP(Model Context Protocol)是一种让 AI 客户端调用外部工具的标准协议。Puter MCP Connector 的特殊之处在于两条设计承诺:
- Worker 本身不保存任何凭据。它不像常见的 MCP 服务器那样用一把「服务账号」密钥代理所有用户,而是让每个请求以调用者本人的身份运行;
- 认证方式对开发者透明。请求既可以通过
Authorization: Bearer <token>头携带个人 Token,也可以通过 Worker 自托管的 OAuth「Sign in with Puter」流程获得 Token(详见认证)。
MCP 客户端 (Claude / Cursor / ...) │ JSON-RPC 2.0 over Streamable HTTP(POST / 或 /mcp) ▼ Cloudflare Worker(puter-mcp,无自有凭据) │ 依据请求头构建调用者本人的 puter.js 实例 ▼ Puter API(api.puter.com 或自托管端点)这意味着部署一次之后,任何持有效 Puter 账号的人都能把 MCP 客户端指向这个 Worker URL 使用自己的账号资源——文件、网站、Worker、KV、应用互不串扰。
工作原理:一个「没有 me 的 Worker」分叉
在 How it works 一节中,README 明确说明:这是src/worker—— Puter 将 puter.js 移植到 Cloudflare Worker 运行时的实现 —— 的一个分叉,仅有两处改动:
- 去掉了
me.puter:原版 Worker 会用globalThis.puter_auth创建一个属于 Worker 自己的 puter 实例;这个分叉删掉了它,于是服务器不持有任何自身凭据。 user.puter改为从Authorization头构建:按请求创建的 puter 实例由Authorization: Bearer <token>生成,而不是原版的puter-auth头。
这两处改动集中在 src/s2w-router.js 的route()中:路由收到请求后,先用getBearerToken()从authorization头解析 Bearer Token,若存在则调用init_puter_portable(token, globalThis.puter_endpoint || 'https://api.puter.com', 'userPuter')生成实例并挂到event.requestor.puter(即event.user.puter);未携带 Token 时则跳过——后续由 MCP 层以 401 应答。
之所以能做到「每个请求各用各的 puter.js」,关键在于 template/puter-portable.template 中定义的init_puter_portable:当类型为userPuter时,它会把全局对象快照进一个goodContext,然后在with (goodContext)语句中内联执行 puter.js。这样每个请求都运行在隔离的with上下文里,并发请求之间不会共享全局可变状态(Token、缓存等)。模板还通过trimPerRequestOverhead()削减了每请求开销:由于单次工具调用并非「打开一次应用」,它会屏蔽request_rao_(记录应用打开的POST /rao)与cacheWhoami_(GET /whoami缓存),并断开 FileSystem 模块只为缓存失效而建立的 socket。一个值得注意的实现细节是:整个模板刻意不做 bundler 转译,因为wrangler.toml里设置了no_bundle = true——现代转译会输出严格模式 ESM,而严格模式禁止with语句("Strict mode code may not include a with statement"),上传原样拼接的脚本才能让它作为 sloppy-mode service worker 运行。
MCP 层:手写的 JSON-RPC 调度器
MCP 传输层采用Streamable HTTP:单一端点接受 JSON-RPC 2.0 的POST请求(单个消息或批量数组),服务器完全无状态。调度器实现在 src/mcp.js,被注册到分叉路由上,形成以下路由表:
| 方法 | 路径 | 用途 |
|---|---|---|
POST | /、/mcp | MCP JSON-RPC 端点(单消息或 batch) |
GET | /、/mcp、/health | 发现 / 健康检查(公开可缓存) |
在 src/mcp.js 的handleMessage()中可以看到协议兼容细节:服务器声明当前协议版本为2025-06-18,同时接受客户端协商2025-03-26、2024-11-05(SUPPORTED_PROTOCOL_VERSIONS);对notifications/*类消息返回空响应(HTTP 202);initialize响应中的instructions会明确告知客户端如何认证、工具分组,以及「写 Worker 代码前先调用puter_docs_get读取Workers/router」。批量数组使用Promise.all并行处理。
未认证访问的路径也经过精心设计:当请求缺少 Token 时,mcpPost返回401,并带WWW-Authenticate: Bearer resource_metadata="<origin>/.well-known/oauth-protected-resource"——这正是 Claude Code 等 MCP 客户端识别「需要走 OAuth」的信号。同时,凡是返回用户数据的响应都强制Cache-Control: no-store,防止 Worker 前面的任何边缘缓存把某一用户的 MCP 结果泄漏给其他人(src/mcp.js);只有公开的发现信息端点显式标注Cache-Control: public, max-age=300以便 CDN 缓存。OAuth 相关响应同样带no-store, no-cache, must-revalidate(见 src/oauth.js),避免缓存层重放某位用户的/authorize重定向。
文件地图
| 路径 | 角色 |
|---|---|
| src/s2w-router.js | 分叉路由:从 Bearer Token 构建event.user.puter(无me.puter),处理 CORS 与 JSON 错误响应 |
| src/index.js | 入口:initS2w()后注册 MCP 与 OAuth 路由 |
| src/mcp.js | MCP JSON-RPC 调度;未认证返回 401 +WWW-Authenticate |
| src/oauth.js | OAuth 桥:发现端点、/register、/authorize→authme、/oauth/callback、/token |
| src/tools.js | 全部工具定义与处理器,调用真实的puter.fs.*/puter.hosting.*/puter.workers.*/puter.apps.* |
| src/tools.upload.test.js | 签名上传工具的真实往返集成测试 |
| template/puter-portable.template | Preamble 模板(定义init_puter_portable,内联 puter.js) |
| wrangler.toml | Workers 配置:入口、no_bundle、[vars]、OAuth 密钥说明 |
工具总览:七个能力域
工具定义与其 JSON Schema 输入参数全部集中在 src/tools.js 的TOOLS数组里,每个条目包含name、description、inputSchema(通过tools/list暴露给客户端)与handler(puter, args)。TOOL_MAP负责按名称查表,listTools()会剥离内部字段后生成tools/list载荷。
Account:身份与路径锚点
| 工具 | 说明 |
|---|---|
whoami | 获取已认证用户信息(username、uuid、home directory)。等价于puter.auth.getUser() |
whoami是绝大多数会话的第一步,因为所有路径都必须位于主目录之下。它的处理器会把返回结果补上home_directory: "/<username>"字段(src/tools.js),让 Agent 据此拼接合法绝对路径。
Filesystem:读写与目录操作
| 工具 | 说明 |
|---|---|
fs_read_file | 读文件(UTF-8 或 base64;可选 byte offset/length 窗口) |
fs_stat | stat 文件或目录(大小、类型、时间戳、uid) |
fs_write_file | 以内联内容创建/覆盖文件(UTF-8 或 base64) |
fs_start_upload | 获取预签名 URL,带外上传本地文件 |
fs_complete_upload | 完成一次fs_start_upload发起的上传 |
fs_abort_upload | 丢弃一次上传而不创建文件 |
fs_mkdir | 创建目录(可选自动创建缺失父目录) |
fs_delete | 删除文件或目录(默认递归) |
fs_readdir | 列出目录条目 |
fs_copy | 复制文件或目录到其他位置 |
fs_move | 移动文件或目录(兼作重命名) |
fs_rename | 原地重命名文件或目录 |
从 src/tools.js 的 inputSchema 中可以提取这些有实践价值的默认值与边界:
fs_read_file:encoding枚举utf8/base64(默认utf8);offset(字节起始,默认 0)、length(返回字节数,默认到文件尾)。读取窗口不是在请求里下发而是在服务器端切片——puter.fs.read会把 offset/byte_count 当查询参数传给后端,而后端只认Range头,透传会静默返回整个文件;因此处理器先全量读取再在decodeReadResult()中做Uint8Array.subarray切片,并在_meta.total_bytes中报告总长以便分页。fs_stat:return_size默认true,对目录也要计算大小。fs_write_file:必填path+content;overwrite默认true、create_missing_parents默认false、dedupe_name默认false。base64 内容会解码成Blob再写入。fs_mkdir:create_missing_parents默认开启(!== false即视为开启)。fs_delete:recursive默认true;path既可以是字符串也可以是路径数组。fs_copy/fs_move:当目标是一个已存在目录时,条目会被「复制/移入」该目录并沿用原名;否则目标被当作新的完整路径。new_name可显式改名;dedupe_name开启时冲突自动改名为file (1).txt。复制/移动的处理器会剥掉 API 返回的{ copied: entry }/{ moved: entry }信封,让所有fs_*工具返回一致的单条目形状。fs_move的一个陷阱:后端/move要求目标父目录必须已存在,所以create_missing_parents开启时,ensureMoveDestination()会先按与puter.fs.move相同的规则确定目标目录,必要时预建(src/tools.js);该目录若后续移动失败会被遗留。fs_rename:new_name是裸文件名而非路径,且只能在同一父目录内重命名。
上传本地大文件:三步签名上传协议
fs_write_file的内容是内联传输的——磁盘上的文件必须先经 Agent 上下文 base64 编码才能到达服务器,大文件会非常慢,且超过客户端消息大小上限后就彻底不可行。
fs_start_upload完全绕开这一点:它返回一个预签名存储 URL,字节直接从持有文件的机器流向存储,既不经由此服务器,也不经过对话上下文。
fs_start_upload({ path: "~/uploads/build.zip", size: 48210433, local_path: "./build.zip" }) -> { upload_id, url, upload_command, expires_at, ... } # 运行返回的 upload_command: curl -sS --fail-with-body -X PUT -H 'Content-Type: application/zip' \ --upload-file './build.zip' 'https://...' fs_complete_upload({ upload_id }) -> 新建的文件条目在fs_complete_upload成功之前,文件在 Puter 中并不存在;上传失败时应调用fs_abort_upload释放挂起的会话。签名本身带来两条硬约束:
size必须是文件的精确字节数(用wc -c < file获取原样传入);- PUT 必须携带签名时一致的
Content-Type——存储端对两者任一不匹配都会拒绝。
服务器生成的upload_command已经替你把这两者都写对(用shellQuote安全地单引号包裹)。Content-Type 会按目标扩展名猜测,映射表覆盖文本、压缩包、图片、音视频等常用类型(src/tools.js),猜不到时回退为application/octet-stream;也可以显式传content_type覆盖。expires_in(签名 URL 有效期秒数)由后端钳制在 60~3600,默认 900,超期未完成则作废。
需要特别说明的是:超过服务器单次 PUT 上限的文件需要走多段 multipart 的分段编排,而这套工具并未实现。fs_start_upload会检测到后端返回的uploadMode不是single或没有url的情况,自动先调用/fs/abortWrite释放该会话,再抛出 "too large for a single-shot signed upload" 的明确错误(src/tools.js)。
这段流程由 src/tools.upload.test.js 做了真实往返集成测试验证:mint 一个 URL → 像 shell 命令那样 PUT 字节 → finalize → 回读文件比对内容;测试同时断言upload_command里携带了签名的Content-Type与正确的--upload-file路径,还覆盖了「abort 后 complete 不会复活文件」「超过单次上限被拒绝」等边界。
Hosting:把目录发布成静态网站
在 Puter 中,「托管一个网站」意味着创建一个托管子域名,站点访问地址为https://<subdomain>.puter.site,后端由你 Puter 文件系统中的一个目录支撑。
| 工具 | 说明 |
|---|---|
hosting_list | 列出调用者已发布的网站(托管子域名) |
hosting_get | 按子域名获取网站 |
hosting_create | 在子域名上发布网站(可选指向某个root_dir) |
hosting_update | 把网站重新指向另一个root_dir |
hosting_delete | 取消发布网站(删除子域名,不删文件) |
按 src/tools.js 的说明,hosting_create的子域名标签要求为小写字母、数字、连字符,最长 64 字符;省略root_dir可以只保留子域名、稍后用hosting_update再挂目录。一个 Agent 发布网站的典型链路是:fs_mkdir建目录 →fs_write_file写入index.html等文件 →hosting_create将root_dir指向该目录。
Workers:从文件部署的无服务器函数
Puter Workers 是从你文件系统中的某个 JS 文件部署的无服务器函数。Worker 文件在全局router对象上定义处理器(router.get/router.post/ …),并且拥有完整的 puter.js SDK(以puter全局可用)——它们的设计目标就是配合 puter.js 与 Puter 认证使用。更新一个 Worker 只需把新代码写回它关联的文件即可(没有单独的 update 调用,传播约需 5–30 秒)。
| 工具 | 说明 |
|---|---|
workers_create | 从 JS 文件部署 Worker;返回其公开 URL |
workers_list | 列出调用者已部署的 Worker |
workers_get | 按名称获取 Worker(名称、URL、源文件) |
workers_exec | 以已认证用户身份通过 HTTP 调用 Worker |
workers_delete | 取消部署 Worker(保留其源文件) |
在 src/tools.js 中可以看到:workers_create要求账号邮箱已验证,worker_name会自动转小写,源文件最大 10MB;workers_exec支持 GET/POST/PUT/DELETE/PATCH/OPTIONS/HEAD,并且会带着调用者的 Puter 认证头去请求——正因如此它有一个硬性安全校验assertWorkerUrl():目标必须是https://且主机名以.puter.work结尾,否则直接拒绝(src/tools.js),从根上杜绝了把用户 Token 误发给任意第三方的可能。
Apps:把网站/Worker 注册成可启动应用
Puterapp是你账号中的一个已注册应用:它会出现在你的 Puter 应用列表里,可以在 Puter 桌面 UI 中启动,获批后还能上架 marketplace。app 的核心是index_url——运行时 Puter 加载的地址,通常是用hosting_create发布的站点或一个 Worker URL。典型流程是:fs_write_file写入文件 →hosting_create发布并取得 URL →apps_create把index_url指向该 URL。
| 工具 | 说明 |
|---|---|
apps_list | 列出调用者拥有/可编辑的应用(名称、URL、图标、聚合使用统计) |
apps_get | 按名称获取应用;传stats_period可看窗口内详细的打开/用户数 |
apps_create | 注册新应用(必填name和index_url) |
apps_update | 按名称更新应用(只改传入字段;new_name用于改名) |
apps_delete | 删除应用(index_url指向的站点/Worker 保留) |
apps_check_name | 创建前检查应用名是否可用 |
apps_create的可选参数相当丰富(见 src/tools.js):title(缺省用 name)、description(最长 7000 字符)、icon(只接受 base64 或data:image/<type>;base64,...URL,不接受任意 http(s) 图标 URL)、maximize_on_start、background、filetype_associations(如[".txt", ".md", "image/png"])、metadata、dedupe_name。apps_get的stats_period枚举包括today/yesterday/7d/30d/this_week/last_week/this_month/last_month/this_year/last_year/12m/all。
KV:JSON 值的键值存储
Puter 的 KV 存储在每个用户账号内按 app 命名空间隔离。此连接器用用户 Token认证,因此这些工具默认读写用户自己的命名空间;每个工具都可选传app_uuid来指向某个单一应用的存储(例如某个已部署 Worker 运行时所在的sandbox-<worker>app)。值以 JSON 存储;接受「点路径」(profile.bio)的工具按路径深入到已存对象内部,空路径表示值本身。
| 工具 | 说明 |
|---|---|
kv_get | 读一个键(缺失键读作null) |
kv_set | 创建/覆盖一个键,可选带过期时间戳 |
kv_del | 删除一个键 |
kv_list | 按 pattern 列出键(或键值对),支持分页 |
kv_incr/kv_decr | 增减一个数字,或按点路径增减对象内数字 |
kv_add | 向已存值累加(数字求和、数组追加) |
kv_update | 设置已存对象内部特定点路径 |
kv_remove | 从已存对象中移除点路径 |
kv_expire/kv_expire_at | 让键在 N 秒后 / 在指定时间戳过期 |
flush被刻意不暴露——「一条调用清空整个存储」不是 Agent 应该具备的能力。实现细节(src/tools.js)中还包含:键最长 1KB,值最长 400KB;kv_list支持pattern(前缀过滤 + 可选尾部*)、return_values、limit/cursor分页(offset最大 5000 且不能与 cursor 混用)、include_total;kv_remove调用puter.kv.remove(key, ...paths)时会把optConfig作为尾参传入——若传undefined会被当成一个路径,因此代码里有专门的参数拼接逻辑;kv_get把undefined归一为null返回,并提示缺失键与「显式存了 null」用kv_list才能区分。
Docs:写代码前先查 puter.js 官方文档
| 工具 | 说明 |
|---|---|
puter_docs_index | 从docs.puter.com/llms.txt加载 puter.js 文档索引(每个主题 + 路径) |
puter_docs_get | 按主题路径获取指定文档页为 Markdown(如Workers/router) |
在 src/tools.js 中,resolveDocUrl()会规范化主题 slug(去掉首尾斜杠与可选的/index.md/.md后缀)拼出https://docs.puter.com/<path>/index.md;如果你直接传 URL,它只放行docs.puter.com主机——这是一道防 SSRF 的护栏。由于 Puter Workers 面向「puter.js + Puter 认证」设计而非普通裸 HTTP handler,工具描述反复提醒 Agent:写 Worker 前先用puter_docs_get读Workers/router指南与规范示例。
路径约定:一切都在主目录之下
每个路径都位于你的主目录(/<username>)下。工具把路径直接透传给 puter.js,因此通行惯例都适用:
- 绝对路径:
/your-username/Desktop/file.txt - 主目录相对:
~/Desktop/file.txt - 相对路径:
Desktop/file.txt(相对于你的主目录解析)
裸根路径如/portfolio/index.html是无效的——先调用whoami拿到 username,再用~/...或/<username>/...。这个提醒(HOME_PATH_NOTE)被嵌入到几乎每个路径参数的描述里(见 src/tools.js),因为它对应 Agent 最常见的一类错误;它甚至还告诫不要污染主目录根、应当为项目创建子路径与文件夹。
构建、本地运行与部署
本地开发
cd src/mcp-connector npm install npm run dev # 先构建,再 wrangler dev —— 服务在 http://localhost:8787对应 package.json 中的脚本:dev = npm run build && wrangler dev。构建依赖wrangler(^4.103.0)、webpack、terser-webpack-plugin。
构建管线(与 src/worker 相同)
npm run build分两步:
- webpack把 src/index.js(router + src/mcp.js + src/tools.js)打成
dist/webpackPreamplePart.js; - scripts/buildPreamble.mjs处理 template/puter-portable.template 中的
#include——拉入src/puter-js/dist/puter.js与上一步的 webpack bundle——产出service-worker 格式的可部署脚本dist/workerPreamble.js。
前提:
src/puter-js/dist/puter.js必须存在。如缺失,先在仓库根目录执行cd src/puter-js && npm run build构建 puter.js。
wrangler.toml 中main = "dist/workerPreamble.js"、compatibility_date = "2025-01-01"、no_bundle = true(原因见前文with语句与严格模式的说明)。
部署到 Cloudflare
npm run deploy # 先构建,再 wrangler deploy若要对接自托管的 Puter 实例,设置puter_endpoint/puter_gui_origin这两个全局变量(取消wrangler.toml中[vars]块的注释):
[vars] # OVERRIDE_ORIGIN = "https://mcp.puter.com" # puter_endpoint = "https://api.puter.com" # puter_gui_origin = "https://puter.com"puter_endpoint:文件系统/子域名等调用的 Puter API 源(默认https://api.puter.com);puter_gui_origin:OAuth「Sign in with Puter」(authme)重定向所用的 Puter GUI 源(默认https://puter.com);OVERRIDE_ORIGIN:当部署到workers.dev域却希望 OAuth 元数据以自定义域为 origin 时使用。
如果要用 OAuth 流程,生产环境还必须设置封签密钥(作为 secret 而非提交进仓库):
wrangler secret put OAUTH_SECRET本地wrangler dev在未设置时会回退到内置的不安全默认值(见 src/oauth.js),该默认值绝不能用于生产。
认证:两种方式,不用复制粘贴 Token
两种方式都以调用者身份运行——Worker 不持有任何自身凭据。
方式一:OAuth「Sign in with Puter」(无需复制 Token)
面向支持 HTTP OAuth 的客户端(如 Claude Code):此时Worker 本身就是授权服务器。首次使用时客户端会打开浏览器,你登录 Puter 并批准,随后 Worker 把 Puter Token 交给客户端。具体实现在 src/oauth.js,流程为:
client → GET /authorize → 302 到 puter.com/?action=authme&redirectURL=<worker>/oauth/callback?flow=… (用户在 puter.com 登录并批准;Puter 以 ?token=… 302 回来) puter → GET /oauth/callback → 302 到 <client redirect_uri>?code=…&state=… client → POST /token → { access_token: <puter token> } client → 携带 Authorization: Bearer <puter token> 发起 MCP 调用无状态性的关键是加密而非持久化:authorize→callback 的短命flow与 callback→token 的codeblob 都用OAUTH_SECRET派生的 AES-GCM 密钥封签(IV 前置拼接、base64url 编码),服务器不落任何盘。TTL 分别为 10 分钟与 5 分钟,超时即拒绝(FLOW_TTL_MS/CODE_TTL_MS)。当客户端提供 challenge 时强制 PKCE 校验(支持 S256 与 plain,S256 先对 verifier 做 SHA-256 再比对)。该模块还实现了完整发现协议:
GET /.well-known/oauth-authorization-server(RFC 8414 授权服务器元数据)及/mcp后缀变体;GET /.well-known/oauth-protected-resource(RFC 9728 保护资源元数据)及/mcp变体;POST /register(RFC 7591 动态客户端注册,不持久化客户端,安全性依赖 PKCE + 封签进 flow 的 redirect_uri)。
方式二:Bearer Token(复制粘贴)
从已登录 Puter 浏览器标签页的 devtools 控制台获取:puter.authToken。请像对待密码一样保管它。使用方式是把 Token 放进Authorization: Bearer <token>头(或.mcpb的 token 字段)。
连接客户端:三种接入方式
方式 A —— Claude Code(OAuth,无需 Token)
claude mcp add --transport http puter https://puter-mcp.<your-subdomain>.workers.dev/首次使用时 Claude Code 会打开浏览器完成 Puter 登录;批准后即连接成功。(若想跳过 OAuth,可追加-H "Authorization: Bearer YOUR_PUTER_TOKEN"。)
方式 B —— 一键.mcpbbundle(Claude Desktop 等)
本目录维护了一份预构建的 MCP Bundle(mcpb) 配置,导入支持 MCPB 的主机(如 Claude Desktop:Settings → Extensions → install from file)后,填写它提示的两个配置字段即可:
- Server URL—— 你部署的 Worker,例如
https://puter-mcp.<your-subdomain>.workers.dev/(本地wrangler dev则填http://127.0.0.1:8799/); - Puter Auth Token—— 你的个人 Token(作为 secret 存储)。
.mcpb的生成命令为:
npm run pack:mcpb # 生成 puter-mcp-connector.mcpb由于连接器是远端 HTTP Worker,而 MCPB 扩展运行本地进程,bundle 附带了一个零依赖的小型 Node stdio↔HTTP 代理(mcpb/server/index.cjs),负责把 JSON-RPC 转发给你的 Worker,并附上Authorization: Bearer头——代理的配置与清单见 mcpb/manifest.json(要求 Node ≥ 18,token 字段标注为敏感)。.mcpb默认未签名,主机可能警告来自未知开发者;如需自签名:
npx @anthropic-ai/mcpb sign --self-signed puter-mcp-connector.mcpb方式 C —— 直接 HTTP
把任意支持 HTTP transport 的 MCP 客户端指向 Worker URL,并把 Token 作为 bearer 头。mcp.json风格示例:
{ "mcpServers": { "puter": { "url": "https://puter-mcp.<your-subdomain>.workers.dev/", "headers": { "Authorization": "Bearer YOUR_PUTER_TOKEN" } } } }用 curl 快速冒烟测试
不依赖任何 MCP 客户端框架,先验证部署正确性:
URL=http://localhost:8787 TOKEN=your_puter_token # initialize(协商协议版本) curl -s $URL -H 'content-type: application/json' -d '{ "jsonrpc":"2.0","id":1,"method":"initialize", "params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}} }' # 列出全部工具 curl -s $URL -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' # stat 你的主目录(需要 Token) curl -s $URL -H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' -d '{ "jsonrpc":"2.0","id":3,"method":"tools/call", "params":{"name":"fs_stat","arguments":{"path":"~"}} }' # 写入再读取一个文件 curl -s $URL -H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' -d '{ "jsonrpc":"2.0","id":4,"method":"tools/call", "params":{"name":"fs_write_file","arguments":{"path":"~/Desktop/hello.txt","content":"hi from MCP"}} }' # 列出已托管的网站 curl -s $URL -H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"hosting_list","arguments":{}}}'逐段解读:请求 1 完成 MCP 握手;请求 2 应返回 src/tools.js 中定义的全部工具及 JSON Schema;请求 3–5 分别验证「以你的 Token 身份」的文件系统与托管域。注意第一个请求故意不带 Token——tools/list之前的认证策略是:initialize与tools/list本身公开,真正的工具调用tools/call在没有user.puter时会以内联 toolError("Missing Authorization: Bearer header.")返回,方便客户端直接把错误显示出来( src/mcp.js)。
安全设计要点小结
从源码可以确认这套连接器把「多租户 + 无凭据」做到了很细的颗粒度,值得在自托管时留意:
- 按调用者隔离:每个请求独立的
with上下文 + 独立 puter.js 实例,Token、缓存互不共享(template/puter-portable.template); - 响应防缓存泄漏:用户数据一律
Cache-Control: no-store,仅公开发现端点允许public, max-age=300(src/mcp.js); - OAuth 防重放:所有授权端点响应带
no-store,flow/code 用OAUTH_SECRETAES-GCM 封签且带 TTL(src/oauth.js); - 外呼目标白名单:
workers_exec仅允许https://*.puter.work;puter_docs_get仅允许docs.puter.com主机,杜绝 SSRF 与 Token 外泄; - 危险操作收敛:KV 不暴露
flush;签名上传会话失败自动 abort,避免悬挂资源;fs_delete之外的删除类工具都不触碰源文件/站点(hosting_delete、workers_delete、apps_delete均如此)。
结合 src/worker(本项目的被分叉来源)与 src/puter-js(被内联的真实 puter.js SDK)对照阅读,可以更完整地理解这套「把整套 Puter 能力装进一个无状态 Worker」的移植思路。若要在生产中使用 OAuth 流程,务必设置wrangler secret put OAUTH_SECRET;若对接自托管 Puter,则按上文配置puter_endpoint/puter_gui_origin。
【免费下载链接】puter🌐 The Internet Computer! Free, Open-Source, and Self-Hostable.项目地址: https://gitcode.com/GitHub_Trending/pu/puter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考