URL: https://gofastmcp.com/servers/visibility
Title: Component Visibility - FastMCP

Documentation Index
Fetch the complete documentation index at:
/llms.txt
Use this file to discover all available pages before exploring further.
Skip to main content
Meet
Prefect Horizon
, the enterprise MCP gateway built by the team behind FastMCP
FastMCP
home page
v3
Prefect Horizon
PrefectHQ/fastmcp
25,596
PrefectHQ/fastmcp
25,596
Search...
Navigation
Working with Tools
Component Visibility
Search the docs...
Ctrl
K
Documentation
Get Started
Welcome!
Installation
Quickstart
Servers
Overview
Core Components
Working with Tools
Overview
Tool Transformation
Code Mode
NEW
Tool Search
NEW
Namespace
Visibility
NEW
Resources as Tools
NEW
Prompts as Tools
NEW
Tool Fingerprinting
MCP Providers
Interactivity
Extensibility
Auth
Deployment
Apps
Overview
Quickstart
NEW
FastMCPApp
NEW
Interactive Tools
NEW
Generative UI
NEW
Custom HTML
Reference
Clients
Overview
Client-Only Package
Transports
fastmcp-remote
Operations
UPDATED
Authentication
UPDATED
Integrations
Auth
Web Frameworks
AI Assistants
AI SDKs
MCP.json
More
Settings
CLI
Upgrading
Development
What's New
FAQ
On this page
Component Visibility
Disabling Components
Enabling Components
Keys and Tags
Component Keys
Tags
Combining Keys and Tags
Allowlist Mode
Allowlist Behavior
Ordering and Overrides
Server vs Provider
Server-Level
Provider-Level
Layered Transforms
Per-Session Visibility
How Session Rules Work
Filter Criteria
Automatic Notifications
Namespace Activation Pattern
Method Reference
Client Notifications
Filtering Logic
The Visibility Transform
Working with Tools
Component Visibility
Copy page
Control which components are available to clients
Copy page
New in version
3.0.0
Components can be dynamically enabled or disabled at runtime. A disabled tool disappears from listings and cannot be called. This enables runtime access control, feature flags, and context-aware component exposure.
​
Component Visibility
Every FastMCP server provides
enable()
and
disable()
methods for controlling component availability.
​
Disabling Components
The
disable()
method marks components as disabled. Disabled components are filtered out from all client queries.
from
fastmcp
import
FastMCP
mcp
=
FastMCP
(
"
Server
"
)
@
mcp
.
tool
(
tags
={
"
admin
"
})
def
delete_everything
()
->
str
:
"""
Delete all data.
"""
return
"
Deleted
"
@
mcp
.
tool
(
tags
={
"
admin
"
})
def
reset_system
()
->
str
:
"""
Reset the system.
"""
return
"
Reset
"
@
mcp
.
tool
def
get_status
()
->
str
:
"""
Get system status.
"""
return
"
OK
"
# Disable admin tools
mcp
.
disable
(
tags
={
"
admin
"
})
# Clients only see: get_status
​
Enabling Components
The
enable()
method re-enables previously disabled components.
# Re-enable admin tools
mcp
.
enable
(
tags
={
"
admin
"
})
# Clients now see all three tools
​
Keys and Tags
Visibility filtering works with two identifiers: keys (for specific components) and tags (for groups).
​
Component Keys
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.
# Disable a specific tool
mcp
.
disable
(
keys
={
"
tool:delete_everything
"
})
# Disable multiple specific components
mcp
.
disable
(
keys
={
"
tool:reset_system
"
,
"
resource:data://secrets
"
})
​
Tags
Tags group components for bulk operations. Define tags when creating components, then filter by them.
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
"
# Disable all admin tools
mcp
.
disable
(
tags
={
"
admin
"
})
# Disable all dangerous tools (some overlap with admin)
mcp
.
disable
(
tags
={
"
dangerous
"
})
A component is disabled if it has
any
of the disabled tags. The component doesn’t need all the tags; one match is enough.
​
Combining Keys and Tags
You can specify both keys and tags in a single call. The filters combine additively.
# Disable specific tools AND all dangerous-tagged components
mcp
.
disable
(
keys
={
"
tool:debug_info
"
},
tags
={
"
dangerous
"
})
​
Allowlist Mode
By default, visibility filtering uses blocklist mode: everything is enabled unless explicitly disabled. The
only=True
parameter switches to allowlist mode, where
only
specified components are enabled.
from
fastmcp
import
FastMCP
mcp
=
FastMCP
(
"
Server
"
)
@
mcp
.
tool
(
tags
={
"
safe
"
})
def
read_only_operation
()
->
str
:
return
"
Read
"
@
mcp
.
tool
(
tags
={
"
safe
"
})
def
list_items
()
->
list
[
str
]:
return
[
"
a
"
,
"
b
"
,
"
c
"
]
@
mcp
.
tool
(
tags
={
"
dangerous
"
})
def
delete_all
()
->
str
:
return
"
Deleted
"
@
mcp
.
tool
def
untagged_tool
()
->
str
:
return
"
Untagged
"
# Only enable safe tools - everything else is disabled
mcp
.
enable
(
tags
={
"
safe
"
},
only
=
True
)
# Clients see: read_only_operation, list_items
# Disabled: delete_all, untagged_tool
Allowlist mode is useful for restrictive environments where you want to explicitly opt-in components rather than opt-out.
​
Allowlist Behavior
When you call
enable(only=True)
:
Default visibility state switches to “disabled”
Previous allowlists are cleared
Only specified keys/tags become enabled
# Start fresh - only enable these specific tools
mcp
.
enable
(
keys
={
"
tool:safe_read
"
,
"
tool:safe_write
"
},
only
=
True
)
# Later, switch to a different allowlist
mcp
.
enable
(
tags
={
"
production
"
},
only
=
True
)
​
Ordering and Overrides
Later
enable()
and
disable()
calls override earlier ones. This lets you create broad rules with specific exceptions.
mcp
.
enable
(
tags
={
"
api
"
},
only
=
True
)
# Allow all api-tagged
mcp
.
disable
(
keys
={
"
tool:api_admin
"
})
# Later disable overrides for this tool
# api_admin is disabled because the later disable() overrides the allowlist
You can always re-enable something that was disabled by adding another
enable()
call after it.
​
Server vs Provider
Visibility state operates at two levels: the server and individual providers.
​
Server-Level
Server-level visibility state applies to all components from all providers. When you call
mcp.enable()
or
mcp.disable()
, you’re filtering the final view that clients see.
from
fastmcp
import
FastMCP
main
=
FastMCP
(
"
Main
"
)
main
.
mount
(
sub_server
,
namespace
=
"
api
"
)
@
main
.
tool
(
tags
={
"
internal
"
})
def
local_debug
()
->
str
:
return
"
Debug
"
# Disable internal tools from ALL sources
main
.
disable
(
tags
={
"
internal
"
})
​
Provider-Level
Each provider can add its own visibility transforms. These run before server-level transforms, so the server can override provider-level disables.
from
fastmcp
import
FastMCP
from
fastmcp
.
server
.
providers
import
LocalProvider
# Create provider with visibility control
admin_tools
=
LocalProvider
()
@
admin_tools
.
tool
(
tags
={
"
admin
"
})
def
admin_action
()
->
str
:
return
"
Admin
"
@
admin_tools
.
tool
def
regular_action
()
->
str
:
return
"
Regular
"
# Disable at provider level
admin_tools
.
disable
(
tags
={
"
admin
"
})
# Server can override if needed
mcp
=
FastMCP
(
"
Server
"
,
providers
=[
admin_tools
])
mcp
.
enable
(
names
={
"
admin_action
"
})
# Re-enables despite provider disable
Provider-level transforms are useful for setting default visibility that servers can selectively override.
​
Layered Transforms
Provider transforms run first, then server transforms. Later transforms override earlier ones, so the server has final say.
from
fastmcp
import
FastMCP
from
fastmcp
.
server
.
providers
import
LocalProvider
provider
=
LocalProvider
()
@
provider
.
tool
(
tags
={
"
feature
"
,
"
beta
"
})
def
new_feature
()
->
str
:
return
"
New
"
# Provider enables feature-tagged
provider
.
enable
(
tags
={
"
feature
"
},
only
=
True
)
# Server disables beta-tagged (runs after provider)
mcp
=
FastMCP
(
"
Server
"
,
providers
=[
provider
])
mcp
.
disable
(
tags
={
"
beta
"
})
# new_feature is disabled (server's later disable overrides provider's enable)
​
Per-Session Visibility
Server-level visibility changes affect all connected clients simultaneously. When you need different clients to see different components, use per-session visibility instead.
Session visibility lets individual sessions customize their view of available components. When a tool calls
ctx.enable_components()
or
ctx.disable_components()
, those rules apply only to the current session. Other sessions continue to see the global defaults. This enables patterns like progressive disclosure, role-based access, and on-demand feature activation.
from
fastmcp
import
FastMCP
from
fastmcp
.
server
.
context
import
Context
mcp
=
FastMCP
(
"
Session-Aware Server
"
)
@
mcp
.
tool
(
tags
={
"
premium
"
})
def
premium_analysis
(
data
:
str
)
->
str
:
"""
Advanced analysis available to premium users.
"""
return
f
"Premium analysis of:
{
data
}
"
@
mcp
.
tool
async
def
unlock_premium
(
ctx
:
Context
)
->
str
:
"""
Unlock premium features for this session.
"""
await
ctx
.
enable_components
(
tags
={
"
premium
"
})
return
"
Premium features unlocked
"
@
mcp
.
tool
async
def
reset_features
(
ctx
:
Context
)
->
str
:
"""
Reset to default feature set.
"""
await
ctx
.
reset_visibility
()
return
"
Features reset to defaults
"
# Premium tools are disabled globally by default
mcp
.
disable
(
tags
={
"
premium
"
})
All sessions start with
premium_analysis
hidden. When a session calls
unlock_premium
, that session gains access to premium tools while other sessions remain unaffected. Calling
reset_features
returns the session to the global defaults.
​
How Session Rules Work
Session rules override global transforms. When listing components, FastMCP first applies global enable/disable rules, then applies session-specific rules on top. Rules within a session accumulate, and later rules override earlier ones for the same component.
@
mcp
.
tool
async
def
customize_session
(
ctx
:
Context
)
->
str
:
# Enable finance tools for this session
await
ctx
.
enable_components
(
tags
={
"
finance
"
})
# Also enable admin tools
await
ctx
.
enable_components
(
tags
={
"
admin
"
})
# Later: disable a specific admin tool
await
ctx
.
disable_components
(
names
={
"
dangerous_admin_tool
"
})
return
"
Session customized
"
Each call adds a rule to the session. The
dangerous_admin_tool
ends up disabled because its disable rule was added after the admin enable rule.
​
Filter Criteria
The session visibility methods accept the same filter criteria as
server.enable()
and
server.disable()
:
Parameter
Description
names
Component names or URIs to match
keys
Component keys (e.g.,
{"tool:my_tool"}
)
tags
Tags to match (component must have at least one)
version
Version specification to match
components
Component types (
{"tool"}
,
{"resource"}
,
{"prompt"}
,
{"template"}
)
match_all
If
True
, matches all components regardless of other criteria
from
fastmcp
.
utilities
.
versions
import
VersionSpec
@
mcp
.
tool
async
def
enable_recent_tools
(
ctx
:
Context
)
->
str
:
"""
Enable only tools from version 2.0.0 or later.
"""
await
ctx
.
enable_components
(
version
=
VersionSpec
(
gte
=
"
2.0.0
"
),
components
={
"
tool
"
}
)
return
"
Recent tools enabled
"
​
Automatic Notifications
When session visibility changes, FastMCP automatically sends notifications to that session. Clients receive
ToolListChangedNotification
,
ResourceListChangedNotification
, and
PromptListChangedNotification
so they can refresh their component lists. These notifications go only to the affected session.
When you specify the
components
parameter, FastMCP optimizes by sending only the relevant notifications:
# Only sends ToolListChangedNotification
await
ctx
.
enable_components
(
tags
={
"
finance
"
},
components
={
"
tool
"
})
# Sends all three notifications (no components filter)
await
ctx
.
enable_components
(
tags
={
"
finance
"
})
​
Namespace Activation Pattern
A common pattern organizes tools into namespaces using tag prefixes, disables them globally, then provides activation tools that unlock namespaces on demand:
from
fastmcp
import
FastMCP
from
fastmcp
.
server
.
context
import
Context
server
=
FastMCP
(
"
Multi-Domain Assistant
"
)
# Finance namespace
@
server
.
tool
(
tags
={
"
namespace:finance
"
})
def
analyze_portfolio
(
symbols
:
list
[
str
])
->
str
:
return
f
"Analysis for:
{
'
,
'
.
join
(
symbols
)
}
"
@
server
.
tool
(
tags
={
"
namespace:finance
"
})
def
get_market_data
(
symbol
:
str
)
->
dict
:
return
{
"
symbol
"
:
symbol
,
"
price
"
:
150.25
}
# Admin namespace
@
server
.
tool
(
tags
={
"
namespace:admin
"
})
def
list_users
()
->
list
[
str
]:
return
[
"
alice
"
,
"
bob
"
,
"
charlie
"
]
# Activation tools - always visible
@
server
.
tool
async
def
activate_finance
(
ctx
:
Context
)
->
str
:
await
ctx
.
enable_components
(
tags
={
"
namespace:finance
"
})
return
"
Finance tools activated
"
@
server
.
tool
async
def
activate_admin
(
ctx
:
Context
)
->
str
:
await
ctx
.
enable_components
(
tags
={
"
namespace:admin
"
})
return
"
Admin tools activated
"
@
server
.
tool
async
def
deactivate_all
(
ctx
:
Context
)
->
str
:
await
ctx
.
reset_visibility
()
return
"
All namespaces deactivated
"
# Disable namespace tools globally
server
.
disable
(
tags
={
"
namespace:finance
"
,
"
namespace:admin
"
})
Sessions start seeing only the activation tools. Calling
activate_finance
reveals finance tools for that session only. Multiple namespaces can be activated independently, and
deactivate_all
returns to the initial state.
​
Method Reference
await ctx.enable_components(...) -> None
: Enable matching components for this session
await ctx.disable_components(...) -> None
: Disable matching components for this session
await ctx.reset_visibility() -> None
: Clear all session rules, returning to global defaults
​
Client Notifications
When visibility state 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.
# This automatically notifies clients
mcp
.
disable
(
tags
={
"
maintenance
"
})
# Clients receive: tools/list_changed, resources/list_changed, etc.
​
Filtering Logic
Understanding the filtering logic helps when debugging visibility state issues.
The
is_enabled()
function checks a component’s internal metadata:
If the component has
meta.fastmcp._internal.visibility = False
, it’s disabled
If the component has
meta.fastmcp._internal.visibility = True
, it’s enabled
If no visibility state is set, the component is enabled by default
When multiple
enable()
and
disable()
calls are made, transforms are applied in order.
Later transforms override earlier ones
, so the last matching transform wins.
​
The Visibility Transform
Under the hood,
enable()
and
disable()
add
Visibility
transforms to the server or provider. The
Visibility
transform marks components with visibility metadata, and the server applies the final filter after all provider and server transforms complete.
from
fastmcp
import
FastMCP
from
fastmcp
.
server
.
transforms
import
Visibility
mcp
=
FastMCP
(
"
Server
"
)
# Using the convenience method (recommended)
mcp
.
disable
(
names
={
"
secret_tool
"
})
# Equivalent to:
mcp
.
add_transform
(
Visibility
(
False
,
names
={
"
secret_tool
"
}))
Server-level transforms override provider-level transforms. If a component is disabled at the provider level but enabled at the server level, the server-level
enable()
can re-enable it.
Namespace Transform
Previous
Resources as Tools
Next
Ctrl
+I
discord
github
website
x
Powered by
This documentation is built and hosted on Mintlify, a developer documentation platform
Assistant
Responses are generated using AI and may contain mistakes.
\n\n
\n
\n \n
\n
