ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Composio Claude Agent SDK Node.js 端到端测试实战:从 fixture 到 MCP 工具调用验证

Composio Claude Agent SDK Node.js 端到端测试实战:从 fixture 到 MCP 工具调用验证 Composio Claude Agent SDK Node.js 端到端测试实战从 fixture 到 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本篇文章围绕 Composio 仓库中 ts/e2e-tests/runtimes/node/claude-agent-sdk/README.md 所描述的端到端测试展开深入讲解如何验证composio/claude-agent-sdk在当前 Node.js 运行时下与真实anthropic-ai/claude-agent-sdk包协同工作的完整链路。读完本文你将掌握该测试套件的运行方式、fixture 脚本的逐行原理、Provider 的底层实现机制以及如何在真实业务中把 Composio 工具以 MCP 形式挂载给 Claude Agent SDK 调用。一、为什么要做 Node.js 运行时上的 E2E 验证composio/claude-agent-sdk是 Composio 为 Claude Agent SDK 提供的官方 Provider 包其职责是把 Composio 工具转换成 Claude Agent SDK 能够识别和调用的 MCP 工具。由于它依赖 Node.js 运行时能力、anthropic-ai/claude-agent-sdk的接口形态以及 MCP 协议交互任何一层的变动都可能破坏集成因此仓库专门在 ts/e2e-tests/runtimes/node/claude-agent-sdk 下建立了一套端到端测试其目标非常明确Verifies thatcomposio/claude-agent-sdkworks on the current Node.js runtime with the realanthropic-ai/claude-agent-sdkpackage.测试采用确定性本地工具 真实 SDK的策略fixture 脚本包装一个确定性的、可预测输出的本地 Composio 风格工具把它挂载进 SDK 的 MCP 服务器然后向 Claude 发起一次真实查询让模型实际调用该工具最终断言调用链完整走通。这种方式既覆盖了真实 LLM 推理路径又通过固定 sentinel 值保证了结果的可判定性。该目录下共包含以下文件构成一个自洽的最小 E2E 工程文件作用fixtures/index.mjs被测脚本包装工具、挂载 MCP 服务器、发起 Claude 查询e2e.test.ts测试断言运行 fixture 并校验退出码与输出package.json包配置与运行脚本tsconfig.jsonTypeScript 编译配置CHANGELOG.md依赖版本变更记录二、前置要求与环境变量运行这套 E2E 测试需要满足两个前提Node.js 环境测试针对 current 版本 Node.js 运行时见 e2e.test.ts 中的versions: { node: [current] }。底层依赖方面composio/claude-agent-sdk的 package.json 声明了engines.node 22.22.3的最低运行时要求。Anthropic API Key因为测试会向 Claude 发起真实查询必须配置ANTHROPIC_API_KEY环境变量如 README 所示ANTHROPIC_API_KEY...在 e2e.test.ts 中该变量通过env配置从Bun.env.ANTHROPIC_API_KEY注入到测试运行环境。三、运行方式与测试断言3.1 一键运行命令README 给出了标准的运行命令pnpm --filter e2e-tests/node-claude-agent-sdk test:e2e:node该命令在 monorepo 中按包名过滤定位到本测试包。查看 package.json 可以发现test:e2e与test:e2e:node均映射到bun test e2e.test.ts即使用 Bun 的测试运行器执行测试文件同时包内还提供了typecheck脚本tsc --noEmit用于静态类型检查。3.2 测试断言逻辑e2e.test.ts 基于bun:test编写核心结构如下e2e(import.meta.url, { versions: { node: [current] }, usesFixtures: true, env: { ANTHROPIC_API_KEY: Bun.env.ANTHROPIC_API_KEY, }, defineTests: ({ runFixture }) { let result: E2ETestResult; beforeAll(async () { result await runFixture({ filename: index.mjs }); }, TIMEOUTS.LLM_LONG); describe(composio/claude-agent-sdk on current Node.js, () { it(exits successfully, () { expect(result.exitCode).toBe(0); }); it(executes the wrapped tool through Claude Agent SDK MCP, () { expect(result.stdout).toContain(claude query executed wrapped tool); }); }); }, });它调用了 ts/e2e-tests/_utils/src/e2e.ts 中导出的e2e()辅助函数。该辅助函数会自动完成三件事校验传入的import.meta.url必须是合法的file://URL从调用者的import.meta.url推断出仓库根目录下的工作目录cwd并以目录名作为测试套件名将配置透传给底层的runE2E执行器。测试设置了两个关键断言退出码为 0fixture 脚本内部任何一步失败工具未被调用、查询结果不含 sentinel、Claude 返回错误等都会通过throw中断进程最终反映为非零退出码stdout 包含哨兵日志fixture 成功跑通后会打印claude query executed wrapped tool该字符串由 fixtures/index.mjs 在全部校验通过后输出。由于涉及真实 LLM 推理beforeAll使用TIMEOUTS.LLM_LONG超时配置来自e2e-tests/utils/const为模型调用预留充足时间。四、fixture 脚本逐行解析完整的工具挂载与调用链路fixtures/index.mjs 是整个测试的核心完整复现了定义工具 → 包装为 MCP 工具 → 挂载 SDK MCP 服务器 → Claude 调用工具 → 校验结果的完整链路。下面分段拆解。4.1 定义确定性的本地工具首先定义了两个常量作为信号值const TOOL_SLUG COMPOSIO_E2E_SENTINEL; const SENTINEL COMPOSIO_CLAUDE_AGENT_SDK_NODE_CURRENT_OK;随后定义一个结构完整的 Composio 风格工具对象包含slug、name、description、version、availableVersions、inputParametersJSON Schema 格式与tagsconst tools provider.wrapTools( [ { slug: TOOL_SLUG, name: Composio E2E Sentinel, description: Returns the exact Composio Claude Agent SDK e2e sentinel. Use this tool when asked for the sentinel., version: e2e, availableVersions: [e2e], inputParameters: { type: object, properties: { label: { type: string, enum: [node-current], description: The e2e runtime label., }, shout: { type: boolean, description: Whether to return the uppercase sentinel., default: true, }, }, required: [label], additionalProperties: false, }, tags: [e2e], }, ], async (toolSlug, input) { ... } );这个工具刻意设计得确定性输入label限定为枚举值node-currentshout控制输出大小写执行处理器会严格校验参数async (toolSlug, input) { calls.push({ toolSlug, input }); if (toolSlug ! TOOL_SLUG) { throw new Error(Unexpected tool slug: ${toolSlug}); } if (input.label ! node-current) { throw new Error(Unexpected label: ${JSON.stringify(input.label)}); } return input.shout false ? SENTINEL.toLowerCase() : SENTINEL; }每次调用都会被记录到calls数组供后续断言工具确实被模型触发过。注意这里返回的是普通字符串而非 MCP 工具约定的{ content: [...] }结构——字符串到 MCP content 的规范化工作由 Provider 在包装层完成详见第五节。4.2 包装并挂载到 SDK MCP 服务器const mcpServer createSdkMcpServer({ name: composio, version: 1.0.0, tools, });createSdkMcpServer来自anthropic-ai/claude-agent-sdk它接收一个工具数组在进程内创建 MCP 服务器——这就是 README 中强调的no separate server to run无需单独运行服务器进程的关键MCP 服务器完全内嵌于当前 Node.js 进程工具执行直接回调到本地函数。4.3 发起 Claude 查询并强制工具调用for await (const message of query({ prompt: [ Use the ${TOOL_SLUG} tool with label node-current and shout true., Reply with exactly the tool result: ${SENTINEL}, Do not use any built-in tools., ].join(\n), options: { mcpServers: { composio: mcpServer }, tools: [], allowedTools: [mcp__composio__${TOOL_SLUG}], permissionMode: bypassPermissions, allowDangerouslySkipPermissions: true, maxTurns: 4, maxBudgetUsd: 0.25, persistSession: false, settingSources: [], }, })) { if (message.type result) { if (message.subtype ! success) { throw new Error(Claude query failed: ${JSON.stringify(message.errors ?? message)}); } queryResult message.result; } }这里的几个关键参数值得展开说明prompt三段式指令。第一段明确要求模型调用指定工具并给出参数第二段要求回复必须恰好包含 sentinel 值第三段禁止模型使用内置工具确保它只能走 Composio 挂载的工具路径mcpServers把上一步创建的 SDK MCP 服务器以composio为名注册给查询会话allowedTools使用mcp__composio__COMPOSIO_E2E_SENTINEL格式显式白名单授权该工具。注意命名规则mcp__{serverName}__{toolSlug}这是 SDK 对 MCP 工具的标准限定名格式permissionMode: bypassPermissions与allowDangerouslySkipPermissions: true跳过权限确认使工具调用可以无人值守地自动执行这是 E2E 场景下的合理选择maxTurns: 4限制多轮推理轮数防止模型陷入循环maxBudgetUsd: 0.25单次查询的美元预算上限控制真实 LLM 调用的成本persistSession: false不持久化会话每次查询独立。查询结束后fixture 对结果做三重校验const sdkCalls calls.filter(call call.toolSlug TOOL_SLUG); if (sdkCalls.length 1) { throw new Error(Expected Claude Agent SDK to call ${TOOL_SLUG}, got ${sdkCalls.length} calls); } if (!queryResult.includes(SENTINEL)) { throw new Error(Expected query result to include ${SENTINEL}, got ${JSON.stringify(queryResult)}); } console.log(claude query executed wrapped tool);只有同时满足模型确实调用了工具和最终回复包含 sentinel 值两个条件才会打印成功日志并正常退出——任何一环缺失都会让进程抛错从而被外层测试捕获为失败。五、Provider 底层原理Composio 工具如何变成 MCP 工具fixture 中provider.wrapTools(...)的背后是 ts/packages/providers/claude-agent-sdk/src/index.ts 中的ClaudeAgentSDKProvider类。理解它的实现才能明白整个 E2E 链路为何能成立。5.1 类结构与职责export class ClaudeAgentSDKProvider extends BaseAgenticProvider ClaudeAgentToolCollection, ClaudeAgentTool, McpServerGetResponse { readonly name claude-agent-sdk;它继承自composio/core的BaseAgenticProvidername标识为claude-agent-sdk。泛型参数明确了它的产出形态ClaudeAgentToolCollectionMCP 工具数组、单个ClaudeAgentToolReturnTypetypeof sdkTool即 Claude Agent SDK 中tool()工厂函数的返回类型以及McpServerGetResponseMCP 服务器响应。5.2 wrapToolJSON Schema 到 Zod 的严格转换wrapTool是核心方法它把单个 Composio 工具转换为 SDK MCP 工具。最关键的一步是输入参数 Schema 的转换const inputZodSchema jsonSchemaToZodSchema( dereferenceJsonSchema( composioTool.inputParameters ?? { type: object, properties: {}, additionalProperties: false, }, { onUnresolved: sentinel } ) );源码注释揭示了两个重要的工程细节必须注册完整对象 Schema 而非裸属性形状如果只取properties的原始映射那么根级约束——包括additionalProperties布尔值或 Schema 值和patternProperties——在结构上无法表达注册时会被丢弃。SDK 随后会静默地剥离未知键而不是拒绝它们这会让免费格式的工具根失去本应承载的内容。无参数工具保持封闭当工具没有inputParameters时兜底 Schema 显式写出additionalProperties: false因为裸的properties: {}现在会被 SDK 解释为开放对象。转换链为原始 JSON Schema →dereferenceJsonSchema解引用未解析引用时使用sentinel占位→jsonSchemaToZodSchema转成 Zod Schema最终通过sdkTool工厂函数注册。5.3 执行回调与错误处理工具处理器接收模型传入的参数并回调 Composio 执行const result await executeTool( composioTool.slug, normalizeToolArguments(args, composioTool.slug) ); return { content: [ { type: text as const, text: typeof result string ? result : (JSON.stringify(result) ?? ), }, ], };这里有两个值得注意的细节normalizeToolArguments源码注释指出模型偶尔会把工具输入编码成 JSON 字符串而非对象对应 issue #2406因此需要对参数做规范化处理返回值标准化无论执行结果是字符串还是对象统一转成 MCP 的content: [{ type: text, text }]结构。异常处理同样被封装进 MCP content而不是直接抛出} catch (error) { return { content: [ { type: text as const, text: JSON.stringify({ successful: false, error: error instanceof Error ? error.message : String(error), data: null, }), }, ], }; }这样即使工具执行失败模型也能在回复中看到结构化的错误信息便于多轮自我修正。5.4 批量包装与会话响应wrapTools只是对wrapTool的批量映射wrapMcpServerResponse则把 MCP URL 响应规范化为{ url: new URL(item.url), name: item.name }的标准形态。此外模块还重新导出了ClaudeAgentOptions类型来自 Claude Agent SDK 的Options方便使用方直接引用。六、从 E2E 到真实业务Provider 的标准用法E2E fixture 中的模式并非测试专属composio/claude-agent-sdk的 包 README 给出了生产场景下的标准用法。首先安装依赖npm install composio/core composio/claude-agent-sdk anthropic-ai/claude-agent-sdk随后创建会话、获取工具、挂载服务器并查询import { Composio } from composio/core; import { ClaudeAgentSDKProvider } from composio/claude-agent-sdk; import { createSdkMcpServer, query } from anthropic-ai/claude-agent-sdk; const composio new Composio({ provider: new ClaudeAgentSDKProvider() }); // Each session is scoped to one of your users const session await composio.create(user_123); const tools await session.tools(); const customServer createSdkMcpServer({ name: composio, version: 1.0.0, tools, }); for await (const stream of query({ prompt: Summarize my emails from today, options: { mcpServers: { composio: customServer }, permissionMode: bypassPermissions, }, })) { if (stream.type assistant) { for (const block of stream.message.content) { if (block.type text) process.stdout.write(block.text); } } }这段代码与 E2E fixture 的差异在于fixture 使用provider.wrapTools包装本地确定性工具而真实业务中工具来自composio.create(user_123)创建的会话每个会话对应一个最终用户实现用户级隔离工具数组直接由session.tools()返回。多轮对话场景下应保存session.sessionId并通过composio.use(sessionId)复用会话而不是每轮都新建。从包配置看package.jsoncomposio/claude-agent-sdk的 peer 依赖要求anthropic-ai/claude-agent-sdk ^0.3.199、composio/core 0.10.0 1.0.0 || 1.0.0-beta.0 1.0.0、zod ^4.0.0而 E2E 工程 package.json 中实际锁定的是anthropic-ai/claude-agent-sdk ^0.3.261、composio/core workspace:*、zod 4.5.4与 Provider 开发依赖保持一致。七、小结这套 E2E 验证了什么综合来看ts/e2e-tests/runtimes/node/claude-agent-sdk 这套测试覆盖了composio/claude-agent-sdk在 Node.js 运行时下的完整信任链包装正确性Composio 风格工具能被ClaudeAgentSDKProvider.wrapTools正确转换为 SDK MCP 工具src/index.ts挂载正确性转换结果能被createSdkMcpServer接受并在进程内提供 MCP 服务真实推理链路Claude 模型能识别 MCP 工具名、按allowedTools授权调用并把参数正确传入本地执行函数结果回传与解析工具返回值能经 MCP content 回传给模型最终进入查询结果文本运行时兼容性以上全部在 current Node.js 版本上通过真实anthropic-ai/claude-agent-sdk包验证e2e.test.ts。由于测试使用了真实的 Anthropic 模型与 API运行前请确保ANTHROPIC_API_KEY已正确配置。这套确定性工具 真实 SDK 哨兵断言的设计思路同样可以迁移到其他 Provider 包如anthropic、langchain、openai等参见 ts/packages/providers 目录的集成验证中作为跨包质量保障的通用范式。【免费下载链接】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),仅供参考
返回列表