给每个用户一把"专属钥匙":Composio Tool Router 隔离 MCP 会话完全讲解
【免费下载链接】composioComposio powers 1000+ toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composio
做 AI 应用的人都遇到过这个麻烦:模型想调用外部工具,但工具背后连着真实账户。A 用户的邮件工具绝不能让 B 用户碰到,每个用户能用哪些功能、授权走到哪一步,都得有人管。Composio 的 Tool Router 就是干这件事的——它帮你为每个用户开一个隔离的 MCP(Model Context Protocol)会话,在会话级别精细圈定可用的 Toolkit 和 Tool,并把多套 OAuth 授权流程统一收口。
先建立心智模型:会话就是一次性保险柜
把 Tool Router 想成酒店前台:每位客人(用户)登记时领一张房卡,房卡只能开自己的房间;房间里能用什么电器、能不能用保险柜,都在入住登记时写死。
一张房卡 = 一个 session。你调用composio.create(userId, config)时,config 就是入住登记表:哪些 Toolkit 能进房间、哪些工具拔掉插头、账户用谁的授权,全部在这里定。而每个会话自带一个 MCP 服务器 URL,任何 MCP 客户端拿 URL 加请求头就能把房间里的工具"搬"进自己的 AI 框架。
5 行代码拿到第一个隔离会话
先装包:
npm install @composio/core@0.4.0然后是最小可运行示例:
import { Composio } from '@composio/core'; const composio = new Composio(); const session = await composio.create('user_123', { toolkits: ['gmail'], }); console.log(session.mcp.url);拿到session.mcp.url后,把它连同session.mcp.headers交给任意 MCP 客户端,这个用户就能访问 Gmail 工具了。注意两点:一是toolkits传的是 slug 字符串数组,等价于"只允许这些 Toolkit 进会话";二是走 MCP 路径时不需要给Composio构造函数传 provider。
场景一:精确圈定这个用户能碰哪些工具
create()的配置里,控制工具范围的主要是三个字段。
Toolkit 级开关——toolkits支持三种写法:
toolkits: ['gmail', 'slack'] // 只启用这些 toolkits: { enable: ['gmail'] } // 显式启用 toolkits: { disable: ['calendar'] } // 全开,唯独禁掉日历Tool 级开关——tools以 Toolkit slug 为 key,细化到单个工具:
const session = await composio.create('user_123', { toolkits: ['gmail', 'slack'], tools: { gmail: ['gmail_fetch_emails', 'gmail_send_email'], // 白名单 // 也可以写成 { disable: ['gmail_delete_email'] } 黑名单 }, });行为标签——tags用行为提示过滤工具,全局生效,也可在单个 Toolkit 下覆盖。可用值只有四个:readOnlyHint(只读)、destructiveHint(会改数据)、idempotentHint(可重试)、openWorldHint(开放世界)。
| 字段 | 控制粒度 | 常见坑 |
|---|---|---|
toolkits | 整个 Toolkit | 数组形式 = enable 白名单 |
tools | Toolkit 内单个工具 | enable/disable/tags三选一,同时传多个会在 Zod 校验时直接报错 |
tags | 跨 Toolkit 的行为维度 | 适合"这个用户只做只读操作"这类需求 |
另外两个绑定字段值得知道:authConfigs把 Toolkit 钉到某个认证配置 ID(例如公司邮箱和个人邮箱用不同的ac_xxx),connectedAccounts把 Toolkit 钉到某个已连接账户 ID。看源码可知,connectedAccounts的值传字符串会被 SDK 自动包成单元素数组再发给后端。
场景二:用户还没授权,会话怎么不卡死
这是 Tool Router 相比"自己拼 OAuth"最大的省心点。
默认做法:manageConnections默认开启(传true或不传都行),会话会带上管理连接的 meta tools,由模型在对话中自动引导用户完成授权:
const session = await composio.create('user_123', { toolkits: ['gmail', 'slack'], manageConnections: { enable: true, callbackUrl: 'https://your-app.com/auth/callback', waitForConnections: true, // 等待用户完成认证后再继续 }, });waitForConnections是 v0.4.0 新加的:会话会阻塞执行,直到所有必需连接建立完成。适合"授权没走完就别开始干活"的批处理或定时任务场景。
手动做法:如果关闭manageConnections(或就是想自己控制时序),用authorize()串联:
const request = await session.authorize('gmail', { callbackUrl: 'https://your-app.com/auth/callback', }); console.log(request.redirectUrl); // 把用户导向这个 URL const account = await request.waitForConnection(); // 阻塞到连接成功授权完可以用session.toolkits()轮询状态,返回每个 Toolkit 的connection.isActive、授权配置 ID、账户状态,支持按 slug 过滤和 cursor 分页。
场景三:把会话接到你正在用的 AI 框架
接入分两条路,选哪条取决于你要不要"框架原生工具对象"。
MCP 路径(多数框架推荐):客户端直接连session.mcp.url,零 provider。以 Vercel AI SDK 为例:
import { experimental_createMCPClient as createMCPClient } from '@ai-sdk/mcp'; const client = await createMCPClient({ transport: { type: 'http', url: session.mcp.url, headers: session.mcp.headers, // 已含 x-api-key 认证头 }, }); const tools = await client.tools(); // 直接喂给 streamTextLangChain(MultiServerMCPClient)、OpenAI Agents SDK(hostedMcpTool)、Claude Agent SDK(mcpServers选项)都是同样的套路:URL + headers。可运行的完整示例在 ts/examples/tool-router/ 目录里。
Provider 路径:只有当你想调用session.tools()拿到框架格式化的工具对象时才需要 provider,构造Composio时传入即可。仓库在 ts/packages/providers/ 下提供了 vercel、openai、openai-agents、langchain、claude-agent-sdk、anthropic、mastra、llamaindex 等十余种实现:
import { Composio } from '@composio/core'; import { VercelProvider } from '@composio/vercel'; const composio = new Composio({ provider: new VercelProvider() }); const session = await composio.create('user_123', { toolkits: ['gmail'] }); const tools = await session.tools(); // Vercel AI SDK 格式mcp.headers里会自动注入构造时传入的apiKey作为x-api-key请求头,类型限定为'http' | 'sse'两种。
场景四:往会话里塞自己的本地工具
experimental.customTools允许你把进程内工具注册进会话,和 Composio 远程工具混编。三种形态:
- 独立工具:无认证,
experimental_createTool('GREP', { inputParams: z.object({...}), execute }); - 扩展工具:加
extendsToolkit: 'gmail',继承 Gmail 的认证,execute的第二个参数ctx提供ctx.execute()复用远程工具; - 自定义工具箱:用
experimental_createToolkit把多个无认证工具打包。
const session = await composio.create('user_123', { toolkits: ['gmail'], experimental: { customTools: [grepTool, importantEmailsTool], }, }); await session.execute('GREP', { pattern: 'TODO', path: '/src' });两个硬约束:绑定了自定义工具的会话必须传 userId,否则构造器直接抛错;自定义工具也会参与session.search()的语义搜索,不用你手动注册。
如果你想深入底层
本地/远程分流是怎么工作的?模型一次批量调多个工具时,SDK 的routeMultiExecute()会解析COMPOSIO_MULTI_EXECUTE_TOOL的tools[]数组:本地工具在进程内并行跑,远程工具并行发后端,最后按原始顺序合并结果,并给出total_count/success_count/error_count统计。execute()对两种工具返回完全相同的{ data, error, logId }结构,你的代码不用关心工具住在哪。
沙箱(workbench)是什么?每个会话默认带一个远程代码执行沙箱,对应workbench配置(源码里新别名是sandbox,两者不能同时传)。关键开关:enable: false会整体关闭COMPOSIO_REMOTE_WORKBENCH与COMPOSIO_REMOTE_BASH_TOOL;autoOffloadThreshold控制响应超过多少字符自动卸载进沙箱;sandboxSize提供 standard(1 vCPU/1GB,默认)、medium、large、xlarge 四档算力。注意:改sandboxSize会重建沙箱,内存文件系统清空,但/mnt/files/持久目录保留。
会话还能"后补货"。session.update()支持部分更新,只改传入字段。三个进阶配置值得一知:sessionPreset: 'direct_tools'把所有通过过滤的工具直接平铺进session.tools()和 MCP 列表,并默认关掉 search 等 meta tools(工具集合固定、想省搜索步数时很好用);preload: { tools: [...] }预加载指定工具免去搜索;multiAccount开启多账户模式(每 Toolkit 最多 10 个账户),之后execute()可传options.account指定账户。
执行前后加钩子。v0.4.0 的会话级 modifiers 携带sessionId上下文:modifySchema改发给模型的 schema,beforeExecute改参数,afterExecute改结果。下图是afterExecute的典型用法——把完整响应裁剪成模型只需要的小字段:
会话自带虚拟文件系统。session.experimental.files提供upload(支持路径、URL、File、buffer)、list、download、delete,适合让 Agent 在会话内存取中间产物。完整的挂载说明见 ts/docs/api/ 下的 Tool Router Session Files 文档。
常见坑位 FAQ
Q:MCP 路径为什么不用 provider,session.tools()却报需要 provider?两条路设计如此:MCP 客户端自己从服务器拉工具定义;tools()要在本地生成框架格式的工具对象,必须由 provider 的wrapTools()完成。只走 MCP 就永远不用装 provider 包。
Q:tools里给同一个 Toolkit 同时写了enable和tags会怎样?直接抛校验错误。每个 Toolkit 的 tools 配置里enable/disable/tags只能出现一个——这是 schema 的superRefine强制的,不是静默忽略。
Q:重启服务后会话还在吗?在,只要保存session.sessionId。用composio.use(sessionId)拿回会话,MCP URL 可继续用;composio.create和composio.use分别是sessions.create/sessions.use的别名。删会话用session.delete()或composio.sessions.delete(),删不存在的会话会拿到后端 404。
Q:manageConnections: false和true差在哪?true(默认)时模型可通过 meta tools 自己发起并管理连接;false时 SDK 完全不代管,你必须自己调authorize()并处理回调,适合把授权流程嵌进自家产品页面的团队。
Q:改sandboxSize后会丢数据吗?内存文件系统会丢(沙箱整体重建),但/mnt/files/下的持久化文件保留。重要产物记得落在持久目录。
速查表
create()配置项一览
| 配置项 | 默认值 | 一句话说明 |
|---|---|---|
toolkits | 不限 | 数组 = 白名单;{enable}/{disable}显式控制 |
tools | 不限 | 按 Toolkit 细管单个工具,enable/disable/tags 三选一 |
tags | 无 | 按行为标签过滤,四个 Hint 可选,可被 tools 覆盖 |
authConfigs | 默认认证 | Toolkit → 认证配置 ID 的映射 |
connectedAccounts | 自动选 | Toolkit → 已连接账户 ID,字符串会自动包成数组 |
manageConnections | true | 含callbackUrl与 v0.4.0 新增的waitForConnections |
workbench/sandbox | 沙箱开启 | 二者互斥;可关、调 offload 阈值、选算力档位 |
sessionPreset | 默认 meta tools | 'direct_tools'平铺全部工具、关闭辅助 meta tools |
preload | 无 | 预加载工具 slug 列表或'all' |
multiAccount | 关闭 | 开启后每 Toolkit 可绑 2~10 个账户 |
experimental.assistivePrompt | 无 | 传 IANA 时区生成时区感知提示词 |
experimental.customTools | 无 | 本地工具/扩展工具,会话必须有 userId |
会话方法一览
| 方法 | 用途 |
|---|---|
session.tools(modifiers?) | 获取框架格式化工具,需 provider |
session.execute(slug, args) | 执行工具,本地与远程统一返回{ data, error, logId } |
session.search({ query }) | 按用例语义搜工具,含自定义工具 |
session.authorize(toolkit, opts?) | 发起授权,支持 callbackUrl、SHARED 连接 |
session.toolkits(opts?) | 查连接状态,支持过滤与分页 |
session.proxyExecute(params) | 借会话账户代理调第三方 API |
session.update(partial) | 部分更新会话配置 |
session.experimental.files | 会话虚拟文件系统的上传/下载/列表/删除 |
写在最后
Tool Router 的本质是把"谁能用什么、用谁的授权"从散落的 if-else 收敛成一张会话配置表:create()定规则,MCP URL 发钥匙,execute()/search()/authorize()管日常,update()管变通。对新手,建议路径是——先跑通最小示例拿到 MCP URL,接进你现有的 AI 框架;再按业务收紧toolkits+tools白名单;最后才碰沙箱、预加载、自定义工具这些进阶项。仓库里 ts/examples/tool-router/ 下的示例脚本(MCP、preload、direct-tools 各一套)和 ts/docs/api/tool-router.md 的完整 API 文档,可以直接对着继续往下挖。
【免费下载链接】composioComposio powers 1000+ toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考