本文基于 2026-08-22 拉取的 OpenConnector
main分支运行。本文本地生成的 catalog 包含 1,404 个 provider 和 14,722 个 Action;该 catalog 持续更新,实际数字请以运行时或官方 catalog 为准。
给 Agent 接 GitHub、Gmail、Slack 或 Notion,最容易的做法是什么?
把 token 塞进环境变量,给模型注册几个函数,几分钟就能跑起来。
但只要继续往前走一步------第二个用户、第二个 GitHub 账号,或者第一个"创建 Issue"操作------问题就不再是"工具怎么调用",而是:
- 这次调用到底使用谁的账号?
- Agent 能否看到、导出或误用原始 token?
- 它可以调用所有 GitHub Action,还是只能读取 Issue?
- 同一个能力接入 MCP、HTTP、SDK 后,是否需要维护三套 schema?
- OAuth 授权被取消、密钥轮换或调用失败时,去哪里排查?
这次我试了 OpenConnector。它不是 Agent 框架,也不只是再包装一层 MCP Server;它更像一层给 Agent 使用的 SaaS 连接 runtime:把 credential、OAuth、provider、Action schema、调用策略和运行记录收口到一起。
先说结论:如果你只是写一个调用固定 API 的脚本,它会显得偏重;但如果你的 Agent 要接多个 SaaS、服务多用户、需要多账号切换或准备进入生产环境,这层边界非常有价值。
一、MCP 解决工具接入,OpenConnector 解决账号边界
MCP 解决的是一个重要问题:Agent 怎么发现和调用外部工具。
但在企业或多用户产品里,工具调用后面还有另一层问题:这个工具以谁的身份调用,调用范围是否受控,调用后是否可审计。
OpenConnector 的结构可以简单理解为:
text
AI Agent / 应用
│
│ MCP / HTTP / SDK / CLI
▼
OpenConnector Runtime
├─ Provider / Action Catalog
├─ API Key 与 OAuth Connections
├─ Action Schema 与 Scope
├─ Runtime Token 与 Action Policy
├─ 临时文件中转
└─ Run Logs / Web Console
│
▼
GitHub / Gmail / Slack / Notion / ...
它的关键不是替 Agent 再加一批"函数",而是让 Agent 调用的是结构化 Action,而不是直接拿着某个 SaaS 的原始密钥去请求 API。
对于一条 GitHub 调用,理想状态是:
- Agent 知道要执行
github.get_current_user; - Agent 选择
work这个连接别名; - runtime 在内部取出对应 credential 并执行;
- Agent 获得执行结果、账号标签和必要的错误信息;
- 原始 GitHub token 不进入 Agent 的上下文。
这不是"绝对安全"的承诺------Action 本身、scope、运行 token、日志内容仍要治理------但至少把治理对象从散落在代码和环境变量里的密钥,收口成了一层明确的 runtime。
二、先跑一个无鉴权 Action
我没有先接 GitHub,而是先选择了 Hacker News。它不需要账号,适合验证 runtime、catalog 和 Action 执行链路。
仓库要求 Node.js 22+。在项目目录中安装依赖并启动 API runtime:
bash
npm ci
npm run dev:api
默认情况下,API runtime 监听在 http://localhost:3000。先查看健康状态:
bash
curl http://127.0.0.1:3000/health
本地返回:
json
{"ok":true}
接着看 Hacker News 暴露了哪些 Action:
bash
curl -s "http://127.0.0.1:3000/v1/actions?service=hackernews"
我本地返回了 14 个 Action;例如:
json
{
"id": "hackernews.get_ask_stories",
"name": "get_ask_stories",
"description": "Get the latest Ask HN story IDs from Hacker News."
}
然后执行 get_top_stories:
bash
curl -s -X POST \
http://127.0.0.1:3000/v1/actions/hackernews.get_top_stories \
-H 'content-type: application/json' \
-d '{"input":{}}'
调用成功后,返回结构中包含 success、message、data 和 meta.executionId。本次 data.story_ids 返回了 500 个 Hacker News 热门文章 ID。
json
{
"success": true,
"message": "OK",
"data": {
"story_ids": [49389430, 49390427, 49393052]
},
"meta": {
"executionId": "..."
}
}
这里有个我觉得很不错的细节:Action 不是黑盒。可以直接取到给 Agent 看的本地说明:
bash
curl -s \
http://127.0.0.1:3000/api/actions/hackernews.get_top_stories/agent.md
这份 Markdown 会写清楚输入参数、需要的 scope、当前连接、执行策略以及 Agent 的调用注意事项。对 Agent 来说,这比"函数名 + 一句 description"更接近一份可执行契约。
三、一个真实踩坑:出网保护不是多余配置
第一次调用 Hacker News 时,我拿到了一个 502,错误信息是目标 URL 解析到了私有或保留地址,因此被 runtime 的出网保护拒绝。
这是当前网络环境经企业 VPN / split DNS 解析造成的,并非 Hacker News provider 本身不可用。确认这个域名可信后,我才显式加入:
bash
OOMOL_CONNECT_EGRESS_TRUSTED_HOSTS='hacker-news.firebaseio.com' \
npm run dev:api
随后 Action 执行成功。
这件事很值得记录:不要为了让调用"先跑通",就全局放开内网或保留地址访问。OOMOL_CONNECT_EGRESS_TRUSTED_HOSTS 应仅用于你确认过、且确实因企业 VPN 或 split DNS 被误判的域名。对一个负责转发 SaaS 请求的 runtime 来说,出网限制本身就是安全边界的一部分。
四、接入 GitHub:Agent 不需要拿到 PAT
Hacker News 证明 runtime 可以工作,下面换成有账号的 GitHub。
如果只是本地验证,GitHub Personal Access Token 是最直接的路径。先创建一个 connection:
bash
curl -s -X PUT http://localhost:3000/api/connections/github \
-H 'content-type: application/json' \
-d '{
"authType": "api_key",
"connectionName": "work",
"values": {
"apiKey": "github_pat_..."
}
}'
这里的 work 是连接别名。它意味着未来可以同时保留个人号与工作号,而不是把"该用哪个账号"的逻辑塞进 prompt。
调用时选择对应的 connection:
bash
curl -s -X POST \
http://localhost:3000/v1/actions/github.get_current_user \
-H 'content-type: application/json' \
-H 'x-oo-connector-alias: work' \
-d '{"input":{}}'
此处真正值得注意的不是这条 curl,而是边界变化:业务 Agent 只需要表达"调用哪个 Action"和"使用哪个 connection alias";PAT 留在 runtime 的 connection 存储中。
当 provider 能验证身份时,runtime 会保存稳定的账号画像,例如 accountId、displayName 和已授予的 grantedScopes。Agent 可以据此知道"这次会以哪个账号执行",却不需要看到原始 token。
五、为什么生产环境通常要用 OAuth,而不是 PAT
PAT 是最快的本地 demo 路径,但对于面向用户的 Agent 产品,OAuth 往往更合适:用户自己授权、可撤销、可限制 scope,也更符合多数 SaaS 的集成方式。
以 GitHub 为例,流程分成三步:
bash
# 1. 保存 OAuth App 配置
curl -s -X PUT http://localhost:3000/api/oauth/configs/github \
-H 'content-type: application/json' \
-d '{"clientId":"...","clientSecret":"..."}'
# 2. 请求授权链接
curl -s -X POST http://localhost:3000/api/oauth/authorizations \
-H 'content-type: application/json' \
-d '{"service":"github","connectionName":"work"}'
# 3. 在浏览器打开返回的 authorizationUrl,完成回调
默认端口下,GitHub OAuth callback 是:
text
http://localhost:3000/oauth/callback
自托管时有两个特别容易漏掉的点。
第一,OAuth client 的创建、回调地址配置、scope 申请和可能的平台审核,仍由部署者负责。OpenConnector 管理运行时连接,不会替你绕过 SaaS 平台的授权要求。
第二,scope 应尽量收窄。例如,支持 requestedScopes 的 provider 可以只申请实际要用的权限,而不是把 provider 的默认 scope 一次性全拿下来。
六、真正值得关注的:限制 Agent 能做什么
"Agent 能调 GitHub"不是权限设计;"某个 Agent 只能用工作账号、只能读取 Issue、不能创建仓库、不能通过通用 proxy 绕过 Action 限制",才是权限设计的开始。
OpenConnector 把这类控制拆在不同层次:
| 层次 | 要解决的问题 |
|---|---|
| Provider credential / OAuth scope | 上游 SaaS 账号本身允许做什么 |
| Connection alias | 当前调用使用个人号、工作号还是某个服务账号 |
| Action allow / block policy | runtime 允许哪些标准化 Action 执行 |
| Persistent runtime token | 哪个 Agent 或客户端可以调用 runtime |
| Connection grant | 某个 runtime token 是否只能用特定 connection |
| Provider proxy grant | 是否能直接通过 provider proxy 调用对应服务 |
| Run logs / Web Console | 事后能否定位本次调用、失败和使用的账号 |
尤其不要把 Action policy 和 provider proxy 当成同一件事。文档里明确说明:persistent runtime token 的 provider proxy 权限默认是空的,必须显式授予相应 provider 或 *。这避免了"前面只开放了几个 Action,后面却通过通用 proxy 放开整个 provider API"的意外绕过。
七、MCP 只是其中一个入口
OpenConnector 可以通过 MCP 暴露 Action,但它并不只服务 MCP Host。
| 入口 | 更适合的场景 |
|---|---|
POST /mcp |
支持 MCP 的 Agent Host |
/v1/* |
自研 Agent、后端服务、自动化脚本 |
GET /openapi.json |
API 导入、生成客户端、限定单 Action 的 API 规格 |
| Connector SDK | TypeScript 应用集成 |
oo connector CLI |
本地 Agent relay 与调试 |
| Web Console | 浏览 provider、配置 connection、调试 Action、查看运行记录 |
同一份 provider / Action contract 被多个入口复用,这一点比"多一个 MCP URL"更有工程意义。它能减少不同调用方式之间的 schema 漂移,也让 HTTP、SDK 和 MCP 不必各自维护一遍权限逻辑。
八、凭据存储:能本地开发,不代表默认可用于生产
Node runtime 默认将 connections、OAuth client 配置、pending OAuth state、runtime token 和近期运行记录保存在 SQLite;也支持 PostgreSQL。Cloudflare 路径则使用 D1 和 R2。
本地开发时,建议从一开始就设置加密 key:
bash
OOMOL_CONNECT_ENCRYPTION_KEY='replace-with-a-long-random-secret' \
npm run dev:api
文档说明该 key 用于 AES-256-GCM 加密 provider credential、OAuth client 配置和部分保存的数据。没有设置 key,runtime 仍可用于开发,但数据库必须被视作敏感文件;而一旦加密 key 丢失,相关加密记录也无法恢复。
另外,暴露控制台和管理 API 到公网前,还需要设置 admin token;/v1 与 /mcp 则应使用独立的 runtime token。不要把"能访问控制台"误当成"已经做好鉴权"。
九、适合谁,不适合谁
适合:
- 正在做客服、运营、数据分析、项目管理等企业 Agent;
- 同时接 GitHub、Gmail、Slack、Notion 等多个 SaaS;
- 有多用户、多账号、OAuth、审计或最小权限需求;
- 需要在 MCP、HTTP、OpenAPI、SDK 间复用同一套 Action contract;
- 希望先接托管能力,未来保留私有化 / 自托管路径的团队。
不太适合:
- 只有一个固定 API 调用的小脚本;
- 纯本地 demo,且没有账号隔离、审计或权限控制诉求;
- 希望用一个开源项目自动消除 OAuth 审核、SaaS 限流、数据合规和安全审查的人。
结语
给 Agent 接 SaaS 的难点,从来不只是"再写一个 API wrapper"。
当连接从一个 token、一条脚本,发展为多个用户、多个账号和多个 Agent,账号归属、scope、Action 契约、运行 token、日志与故障定位都会变成产品问题。
OpenConnector 不会替你完成全部安全治理,但它把这些问题从 prompt glue 和环境变量中拆出来,放进一个可以部署、检查、收权限和追踪的 runtime。
如果你正在做会访问用户 SaaS 账号的 Agent,我建议不要只问:"模型能不能调用这个工具?"
还要继续问一句:它是以谁的账号、在什么边界内、以什么方式留下记录而调用的?