
FastMCP v4 的 2026-07-28 协议支持双时代服务、SEP-990 身份断言与现代能力全景【免费下载链接】fastmcp The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp本指南以 FastMCP v4 开发笔记中的 2026-07-28 Protocol Support 为骨架系统梳理 v4 在现代2026-07-28协议时代上的完整能力一个服务器如何同时服务无会话新协议与基于握手的老协议、如何通过一个参数开启 SEP-990 企业级身份断言ID-JAG以及 v4 在现代协议上到底能做什么、哪些能力仍在规划中。读完本文你将掌握 v4 现代时代的协议机制、SEP-990 的配置与底层验证原理以及每项能力对应的仓库实现位置可作为 v4 部署与二次开发的参考底稿。背景2026-07-28 时代与双时代服务FastMCP v4.0 是一次引擎更换底层切换到 MCP Python SDK v2 线而 SDK v2 在协议层的核心变化之一是在同一个服务器上服务多个协议时代protocol era。除基于会话的握手时代handshake erasinitialize协商外SDK v2 引入了无会话的2026-07-28时代它通过server/discover发现能力并移除了服务器向客户端主动发起请求的机制SEP-2577。这一变化正式取代了 FastMCP 此前只支持最新协议的立场——现在单个服务器可以同时与协议过渡期内的新旧客户端协同工作详见 v4.0 Development Notes。协议时代的核心差异在于会话模型。按 Known Gaps and Upstream Dependencies 的记录2026-07-28时代在协议构造上就是无状态的现代路径上 SDK 的Connection严格按请求创建每个 POST 请求构建一个全新的Connectionconnection.session_id恒为Noneconnection.state是每次请求新生成的字典请求返回后即销毁。没有常驻的服务器→客户端流服务器→客户端请求会抛出NoBackChannelError。这对哪些能力在现代时代可用产生了决定性影响下文能力清单会逐项对照。FastMCP v4 的做法是双时代服务dual-era serving一个服务器同时应答server/discover现代、无会话与initialize握手两类连接并按每个连接自动检测时代。因此普通负载均衡器后面的任意副本都能应答现代请求无需会话亲和。SEP-990 身份断言一个参数开启企业 on-behalf-of 访问什么是 SEP-990 / ID-JAGSEP-990 定义了企业级的代表访问on-behalf-of流程企业身份提供商Okta、Microsoft Entra 等签发一个签名的ID-JAGIdentity Assertion JWT Authorization Grant断言员工的真实身份指向某个特定的 MCP 授权服务器员工的 Agent 通过 RFC 7523 的urn:ietf:params:oauth:grant-type:jwt-bearer授权类型把 ID-JAG 提交到 MCP 授权服务器的令牌端点授权服务器验证后签发一个短生命周期访问令牌。整个过程没有浏览器登录、没有逐用户同意页面撤销也发生在 IdP 侧。从职责划分上看FastMCP 与现代协议的对接可以拆成两层协议层来自 MCP Python SDK授权类型解析grant parsing、exchange_identity_assertionprovider 钩子、授权服务器元数据中的能力宣告实现层在 FastMCP 内部让流程真正工作的校验与签发逻辑是 FastMCP 自己实现的存放于 fastmcp_slim/fastmcp/server/auth/identity_assertion.py并接入 OAuthProxy 的授权服务器栈。而开启它只是在现有 auth provider 上加一个参数from fastmcp import FastMCP from fastmcp.server.auth import OAuthProxy, IdentityAssertion auth OAuthProxy( ..., # 既有 upstream 配置保持不变 identity_assertionIdentityAssertion( trusted_issuers[https://login.acme-corp.com], ), ) mcp FastMCP(Internal API, authauth)IdentityAssertion 配置参数详解IdentityAssertion是一个 pydantic 配置模型identity_assertion.py挂到OAuthProxy(identity_assertion...)上后代理的令牌端点就接受来自trusted_issuers的 ID-JAG并为被断言的主体签发短生命周期访问令牌。各参数如下参数类型默认值含义trusted_issuerslist[str]必填授权服务器接受的iss值必须与断言中的iss声明完全一致。每个 issuer 的 JWKS 默认通过 OIDC 发现获取{issuer}/.well-known/openid-configuration除非在jwks_uris中覆盖。不可为空源码_validate_trusted_issuers校验。jwks_urisdict[str, str] \| NoneNone按 issuer 字符串键控的显式 JWKS URI。对不发布 OIDC 发现文档的 IdP 必须提供此项。audiencestr \| NoneNoneID-JAG 上期望的aud值。省略时默认使用本服务器自身的 issuer 标识授权服务器元数据中发布的issuer即设置了issuer_url时用它、否则用base_urlSEP-990 要求 ID-JAG 的aud指向此处。仅当 IdP 为不同受众标识签发断言时才覆盖。required_scopeslist[str] \| NoneNone签发的访问令牌上必须存在的 scope 集合从断言中派生并核对。algorithmstr \| NoneNone可信 issuer 使用的 JWS 签名算法如ES256、PS256。省略时默认按RS256校验用其他算法签名的 IdP 必须显式设置。不同 issuer 使用不同算法时用algorithms逐 issuer 覆盖。仅支持非对称算法JWKS 只含公钥。algorithmsdict[str, str] \| NoneNone按 issuer 键控的签名算法覆盖与jwks_uris对应。缺省的 issuer 回落到algorithm。access_token_expiry_secondsint300从 ID-JAG 铸造的访问令牌生命周期秒。SEP-990 依赖客户端重新交换新断言因此刻意设短且不签发 refresh token。源码中SUPPORTED_ASSERTION_ALGORITHMSidentity_assertion.py定义了 JWKS 校验支持的非对称 JWS 算法集合RS256/RS384/RS512、PS256/PS384/PS512、ES256/ES384/ES512。配置校验器会拒绝集合之外的算法如 HS* 共享密钥或拼写错误的算法名避免在第一次交换时才暴露为 500而是立刻给出清晰的配置错误。底层验证流程SEP-990 §5.1 / RFC 7523 §3 的完整处理在IdentityAssertion参数背后IdentityAssertionValidatoridentity_assertion.py执行完整的 SEP-990 §5.1 / RFC 7523 §3 处理validate()方法按固定顺序执行以下检查typ头校验JOSE 头的typ必须是oauth-id-jagjwt常量ID_JAG_TYPSEP-990 §5.1 强制要求。可信 issuer 预检先用未验签解码读取ississ必须命中trusted_issuers才会为该 issuer 拉取密钥——一个畸形但受信任 issuer的断言在验签前就会触发 OIDC 发现出站请求因此源码对发现过程做了并发串行化与失败冷却_discovery_failures 30 秒 cooldown防止垃圾请求放大成请求洪泛。签名与标准声明验证复用JWTVerifierfastmcp_slim/fastmcp/server/auth/providers/jwt.py做 JWKS 签名校验及iss/aud/exp检查JWKS URI 优先取jwks_uris配置否则通过 OIDC 发现获取JWTVerifier按 issuer 惰性创建并缓存。时间类校验exp必须存在nbf不得早于当前时间带 30 秒时钟偏移容忍CLOCK_SKEW_SECONDSiat不得在未来断言总生命周期不得超过MAX_ASSERTION_LIFETIME300 秒即 5 分钟符合 RFC 7523 的短生命周期建议非数值时间声明会被干净地拒绝为invalid_grant。sub必填RFC 7523 §3 要求sub声明标识终端用户。scope 派生与收紧签发令牌的 scope 从签名的断言中派生支持scope与scp两种声明客户端请求的 scope只能收窄、不能加宽。client_id与resource绑定校验断言的签名client_id必须与当前认证客户端一致resource声明必须与服务器资源 URL 匹配比较前规范化去查询参数与尾部斜杠兼容 RFC 8707。这一步在jti记为已消费之前执行因此被错误绑定提交的断言不会烧掉合法持有者的重放保护。jti重放拒绝jti必须是非空字符串已见过的jti在过期前重复使用会被拒绝。缓存按断言过期时间清理每 60 秒并设有 10000 条紧急容量上限——超过容量时先清理过期条目仍超限则直接拒绝并记录可能的攻击告警。校验通过后exchange_identity_assertion钩子oauth_proxy/proxy.py以access_token_expiry_seconds为生命周期铸造短生命周期访问令牌无 refresh token并记录已签发令牌的撤销追踪。断言中的 subject 流入常规 FastMCP 认证上下文工具像对待任何其他身份一样通过get_access_token()fastmcp_slim/fastmcp/server/dependencies.py读取。源码与测试佐证这一整套逻辑有完整的测试覆盖见 tests/server/auth/oauth_proxy/test_identity_assertion.py覆盖场景包括可信/不可信 issuer、错误aud/typ/签名、过期断言、未来nbf、jti重放拒绝、请求 scope 不能加宽断言 scope可收窄、client_id/resource绑定不匹配、断言 subject 流入认证上下文、非数值时间声明拒绝、未配置时授权类型被拒等。值得一提的实现细节模块通过from fastmcp.server.auth import ...惰性再导出测试test_lazy_reexport_does_not_import_module确保未启用身份断言时不引入额外依赖。在企业栈中的位置身份断言并不是孤立的特性它嵌入 FastMCP 既有的授权服务器栈OAuth 代理的动态客户端注册DCR、同意流程、自签发 JWTself-issued JWTs、受保护资源元数据RFC 9728。正是因为有这套完整栈才使得单参数开启企业部署成为可能——授权服务器元数据会在启用后宣告urn:ietf:params:oauth:grant-profile:id-jag授权类型档案常量ID_JAG_GRANT_PROFILE。需要说明的是jti重放缓存是进程内的与 CIMD 断言验证器一致横向扩展的多个 worker 或副本之间不共享这是文档明确记录的部署注意事项。现代时代能力清单v4 部署在现代协议上能做什么下表是 FastMCP v4 服务器与客户端在2026-07-28时代提供的完整能力继承自 protocol-2026.md随后逐项展开能力FastMCP 提供的支持双时代服务一个服务器同时应答server/discover现代、无会话与initialize握手连接按连接自动检测。普通负载均衡器后的任意副本都能应答现代请求。身份断言SEP-990完整的服务端实现一个参数开启见上文。授权服务器完整 AS 栈OAuthProxy桥接期望 DCR 的 MCP 客户端与非 DCR 企业 IdP约 18 个内置 provider同意 UI自签发 JWT受保护资源元数据RFC 9728。缓存提示SEP-2549服务器级创作FastMCP(cache_ttl..., cache_scope...)为每个可缓存结果盖章FastMCP 客户端以可选响应缓存遵循提示。分布式响应缓存KeyValueResponseCacheStore用任意键值存储Redis、内存、文件树支撑客户端缓存客户端集群或代理副本跨进程共享缓存填充。资源路径安全模板化资源参数在 handler 运行前筛查目录穿越、绝对路径与空字节——默认开启含 provider 来源与 mount 的模板。客户端协议协商Client(modeauto)v4 起为默认探测server/discover回落到经典握手客户端通过既有 handlers 应答多轮input_required请求。modelegacy强制握手。现代协议上的 ElicitationSEP-2322工具通过多轮往返请求用户输入工具返回InputRequiredResult并逐轮重跑从ctx.input_responses/ctx.request_state读取客户端回答guard 模式。每轮是一个完整的请求→响应周期框架在线上密封request_state、工具运行前解封共享密钥request_state_security策略跨副本携带状态。在握手时代连接上返回此结果会产生明确的时代错误。规范标准错误SEP-2164缺失资源读取返回-32602现代连接上的 push 特性调用失败会得到明确的时代特定错误而非笼统的 method-not-found。中间件类型化按方法钩子on_call_tool、on_list_tools等及一组内置中间件auth、限流、缓存、错误处理、日志、计时等。组合mount()、providers、代理与工具变换在运行时动态组合服务器lifespan 与中间件由 SDK 会话管理器驱动。分页声明式FastMCP(list_page_size...)为高级服务器中的所有 list 操作分页客户端自动分页并带循环检测。遥测OpenTelemetry spans 默认开启无 exporter 时为 no-opSDK 对齐属性mcp.method.name、mcp.protocol.version、gen_ai.*另有 auth 与 provider 委托 spansFASTMCP_TELEMETRY_MODE选择native、propagation_only与外部 MCP 插桩层互操作或off。后台任务SEP-2663fastmcp-tasks端到端实现io.modelcontextprotocol/tasks扩展mcp.add_extension(TasksExtension())加taskTrue把工具作为后台任务运行由 FastMCP 3 就使用的同一 Docket 引擎驱动。客户端透明地完成被任务化的调用任务中途收集输入使用与前台多轮工具相同的 guard 模式工具只需写一次、两种方式都可用。仅限现代协议——被取代的 SEP-1686taskTrue运行时已整体移除不做桥接。双时代服务与客户端协商服务端双时代已经在上文介绍。客户端一侧的对应物是modeautov4 起默认fastmcp_slim/fastmcp/client/client.py 文档明确——auto 模式探测最新现代版本上的server/discover若服务器无server/discover则回落到经典握手协商连接建立后mode与协商出的协议版本可从连接对象读取。modelegacy或直接钉住旧版本则跳过探测、直接走握手。需要注意的是SSE 传输上的modeauto会直接协商经典握手见 transports/sse.py 与 transports/base.py 的注释因为部分服务器能应答server/discover却无法通过 SSE 提供后续服务。缓存提示与分布式响应缓存服务器侧SEP-2549在FastMCP(cache_ttl..., cache_scope...)设置后fastmcp_slim/fastmcp/server/caching.py 会为每个可缓存方法构建CacheHint映射cache_ttl以秒为单位、转换为线上毫秒cache_scope缺省为private。源码的约束很明确cache_scope没有cache_ttl是无意义的客户端以 hint 是否存在为缓存开关cache_ttl必须为正整数否则抛ValueError未设置cache_ttl时服务器不发出任何 hint线上输出与未设置者完全一致。客户端侧KeyValueResponseCacheStorefastmcp_slim/fastmcp/client/caching.py实现 SDK 客户端响应缓存契约get/set/delete/clear底层是 FastMCP 已在别处使用的键值抽象Redis、内存、文件树等任意AsyncKeyValue存储因此一个客户端集群或代理副本可以跨进程共享缓存填充。用法示例from fastmcp import Client from fastmcp.client.caching import KeyValueResponseCacheStore from mcp.client.caching import CacheConfig from key_value.aio.stores.redis import RedisStore store KeyValueResponseCacheStore(storageRedisStore(urlredis://localhost)) config CacheConfig(storestore, partitiontenant-a, target_idweather-api) client Client(https://example.com/mcp, modeauto, cacheconfig)实现上值得注意缓存条目序列化时带type_tag模型类名读取时按白名单CACHEABLE_RESULT_MODELS由 SDK 的MONOLITH_RESULTS方法结果注册表自动推导重建模型而不是从存储内容导入任意名字——这是防止存储内容被篡改后反序列化攻击的一层防护DEFAULT_CACHE_COLLECTION命名空间保证clear()不会越界清到其他适配器实例的数据。资源路径安全默认开启模板化资源mcp.resource(file:///{path})风格从请求 URI 直接提取参数值交给资源函数当这些值流入文件系统或 URI 构造时恶意客户端可以通过模板夹带目录穿越载荷../、绝对路径、空字节。FastMCP 的ResourceSecurityfastmcp_slim/fastmcp/resources/security.py在资源 handler 运行之前筛查提取出的参数值默认开启覆盖 provider 来源与 mount 的模板reject_path_traversal默认True拒绝包含..路径分量的值reject_absolute_paths默认True拒绝形如绝对文件系统路径的值reject_null_bytes默认True拒绝含 NUL\x00的值——空字节会破坏字符串比较..\x00 ! ..并可能在 C 扩展或子进程调用中被截断exempt_params默认空跳过检查的参数名集合支持 URI 模板连字符拼写{git-ref}提取为git_ref两种写法都能匹配豁免。筛查发生在 URI 匹配模板、参数值提取并 percent-decode 之后因此无论值以字面量、%2F、%5C还是%2E%2E编码检查都生效而复用 SDK 的组件级穿越检查意味着只含点号的值如HEAD~3..HEAD、v1..v2、file.tar.gz不会被误杀只有真正的..路径段才会被判定为穿越。需要豁免的场景如可能合法包含..的 git ref可通过securityResourceSecurity(exempt_params{ref})按组件关闭。现代协议上的 ElicitationSEP-2322guard 模式2026-07-28时代移除了服务器向客户端推送请求的能力因此依赖会话反向通道的命令式ctx.elicit在现代连接上不可用取而代之的是多轮往返MRTRguard 模式工具返回InputRequiredResult逐轮重跑从ctx.input_responses/ctx.request_state读取客户端回答。每轮是一个完整的请求→响应周期框架在线上密封sealrequest_state工具运行前解封unseal共享密钥request_state_security策略让状态可以跨副本携带这解决了无状态协议下多副本间状态如何传递的问题。在握手时代连接上返回此结果会产生明确的时代错误而不是静默降级。该模式的完整用户文档见 docs/servers/elicitation.mdx。规范标准错误SEP-2164现代时代下错误语义更严格缺失资源读取返回-32602invalid params 类错误而非笼统的 method-not-foundpush 类特性如采样在现代连接上被调用时会得到清晰的时代特定错误而非泛化的方法不存在错误——例如ctx.elicit/ctx.sample在现代连接上被时代门控为抛出明确错误对应 PR #4448见 feature-program.md 与 known-gaps.md 的 sdk-feedback #10 记录。中间件、组合、分页与遥测中间件类型化按方法钩子on_call_tool、on_list_tools等加一组内置中间件auth、限流、缓存、错误处理、日志、计时等initialize拦截已接入 SDK 的ServerMiddleware列表并作为中间件分发的根入口见 feature-program.md 的 Middleware root dispatchPR #4553。组合mount()、providers、代理与工具变换在运行时动态组合服务器lifespan 与中间件经 SDK 会话管理器驱动。分页声明式FastMCP(list_page_size...)为高级服务器中的所有 list 操作分页客户端自动分页并带循环检测避免分页游标成环。遥测OpenTelemetry spans 默认开启无 exporter 时为 no-op属性与 SDK 对齐mcp.method.name、mcp.protocol.version、gen_ai.*另有 auth 与 provider 委托 spansFASTMCP_TELEMETRY_MODE支持native、propagation_only与外部 MCP 插桩层互操作与off三档对应 PR #4481。后台任务SEP-2663后台任务在现代时代以fastmcp-tasks可选包的形式回归完整设计见 Background Tasks (SEP-2663)用户文档见 docs/servers/tasks.mdx。要点如下扩展机制SEP-2663 定义io.modelcontextprotocol/tasks扩展基于 SEP-2133 的扩展协商机制。服务端通过mcp.add_extension(TasksExtension(urlredis://...))注册这是启用任务所必需的不会被taskTrue自动推断taskTrue只是逐组件声明这个工具可以作为任务运行。两者分离的设计是刻意的扩展配置后端 URL、worker 并发、TTL 默认值需要明确的安放处同时保持能力宣告诚实——服务器仅当扩展已注册时才宣告tasks能力避免生产环境里工具静默跑在内存后端的坑。taskTrue未注册扩展会得到响亮的构建期错误。线上形态客户端按请求在_meta中宣告任务能力服务器决定是否任务化一次tools/call若任务化返回携带服务器生成taskId的CreateTaskResult客户端轮询tasks/get直到终态结果内联在响应中任务执行中的输入收集是轮询式的状态翻转为input_required请求出现在inputRequests映射客户端经tasks/update应答tasks/cancel是协作式的。Mcp-Name: taskId路由头在多副本共享 Redis 的部署中不再必要——任意副本都能服务轮询。客户端体验友好接口call_tool透明驱动轮询循环并返回完成结果是否被任务化对调用方不可见低层call_tool_mcp返回原始CreateTaskResult快速返回标志可拿到Task句柄.status()、.wait()、.cancel()、可 await。适用范围v1 范围是轮询-only、tools/call-only可选的notifications/tasks推送与subscriptions/listen集成推迟到后续版本task不扩展到 prompts/resources纠正了 SEP-1686 时代的错误。被取代的 SEP-1686 运行时含 Redis push 中继整体移除不做桥接。仍在计划中的能力现代协议上的 Elicitation 目前以guard 形式发布——工具返回InputRequiredResult并逐轮重跑以通过多轮往返收集用户输入见上文与 docs/servers/elicitation.mdx。声明式Resolve(...)层仍处于设计阶段对应 Feature Program 中的 MRTR elicitation 条目规划中的fastmcp.elicitation模块Resolve、Elicit、ElicitationResult作为已发布 guard 原语之上的薄封装检测Annotated[_, Resolve(...)]参数、构建 resolver 计划、首轮返回 SDK 的InputRequiredResult而非工具体。注意这是设计草案模块当前尚不存在feature-program.md 明确标注 sketch 代码不解析当前代码树。同样未启动的还有统一的subscriptions/listen流订阅总线后端。这些能力被上游依赖门控的情况记录在 Known Gaps其中 sdk-feedback #2SDK 在低于 2026 的协商版本上剥离capabilities.extensions现已升级为门控io.modelcontextprotocol/tasks扩展与 MCP Apps 的关键问题sdk-feedback #10现代连接上 push 特性降级错误质量不一致已在 FastMCP 侧解决。延伸阅读v4 笔记体系与仓库对应实现协议支持总览本文主体dev-docs/v4-notes/protocol-2026.mdv4 变更与特性规划dev-docs/v4-notes/index.md、dev-docs/v4-notes/feature-program.md、dev-docs/v4-notes/change-register.md已知缺口与上游依赖dev-docs/v4-notes/known-gaps.md后台任务设计dev-docs/v4-notes/background-tasks.md核心实现身份断言 fastmcp_slim/fastmcp/server/auth/identity_assertion.py、OAuth 代理 fastmcp_slim/fastmcp/server/auth/oauth_proxy/proxy.py、资源路径安全 fastmcp_slim/fastmcp/resources/security.py、服务器缓存 fastmcp_slim/fastmcp/server/caching.py、客户端缓存 fastmcp_slim/fastmcp/client/caching.py、客户端协商 fastmcp_slim/fastmcp/client/client.py测试佐证身份断言 tests/server/auth/oauth_proxy/test_identity_assertion.py另有 tests/server 下覆盖缓存、会话、协议时代等主题的完整套件【免费下载链接】fastmcp The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考