
FastMCP 4 服务器端文本生成工具直接调用 LLM 与向调用方发起采样怎么选【免费下载链接】fastmcp The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp在 FastMCP 4 中服务器端的工具需要生成文本摘要、问答、改写时可用的做法只有两种工具内部直接调用一个模型 SDK或者向调用方发起一次采样请求、借用调用方的模型。旧版里的ctx.sample()和ctx.sample_step()已经在 FastMCP 4 中移除本文给出两条新路径的完整代码、客户端配套配置以及验证每种方式确实生效的检查点。内容基于 docs/servers/sampling.mdx 与 docs/clients/sampling.mdx。FastMCP 4 为什么不再支持原来的采样 APIMCP 在2026-07-28协议版本中移除了服务器主动发起的请求SEP-2577现代协议是无会话的服务器没有可以推送请求给客户端的通道。原来“工具执行到一半、通过会话反向通道向客户端要一次补全”的做法失去了载体因此Context不再有sample()和sample_step()。在任何协议时代的连接上触碰这两个方法都会直接抛AttributeError而不是等运行到现代客户端时才失败FastMCP()也不再接受sampling_handler或sampling_handler_behavior参数传入会抛TypeError错误信息会指向迁移路径相比之下日志 这类通知ctx.info()等不受影响——通知是发完即走走客户端已经打开的响应流不需要服务器端保持一条可寻址连接。如果业务仍依赖服务器主动发起的采样可以停留在 FastMCP 3.x那里的ctx.sample()和ctx.sample_step()继续可用3.x 采样文档的入口链接在 docs/servers/sampling.mdx 开头的提示框中。升级前可以先用下面的两条路径评估是否还需要借用调用方模型。怎么选生成用的是谁的模型两种方式的核心差别是模型归属和往返成本文档给出的对比是维度工具直接调用 LLM向调用方发起采样模型与凭据服务器环境持有 API key模型由你选、提示词由你控制借用调用方的 provider、凭据和账单对客户端的要求不需要客户端实现任何东西对没实现过采样的客户端行为也完全一致客户端必须注册了sampling_handler成本工具里串联多次生成第二次、第三次不额外付费每次请求都是一个完整的往返循环生成的工具每轮都付这个成本可测试性可以不接任何客户端单独测试工具需要配好 handler 的客户端配合官方文档给出的判断标准原文见 docs/servers/sampling.mdx 与 docs/servers/elicitation.mdx是采样的价值“只在借用调用方模型本身是目的时才成立其他情况很少成立”。换句话说默认选直接调用 LLM只有“必须用调用方那个模型”比如调用方有私有模型、或费用必须记在调用方头上才选采样路径。路径一工具内直接调用 LLM做法就是普通 PythonAPI key 放在服务器环境里provider 客户端在模块作用域创建一次连接可跨调用复用生成逻辑写在工具里。文档示例摘自 docs/servers/sampling.mdximport anthropic from fastmcp import FastMCP mcp FastMCP(Summarizer) llm anthropic.AsyncAnthropic() mcp.tool async def summarize(text: str) - str: Summarize a document in two sentences. response await llm.messages.create( modelclaude-sonnet-4-5, max_tokens512, systemSummarize the users text in exactly two sentences., messages[{role: user, content: text}], ) return response.content[0].text换成其他 provider 时换掉客户端和调用即可工具签名不变任何 provider SDK 都走同样的模式。因为生成就是应用代码重试、超时、缓存、成本统计都按普通应用的方式处理不需要跨协议边界协商。验证方式也最简单文档明确这条路径的工具“可以不接客户端单独测试”并且对每个客户端包括从未实现采样的客户端行为一致。路径二向调用方发起采样guard pattern服务端返回 InputRequiredResult 而不是阻塞现代协议下的机制是工具通过返回一个InputRequiredResult来“要”一次补全——其input_requests映射里在你自定的 key 下放一个CreateMessageRequest。这一轮正常结束客户端执行补全后用同一个 key 把答案附上、重新发起同一个call_tool工具从ctx.input_responses里按同一个 key 读到CreateMessageResult。由于工具每一轮都从头执行区分两轮的依据就是ctx.input_responses首轮为None续轮有值。完整示例摘自 docs/servers/sampling.mdxfrom fastmcp import Context, FastMCP from mcp.types import ( CreateMessageRequest, CreateMessageRequestParams, CreateMessageResult, InputRequiredResult, SamplingMessage, TextContent, ) mcp FastMCP(Research) mcp.tool async def ask_the_caller(question: str, ctx: Context) - str | InputRequiredResult: Put a question to the callers model and report what it answered. responses ctx.input_responses if responses is None: return InputRequiredResult( result_typeinput_required, input_requests{ answer: CreateMessageRequest( methodsampling/createMessage, paramsCreateMessageRequestParams( messages[ SamplingMessage( roleuser, contentTextContent(typetext, textquestion), ) ], max_tokens100, ), ) }, ) answer responses[answer] if isinstance(answer, CreateMessageResult) and isinstance( answer.content, TextContent ): return answer.content.text return The client returned no completion.一个前提要记住返回InputRequiredResult需要2026-07-28的连接。如果握手时代的旧客户端调到这个工具FastMCP 会明确报出时代不匹配而不是静默失败。input_requests还可以一次携带多个请求、混装类型采样请求可以和 elicitation、roots 请求放在同一个 map 里每个答案按各自的 key 返回多轮工具跨轮携带状态的完整机制见 docs/servers/elicitation.mdx。客户端注册 sampling_handlerfastmcp.Client会自动驱动上面的多轮循环并用你注册好的sampling_handler回答为握手时代服务器写的客户端满足现代工具时不需要额外接线见 docs/clients/sampling.mdx。handler 收到服务器想补全的会话messages、参数params和请求上下文返回字符串即可FastMCP 会替你包成协议结果想报告真实模型名或返回非文本内容时自己返回CreateMessageResult。handler 抛异常时客户端会把错误作为补全的替代发回服务器由工具自己决定怎么处理。params里携带的字段包括system_prompt、model_preferences、temperature、max_tokens、stop_sequences、tools、tool_choice——客户端拥有模型服务器表达的偏好可以由客户端自行决定接受多少。不想手写 provider 调用时FastMCP 自带 OpenAI、Anthropic、Google Gemini 三个 handler实现了完整采样 API含工具调用pip install fastmcp[openai] # OpenAI handler pip install fastmcp[anthropic] # Anthropic handler pip install fastmcp[gemini] # Google Gemini handlerfrom fastmcp import Client from fastmcp.client.sampling.handlers.openai import OpenAISamplingHandler client Client( my_mcp_server.py, sampling_handlerOpenAISamplingHandler(default_modelgpt-4o), )OpenAI handler 还可以通过传入自己的 provider 客户端指向任何 OpenAI 兼容 API包括本地模型服务例如OpenAISamplingHandler(default_modelllama-3.1-70b, clientAsyncOpenAI(base_urlhttp://localhost:8000/v1))。需要跨 provider 路由、缓存或不被覆盖的 provider 时才写自定义 handler内置 handler 的实现是最好的参考。两个容易踩的点工具调用采样请求可以携带 tools。handler 把工具传给模型并原样返回含 tool calls工具由服务器自己执行、需要下一轮时再发采样请求——你的 handler 永远不执行工具。只生成文本的 handler应显式声明sampling_capabilitiesSamplingCapability()这样服务器知道不要发送会被丢弃的工具。跑起来并验证服务端按 快速上手 的方式启动。以 HTTP 传输为例在服务器文件末尾加if __name__ __main__: mcp.run(transporthttp, port8000)然后用python my_server.py启动或用 CLIfastmcp run my_server.py:mcp --transport http --port 8000客户端结合 docs/clients/sampling.mdx 的 handler 与 docs/getting-started/quickstart.mdx 的连接方式import asyncio from fastmcp import Client from fastmcp.client.sampling.handlers.openai import OpenAISamplingHandler client Client( http://localhost:8000/mcp, sampling_handlerOpenAISamplingHandler(default_modelgpt-4o), ) async def main(): async with client: print(client.protocol_version) result await client.call_tool( ask_the_caller, {question: What is the capital of France?} ) print(result) asyncio.run(main())验证看三处协议时代client.protocol_version在连接后报告协商到的协议版本。默认modeauto的客户端在 streamable HTTP 或 stdio 连到 FastMCP 服务器时协商到的就是无会话的2026-07-28这正是 guard 路径要求的连接见 docs/clients/client.mdx 的 Protocol negotiation 一节与 docs/more/faq.mdx。工具侧也可以在运行时读ctx.request_context.protocol_version。能力声明调用方必须在客户端能力里声明 sampling否则得到的是-32021错误而不是工具结果。仓库一致性测试服务器 tests/conformance/server.py 里的test_input_required_result_sampling工具展示了完整模式包括用require_client_capability(ctx, sampling)先检查能力再响应。端到端路线FastMCP 的一致性测试套件tests/conformance/在2026-07-28版本上跑的就是这条采样路线可以作为“这套接线应该是什么样”的参照。边界与限制往返成本是硬约束每次采样都是一个完整的请求-响应循环。生成很少适合循环着来——循环工具每一轮都付一次往返所以文档的建议是除非目的就是用调用方的模型否则在服务器里直接调用 LLM。SSE 传输的例外SSE 早于无会话时代携带不了它modeauto下会直接落在握手时代。此时 guard 路径不可用返回InputRequiredResult会得到明确的 era 错误依赖服务器主动发起采样的应用应固定modelegacy见 docs/more/faq.mdx。FastMCP 3 服务器不受影响3.x 的ctx.sample()/ctx.sample_step()原样保留升级前行为不变。handler 抛错时错误会传回服务器由工具决定如何处理不会挂起整个调用。下一步如果工具需要向用户要输入而不只是向模型要补全guard 模式的完整机制——包括跨轮状态的密封与校验——在 docs/servers/elicitation.mdx 中有覆盖采样和 elicitation 走的是同一套input_requests/input_responses通道。【免费下载链接】fastmcp The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考