返回市场
代码执行with MCP

代码执行with MCP

作者:olaservo2 星标更新:2025-11-21

项目介绍

使用Claude Agent SDK进行MCP代码执行演示

使用Claude Agent SDK演示MCP代码执行模式。

概述

该项目灵感来源于Anthropic的一篇博客文章。该博客文章没有提供完整的代码,但提供了许多关于如何实现这一模式的提示。

我想要保持这个版本尽可能简单,并且与博客内容一致。我决定使用Claude Agent SDK,因为它已经支持代理技能、MCP和其他必要的功能。

此模式的实现生成了用于MCP工具的RPC包装文件。这些包装器是类型安全接口,代理可以发现并作为代码使用它们。

这是否表明MCP是一个巨大的错误/过度工程化等?

看到对这篇博客文章的所有反应,认为“MCP不好”,我感到(某种程度上)惊讶。这只是使用它的一种新方式。有时这有意义,有时则不然。

我更喜欢用实证证据来更好地理解这类问题,而不是陷入理论辩论。希望这些想法的具体解释能帮助生成更多证据,以便你自己判断这种解决方案是否适合某个用例。

我还喜欢Shaunak Joshi在他的回应这条推文时的观点:

MCP处理分发和发现(安装应用程序如连接器暴露能力),而代码模式仅处理纯执行(模型使用从MCP模式自动生成的SDK生成代码)。因此,MCP更像是一个打包层,你可以同时获得生态系统的好处和可组合性。

⚠️ 安全性和沙箱限制

重要: 当前实现不包括开箱即用的工作沙箱配置在Claude Agent SDK中。这意味着:

  • 不受限访问: 执行代码的代理具有对你的文件系统、网络和系统资源的完全访问权限
  • 安全风险: 没有内置保护措施防止潜在有害操作
  • 谨慎使用: 只在你完全理解任务的受信任环境中使用

计划改进:

我们正在积极研究解决这些限制的沙箱解决方案:

  1. Anthropic沙箱运行时 - 一种轻量级沙箱工具,使用原生OS基础结构(macOS上的sandbox-exec,Linux上的bubblewrap)强制执行文件系统和网络限制
  2. 基于Docker的配置 - 一种替代容器化方法,用于进程隔离

建议:

  • 只在控制的非生产环境中执行代码
  • 在允许执行之前审查生成的代码
  • 避免使用不可信的数据源或提示
  • 根据你的安全需求考虑实现自己的沙箱解决方案

直到强大的沙箱集成完成,将其视为实验演示而非生产就绪基础设施。

理解模式

什么是MCP代码执行?

MCP代码执行是一种构建高效AI代理的实验模式。

  • 将MCP工具暴露为RPC包装文件在文件系统结构中(类型安全接口,实际实现保留在MCP服务器上)
  • 按需发现和加载工具通过探索文件系统
  • 在代码环境中执行数据处理,然后将结果传递给LLM
  • 代理发现并构建持久、可重用的技能,利用这些工具包装器。

假设

一个假设是代码执行应该显著减少数据密集型工作流程中的令牌消耗,通过:

  1. 按需发现工具,而不是一开始就加载所有定义
  2. 在传递给LLM之前,在代码中处理大型数据集
  3. 允许复杂的数据转换,而无需多次调用工具

此存储库提供了两种模式,以便你可以测试并比较实际结果以适应你的用例。

示例性能结果:分析GitHub问题

我在两个真实世界仓库中测试了这两种方法:

感谢@johncburns1提出GitHub问题用例的想法!

大数据集示例:Claude Code仓库(5,205个开放问题)

Claude Code仓库提供了很好的压力测试,当时有大约5,000个开放问题,这是一个足够大的数据集,可以揭示两种方法之间的基本架构差异。

每种方法5次运行的结果:

代码执行在所有5次运行中都成功了。Claude一致创建了可重复使用的技能,并使用list_issues工具包装器成功获取和处理了所有问题。

直接MCP在所有5次运行中都失败了,尝试一次性将所有问题加载到上下文中时遇到了上下文溢出错误。

方法成功率平均持续时间平均成本输出
代码执行100% (5/5)343秒 (5.7分钟)0.34美元完整报告 + JSON
直接MCP0% (5/5)失败前31秒N/AN/A

为什么直接MCP失败:

  • 尝试一次性加载所有5,205个问题到上下文中
  • 在尝试加载约600-800个问题后达到200K令牌限制(第3轮)

为什么代码执行成功:

  • 编写了TypeScript代码,使用list_issues工具包装器按批次获取问题
  • 在内存中处理和聚合数据(约520K令牌)
  • 只将汇总统计数据传递给模型(约10K令牌)

小数据集:Anthropic SDK Python(45个问题)

当使用包含约45个开放问题的anthropic-sdk-python仓库进行测试时,两种方法都成功了,但代码执行仍然显著优于直接MCP:

