Skip to main content
New in version 3.0.0 LocalProvider stores components that you define directly on your server. When you use @mcp.tool, @mcp.resource, or @mcp.prompt, you’re adding components to your server’s LocalProvider.

How It Works

Every FastMCP server has a LocalProvider as its first provider. Components registered via decorators or direct methods are stored here:
from fastmcp import FastMCP

mcp = FastMCP("MyServer")

# These are stored in the server's `LocalProvider`
@mcp.tool
def greet(name: str) -> str:
    """Greet someone by name."""
    return f"Hello, {name}!"

@mcp.resource("data://config")
def get_config() -> str:
    """Return configuration data."""
    return '{"version": "1.0"}'

@mcp.prompt
def analyze(topic: str) -> str:
    """Create an analysis prompt."""
    return f"Please analyze: {topic}"
The LocalProvider is always queried first when clients request components, ensuring that your directly-defined components take precedence over those from mounted or proxied servers.

Component Registration

Using Decorators

The most common way to register components:
@mcp.tool
def my_tool(x: int) -> str:
    return str(x)

@mcp.resource("data://info")
def my_resource() -> str:
    return "info"

@mcp.prompt
def my_prompt(topic: str) -> str:
    return f"Discuss: {topic}"

Using Direct Methods

You can also add pre-built component objects:
from fastmcp.tools import Tool

# Create a tool object
my_tool = Tool.from_function(some_function, name="custom_tool")

# Add it to the server
mcp.add_tool(my_tool)
mcp.add_resource(my_resource)
mcp.add_prompt(my_prompt)

Removing Components

Remove components by name or URI:
mcp.remove_tool("my_tool")
mcp.remove_resource("data://info")
mcp.remove_prompt("my_prompt")

Duplicate Handling

When you try to add a component that already exists, the behavior depends on the on_duplicate setting:
ModeBehavior
"error" (default)Raise ValueError
"warn"Log warning and replace
"replace"Silently replace
"ignore"Keep existing component
Configure this when creating the server:
mcp = FastMCP("MyServer", on_duplicate="warn")

Visibility Control

New in version 3.0.0 You can enable or disable components at runtime. Disabled components don’t appear in listings and can’t be called.

Disabling Components

Use disable() to hide components:
# Disable by key
mcp.disable(keys=["tool:admin_action"])

# Disable by tag
mcp.disable(tags={"internal"})

# Disable multiple
mcp.disable(keys=["tool:debug"], tags={"deprecated"})

Enabling Components

Use enable() to re-enable disabled components:
# Re-enable by key
mcp.enable(keys=["tool:admin_action"])

# Re-enable by tag
mcp.enable(tags={"internal"})

Allowlist Mode

Use only=True to switch to allowlist mode, where only the specified components are visible:
# Only show public tools
mcp.enable(tags={"public"}, only=True)

# Only show specific tools
mcp.enable(keys=["tool:safe_tool", "tool:read_only"], only=True)

Component Keys

Keys follow the format {type}:{identifier}:
Component TypeKey FormatExample
Tooltool:{name}tool:greet
Resourceresource:{uri}resource:data://config
Templatetemplate:{uri}template:data://{id}
Promptprompt:{name}prompt:analyze

Using Tags

Add tags when defining components to enable group-based visibility control:
@mcp.tool(tags={"admin", "dangerous"})
def delete_all() -> str:
    """Delete everything."""
    return "Deleted"

@mcp.tool(tags={"public", "safe"})
def get_status() -> str:
    """Get system status."""
    return "OK"

# Hide all admin tools
mcp.disable(tags={"admin"})

# Or only show safe tools
mcp.enable(tags={"safe"}, only=True)

Automatic Notifications

When you enable or disable components, FastMCP automatically sends list_changed notifications to connected clients. Clients that support notifications will refresh their component lists automatically.

Standalone LocalProvider

You can create a LocalProvider independently and attach it to multiple servers:
from fastmcp import FastMCP
from fastmcp.server.providers import LocalProvider

# Create a reusable provider
shared_tools = LocalProvider()

@shared_tools.tool
def greet(name: str) -> str:
    return f"Hello, {name}!"

@shared_tools.resource("data://version")
def get_version() -> str:
    return "1.0.0"

# Attach to multiple servers
server1 = FastMCP("Server1", providers=[shared_tools])
server2 = FastMCP("Server2", providers=[shared_tools])
This is useful for:
  • Sharing components across servers
  • Testing components in isolation
  • Building reusable component libraries

Provider-Level Visibility

Visibility can be controlled at the provider level as well:
from fastmcp.server.providers import LocalProvider

provider = LocalProvider()

@provider.tool(tags={"internal"})
def internal_tool() -> str:
    return "Internal"

# Disable at provider level
provider.disable(tags={"internal"})

# This affects all servers using this provider
mcp = FastMCP("Server", providers=[provider])
When a component is disabled at the provider level, it’s hidden from all servers using that provider. Server-level visibility adds another layer of filtering on top of provider-level visibility.