跳到主要内容

接入外部工具 (MCP)

你可以把任意一个符合 MCP (Model Context Protocol) 的外部服务挂到 Agent 上,让它在对话里调用你自己的工具——查订单、改仓库、拉数据都行。SDK 更进一步:让每个终端用户都用「他自己的」凭据去调,而不是全员共用一把后台密钥。 这对内嵌到你自己产品里的场景尤其重要。

自定义连接器是进阶能力,需要为你的账号开通后才能配置。如果你在「应用」里看不到自定义连接器入口,请联系 OpenHex 团队开通。

一个连接器,三种凭据来源

把外部 MCP 挂到 Agent 上,叫做配置一个连接器 (Connector)。配置时最关键的一个选择是:注入给外部服务的那个 Token 从哪来?

凭据来源 tokenSourceToken 从哪来适用场景
owner(默认)所有者配置一次的共享密钥不区分用户的后台工具,如一个内部只读 API
perUser每个终端用户在对话里通过卡片自助填写用户有 OpenHex 账号、愿意自助填 Token 的 BYOK 场景
session你的应用在每次发送时通过 SDK 带上该用户的 Token企业内嵌:用户在你自己的站点登录,你的后端已持有他的 OAuth Token

三种来源注入到外部服务的形状完全一致(都是往同一个鉴权头里塞 Token),区别只在"值从哪取"。所以你随时能切换来源,而不用改外部服务。

Token 全程不落库、不进 Prompt、也不进入模型上下文——平台只在需要时短暂持有,由连接器网关在出站调用时注入。

session:让每个用户用自己的 Token(推荐用于内嵌)

这是企业内嵌的首选:终端用户在你的站点登录、可能没有 OpenHex 账号,而你的后端已经握着他的第三方 Access Token。用 SDK 的 mcpTokens 在每次发送时带上即可,用户全程无感

mcpTokens 的 key 是连接器的 slug,value 是该用户的 Token:

slug 在哪看? 它就是下方代码里 mcpTokens 返回对象的 key——本页示例中的 'custom-crm'。 到网页端复制:打开该 Agent 的管理后台,左侧导航进入**「应用」→「自定义应用」,每个连接器卡片的名称旁都有一个 slug 徽章(标注「Slug(SDK 集成标识)」),点旁边的复制按钮,粘贴进代码即可。 创建连接器时也可以在「Slug(SDK 集成标识)」输入框自定义一个好记的后缀**——例如填 crm,实际 slug 即为 custom-crm(固定带 custom- 前缀,弹窗会实时预览);留空则按名称自动生成。slug 创建后不可修改。

import { OpenhexClient } from '@openhex-ai/agent-sdk';

const client = new OpenhexClient({
apiKey,
agentId,
// 用回调,每次发送前重新求值——轮换中的 OAuth Token 自动保持最新
// key 'custom-crm' = 连接器 slug,在「应用 → 自定义应用」的连接器卡片上复制
mcpTokens: () => ({ 'custom-crm': currentUser.acmeAccessToken }),
});

const turn = await client.sendMessage('帮我查一下我名下所有未结的工单');
console.log(turn.text);

也可以按单轮覆盖(单轮优先于客户端级):

await client.sendMessage('同步我的日历到本周任务', {
mcpTokens: { 'custom-crm': oneOffToken },
});

优先级:单轮 opts.mcpTokens > 会话级 > 客户端级

处理"需要重新授权"

当某用户的 Token 过期或从未提供,平台会返回一个刷新信号。平台不会偷偷改用所有者的密钥替他调用(那是跨身份越权),而是让你刷新后重发:

import { getRefreshSessionTokenSignal } from '@openhex-ai/agent-sdk';

try {
await convo.send('查一下我的工单');
} catch (err) {
const need = getRefreshSessionTokenSignal(err);
if (need) {
const token = await refreshUserToken(need.connectorSlug); // key 就是连接器 slug
await convo.send('查一下我的工单', { mcpTokens: { [need.connectorSlug]: token } });
} else {
throw err;
}
}

perUser:让用户自助填写(BYOK 卡片)

当连接器配成 perUser 时,若用户还没填过 Token,Agent 首次调用该工具会在对话里放出一张连接卡片。SDK 提供工具解析它、并把用户填的凭据存到他自己的账户下:

import { OpenhexClient, extractConnectorSetup } from '@openhex-ai/agent-sdk';

const client = new OpenhexClient({ apiKey, agentId });
const convo = client.conversation();

await convo.send('用我的 Notion 建一个页面');

// 从消息历史里解析出连接卡片
const { entries } = await client.chat.messages(convo.id);
let setup;
for (const e of entries) {
const cards = extractConnectorSetup(e.data);
if (cards.length) { setup = cards[0]; break; }
}

// 用户填好后提交(存到该用户自己的账户),再让 Agent 重试
if (setup) {
await convo.submitConnectorSetup(setup, { token: userTypedToken });
await convo.send('好了,请继续');
}

在 React 里使用

会话级凭据可直接挂在聊天连接上,hook 会在每次发送时自动带上:

import { useOpenhexChat } from '@openhex-ai/agent-sdk/react';

const chat = useOpenhexChat({
connection: {
apiKey,
agentId,
// key = 连接器 slug(见上文「slug 在哪看?」)
mcpTokens: () => ({ 'custom-crm': currentUser.acmeAccessToken }),
},
});

外部服务需要满足什么

你的 MCP 服务(或你指向的第三方 MCP)需要:

  • 协议:MCPstreamable-HTTP(一个 POST 端点)。
  • 鉴权:从请求头读取网关注入的凭据(如 Authorization: Bearer <token>)。
  • 公网可达:HTTPS

不想自建?可以直接指向成熟的托管 MCP。

下一步