指标代码执行直接MCP优势
成功率100% (5/5)100% (5/5)平局
平均持续时间76秒269秒快3.5倍
平均成本0.18美元0.54美元便宜67%
平均轮数11.64.8轮数多2.4倍
输出令牌2,05315,287少7.4倍
输出质量结构化,简洁叙事性,详细不同风格

输出样式差异:

两种方法产生了明显不同的报告风格:

  • 代码执行: 生成了结构化、数据导向的报告(约9.7KB),优化了快速扫描和机器解析。
  • 直接MCP: 生成了更丰富的叙事性报告(约15.8-19.5KB),包含更多的背景和解释。

两者准确地捕获了相同的数据(全部45个问题,正确的分类),但直接MCP的7.4倍更高的输出令牌数量反映了更冗长的解释性文本,而不是额外的见解。

复杂性权衡:

代码执行需要2.4倍更多的代理轮数(11.6比4.8),反映了以下开销:

  • 编写和调试TypeScript代码
  • 执行脚本并审查输出
  • 迭代数据处理逻辑

然而,这种复杂性开销被执行速度和成本节省所抵消。额外的轮数发生得很快,因为代理将计算委托给了代码,而不是生成大量的分析文本。

即使直接MCP在技术上可以成功,代码执行也提供了显著更好的性能。在这个例子中的主要权衡是“结构化”与“叙事性”的输出风格。

我对这个结果感到意外,因为我原本预计直接MCP在小数据集上会有优势,因为上下文限制不是问题。相反,代码执行由于数据处理的效率提升,即使在小规模下也超过了其额外的复杂性开销。

未来改进

技能优化: 代码执行方法的平均轮数(11.6)可以通过优化技能实现来减少。当前代理有时会迭代地编写和调试代码,而更高效的流程可能在较少的轮数内生成工作的代码。

完整实验数据

你可以在本仓库的发布标签页中找到由这些实验生成的日志、指标和工作区文件的完整压缩包

这些结果意味着什么

基于这些GitHub问题分析实验:

对于这个特定用例(分析仓库问题):

  • 代码执行是唯一可行的大数据集方法(5K+问题)
  • 即使在小数据集(45个问题)上,代码执行也比直接MCP快3.5倍,便宜67%
  • 主要权衡是结构化与叙事性输出风格,代码执行需要更多的代理轮数

开放问题:

这些结果只涵盖了任务的一种类型。需要更多的测试:

  • 不同的数据类型(结构化与非结构化)
  • 不同的操作(CRUD与分析)
  • 不同的MCP服务器(文件系统、数据库、API)
  • 实时与批处理工作负载
  • 需要来回迭代的任务

值得测试的假设:

代码执行可能在以下情况下有益:

  • 数据集大小未知或可能很大
  • 数据需要过滤/转换后再进行分析
  • 需要连接多个数据源
  • 同一工作流将被重复

但这仍然是假设,尚未证明结论。具体情况可能有所不同。

帮助建立证据:

如果你用不同的用例测试此模式,请在MCP社区讨论中分享你的发现,或在此仓库中打开一个问题。更多的数据点将帮助社区了解何时采用这种方法是有意义的。

执行流程

代理的代码                      传输              MCP服务器
─────────────                     ─────────              ──────────
import * as github from '...';

issues = await github.list_issues()
  → callMCPTool()
    → MCP客户端                  ═=HTTP/Stdio═>        GitHub API调用
                                                         认证
    ← 返回数据                <══════════            数据处理

filtered = issues.filter(...)     [停留在代码中]
sorted = filtered.sort(...)       [停留在代码中]

console.log(sorted)               → 回到LLM上下文

大数据集一次获取,然后在代码中处理,只有最终结果返回到LLM。这减少了与多次调用工具或在上下文中分析整个数据集相比的令牌消耗,以及完成任务所需的轮数。


设置

1. 环境变量

创建一个.env文件:

GITHUB_PAT=your_github_personal_access_token # 如果使用此仓库中的GitHub MCP服务器配置,则需要。需要读取目标仓库问题的权限。
ANTHROPIC_API_KEY=your_anthropic_api_key # 或者:使用AWS Bedrock设置
CLAUDE_CODE_USE_BEDROCK=0  # 设置为1以使用AWS Bedrock模型
ANTHROPIC_DEFAULT_HAIKU_MODEL=us.anthropic.claude-haiku-4-5-20251001-v1:0 # 如果使用AWS Bedrock,最新Haiku不会默认使用,需要显式设置

模型选择:

代理根据CLAUDE_CODE_USE_BEDROCK环境变量自动选择适当的模型:

  • CLAUDE_CODE_USE_BEDROCK=0(默认):使用标准Anthropic API模型

    • claude-haiku-4-5-20251001
    • claude-sonnet-4-5-20250929
  • CLAUDE_CODE_USE_B_1:使用AWS Bedrock模型

    • us.anthropic.claude-haiku-4-5-20251001-v1:0
    • us.anthropic.claude-sonnet-4-5-20250929-v1:0

