New in version 3.0.0Visibility control lets you dynamically show or hide components from clients. A disabled tool disappears from listings and cannot be called. This enables runtime access control, feature flags, and context-aware component exposure.
Every component has a unique key in the format {type}:{identifier}.
Component
Key Format
Example
Tool
tool:{name}
tool:delete_everything
Resource
resource:{uri}
resource:data://config
Template
template:{uri}
template:file://{path}
Prompt
prompt:{name}
prompt:analyze
Use keys to target specific components.
Copy
# Disable a specific toolmcp.disable(keys=["tool:delete_everything"])# Disable multiple specific componentsmcp.disable(keys=["tool:reset_system", "resource:data://secrets"])
By default, visibility uses blocklist mode: everything is visible unless explicitly disabled. The only=True parameter switches to allowlist mode, where only specified components are visible.
# Start fresh - only show these specific toolsmcp.enable(keys=["tool:safe_read", "tool:safe_write"], only=True)# Later, switch to a different allowlistmcp.enable(tags={"production"}, only=True)
Even in allowlist mode, the blocklist takes precedence. A component that’s both allowlisted and blocklisted remains hidden.
Copy
mcp.enable(tags={"api"}, only=True) # Allow all api-taggedmcp.disable(keys=["tool:api_admin"]) # But block this specific one# api_admin is hidden despite having the "api" tag
This lets you create broad allowlists with specific exceptions.
Server visibility applies to all components from all providers. When you call mcp.enable() or mcp.disable(), you’re filtering the final view that clients see.
Copy
from fastmcp import FastMCPmain = FastMCP("Main")main.mount(sub_server, namespace="api")@main.tool(tags={"internal"})def local_debug() -> str: return "Debug"# Hide internal tools from ALL sourcesmain.disable(tags={"internal"})
Visibility changes take effect immediately. You can adjust visibility during request handling based on context.
Copy
from fastmcp import FastMCPfrom fastmcp.server import Contextmcp = FastMCP("Server")@mcp.tool(tags={"admin"})def admin_action() -> str: return "Admin action performed"@mcp.tooldef check_permissions(ctx: Context) -> str: """Check if admin tools should be available.""" user = ctx.request_context.get_user() if user and user.is_admin: mcp.enable(tags={"admin"}) return "Admin tools enabled" else: mcp.disable(tags={"admin"}) return "Admin tools disabled"
Dynamic visibility affects all connected clients. For per-user visibility, consider using separate server instances or implementing authorization in the tools themselves.
When visibility changes, FastMCP automatically notifies connected clients. Clients supporting the MCP notification protocol receive list_changed events and can refresh their component lists.This happens automatically. You don’t need to trigger notifications manually.
Copy
# This automatically notifies clientsmcp.disable(tags={"maintenance"})# Clients receive: tools/list_changed, resources/list_changed, etc.