news 2026/9/13 12:07:57

如何在 FastMCP 服务器上按标签动态启用和禁用组件做运行时可见性控制?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何在 FastMCP 服务器上按标签动态启用和禁用组件做运行时可见性控制?

如何在 FastMCP 服务器上按标签动态启用和禁用组件做运行时可见性控制?

【免费下载链接】fastmcp🚀 The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp

在一个 FastMCP 服务器上,工具、资源、模板和 Prompt 默认对客户端全部可见。当服务器承载了 admin 工具、beta 功能或不同角色才需要用的能力时,就需要在运行时按标签(tag)把这些组件动态隐藏或恢复:被禁用的组件会从所有客户端查询中消失,也无法被调用;重新启用后它们再次出现在列表里。这个能力在 Component Visibility 文档中说明,自 FastMCP 3.0.0 起可用。本文的任务路径是:给组件打标签 → 用enable()/disable()按标签控制可见性 → 用Clientlist_tools()验证客户端实际看到的内容。

准备:安装并确认版本

按 Installation 文档安装:

uv add fastmcp

也可以用 pip:

pip install fastmcp

用下面命令确认安装成功:

fastmcp version

安装文档给出的示例输出(文档示例,版本和平台信息以实际环境为准):

$ fastmcp version FastMCP version: 4.0.0 MCP version: 2.0.0 Python version: 3.12.2

可见性控制功能需要 3.0.0 及以上版本,4.x 已包含该功能。

第一步:在创建组件时用tags参数打标签

标签要在组件注册时定义,之后才能按标签做批量操作。以工具为例,@mcp.tool装饰器接受tags参数,类型是字符串集合(Tools 文档):

from fastmcp import FastMCP mcp = FastMCP("Server") @mcp.tool(tags={"public", "read"}) def get_data() -> str: return "data" @mcp.tool(tags={"admin", "write"}) def set_data(value: str) -> str: return f"Set: {value}" @mcp.tool(tags={"admin", "dangerous"}) def delete_data() -> str: return "Deleted" @mcp.tool def get_status() -> str: return "OK"

资源、模板和 Prompt 同理:它们的注册接口也支持tags参数,可见性规则对所有组件类型生效。

第二步:按标签禁用与恢复组件

每个 FastMCP 服务器都提供enable()disable()方法,用来控制组件可见性:

# 禁用所有带 admin 标签的工具 mcp.disable(tags={"admin"}) # 此时客户端只能看到 get_data 和 get_status # 恢复带 admin 标签的工具 mcp.enable(tags={"admin"}) # 此时客户端又能看到全部四个工具

判定规则是:只要组件拥有任意一个被禁用的标签,它就会被禁用,不需要同时拥有多个标签。上面的delete_data同时带admindangerous两个标签,两次独立的disable(tags={...})调用都能命中它:

# 禁用所有 admin 工具 mcp.disable(tags={"admin"}) # 禁用所有 dangerous 工具(与 admin 有重叠) mcp.disable(tags={"dangerous"})

需要注意过滤参数的组合语义:同一次调用里的多个条件互相收窄(取交集),而要做并集得分别调用多次。比如mcp.disable(names={"debug_info"}, tags={"dangerous"})只有在debug_info恰好也带dangerous标签时才生效,否则什么都不做——这是一个不会报错的静默失败。如果要禁用debug_info和所有dangerous标签组件,应拆成两次调用:

mcp.disable(names={"debug_info"}) mcp.disable(tags={"dangerous"})

多次调用中后执行的规则覆盖先执行的规则,所以连续调用可以叠加出"宽泛规则 + 例外"的效果。

可选分支:白名单模式

默认是黑名单模式——未显式禁用的组件全部可见。如果想反过来,只放行指定标签的组件,用only=True切换为白名单模式(Visibility 文档的 Allowlist Mode 一节):

@mcp.tool(tags={"safe"}) def read_only_operation() -> str: return "Read" @mcp.tool(tags={"dangerous"}) def delete_all() -> str: return "Deleted" # 只启用 safe 标签的组件,其余全部禁用 mcp.enable(tags={"safe"}, only=True)

调用enable(only=True)后:默认可见性状态切换为 disabled,之前的白名单被清空,只有命中的标签/名称被启用。之后再调用一次enable(..., only=True)就切换到新的白名单,比如从names白名单切到tags={"production"}白名单。白名单适合需要显式 opt-in 的受限环境;如果只是想关掉一组组件,用黑名单模式的disable()更直接。

验证:用 Client 确认客户端实际看到的组件

验证方式是走一次真实客户端会话,调用list_tools()查看过滤后的列表。仓库里的 namespace_activation 示例 展示了完整流程:服务端定义带标签的工具并全局禁用,客户端用 Client 依次查看初始列表、激活、再查看。核心逻辑是:

