Skip to content

Add standalone decorators and eliminate fastmcp.fs module#2832

Merged
jlowin merged 5 commits intomainfrom
standalone-decorators-refactor
Jan 10, 2026
Merged

Add standalone decorators and eliminate fastmcp.fs module#2832
jlowin merged 5 commits intomainfrom
standalone-decorators-refactor

Conversation

@jlowin
Copy link
Copy Markdown
Member

@jlowin jlowin commented Jan 10, 2026

Standalone decorators (@tool, @resource, @prompt) now create MCP objects without registering them to a server. This enables workflows where you create an object first, then register it—useful for tool transformations and FileSystemProvider discovery.

from fastmcp.tools import tool
from fastmcp import FastMCP

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

# greet is now a FunctionTool, can be registered to any server
mcp = FastMCP("MyServer")
mcp.add_tool(greet)

Changes:

  • Standalone decorators in fastmcp.tools, fastmcp.resources, fastmcp.prompts
  • FileSystemProvider moved to fastmcp.server.providers
  • LocalProvider.resource() and prompt() delegate to standalone decorators
  • Comprehensive enabled=False tests for all component types
  • Eliminates fastmcp.fs module entirely

Note: this is also a significant refactor of the new FileSystemProvider (#2823) which had its own metadata-based decorators and was housed in the wrong submodule

- Add standalone @tool, @resource, @prompt decorators that create objects
  without registering to a server
- Move FileSystemProvider to fastmcp.server.providers
- Refactor LocalProvider.resource() and prompt() to delegate to standalone
  decorators
- Update all imports to use canonical paths
- Add comprehensive tests for enabled=False behavior
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 10, 2026

Warning

Rate limit exceeded

@jlowin has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 4 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 1418333 and fe49d0b.

⛔ Files ignored due to path filters (6)
  • tests/prompts/test_standalone_decorator.py is excluded by none and included by none
  • tests/resources/test_standalone_decorator.py is excluded by none and included by none
  • tests/server/providers/test_local_provider_prompts.py is excluded by none and included by none
  • tests/server/providers/test_local_provider_resources.py is excluded by none and included by none
  • tests/server/providers/test_local_provider_tools.py is excluded by none and included by none
  • tests/tools/test_standalone_decorator.py is excluded by none and included by none
📒 Files selected for processing (5)
  • src/fastmcp/prompts/prompt.py
  • src/fastmcp/resources/resource.py
  • src/fastmcp/server/providers/filesystem.py
  • src/fastmcp/server/providers/local_provider.py
  • src/fastmcp/tools/tool.py

Walkthrough

The pull request removes the public fastmcp.fs module and redistributes its exports across respective packages: tool decorator moves to fastmcp.tools, resource to fastmcp.resources, prompt to fastmcp.prompts, and FileSystemProvider to fastmcp.server.providers. The FileSystemProvider and filesystem discovery pipeline are refactored to work directly with component instances (Tool, Resource, ResourceTemplate, Prompt) rather than decorated functions with separate metadata. Standalone decorator implementations are added to enable component creation without server registration. All examples and documentation are updated to reflect the new import paths and decorator patterns.

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 61.54% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main changes: introducing standalone decorators and removing the fastmcp.fs module.
Description check ✅ Passed The description provides clear context, a code example, and a bulleted list of changes, though it lacks explicit checklist confirmations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@marvin-context-protocol marvin-context-protocol Bot added feature Major new functionality. Reserved for 2-4 significant PRs per release. Not for issues. breaking change Breaks backward compatibility. Requires minor version bump. Critical for maintainer attention. server Related to FastMCP server implementation or server-side functionality. labels Jan 10, 2026
@jlowin
Copy link
Copy Markdown
Member Author

jlowin commented Jan 10, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 10, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/patterns/tool-transformation.mdx (1)

31-67: Update to second-person voice + make the example runnable (define database).

The new standalone-decorator flow is clear, but the copy uses “we” (Line 31) and the code sample isn’t runnable because database is undefined (Line 42). As per coding guidelines for docs/**/*.mdx, prefer 2nd person and fully runnable snippets. Based on coding guidelines, …

Proposed doc patch
-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.
+In the following example, you take a generic `search` tool and adjust its name and description to help an LLM client understand its purpose.

 ```python {1, 6, 11-19, 22}
 from fastmcp.tools import tool, Tool
 from fastmcp import FastMCP
+
+class _Database:
+    def search(self, query: str, category: str) -> list[dict]:
+        return [{"query": query, "category": category, "id": "item_123"}]
+
+database = _Database()

 # 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)
</details>

</blockquote></details>
<details>
<summary>src/fastmcp/server/providers/filesystem_discovery.py (1)</summary><blockquote>

`11-18`: **Blocker: `importlib` is used but never imported.**

`import_module_from_file()` calls `importlib.reload` / `importlib.import_module` (Line 143-144), but the module only imports `importlib.util` (Line 11). This will raise `NameError: name 'importlib' is not defined`.

<details>
<summary>Proposed fix</summary>

```diff
-import importlib.util
+import importlib
+import importlib.util

Also applies to: 140-148

🧹 Nitpick comments (4)
src/fastmcp/tools/tool.py (1)

881-891: Prefer TypeError for invalid type argument.

When rejecting classmethod as input, TypeError is more semantically appropriate than ValueError since the issue is with the type of the argument, not its value. This aligns with the static analysis hint (Ruff TRY004).

♻️ Suggested fix
     if isinstance(name_or_fn, classmethod):
-        raise ValueError(
+        raise TypeError(
             inspect.cleandoc(
                 """
                 To decorate a classmethod, first define the method and then call
                 tool() directly on the method instead of using it as a
                 decorator. See https://gofastmcp.com/patterns/decorating-methods
                 for examples and more information.
                 """
             )
         )
src/fastmcp/resources/resource.py (1)

590-624: Remove unreachable else branch.

The else branch at lines 620-624 is logically unreachable. The two conditions are exhaustive:

  • If has_uri_params or has_func_params is True → first branch
  • If has_uri_params or has_func_params is False → equivalent to not has_uri_params and not has_func_params → second branch

The else case can never execute because every possible combination of boolean values is covered by the first two branches.

♻️ Simplify by removing unreachable code
         if has_uri_params or has_func_params:
             from fastmcp.resources.template import ResourceTemplate
 
             return ResourceTemplate.from_function(
                 fn=fn,
                 uri_template=uri,
                 name=name,
                 title=title,
                 description=description,
                 icons=icons,
                 mime_type=mime_type,
                 tags=tags,
                 annotations=annotations,
                 meta=meta,
                 task=supports_task,
             )
-        elif not has_uri_params and not has_func_params:
+        else:
             return Resource.from_function(
                 fn=fn,
                 uri=uri,
                 name=name,
                 title=title,
                 description=description,
                 icons=icons,
                 mime_type=mime_type,
                 tags=tags,
                 annotations=annotations,
                 meta=meta,
                 task=supports_task,
             )
-        else:
-            raise ValueError(
-                "Invalid resource or template definition due to a "
-                "mismatch between URI parameters and function parameters."
-            )
src/fastmcp/prompts/prompt.py (1)

614-773: Standalone prompt decorator: clarify callable support + consider TypeError for invalid decorator target.

  • If @prompt is intended to support only real functions, consider tightening wording (AnyFunction) / docs accordingly; otherwise, inspect.isroutine(...) (Line 727) blocks callable instances even though Prompt.from_function later handles callable classes.
  • For classmethod being an invalid decorator target, TypeError is a better fit than ValueError (Line 714-725) (and matches Ruff TRY004).
src/fastmcp/server/providers/filesystem_discovery.py (1)

175-210: Avoid registering re-exported/imported components during extraction.

extract_components() currently registers any Tool/Resource/ResourceTemplate/Prompt instance reachable as a module attribute (Line 196-209). That will also include components imported from other modules (e.g., convenience re-exports), which is likely surprising for filesystem discovery.

Consider filtering to objects “owned” by the module, e.g. getattr(obj, "__module__", None) == module.__name__, and/or iterating module.__dict__.items() instead of dir(...).

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9a9df1 and 1418333.

⛔ Files ignored due to path filters (7)
  • tests/fs/test_decorators.py is excluded by none and included by none
  • tests/fs/test_discovery.py is excluded by none and included by none
  • tests/fs/test_provider.py is excluded by none and included by none
  • tests/prompts/test_standalone_decorator.py is excluded by none and included by none
  • tests/resources/test_standalone_decorator.py is excluded by none and included by none
  • tests/server/providers/test_local_provider.py is excluded by none and included by none
  • tests/tools/test_standalone_decorator.py is excluded by none and included by none
📒 Files selected for processing (20)
  • docs/docs.json
  • docs/patterns/tool-transformation.mdx
  • docs/servers/providers/filesystem.mdx
  • examples/filesystem-provider/mcp/prompts/assistant.py
  • examples/filesystem-provider/mcp/resources/config.py
  • examples/filesystem-provider/mcp/tools/calculator.py
  • examples/filesystem-provider/mcp/tools/greeting.py
  • examples/filesystem-provider/server.py
  • src/fastmcp/fs/__init__.py
  • src/fastmcp/fs/decorators.py
  • src/fastmcp/prompts/__init__.py
  • src/fastmcp/prompts/prompt.py
  • src/fastmcp/resources/__init__.py
  • src/fastmcp/resources/resource.py
  • src/fastmcp/server/providers/__init__.py
  • src/fastmcp/server/providers/filesystem.py
  • src/fastmcp/server/providers/filesystem_discovery.py
  • src/fastmcp/server/providers/local_provider.py
  • src/fastmcp/tools/__init__.py
  • src/fastmcp/tools/tool.py
💤 Files with no reviewable changes (3)
  • docs/docs.json
  • src/fastmcp/fs/decorators.py
  • src/fastmcp/fs/init.py
🧰 Additional context used
📓 Path-based instructions (4)
src/fastmcp/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/fastmcp/**/*.py: Python ≥ 3.10 with full type annotations required
Prioritize readable, understandable code - clarity over cleverness. Avoid obfuscated or confusing patterns even if shorter
Follow existing patterns and maintain consistency in code implementation
Be intentional about re-exports - don't blindly re-export everything to parent namespaces. Core types defining a module's purpose should be exported. Specialized features can live in submodules. Only re-export to fastmcp.* for most fundamental types
Never use bare except - be specific with exception types

Files:

  • src/fastmcp/server/providers/__init__.py
  • src/fastmcp/resources/resource.py
  • src/fastmcp/prompts/__init__.py
  • src/fastmcp/server/providers/filesystem.py
  • src/fastmcp/tools/__init__.py
  • src/fastmcp/prompts/prompt.py
  • src/fastmcp/tools/tool.py
  • src/fastmcp/server/providers/filesystem_discovery.py
  • src/fastmcp/server/providers/local_provider.py
  • src/fastmcp/resources/__init__.py
docs/**/*.mdx

📄 CodeRabbit inference engine (docs/.cursor/rules/mintlify.mdc)

docs/**/*.mdx: Use clear, direct language appropriate for technical audiences
Write in second person ('you') for instructions and procedures in MDX documentation
Use active voice over passive voice in MDX technical documentation
Employ present tense for current states and future tense for outcomes in MDX documentation
Maintain consistent terminology throughout all MDX documentation
Keep sentences concise while providing necessary context in MDX documentation
Use parallel structure in lists, headings, and procedures in MDX documentation
Lead with the most important information using inverted pyramid structure in MDX documentation
Use progressive disclosure in MDX documentation: present basic concepts before advanced ones
Break complex procedures into numbered steps in MDX documentation
Include prerequisites and context before instructions in MDX documentation
Provide expected outcomes for each major step in MDX documentation
End sections with next steps or related information in MDX documentation
Use descriptive, keyword-rich headings for navigation and SEO in MDX documentation
Focus on user goals and outcomes rather than system features in MDX documentation
Anticipate common questions and address them proactively in MDX documentation
Include troubleshooting for likely failure points in MDX documentation
Provide multiple pathways (beginner vs advanced) but offer an opinionated path to avoid overwhelming users in MDX documentation
Always include complete, runnable code examples that users can copy and execute in MDX documentation
Show proper error handling and edge case management in MDX code examples
Use realistic data instead of placeholder values in MDX code examples
Include expected outputs and results for verification in MDX code examples
Test all code examples thoroughly before publishing in MDX documentation
Specify language and include filename when relevant in MDX code examples
Add explanatory comments for complex logic in MDX code examples
Document all API...

Files:

  • docs/patterns/tool-transformation.mdx
  • docs/servers/providers/filesystem.mdx
docs/**/*.{md,mdx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Documentation uses Mintlify framework. Files must be in docs.json to be included. Never modify docs/python-sdk/** (auto-generated)

Files:

  • docs/patterns/tool-transformation.mdx
  • docs/servers/providers/filesystem.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.{md,mdx}: Code examples in documentation must explain before showing code and make blocks fully runnable (include imports)
Documentation structure: Headers form navigation guide with logical H2/H3 hierarchy. Content should be user-focused with sections motivating features (why) before mechanics (how). Use prose over code comments for important information
Never use 'This isn't...' or 'not just...' constructions in writing - state what something IS directly. Avoid defensive writing patterns

Files:

  • docs/patterns/tool-transformation.mdx
  • docs/servers/providers/filesystem.mdx
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-25T15:53:07.656Z
Learning: Applies to src/fastmcp/**/*.py : Be intentional about re-exports - don't blindly re-export everything to parent namespaces. Core types defining a module's purpose should be exported. Specialized features can live in submodules. Only re-export to fastmcp.* for most fundamental types
📚 Learning: 2025-12-25T15:53:07.656Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-25T15:53:07.656Z
Learning: Applies to src/fastmcp/**/*.py : Python ≥ 3.10 with full type annotations required

Applied to files:

  • examples/filesystem-provider/server.py
  • src/fastmcp/resources/resource.py
  • src/fastmcp/server/providers/filesystem.py
  • src/fastmcp/tools/tool.py
  • src/fastmcp/server/providers/filesystem_discovery.py
  • src/fastmcp/server/providers/local_provider.py
  • docs/servers/providers/filesystem.mdx
📚 Learning: 2025-12-25T15:53:07.656Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-25T15:53:07.656Z
Learning: Applies to src/fastmcp/**/*.py : Be intentional about re-exports - don't blindly re-export everything to parent namespaces. Core types defining a module's purpose should be exported. Specialized features can live in submodules. Only re-export to fastmcp.* for most fundamental types

Applied to files:

  • src/fastmcp/server/providers/__init__.py
  • examples/filesystem-provider/mcp/tools/greeting.py
  • src/fastmcp/prompts/__init__.py
  • examples/filesystem-provider/mcp/resources/config.py
  • src/fastmcp/tools/__init__.py
  • src/fastmcp/server/providers/filesystem_discovery.py
  • src/fastmcp/resources/__init__.py
📚 Learning: 2025-12-25T15:53:07.656Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-25T15:53:07.656Z
Learning: Applies to tests/**/*.py : Pass FastMCP servers directly to clients for testing without network complexity; only use HTTP transport when explicitly testing network features

Applied to files:

  • docs/servers/providers/filesystem.mdx
🧬 Code graph analysis (10)
examples/filesystem-provider/server.py (1)
src/fastmcp/server/providers/filesystem.py (1)
  • FileSystemProvider (46-215)
src/fastmcp/server/providers/__init__.py (1)
src/fastmcp/server/providers/filesystem.py (1)
  • FileSystemProvider (46-215)
examples/filesystem-provider/mcp/tools/greeting.py (1)
src/fastmcp/tools/tool.py (4)
  • tool (775-775)
  • tool (779-790)
  • tool (794-806)
  • tool (809-944)
examples/filesystem-provider/mcp/prompts/assistant.py (2)
src/fastmcp/prompts/prompt.py (4)
  • prompt (619-619)
  • prompt (623-632)
  • prompt (636-646)
  • prompt (649-773)
src/fastmcp/server/providers/local_provider.py (3)
  • prompt (621-633)
  • prompt (636-648)
  • prompt (650-738)
examples/filesystem-provider/mcp/resources/config.py (2)
src/fastmcp/resources/resource.py (1)
  • resource (495-626)
src/fastmcp/server/providers/local_provider.py (1)
  • resource (539-618)
src/fastmcp/server/providers/filesystem.py (5)
src/fastmcp/resources/resource.py (2)
  • resource (495-626)
  • Resource (210-399)
src/fastmcp/resources/template.py (1)
  • ResourceTemplate (97-305)
src/fastmcp/server/providers/filesystem_discovery.py (1)
  • discover_and_import (213-245)
src/fastmcp/tools/tool.py (5)
  • tool (775-775)
  • tool (779-790)
  • tool (794-806)
  • tool (809-944)
  • Tool (141-395)
src/fastmcp/utilities/components.py (1)
  • FastMCPComponent (34-184)
src/fastmcp/tools/__init__.py (1)
src/fastmcp/tools/tool.py (6)
  • tool (775-775)
  • tool (779-790)
  • tool (794-806)
  • tool (809-944)
  • FunctionTool (398-545)
  • Tool (141-395)
src/fastmcp/prompts/prompt.py (2)
src/fastmcp/server/providers/local_provider.py (3)
  • prompt (621-633)
  • prompt (636-648)
  • prompt (650-738)
src/fastmcp/server/tasks/config.py (1)
  • TaskConfig (41-120)
src/fastmcp/server/providers/filesystem_discovery.py (1)
src/fastmcp/utilities/components.py (1)
  • FastMCPComponent (34-184)
src/fastmcp/resources/__init__.py (1)
src/fastmcp/resources/resource.py (2)
  • resource (495-626)
  • Resource (210-399)
🪛 Ruff (0.14.10)
src/fastmcp/resources/resource.py

561-564: Avoid specifying long messages outside the exception class

(TRY003)


568-577: Prefer TypeError exception for invalid type

(TRY004)


621-624: Avoid specifying long messages outside the exception class

(TRY003)

src/fastmcp/server/providers/filesystem.py

132-132: Do not catch blind exception: Exception

(BLE001)

src/fastmcp/prompts/prompt.py

715-724: Prefer TypeError exception for invalid type

(TRY004)


750-753: Avoid specifying long messages outside the exception class

(TRY003)


759-761: Avoid specifying long messages outside the exception class

(TRY003)

src/fastmcp/tools/tool.py

882-891: Prefer TypeError exception for invalid type

(TRY004)


919-922: Avoid specifying long messages outside the exception class

(TRY003)


928-930: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Run tests: Python 3.10 on ubuntu-latest
  • GitHub Check: Run tests: Python 3.10 on windows-latest
  • GitHub Check: Run tests: Python 3.13 on ubuntu-latest
  • GitHub Check: Run tests with lowest-direct dependencies
🔇 Additional comments (20)
src/fastmcp/tools/__init__.py (1)

1-4: LGTM!

The export of tool alongside FunctionTool and Tool is appropriate. These are core types defining the module's purpose, following the principle of being intentional about re-exports. Based on learnings, this aligns with the guideline to export core types that define a module's purpose.

examples/filesystem-provider/mcp/tools/greeting.py (1)

3-3: LGTM!

The import path update from fastmcp.fs to fastmcp.tools aligns with the PR's objective to eliminate the fastmcp.fs module and use canonical import paths.

src/fastmcp/tools/tool.py (1)

809-944: Well-structured standalone decorator implementation.

The tool() function correctly handles all calling patterns (@tool, @tool(), @tool("name"), @tool(name="x")) with proper type overloads and comprehensive documentation. The use of partial for deferred decoration is appropriate.

examples/filesystem-provider/mcp/tools/calculator.py (1)

3-3: LGTM!

Import path correctly updated to fastmcp.tools. The example demonstrates proper usage of the standalone @tool decorator with various parameters.

src/fastmcp/server/providers/__init__.py (1)

32-48: LGTM!

The direct import of FileSystemProvider (rather than lazy-loading) is appropriate since it's a core provider type that will be commonly used. The __all__ list is correctly updated. Based on learnings, this aligns with exporting core types that define the module's purpose.

examples/filesystem-provider/mcp/resources/config.py (1)

5-5: LGTM!

Import path correctly updated to fastmcp.resources. The examples effectively demonstrate static resources, templated resources with URI parameters, and resources with custom metadata.

examples/filesystem-provider/mcp/prompts/assistant.py (1)

3-3: LGTM!

Import path correctly updated to fastmcp.prompts. The examples demonstrate both the bare @prompt decorator and @prompt(...) with custom parameters.

examples/filesystem-provider/server.py (1)

19-19: LGTM! Import path correctly updated.

The import path change from fastmcp.fs to fastmcp.server.providers aligns with the PR's module reorganization and follows the more specific namespace structure.

src/fastmcp/prompts/__init__.py (1)

1-10: LGTM! Appropriate public API expansion.

The addition of FunctionPrompt and prompt to the module's public API is intentional and aligns with the standalone decorator pattern introduced in this PR. These are core types for the prompts module's purpose.

Based on learnings, the re-exports are appropriately scoped to fundamental types.

src/fastmcp/resources/__init__.py (1)

1-29: LGTM! Consistent with standalone decorator pattern.

The addition of the resource decorator to the public API is consistent with the parallel changes in prompts/__init__.py and appropriately exposes a core type for this module.

Based on learnings, the re-export follows the guideline of exposing core types that define the module's purpose.

docs/servers/providers/filesystem.mdx (4)

18-18: LGTM! Clear explanation of standalone decorators.

The updated description accurately explains the decoupling achieved by standalone decorators and aligns with the PR's objectives.


28-37: LGTM! Example demonstrates best practices.

The quick start example correctly:

  • Uses Path(__file__).parent for relative paths (better than hardcoded strings)
  • Shows the updated import path
  • Provides clear, runnable code

43-133: LGTM! Decorator examples are comprehensive and accurate.

All decorator examples:

  • Use the correct new import paths
  • Include complete, runnable code
  • Show both basic and advanced usage patterns
  • Follow MDX documentation guidelines with proper code blocks

195-200: LGTM! Reload mode example is clear.

The example correctly demonstrates the reload mode configuration with the updated import path and Path-based root specification.

src/fastmcp/resources/resource.py (3)

15-16: LGTM! Appropriate use of TYPE_CHECKING.

The conditional import of ResourceTemplate under TYPE_CHECKING avoids circular import issues while maintaining type hints. The runtime import at line 591 ensures the class is available when needed.


491-492: LGTM! Clear type alias.

The AnyFunction alias provides clear documentation for the decorator's input type.


495-565: LGTM! Well-designed decorator with proper safeguards.

The decorator signature, docstring, and guard clauses are well-implemented:

  • Comprehensive parameter documentation
  • Clear examples showing both Resource and ResourceTemplate usage
  • Proper normalization of annotations dict
  • Guard against incorrect usage (@resource without calling it)
  • Guard against classmethod decoration with helpful error message and documentation link
src/fastmcp/prompts/prompt.py (1)

588-612: FunctionPrompt.add_to_docket argument passing fix looks correct.

Using docket.add(...)(**(arguments or {})) (Line 611) matches the expectation that FunctionPrompt.fn is invoked with keyword args.

src/fastmcp/server/providers/local_provider.py (2)

704-738: prompt() delegation and registration wrapper are solid.

Handling both “direct FunctionPrompt return” vs “decorator/partial” (Line 728-738) is the right pattern to preserve all call styles while centralizing object creation.


588-618: Delegation looks good; no behavioral regression.

The flow is clean and consistent. Server decorators always pass an explicit task parameter (either user-provided or self._support_tasks_by_default), so the False default at line 589 only applies to standalone decorator usage, which is correct. No behavior change for server-attached resources/prompts.

Comment on lines 124 to 128
# Clear warnings for files that now import successfully
successful_files = {fp for fp, _, _ in result.components}
successful_files = {fp for fp, _ in result.components}
for fp in successful_files:
self._warned_files.pop(fp, None)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

successful_files should reflect “import succeeded”, not “components found”.

Right now you only clear _warned_files for files that produced at least one component (Line 125). If a file previously failed to import, then later imports successfully but defines no components, the stale _warned_files entry remains.

Consider tracking successful imports in DiscoveryResult (e.g., imported_files: set[Path]) or returning it from discover_and_import, then clearing _warned_files for (all_discovered_files - failed_files).

Comment thread src/fastmcp/server/providers/filesystem.py
- Use TypeError instead of ValueError for classmethod rejection
- Remove unreachable else branch in resource decorator
- Use logger.exception for registration failures
- Add defensive else branch in _register_component
- Remove incorrect subclass comment
Update LocalProvider.tool() and all related tests to use TypeError
instead of ValueError when rejecting classmethod-decorated functions.
This is consistent with the standalone decorators.
@jlowin jlowin merged commit daa2dac into main Jan 10, 2026
11 checks passed
@jlowin jlowin deleted the standalone-decorators-refactor branch January 10, 2026 17:16
@jlowin jlowin added this to the 3.0 milestone Jan 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change Breaks backward compatibility. Requires minor version bump. Critical for maintainer attention. feature Major new functionality. Reserved for 2-4 significant PRs per release. Not for issues. server Related to FastMCP server implementation or server-side functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant