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

资讯详情

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

FastMCP 服务器框架实战:Context 对象与 RequestContext 类型注解配置指南

FastMCP 服务器框架实战:Context 对象与 RequestContext 类型注解配置指南 1. 为什么你的 FastMCP 工具函数拿不到请求上下文如果你正在用 FastMCP 写 MCP 服务器大概率遇到过这种场景工具函数里想打一条带请求 ID 的日志或者想给客户端报告进度结果发现根本不知道当前请求是谁发来的、进度该往哪个会话推。这不是你代码写错了而是没有把 Context 对象接进来。FastMCP 是构建 MCP 服务器的 Python 框架它把底层会话、请求元数据、进度令牌这些通信细节封装成了一个 Context 对象。你只需要在工具函数、资源函数或提示词函数的参数列表里声明一个类型注解为 Context 的参数框架就会在调用时自动把当前请求的上下文注入进去。参数名随便叫 ctx、context、c 都行关键是类型注解要对。这套机制适合三类人一是刚接触 MCP 协议、想把本地工具暴露给 AI 客户端的开发者二是已经在写 FastMCP 服务器但日志和进度报告一直没跑通的调试者三是需要给多个 AI 工具接入统一 API 通道、想用一套 Key 管理所有模型调用的团队。本文会从 Context 与 RequestContext 的封装关系讲起给出可复制的 config.toml 骨架和 TaoToken 统一 Key 配置然后演示通过类型注解获取请求上下文、验证注入是否生效的完整动作最后把常见的注入失败、类型不匹配、进度不显示等问题逐个排查。2. TaoToken 前置统一 Key 与 API 通道准备在写 FastMCP 服务器之前先把模型调用的通道准备好。TaoToken 提供统一的 API 入口你不需要为每个模型单独维护一套 Key 和地址。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 根地址是 https://taotoken.net/api 。第一步去控制台创建一个 API Key。打开 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 登录后在 API Keys 页面点新建复制生成的 Key。这个 Key 后面会写进 config.toml供 FastMCP 服务器在需要调用模型时使用。第二步确认你要用的模型名称。在模型对话页面 https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 可以直接测试模型是否可用把返回正常的模型名记下来。第三步如果你打算长期跑编码类 Agent 或需要稳定的调用配额可以看一下 Coding Plan 页面 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 它适合需要持续调用、不想每次手动换 Key 的场景。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有完整的请求格式和参数说明。API Keys 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 随时可以回来查看或轮换 Key。注意config.toml 里不要硬编码 Key 到代码仓库。用环境变量读取或者放在本地不提交的配置文件里。3. 可复制配置config.toml 骨架与 Context 注入代码3.1 config.toml 骨架先建一个项目目录比如 fastmcp-context-demo在里面创建 config.toml[server] name context-demo version 0.1.0 transport stdio [taotoken] base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY default_model gpt-4o-mini timeout 60 [logging] level INFO include_request_id true这里的关键是 api_key_env 指向环境变量名而不是直接写 Key。启动前在终端执行export TAOTOKEN_API_KEY你的KeyWindows PowerShell 用$env:TAOTOKEN_API_KEY你的Key3.2 最小可运行的 FastMCP 服务器安装依赖pip install fastmcp pydantic创建 server.pyimport os import tomllib from fastmcp import FastMCP from fastmcp.server.context import Context with open(config.toml, rb) as f: config tomllib.load(f) mcp FastMCP(config[server][name]) mcp.tool() async def long_running_task( task_name: str, ctx: Context, steps: int 5, ) - str: 执行带有进度更新的任务。 await ctx.info(f开始任务: {task_name}) for i in range(steps): progress (i 1) / steps await ctx.report_progress( progressprogress, total1.0, messagef步骤 {i 1}/{steps}, ) await ctx.debug(f已完成步骤 {i 1}) return f任务 {task_name} 已完成 mcp.tool() async def who_am_i(ctx: Context) - dict: 返回当前请求的元数据。 return { request_id: ctx.request_id, client_id: ctx.client_id, } if __name__ __main__: mcp.run(transportconfig[server][transport])这段代码里ctx: Context 就是类型注解注入的入口。框架在调用 long_running_task 时会自动识别这个注解把当前请求的 Context 实例传进来。你不需要手动 new 一个 Context也不需要从全局变量里取。3.3 Context 与 RequestContext 的封装关系Context 本质上是对 RequestContext 的封装。RequestContext 持有 request_id、meta、session、lifespan_context 这些底层字段而 Context 在其上加了 report_progress、read_resource、elicit、log 这些便捷方法。你在工具函数里拿到的 ctx 是 Context但通过 ctx.request_context 可以访问到底层的 RequestContext。mcp.tool() async def inspect_context(ctx: Context) - dict: 查看 Context 与 RequestContext 的字段。 rc ctx.request_context return { ctx_request_id: ctx.request_id, rc_request_id: str(rc.request_id), has_meta: rc.meta is not None, session_type: type(rc.session).__name__, }这样你既能用高层 API 打日志、报进度也能在需要时下钻到原始请求元数据。4. 验证请求确认 Context 注入是否生效4.1 用 MCP Inspector 或客户端调用启动服务器python server.py如果你用的是支持 MCP 的客户端把服务器配置指向这个 stdio 进程。调用 who_am_i 工具应该返回类似{ request_id: req_abc123, client_id: client_xyz }如果 request_id 是空字符串或者报 AttributeError说明 Context 没有被注入。最常见的原因是类型注解写成了字符串形式但没导入 Context或者参数名和类型注解不匹配。4.2 验证进度报告调用 long_running_task传入 task_name测试、steps3。客户端应该依次收到三条进度通知每条带 message 字段。如果客户端没有显示进度先检查客户端是否支持 progressToken再检查 report_progress 的 total 参数是否传了 1.0 而不是 steps。4.3 验证日志关联在服务器终端或客户端日志面板里应该能看到带 request_id 的 info 和 debug 消息。如果日志里没有 request_id检查 config.toml 的 include_request_id 是否为 true以及你的日志处理器是否读取了这个配置。4.4 用 TaoToken 模型对话做端到端验证打开 https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 选一个模型发一条消息确认 API 通道正常。然后在 FastMCP 服务器里加一个调用模型的工具import httpx mcp.tool() async def ask_model(prompt: str, ctx: Context) - str: 通过 TaoToken 调用模型并记录请求上下文。 await ctx.info(f收到请求 {ctx.request_id}准备调用模型) api_key os.environ[config[taotoken][api_key_env]] async with httpx.AsyncClient(timeoutconfig[taotoken][timeout]) as client: resp await client.post( f{config[taotoken][base_url]}/v1/chat/completions, headers{Authorization: fBearer {api_key}}, json{ model: config[taotoken][default_model], messages: [{role: user, content: prompt}], }, ) resp.raise_for_status() data resp.json() await ctx.debug(f模型返回完成request_id{ctx.request_id}) return data[choices][0][message][content]调用这个工具如果返回模型回复且日志里有 request_id说明 Context 注入和 TaoToken 通道都正常。5. 本篇常见错排查5.1 Context 参数没有被注入现象调用工具时报 TypeError: missing required positional argument ctx或者 ctx 是 None。原因通常是类型注解写错了。比如写成了 ctx: Context 但没有从 fastmcp.server.context 导入 Context或者写成了 ctx: RequestContext。FastMCP 识别的是 Context 类型不是 RequestContext。RequestContext 是底层对象不会自动注入到工具函数参数里。修复确保文件顶部有 from fastmcp.server.context import Context参数写成 ctx: Context。5.2 进度报告不显示现象report_progress 调用了但客户端没反应。先确认 total 参数。如果你传 totalsteps而 progress 是 1 到 steps 的整数有些客户端会按百分比解析导致显示异常。建议统一用 progress 为 0 到 1 的浮点数total1.0。再确认客户端是否在请求里带了 progressToken。如果客户端没带服务器端的进度通知可能被丢弃。可以在 inspect_context 里打印 rc.meta看有没有 progressToken 字段。5.3 日志没有 request_id现象ctx.info 输出的日志里没有请求 ID。检查 config.toml 的 include_request_id。另外FastMCP 的日志默认走会话发送给客户端如果你同时配置了本地 logging本地日志可能不自动带 request_id。可以在日志格式里手动加import logging logging.basicConfig( format%(asctime)s %(levelname)s %(message)s )然后在 ctx.info 的消息里自己拼上 ctx.request_id。5.4 异步函数里混用同步调用现象工具函数是 async def但里面调用了同步的 requests.get导致事件循环阻塞进度报告卡住。修复统一用 httpx.AsyncClient 或 aiohttp。如果必须调用同步库用 asyncio.to_thread 包一层。5.5 config.toml 读取失败现象tomllib.load 报 KeyError 或文件找不到。确认 Python 版本是 3.11tomllib 是标准库。如果是 3.10 及以下用 tomli 替代pip install tomliimport tomli as tomllib另外确认 config.toml 和 server.py 在同一目录或者用绝对路径读取。5.6 TaoToken 调用返回 401现象ask_model 工具报 401 Unauthorized。检查环境变量 TAOTOKEN_API_KEY 是否在当前终端会话里设置。如果你在 IDE 里运行IDE 可能没有继承终端的环境变量。可以在代码里加一行调试print(key prefix:, os.environ.get(TAOTOKEN_API_KEY, )[:8])如果打印为空说明环境变量没传进来。去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 重新复制 Key确认没有多余空格。6. 接入文档与后续动作Context 注入跑通之后下一步是把 read_resource 和 elicit 也用起来。read_resource 让你在工具里读取 MCP 资源elicit 让你在任务执行中途向用户追问信息。这两个方法的签名和示例在接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里有完整说明。如果你需要长期跑编码类 Agent或者多个工具共享同一套模型调用配额Coding Plan 页面 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 有对应的方案说明。API Keys 管理页 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 可以随时轮换 Key。模型对话页 https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 用来快速验证某个模型是否可用。最后提醒一个实操细节Context 参数在函数签名里的位置不影响注入但如果你同时有多个参数建议把 ctx 放在靠前的位置方便阅读。另外Context 是可选参数不需要它的函数完全不用声明框架不会强制注入。
返回列表