Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -350,15 +350,6 @@
"python-sdk/fastmcp-client-transports"
]
},
{
"group": "fastmcp.fs",
"pages": [
"python-sdk/fastmcp-fs-__init__",
"python-sdk/fastmcp-fs-decorators",
"python-sdk/fastmcp-fs-discovery",
"python-sdk/fastmcp-fs-provider"
]
},
{
"group": "fastmcp.prompts",
"pages": [
Expand Down
45 changes: 15 additions & 30 deletions docs/patterns/tool-transformation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@ Transformation is also powerful for **environment-aware tools**. You can dynamic

The primary way to create a transformed tool is with the `Tool.from_tool()` class method. At its simplest, you can use it to change a tool's top-level metadata like its `name`, `description`, or `tags`.

In the following simple example, we take a generic `search` tool and adjust its name and description to help an LLM client better understand its purpose.
In the following example, we take a generic `search` tool and adjust its name and description to help an LLM client better understand its purpose.

```python {13-21}
```python {1, 6, 11-19, 22}
from fastmcp.tools import tool, Tool
from fastmcp import FastMCP
from fastmcp.tools import Tool

mcp = FastMCP()

# The original, generic tool
@mcp.tool
# Create a tool without registering it using the standalone @tool decorator
# This creates a Tool object that can be transformed before registration
@tool
def search(query: str, category: str = "all") -> list[dict]:
"""Searches for items in the database."""
return database.search(query, category)
Expand All @@ -47,39 +46,25 @@ product_search_tool = Tool.from_tool(
search,
name="find_products",
description="""
Search for products in the e-commerce catalog.
Use this when customers ask about finding specific items,
Search for products in the e-commerce catalog.
Use this when customers ask about finding specific items,
checking availability, or browsing product categories.
""",
)

# Only register the transformed version
mcp = FastMCP()
mcp.add_tool(product_search_tool)
```

<Tip>
When you transform a tool, the original tool remains registered on the server. To avoid confusing an LLM with two similar tools, you can disable the original one:

```python
from fastmcp import FastMCP
from fastmcp.tools import Tool

mcp = FastMCP()

# The original, generic tool
@mcp.tool
def search(query: str, category: str = "all") -> list[dict]:
...

# Create a more domain-specific version
product_search_tool = Tool.from_tool(search, ...)
mcp.add_tool(product_search_tool)

# Disable the original tool
search.disable()
```
The standalone `@tool` decorator (from `fastmcp.tools`) creates a Tool object without registering it to any server. This is the recommended approach for tool transformation because:
- You only register the tools you want exposed
- No need to disable or remove the original
- Cleaner separation between tool creation and registration
</Tip>

Now, clients see a tool named `find_products` with a clear, domain-specific purpose and relevant tags, even though it still uses the original generic `search` function's logic.
Now, clients see a tool named `find_products` with a clear, domain-specific purpose, even though it still uses the original generic `search` function's logic.

### Parameters

Expand Down
34 changes: 19 additions & 15 deletions docs/servers/providers/filesystem.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { VersionBadge } from '/snippets/version-badge.mdx'

Traditional FastMCP servers require coordination between files. Either your tool files import the server to call `@server.tool()`, or your server file imports all the tool modules. Both approaches create coupling that some developers prefer to avoid.

`FileSystemProvider` eliminates this coordination. Each file is self-contained—it uses decorators from `fastmcp.fs` that don't require access to a server instance. The provider discovers these files at startup, so you can add new tools without modifying your server file.
`FileSystemProvider` eliminates this coordination. Each file is self-contained—it uses standalone decorators (`@tool`, `@resource`, `@prompt`) that don't require access to a server instance. The provider discovers these files at startup, so you can add new tools without modifying your server file.

This is a convention some teams prefer, not necessarily better for all projects. The tradeoffs:

Expand All @@ -25,20 +25,22 @@ This is a convention some teams prefer, not necessarily better for all projects.

## Quick Start

Create a provider pointing to your components directory, then pass it to your server.
Create a provider pointing to your components directory, then pass it to your server. Use `Path(__file__).parent` to make the path relative to your server file.

```python
from pathlib import Path

from fastmcp import FastMCP
from fastmcp.fs import FileSystemProvider
from fastmcp.server.providers import FileSystemProvider

mcp = FastMCP("MyServer", providers=[FileSystemProvider("mcp/")])
mcp = FastMCP("MyServer", providers=[FileSystemProvider(Path(__file__).parent / "mcp")])
```

In your `mcp/` directory, create Python files with decorated functions.

```python
# mcp/tools/greet.py
from fastmcp.fs import tool
from fastmcp.tools import tool

@tool
def greet(name: str) -> str:
Expand All @@ -50,14 +52,14 @@ When the server starts, `FileSystemProvider` scans the directory, imports all Py

## Decorators

The `fastmcp.fs` module provides three decorators that mark functions for discovery: `@tool`, `@resource`, and `@prompt`. These support the full syntax of standard FastMCP decorators—all the same parameters work identically.
FastMCP provides standalone decorators that mark functions for discovery: `@tool` from `fastmcp.tools`, `@resource` from `fastmcp.resources`, and `@prompt` from `fastmcp.prompts`. These support the full syntax of server-bound decorators—all the same parameters work identically.

### @tool

Mark a function as a tool. The function name becomes the tool name by default.

```python
from fastmcp.fs import tool
from fastmcp.tools import tool

@tool
def calculate_sum(a: float, b: float) -> float:
Expand All @@ -68,7 +70,7 @@ def calculate_sum(a: float, b: float) -> float:
Customize the tool with optional parameters.

```python
from fastmcp.fs import tool
from fastmcp.tools import tool

@tool(
name="add-numbers",
Expand All @@ -86,7 +88,7 @@ The decorator supports all standard tool options: `name`, `title`, `description`
Mark a function as a resource. Unlike `@tool`, the `@resource` decorator requires a URI argument.

```python
from fastmcp.fs import resource
from fastmcp.resources import resource

@resource("config://app")
def get_app_config() -> str:
Expand All @@ -97,7 +99,7 @@ def get_app_config() -> str:
URIs with template parameters create resource templates. The provider automatically detects whether to register a static resource or a template based on whether the URI contains `{parameters}` or the function has arguments.

```python
from fastmcp.fs import resource
from fastmcp.resources import resource

@resource("users://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
Expand All @@ -112,7 +114,7 @@ The decorator supports: `uri` (required), `name`, `title`, `description`, `icons
Mark a function as a prompt template.

```python
from fastmcp.fs import prompt
from fastmcp.prompts import prompt

@prompt
def code_review(code: str, language: str = "python") -> str:
Expand All @@ -121,7 +123,7 @@ def code_review(code: str, language: str = "python") -> str:
```

```python
from fastmcp.fs import prompt
from fastmcp.prompts import prompt

@prompt(name="explain-concept", tags={"education"})
def explain(topic: str) -> str:
Expand Down Expand Up @@ -190,9 +192,11 @@ Without `__init__.py`, files are imported directly using `importlib.util.spec_fr
During development, you may want changes to component files to take effect without restarting the server. Enable reload mode to re-scan the directory on every request.

```python
from fastmcp.fs import FileSystemProvider
from pathlib import Path

from fastmcp.server.providers import FileSystemProvider

provider = FileSystemProvider("mcp/", reload=True)
provider = FileSystemProvider(Path(__file__).parent / "mcp", reload=True)
```

With `reload=True`, the provider:
Expand Down Expand Up @@ -238,7 +242,7 @@ The server entry point is minimal.
from pathlib import Path

from fastmcp import FastMCP
from fastmcp.fs import FileSystemProvider
from fastmcp.server.providers import FileSystemProvider

provider = FileSystemProvider(
root=Path(__file__).parent / "mcp",
Expand Down
2 changes: 1 addition & 1 deletion examples/filesystem-provider/mcp/prompts/assistant.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Assistant prompts."""

from fastmcp.fs import prompt
from fastmcp.prompts import prompt


@prompt
Expand Down
2 changes: 1 addition & 1 deletion examples/filesystem-provider/mcp/resources/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import json

from fastmcp.fs import resource
from fastmcp.resources import resource


# Static resource - no parameters in URI
Expand Down
2 changes: 1 addition & 1 deletion examples/filesystem-provider/mcp/tools/calculator.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Math tools with custom metadata."""

from fastmcp.fs import tool
from fastmcp.tools import tool


@tool(
Expand Down
2 changes: 1 addition & 1 deletion examples/filesystem-provider/mcp/tools/greeting.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Greeting tools - multiple tools in one file."""

from fastmcp.fs import tool
from fastmcp.tools import tool


@tool
Expand Down
2 changes: 1 addition & 1 deletion examples/filesystem-provider/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from pathlib import Path

from fastmcp import FastMCP
from fastmcp.fs import FileSystemProvider
from fastmcp.server.providers import FileSystemProvider

# The provider scans all .py files in the directory recursively.
# Functions decorated with @tool, @resource, or @prompt are registered.
Expand Down
45 changes: 0 additions & 45 deletions src/fastmcp/fs/__init__.py

This file was deleted.

Loading