接入外部工具 (MCP)
你可以把任意一个符合 MCP (Model Context Protocol) 的外部服务挂到 Agent 上,让它在对话里调用你自己的工具——查订单、改工单、拉数据都行。SDK 更进一步:让每个终端用户都用「他自己的」凭据去调用,而不是所有人共用一把后台密钥。 这对把 Agent 嵌进你自己产品的场景尤其重要。
自定义连接器是进阶能力,需要为你的账号开通后才能配置。如果你在「应用」里看不到自定义连接器入口,请联系 OpenHex 团队开通。
一个连接器,三种凭据来源
把外部 MCP 挂到 Agent 上,叫做配置一个连接器 (Connector)。配置时最关键的选择是:注入给外部服务的 Token 从哪来?
凭据来源 tokenSource | Token 从哪来 | 适用场景 |
|---|---|---|
owner(默认) | 所有者配置一次的共享密钥 | 不区分用户的后台工具,如一个内部只读 API |
perUser | 每个终端用户在对话里通过卡片自助填写 | 用户有 OpenHex 账号、愿意自己填 Token |
session | 你的应用在每次发送时通过 SDK 带上该用户的 Token | 企业内嵌:用户在你自己的站点登录,你的后端已持有他的 Token |
三种来源注入到外部服务的方式完全一致(都放进同一个鉴权头),区别只在「值从哪取」,所以随时可以切换来源而不用改外部服务。
Token 全程不落库、不进 Prompt、也不进入模型上下文——平台只在短时间内持有,由网关在调用外部服务时注入。
session:让每个用户用自己的 Token(推荐用于内嵌)
终端用户在你的站点登录、可能没有 OpenHex 账号,而你的后端已经握着他的第三方 Access Token。用 SDK 的 mcpTokens 在每次发送时带上即可,用户全程无感。
mcpTokens 的 key 是连接器的 slug,value 是该用户的 Token。
slug 在哪看? 打开该 Agent 的管理后台,进入**「应用」→「自定义应用」**,每个连接器卡片的名称旁都有一个 slug 徽章(标注「Slug(SDK 集成标识)」),点旁边的复制按钮即可。创建连接器时也可以在「Slug(SDK 集成标识)」输入框里自定义后缀——例如填
crm,实际 slug 为custom-crm(固定带custom-前缀);留空则按名称自动生成。slug 创建后不可修改。
import { OpenhexClient } from '@openhex-ai/agent-sdk';
const client = new OpenhexClient({
apiKey: sessionToken,
agentId,
// 传函数:每次发送前重新求值,轮换中的 OAuth Token 自动保持最新
mcpTokens: () => ({ 'custom-crm': currentUser.crmAccessToken }),
});
const turn = await client.sendMessage('帮我查一下我名下所有未结的工单');
也可以按对话或按单轮指定,优先级为 单轮 > 对话 > 客户端:
const convo = client.conversation({ mcpTokens: { 'custom-crm': tokenForThisChat } });
await convo.send('同步我的日历到本周任务', {
mcpTokens: { 'custom-crm': oneOffToken },
});
Token 过期了怎么办
平台不会在用户 Token 缺失或过期时改用所有者的密钥代为调用——那是跨身份越权。Token 失效时,这一轮里对应的工具调用会失败,Agent 会据此回复用户。
因为 SDK 在每次发送时都会重新带上 Token,你只需要保证 mcpTokens 回调返回的是最新的 Token(例如在回调里刷新你自己的 OAuth 会话),下一轮就会恢复正常,不需要额外处理。
perUser:让用户自助填写(BYOK 卡片)
连接器配成 perUser 时,如果用户还没填过 Token,Agent 首次调用该工具会在对话里放出一张连接卡片。SDK 负责解析卡片,并把用户填写的凭据保存到他自己的账户下(不会交给 Agent 所有者)。
import { OpenhexClient, extractConnectorSetup } from '@openhex-ai/agent-sdk';
const client = new OpenhexClient({ apiKey: userToken, agentId });
const convo = client.conversation();
const turn = await convo.send('用我的 Notion 建一个页面');
// 从本轮记录里找连接卡片
const setup = turn.records.flatMap(extractConnectorSetup)[0];
if (setup) {
// setup.fields: [{ key, label, … }],按字段渲染表单,收集用户输入
const retry = await convo.submitConnectorSetup(setup, { token: userTypedToken });
console.log(retry?.text); // 保存后 SDK 自动发一条提示,让 Agent 带着新凭据重试
}
submitConnectorSetup 保存凭据后,默认会自动发送一条提示消息让 Agent 重试,并返回这一轮的结果;不要再自己补发一条,否则 Agent 会收到两次。只想保存、不想触发重试时传 { notify: false }。
在 React 里使用
会话级凭据直接作为组件 / Hook 的属性传入,每次发送时自动带上:
import { ChatWidget } from '@openhex-ai/agent-sdk/react';
<ChatWidget
agentId="你的-agent-id"
getToken={getToken}
mcpTokens={() => ({ 'custom-crm': currentUser.crmAccessToken })}
/>;
连接卡片出现在消息的 connectorSetup 上;用 useOpenhexChat 自己画界面时,调用返回值里的 submitConnectorSetup(setup, values) 提交。
外部服务需要满足什么
你的 MCP 服务(或你指向的第三方 MCP)需要:
- 协议:MCP 的
streamable-HTTP(一个POST端点)。 - 鉴权:从请求头读取网关注入的凭据(如
Authorization: Bearer <token>)。 - 公网可达:HTTPS。