2. 安装依赖

npm install

3. 生成MCP包装器

必需 - 包装器未提交到git(除了client.ts):

npm run generate-wrappers

这将连接到GitHub MCP服务器并为所有40个工具生成TypeScript包装器。

注意: 代理在执行前自动运行ensure-wrappers.ts,它:

  • 只在缺失或过期时重新生成包装器
  • 如果重新生成失败(例如,网络问题),则回退到现有包装器
  • .metadata.json文件中跟踪元数据

使用

执行模式

代理支持两种执行模式,用于比较MCP代码执行与基线MCP工具调用方法。详细的会话日志捕获了两种模式的详细指标,使您可以直接比较令牌使用情况、成本和执行模式。

运行代理

# 默认:代码执行模式,带有默认任务
npm start

# 直接MCP模式
npm run start:mcp           # 直接MCP模式

# 分析结果任务(用于比较实验结果)
npm run start:analyze-results

# CLI选项
tsx agent.ts --task=task-analyze-results.md  # 指定不同的任务文件
tsx agent.ts --model=haiku                   # 使用Haiku而不是Sonnet
tsx agent.ts --help                          # 显示所有选项

任务输入文件:

某些任务(如task-analyze-results.md)需要输入文件。要指定输入文件,请直接编辑任务文件中的路径prompts/task-analyze-results.md


### 会话日志

每次运行都会自动创建带有唯一会话ID的详细会话日志:

```bash
会话ID:code-execution-2025-11-18T15-32-10-123Z

日志文件:

  • logs/{session-id}.json - 用于程序分析的完整结构化数据
  • logs/{session-id}.md - 便于审阅的人类可读markdown格式

捕获的内容:

  • 每个工具使用及其完整输入参数
  • 每个助手消息和推理
  • 工具完成状态和错误
  • 每一步的时间信息
  • 最终指标(成本、令牌、持续时间)

失败运行追踪: 对于因错误而失败的运行,会话ID会被前缀为FAILED__以便于识别。日志文件和任何归档的工作区数据都会使用此前缀,使得诊断问题变得简单。

用途: 会话日志让你能够精确重现执行期间发生了什么,比较不同运行,并调试代理行为。它们特别适用于比较代码执行与直接MCP模式。

验证MCP设置

为了验证你的MCP配置是否正确,代理会在启动时自动检查包装器可用性和连通性。如果有问题,你会看到详细的错误消息。

你也可以手动重新生成包装器以测试连通性:

npm run generate-wrappers

这将连接到服务器并重新生成所有工具包装器。如果成功,你会看到显示生成工具数量的输出。

运行第一个任务

npm start

代理将:

  1. 归档之前的workspace内容(如有)到workspace_archive/
  2. 清除workspace目录以进行干净的运行
  3. 确保MCP包装器是最新的(如果过期则重新生成)
  4. prompts/加载模式特定的系统提示和任务
  5. 使用选定的执行模式执行任务
  6. 显示全面的指标并保存会话日志

它是如何工作的

MCP配置

.mcp.json文件配置要连接的MCP服务器:

{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/",
      "headers": {
        "Authorization": "Bearer ${GITHUB_PAT}"
      }
    }
  }
}

注意: 加载配置时会替换环境变量(例如,${GITHUB_PAT})。

传输支持

客户端支持:

  • HTTP传输type: "http"):使用StreamableHTTPClientTransport连接远程服务器
  • Stdio传输type: "stdio"):使用StdioClientTransport连接本地子进程服务器

RPC客户端桥接

servers/client.ts实现了callMCPTool()

export async function callMCPTool<T = any>(
  serverName: string,   // 'github'
  toolName: string,     // 'get_me'(短名称)
  input: any
): Promise<T> {
  // 获取或创建MCP客户端连接
  let client = mcpClients.get(serverName);
  if (!client) {
    client = await connectToMCPServer(serverName);
    mcpClients.set(serverName, client);
  }

  // 调用MCP工具
  const result = await client.callTool({
    name: toolName,
    arguments: input
  });

  // 解析并返回结果
  if (result.content && result.content[0]) {
    const content = result.content[0];
    if ('text' in content && content.text) {
      try {
        return JSON.parse(content.text);
      } catch {
        return content.text as T;
      }
    }
  }
  return result as T;
}

服务器指令

在生成包装器的过程中,脚本会从MCP服务器的InitializeResult(如果提供)中捕获服务器指令,并将它们保存到servers/{server-name}/README.md

代理应在使用该服务器的工具之前阅读这些指令,以确保正确的使用模式。你可以查看[这篇博客](https://blog.modelcontextprotocol.io/posts/2025