实测 OpenConnector:给 Agent 接 SaaS,别再把 Token 塞进环境变量

本文基于 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 调用,理想状态是:

  1. Agent 知道要执行 github.get_current_user
  2. Agent 选择 work 这个连接别名;
  3. runtime 在内部取出对应 credential 并执行;
  4. Agent 获得执行结果、账号标签和必要的错误信息;
  5. 原始 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":{}}'

调用成功后,返回结构中包含 successmessagedatameta.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 会保存稳定的账号画像,例如 accountIddisplayName 和已授予的 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,我建议不要只问:"模型能不能调用这个工具?"

还要继续问一句:它是以谁的账号、在什么边界内、以什么方式留下记录而调用的?


参考资料

相关推荐
ryan_9961 小时前
一次讲清 A2A 协议与 MCP 边界:从 Agent Card 到 Task 生命周期
agent·mcp·a2a·json-rpc·agent通信
xrlfreedom4 小时前
大厂 MCP 面试实录:本地 Server 远程化改造中的技术选型与落地实践
docker·json schema·mcp
五度易链-区域产业数字化管理平台1 天前
WorkBuddy 实战:将带 MD5 签名的第三方 API 封装为 MCP 服务(企业模糊搜索接口案例)
大数据·人工智能·mcp
栩栩云生1 天前
别再硬记 AWS 和 k8s 命令了!一行命令把十几个云平台的 CLI 全接进 AI
kubernetes·agent·mcp
枝枝在Coding1 天前
我把 Codex 接进 SSH 后,才发现 Xterminal MCP 最难的是敢不敢让 Agent 动手
ssh·mcp
可乐ea1 天前
Anthropic 的 CI/CD 值班智能体:Claude Tag 当一线响应者的架构拆解与踩坑复盘
ci/cd·架构·claude·devops·ai智能体·mcp
xrlfreedom2 天前
大厂 MCP 面试实录:内部 REST API 封装为可审计 MCP Tools 的落地方案
docker·mcp·提示注入防护
人间凡尔赛2 天前
多智能体系统(MAS)实战:Agent时代的“TCP/IP“如何落地?
ai·agent·多智能体·mcp·a2a
LHX sir2 天前
MCP 协议是什么?HubPort 如何让设备被 AI 智能体调用
人工智能·物联网·ai智能体·mcp