尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

FastMCP CodeMode 实战:用 search + execute 两个元工具把整个工具目录折叠进沙箱

FastMCP CodeMode 实战:用 search + execute 两个元工具把整个工具目录折叠进沙箱 FastMCP CodeMode 实战用 search execute 两个元工具把整个工具目录折叠进沙箱【免费下载链接】fastmcp The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcpCodeMode 是 FastMCP 提供的一种服务端 Transform它把完整的工具目录折叠成search关键词发现与execute沙箱内执行 Python 脚本、链式调用工具两个元工具。LLM 不再为每个中间结果消耗上下文 token而是编写一段在服务端沙箱中运行的脚本只把最终答案传回。本文以仓库中的 examples/code_mode 示例为主线结合源码与官方文档讲清 CodeMode 的原理、运行方式、配置手段与安全边界。CodeMode 要解决的两个扩展性问题标准 MCP 的工具调用模式存在两个规模化瓶颈目录全量加载整个工具目录会在开始时全部装入 LLM 上下文。当工具数量达到数百个时LLM 在读取用户请求之前就已经消耗了数万 token。逐次往返每一次call_tool都是一次LLM 调用工具 → 结果穿回上下文 → LLM 推理 → 再调用下一个工具的完整往返仅用于喂给下一步的中间结果也在反复烧 token。CodeMode 同时解决这两个问题LLM 看到的不是完整工具目录而是发现工具和编写并执行代码两类元工具。它按需发现on demand discovery在沙箱里写一段链式调用工具的脚本最终只拿到最终答案。该思路最初由 Cloudflare 在 Code Mode 中提出后被 Anthropic 在 Code Execution with MCP 中进一步探索详见 docs/servers/transforms/code-mode.mdx。快速运行两个终端即可体验仓库中的 examples/code_mode 目录包含三个文件README.md示例说明与运行方式server.py定义 8 个普通工具并挂载 CodeMode Transformclient.py演示search与execute的完整调用链启动方式两个终端uv run python server.py # 终端一启动服务 uv run python client.py # 终端二运行客户端也可以按 server.py 文件头注释中的方式运行uv run python examples/code_mode/client.py。依赖前提沙箱依赖pydantic-monty需要安装code-modeextrapip install fastmcp[code-mode]安装后uv或pip均可解析依赖。如果未安装pydantic-montyexecute会抛出ImportError提示Install it withfastmcp[code-mode]or pass a custom SandboxProvider见 code_mode.py。服务端一行 Transform 折叠 8 个工具server.py 用mcp.tool定义了 8 个普通工具add、multiply、fibonacci、reverse_string、word_count、to_uppercase、list_files、read_file。这些函数与标准 FastMCP 服务没有任何区别关键在最后一行from fastmcp import FastMCP from fastmcp.experimental.transforms.code_mode import CodeMode mcp FastMCP(CodeMode Demo) # ... 8 个 mcp.tool 定义 ... mcp.add_transform(CodeMode())也可以采用官方文档推荐的构造方式mcp FastMCP(Server, transforms[CodeMode()])见 docs/servers/transforms/code-mode.mdx。Transform 包裹已有工具工具函数本身完全不用改动。客户端发现、检索、一次往返执行client.py 完整演示了三步流程第一步list_tools()只返回两个合成元工具async with Client(Path(examples/code_mode/server.py)) as client: tools await client.list_tools()服务端明明有 8 个工具但客户端此时只能看到两个┌────────────── list_tools() ──────────────┐ │ Tool Description │ │ search Search for available tools ... │ │ execute Chain await call_tool(...) ... │ └── 8 backend tools collapsed into 2 ──────┘第二步search按关键词发现工具result await client.call_tool(search, {query: add multiply numbers})返回按相关度排序的匹配结果示例输出中命中 3 个┌──── search(querymath arithmetic) ─────┐ │ # Tool Description │ │ 1 add Add two numbers together. │ │ 2 multiply Multiply two numbers. │ │ 3 fibonacci Generate the first n ... │ └── 3 results ─────────────────────────────┘第三步execute一段脚本完成全部链式调用code \ a await call_tool(add, {a: 3, b: 4}) b await call_tool(multiply, {x: a[result], y: 2}) fib await call_tool(fibonacci, {n: b[result]}) return {sum: a[result], product: b[result], fibonacci: fib[result]} result await client.call_tool(execute, {code: code})整段脚本在服务端沙箱中运行只有最终return的值穿回上下文┌────────────── execute ───────────────────┐ │ a await call_tool(add, {a: 3 ... │ │ b await call_tool(multiply, ... │ │ return b │ └── result: 14.0 ──────────────────────────┘核心洞察README 原话标准 MCP 中每次call_tool都是经过 LLM 的一次往返而 CodeMode 下 LLM 只写一段脚本所有工具调用在服务端完成中间数据永远不会进入上下文窗口。源码级原理CodeMode 是如何折叠目录的code_mode.py 是完整实现核心类CodeMode继承自CatalogTransform。从源码结构看它通过两个钩子改造工具暴露面transform_tools(tools)把完整目录替换为发现工具列表 execute即[search, get_schema, execute]默认配置见 code_mode.pyget_tool(name, call_next)拦截对合成工具的查找其余名字继续走下游 Transform 链见 code_mode.py。execute工具的内部实现值得细看code_mode.py沙箱内只注入一个异步函数call_tool(tool_name, params)它先通过transform.get_tool_catalog(ctx)拿到经过鉴权过滤的工具目录找不到工具时抛NotFoundError(Unknown tool: ...)每次调用先检查max_tool_calls计数默认 50超限抛ToolError防止一段 LLM 生成的代码里的循环扇出成大量后端操作工具返回值经_unwrap_tool_result规范化有输出 schema 时返回structured_content否则把文本内容拼接成字符串返回见 code_mode.py。沙箱默认 MontySandboxProvider 与资源限制默认沙箱MontySandboxProvider由pydantic-monty驱动。源码中的_DEFAULT_LIMITS给出了开箱即用的保守基线code_mode.py_DEFAULT_LIMITS { max_duration_secs: 30.0, max_memory: 100_000_000, # 100 MB }即不传limits时默认 30 秒超时、100 MB 内存上限确保开箱配置不会无界运行。三个构造形态MontySandboxProvider() # 基线30s、100 MB MontySandboxProvider(limits{...}) # 自定义 MontySandboxProvider(limitsNone) # 显式不限limits支持的键全部可选省略即表示该维度不设上限见 docs/servers/transforms/code-mode.mdxKey类型说明max_duration_secsfloat最大墙钟执行时间max_memoryint内存上限字节max_allocationsint对象分配总数上限max_recursion_depthint最大递归深度gc_intervalint垃圾回收频率安全警告SandboxProvider协议注释明确强调run收到的code是不可信的 LLM 生成代码实现必须将其放入隔离沙箱执行绝不能直接exec()生产环境应使用MontySandboxProvider见 code_mode.py。仓库测试中的_UnsafeTestSandboxProvider也自注释为 UNSAFE: Uses exec() for testing only见 tests/experimental/transforms/test_code_mode.py。工具调用上限同样可调CodeMode() # 默认每次 execute 最多 50 次 call_tool() CodeMode(max_tool_calls200) # 调高上限 CodeMode(max_tool_callsNone) # 不设上限发现工具Search / GetSchemas / GetTags / ListToolsCodeMode 内置 4 个发现工具工厂默认只启用Search和GetSchemascode_mode.py。每个工具都支持default_detailLLM 也可在单次调用中覆盖。Search与GetSchemas共享同一套三种详细度输出格式一致级别输出Token 成本brief工具名 一行描述最低适合扫描detailed紧凑 Markdown含参数名、类型、必填标记中等通常足够写代码full完整 JSON schema最高Search基于 BM25 排序做自然语言检索默认最大 50 条。命中数少于目录总数时结果带N of M tools:前缀提示 LLM 还有更多可发现支持default_limit限制结果数、tags参数先按标签过滤再检索。示例Search(default_limit5)。GetSchemas按工具名返回参数细节detailfull时给出完整 JSON schema适合参数深度嵌套的场景。GetTags按标签浏览目录brief 输出- math (3 tools)这类计数full 输出各标签下的工具列表。默认不启用适合大目录让 LLM 先按类别定位。ListTools整体倾倒目录默认brief。默认不启用——对小型目录约 20 个工具以内一次性看全比多次 search 往返更快大目录则 search 更省 tokenfrom fastmcp.experimental.transforms.code_mode import CodeMode, ListTools, GetSchemas code_mode CodeMode( discovery_tools[ListTools(), GetSchemas()], )三种发现模式按目录规模取舍三阶段默认search → get_schema → execute。适合大型/复杂工具集LLM 只为真正用到的 schema 付费mcp FastMCP(Server, transforms[CodeMode()])如果工具带标签可加GetTags形成四阶段渐进式披露code_mode CodeMode( discovery_tools[GetTags(), Search(), GetSchemas()], ) mcp FastMCP(Server, transforms[code_mode])两阶段让 Search 直接返回参数 schema少一次往返适合中小目录code_mode CodeMode( discovery_tools[Search(default_detaildetailed), GetSchemas()], ) mcp FastMCP(Server, transforms[code_mode])单阶段跳过发现把工具说明写进 execute 的描述里适合工具很少、LLM 已知晓目录的场景code_mode CodeMode( discovery_tools[], execute_description( Available tools:\n - add(x: int, y: int) - int: Add two numbers\n - multiply(x: int, y: int) - int: Multiply two numbers\n\n Write Python using await call_tool(name, params) and return the result. ), ) mcp FastMCP(Server, transforms[code_mode])自定义发现工具与命名发现工具是工厂可组合的每个工厂接收GetToolCatalog目录访问函数而非目录本身——因为目录是请求级作用域的不同用户基于鉴权可能看到不同工具返回一个Toolfrom fastmcp.experimental.transforms.code_mode import CodeMode, GetToolCatalog, GetSchemas from fastmcp.server.context import Context from fastmcp.tools import Tool def list_all_tools(get_catalog: GetToolCatalog) - Tool: async def list_tools(ctx: Context) - str: List all available tool names. tools await get_catalog(ctx) return , .join(t.name for t in tools) return Tool.from_function(fnlist_tools, namelist_tools) code_mode CodeMode(discovery_tools[list_all_tools, GetSchemas()])注意LLM 看到的工具描述来自发现工具内部函数的 docstring因此 docstring 应写清返回什么、何时该调用。工具名也可自定义code_mode CodeMode( discovery_tools[ Search(namefind_tools), GetSchemas(namedescribe), ], execute_tool_namerun_workflow, )源码中_build_discovery_tools会校验名称唯一性并禁止发现工具与execute_tool_name重名见 code_mode.py。何时使用 CodeMode结合官方文档的指引CodeMode 特别适合工具数量多、LLM 需要编排多步工具调用的服务上下文占用从目录全量 每步中间结果降为按需发现 最终答案往返次数从每步一次降为一段脚本一次。官方文档同时给出经验之谈对于真正复杂的服务器分阶段发现往往效果更好——把用不上的工具详细 schema 一次性灌给 LLM其代价可能超过多一次往返的成本。需要注意的是CodeMode 目前属于实验性功能官方文档标注版本 3.1.0核心接口稳定但具体发现工具及其参数可能随实践演进。生产使用务必先落实code-modeextra 安装与沙箱资源限制并针对自己的工具目录跑通端到端调用链可参考 tests/experimental/transforms/test_code_mode.py 中的测试模式与 docs/servers/transforms/code-mode.mdx 的完整配置说明。【免费下载链接】fastmcp The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表