import asyncio from fastmcp import Client async def main(): async with Client(server) as client: # 初始状态下客户端看到的工具 tools = await client.list_tools() print([t.name for t in tools]) # 调用激活工具后,本会话的可见性变化 result = await client.call_tool("activate_finance", {}) print(result.data) tools = await client.list_tools() print([t.name for t in tools])

可见性状态变化时 FastMCP 会自动向客户端发送tools/list_changedresources/list_changedprompts/list_changed等通知,支持通知协议的客户端会刷新组件列表,不需要手动触发。

进阶:让不同会话看到不同组件

服务器级的enable()/disable()影响所有连接的客户端。如果需要"同一个服务器、不同客户端看到不同组件"(例如按角色放行),文档给出 per-session 可见性:在工具里通过Context调用ctx.enable_components()ctx.disable_components()ctx.reset_visibility(),规则只作用于当前会话,其他会话继续看到全局默认值(Context 与 Visibility 文档)。

仓库提供了完整的可运行示例 examples/namespace_activation/server.py,结构是:

from fastmcp import FastMCP from fastmcp.server.context import Context server = FastMCP("Multi-Domain Assistant") # Finance 命名空间:用带前缀的标签标记 @server.tool(tags={"namespace:finance"}) def get_market_data(symbol: str) -> dict: """Get current market data for a symbol.""" return {"symbol": symbol, "price": 150.25} # 始终可见的激活工具 @server.tool async def activate_finance(ctx: Context) -> str: await ctx.enable_components(tags={"namespace:finance"}) return "Finance tools activated" @server.tool async def deactivate_all(ctx: Context) -> str: await ctx.reset_visibility() return "All namespaces deactivated" # 全局禁用命名空间工具,会话默认看不到 server.disable(tags={"namespace:finance"})

会话内规则的处理顺序是:先应用全局 enable/disable 规则,再叠加会话规则;会话内规则按加入顺序累积,同一组件上后加入的规则生效。

运行这个示例的验证方法(README 给出的启动方式):

# 终端一 uv run python server.py # 终端二 uv run python client.py

README 中给出的示例输出(文档示例):

Namespace Activation Demo ╭─────────────────── Initial Tools ───────────────────╮ │ activate_finance, activate_admin, deactivate_all │ ╰─────────────────────────────────────────────────────╯ → Calling activate_finance() Finance tools activated ╭─────────────── After Activating Finance ────────────╮ │ analyze_portfolio, get_market_data, execute_trade, │ │ activate_finance, activate_admin, deactivate_all │ ╰─────────────────────────────────────────────────────╯

对照这个输出可以核对三点:初始只看到激活类工具;调用activate_finance后 finance 工具进入列表;调用deactivate_all后回到初始状态。

限制与排查要点

  • 组合条件取交集:一次调用里names+tags是 AND 关系,不满足全部条件就静默不生效。想表达并集时拆成多次调用,多次调用是累积的。
  • 覆盖顺序:多次enable()/disable()调用按顺序应用,后面的覆盖前面的;白名单only=True会清空之前的白名单并把默认状态切为 disabled。
  • 服务器级 vs Provider 级mcp.enable()/mcp.disable()作用于最终视图;LocalProvider上也可以各自设置可见性,Provider 的 transform 先执行,服务器级的后执行并拥有最终决定权,因此服务器可以对 Provider 禁用的组件重新enable()
  • 组件挂载:服务器级可见性对所有来源的组件生效,包括通过mount()挂载进来的子服务器组件。

组件被禁用后,它会从列表查询中消失且无法被调用;需要恢复时再执行一次对应的enable()即可。如果还需要按单个组件精确定位,Visibility 文档的 Component Keys 一节介绍了keys过滤器和VersionSpec版本过滤的用法。

【免费下载链接】fastmcp🚀 The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 12:07:07

ARIMA电价预测与置信区间:Matlab完整实现与工程实践

电价预测这件事,在电力行业里被翻来覆去说了很多年,但我发现真正能落到代码层面、把完整链路跑通的人其实不多。很多同学一上来就问“哪个模型预测最准”,真正上手之后才发现,数据预处理、模型定阶、残差检验、置信区间计算这些环…

作者头像 李华
网站建设 2026/9/13 12:05:25

STM32嵌入式开发入门:从点灯到物理层调试的实操指南

1. 别再被“嵌入式”三个字吓退:这其实是一门可触摸、可调试、可点亮LED的实操手艺你是不是也经历过这样的场景:打开招聘网站,嵌入式开发岗写着“精通C语言、熟悉STM32、掌握RTOS、了解硬件原理”,再点开学习路线图,密…

作者头像 李华
网站建设 2026/9/13 12:04:04

Java中static关键字的深度解析与应用实践

1. static关键字的本质解析 static关键字在面向对象编程中扮演着独特角色,它打破了常规成员变量与方法的绑定规则。与实例成员不同,static成员属于类本身而非特定对象。这种设计带来了内存分配和行为模式的根本差异: 类加载时初始化 &#…

作者头像 李华