fastmcp/docs/servers/providers/local.mdx
2025-12-25 09:00:20 -05:00

238 lines
5.6 KiB
Text

---
title: Local Provider
sidebarTitle: Local
description: The default provider for decorator-registered components
icon: house
---
import { VersionBadge } from '/snippets/version-badge.mdx'
<VersionBadge 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:
```python
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:
```python
@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:
```python
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:
```python
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:
| Mode | Behavior |
|------|----------|
| `"error"` (default) | Raise `ValueError` |
| `"warn"` | Log warning and replace |
| `"replace"` | Silently replace |
| `"ignore"` | Keep existing component |
Configure this when creating the server:
```python
mcp = FastMCP("MyServer", on_duplicate="warn")
```
## Visibility Control
<VersionBadge 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:
```python
# 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:
```python
# 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:
```python
# 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 Type | Key Format | Example |
|----------------|------------|---------|
| Tool | `tool:{name}` | `tool:greet` |
| Resource | `resource:{uri}` | `resource:data://config` |
| Template | `template:{uri}` | `template:data://{id}` |
| Prompt | `prompt:{name}` | `prompt:analyze` |
### Using Tags
Add tags when defining components to enable group-based visibility control:
```python
@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:
```python
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:
```python
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])
```
<Note>
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.
</Note>