-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Decorators return functions instead of component objects #2856
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Test Failure AnalysisSummary: Static analysis failed due to file size violations - 14 files exceed their configured line limits. Root Cause: The decorator refactoring changes caused multiple files to exceed their Suggested Solution: Run uv run loq baselineThis will update Detailed AnalysisThe From CI logs (workflow run 20942110036): Analysis:
This is a straightforward fix - the code changes are legitimate, and the file size limits just need to be updated to reflect the new reality. Related FilesFiles exceeding limits:
New files needing baseline entries:
Latest analysis from workflow run 20942110036 (commit a8258f1). Updated by marvin. |
Test Failure AnalysisSummary: Windows-only test timeout in Root Cause: The test hangs at This is a Windows-specific issue (tests pass on Linux/macOS). The test uses This is NOT related to the decorator changes in this PR - it's a pre-existing Windows test environment issue with DiskStore/SQLite resource management. Suggested Solution: Option 1 (Recommended): Skip disk-based storage tests on Windows and use in-memory storage instead: @pytest.mark.skipif(sys.platform == 'win32', reason="SQLite disk storage flaky on Windows")
async def test_register_and_get_client(self, jwt_verifier, temp_storage):
...
# Or modify the fixture to use MemoryStore on Windows:
@pytest.fixture
async def temp_storage(self) -> AsyncGenerator[AsyncKeyValue, None]:
if sys.platform == 'win32':
# Use MemoryStore on Windows to avoid SQLite file locking issues
yield MemoryStore()
else:
# Use disk storage on Unix for more realistic testing
with tempfile.TemporaryDirectory() as temp_dir:
disk_store = MultiDiskStore(base_directory=Path(temp_dir))
yield disk_store
await disk_store.close()Option 2: Increase the timeout for this specific test on Windows: @pytest.mark.timeout(30 if sys.platform == 'win32' else 5)
async def test_register_and_get_client(self, jwt_verifier, temp_storage):
...Option 3: Mark the entire test class as integration tests to exclude from the main test suite: @pytest.mark.integration
class TestOAuthProxyStorage:
...Detailed AnalysisFrom workflow run 20941161722 (commit fb4f1e9): The test
Known diskcache/SQLite Windows issues:
Why it doesn't affect Linux/macOS: Unix systems handle SQLite file locking more gracefully and have better support for concurrent database access. Related Files
Updated for workflow run 20941161722 - commit fb4f1e9 |
Move FunctionTool/FunctionResource/FunctionPrompt and their metadata classes into function_*.py files. Base classes now use @classmethod with keyword-only args for LSP compatibility. Old import paths work via __getattr__ with deprecation warnings (respects settings).
# Conflicts: # src/fastmcp/prompts/prompt.py # src/fastmcp/resources/resource.py # src/fastmcp/server/providers/local_provider.py # src/fastmcp/server/server.py # src/fastmcp/tools/tool.py
- Add auth=meta.auth to filesystem_discovery.py for all component types - Add tool decorator to __getattr__ deprecation re-exports in tool.py - Add test for tool decorator deprecated import path
|
Warning Rate limit exceeded@jlowin has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 18 minutes and 51 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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. 📒 Files selected for processing (2)
WalkthroughThis PR changes decorators ( Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ 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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/fastmcp/tools/tool_transform.py (1)
1-19: Pipeline failure: file size limit exceeded.Static analysis reports the file exceeds the 952-line limit (currently 954 lines). While the import changes in this PR are minimal, consider whether this file could be split further. The
ArgTransform,ArgTransformConfig,ToolTransformConfig, and helper functions could potentially be extracted to a separate module (e.g.,tool_transform_config.py) to reduce file size and improve maintainability.src/fastmcp/server/providers/local_provider.py (1)
1-997: Pipeline failure: File size limit exceeded.The static analysis reports this file exceeds the line limit (997 > 738). The duplicated patterns identified above contribute significantly to the file size. Refactoring the common patterns into shared utilities would help address this limit while also improving maintainability.
src/fastmcp/tools/function_tool.py (1)
1-604: Pipeline failure: File size limit exceeded.The static analysis reports this file exceeds the line limit (604 > 500). Consider splitting
ParsedFunctioninto a separate module (e.g.,parsed_function.py) since it's a self-contained data class with its own logic.
🧹 Nitpick comments (7)
src/fastmcp/settings.py (1)
352-367: Consider adding a deprecation warning validator for "object" mode.The description notes that
"object"mode is deprecated, but unlikeenable_new_openapi_parser(lines 128-139), there's nofield_validatorto emit aDeprecationWarningwhen this mode is selected. This would provide consistent behavior and help users migrate.♻️ Suggested validator
@field_validator("decorator_mode", mode="after") @classmethod def _warn_decorator_mode_deprecated(cls, v: str) -> str: if v == "object": warnings.warn( "decorator_mode='object' is deprecated. " "Decorators now return the original function by default. " "See https://gofastmcp.com/development/upgrade-guide for migration.", DeprecationWarning, stacklevel=2, ) return vsrc/fastmcp/server/server.py (1)
1-2799: Pipeline failure: File size limit exceeded.The pipeline reports
LOQ: file size limit exceeded (2799 > 2682). This is an operational concern—the file has grown beyond the configured limit. Consider refactoring to extract some functionality into separate modules to reduce file size.Potential candidates for extraction:
- HTTP transport methods (
run_http_async,http_app) → dedicated transport module- Mount/import server logic → dedicated composition module
- Factory methods (
from_openapi,from_fastapi,create_proxy) → dedicated factory modulesrc/fastmcp/resources/function_resource.py (1)
241-282: RedundantResourceMetaconstruction increate_resource.The
resource_metaobject is created on lines 251-263 but is only used in theelsebranch (line 282). For theifbranch (lines 265-280), all individual parameters are passed directly toResourceTemplate.from_function. Consider restructuring to avoid redundant object creation when not needed.src/fastmcp/server/providers/local_provider.py (1)
578-599: Significant code duplication across tool/resource/prompt decorators.The unbound method detection logic (checking for
self/clsas first parameter) is duplicated nearly identically three times:
- Lines 578-599 (tool)
- Lines 748-766 (resource)
- Lines 910-931 (prompt)
Consider extracting this into a shared helper function to reduce duplication and simplify maintenance.
Suggested helper function
def _validate_not_unbound_method( fn: Callable[..., Any], decorator_name: str, import_path: str, uri_or_name: str | None = None, ) -> None: """Raise TypeError if fn appears to be an unbound method.""" try: params = list(inspect.signature(fn).parameters.keys()) except (ValueError, TypeError): params = [] if params and params[0] in ("self", "cls"): fn_name = getattr(fn, "__name__", "function") uri_hint = f"('{uri_or_name}')" if uri_or_name else "" raise TypeError( f"The function '{fn_name}' has '{params[0]}' as its first parameter. " f"Use the standalone @{decorator_name} decorator and register the bound method:\n\n" f" from {import_path} import {decorator_name}\n\n" f" class MyClass:\n" f" @{decorator_name}{uri_hint}\n" f" def {fn_name}(...):\n" f" ...\n\n" f" obj = MyClass()\n" f" mcp.add_{decorator_name}(obj.{fn_name})\n\n" f"See https://gofastmcp.com/patterns/decorating-methods" )Also applies to: 748-766, 910-931
src/fastmcp/prompts/function_prompt.py (2)
200-202: Silent exception swallowing during schema generation.The bare
except Exception: passsilently ignores schema generation failures. While the intent is to gracefully degrade when schema enhancement fails, this makes debugging difficult. Consider logging at debug level to aid troubleshooting.Proposed fix
except Exception: # If schema generation fails, skip enhancement - pass + logger.debug( + f"Schema generation failed for parameter '{param_name}', " + "skipping description enhancement" + )
134-143: Comment is misplaced after the lambda check.The comment
# Reject functions with *args or **kwargson line 136 appears after the lambda ValueError on line 135, making it look like it's documenting the lambda check rather than the subsequent validation loop. This is a minor readability issue.Proposed fix
if func_name == "<lambda>": raise ValueError("You must provide a name for lambda functions") - # Reject functions with *args or **kwargs + + # Reject functions with *args or **kwargs sig = inspect.signature(fn)src/fastmcp/tools/function_tool.py (1)
199-201: Silent exception swallowing during type hint resolution.Same issue as in
function_prompt.py- the bareexcept Exception: passsilently ignores failures when resolving string type annotations. Consider logging at debug level.Proposed fix
except Exception: # If resolution fails, keep the string annotation - pass + logger.debug(f"Unable to resolve type hint for return annotation: {output_type!r}")
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (15)
tests/deprecated/test_function_component_imports.pyis excluded by none and included by nonetests/deprecated/test_import_server.pyis excluded by none and included by nonetests/prompts/test_standalone_decorator.pyis excluded by none and included by nonetests/resources/test_function_resources.pyis excluded by none and included by nonetests/resources/test_resource_template.pyis excluded by none and included by nonetests/resources/test_resources.pyis excluded by none and included by nonetests/resources/test_standalone_decorator.pyis excluded by none and included by nonetests/server/middleware/test_caching.pyis excluded by none and included by nonetests/server/middleware/test_tool_injection.pyis excluded by none and included by nonetests/server/providers/test_local_provider_prompts.pyis excluded by none and included by nonetests/server/providers/test_local_provider_tools.pyis excluded by none and included by nonetests/server/tasks/test_sync_function_task_disabled.pyis excluded by none and included by nonetests/server/test_providers.pyis excluded by none and included by nonetests/tools/test_standalone_decorator.pyis excluded by none and included by nonetests/tools/test_tool_transform.pyis excluded by none and included by none
📒 Files selected for processing (18)
docs/development/upgrade-guide.mdxdocs/development/v3-notes/v3-features.mdxsrc/fastmcp/decorators.pysrc/fastmcp/prompts/__init__.pysrc/fastmcp/prompts/function_prompt.pysrc/fastmcp/prompts/prompt.pysrc/fastmcp/resources/__init__.pysrc/fastmcp/resources/function_resource.pysrc/fastmcp/resources/resource.pysrc/fastmcp/server/providers/filesystem_discovery.pysrc/fastmcp/server/providers/local_provider.pysrc/fastmcp/server/sampling/sampling_tool.pysrc/fastmcp/server/server.pysrc/fastmcp/settings.pysrc/fastmcp/tools/__init__.pysrc/fastmcp/tools/function_tool.pysrc/fastmcp/tools/tool.pysrc/fastmcp/tools/tool_transform.py
🧰 Additional context used
📓 Path-based instructions (3)
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/development/upgrade-guide.mdxdocs/development/v3-notes/v3-features.mdx
src/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.py: Python source code must use Python ≥3.10 with full type annotations
Never use bareexcept- be specific with exception types
Prioritize readable, understandable code - clarity over cleverness; avoid obfuscated or confusing patterns
Follow existing patterns and maintain consistency across the codebase
Files:
src/fastmcp/decorators.pysrc/fastmcp/settings.pysrc/fastmcp/server/sampling/sampling_tool.pysrc/fastmcp/tools/tool_transform.pysrc/fastmcp/server/server.pysrc/fastmcp/tools/tool.pysrc/fastmcp/resources/function_resource.pysrc/fastmcp/prompts/function_prompt.pysrc/fastmcp/server/providers/filesystem_discovery.pysrc/fastmcp/resources/resource.pysrc/fastmcp/tools/function_tool.pysrc/fastmcp/server/providers/local_provider.pysrc/fastmcp/resources/__init__.pysrc/fastmcp/tools/__init__.pysrc/fastmcp/prompts/__init__.pysrc/fastmcp/prompts/prompt.py
src/**/__init__.py
📄 CodeRabbit inference engine (AGENTS.md)
Be intentional about re-exports - don't blindly re-export everything to parent namespaces; only re-export fundamental types to fastmcp.*
Files:
src/fastmcp/resources/__init__.pysrc/fastmcp/tools/__init__.pysrc/fastmcp/prompts/__init__.py
🧠 Learnings (5)
📚 Learning: 2026-01-12T16:24:54.978Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: .cursor/rules/core-mcp-objects.mdc:0-0
Timestamp: 2026-01-12T16:24:54.978Z
Learning: Applies to src/prompts/**/*.{ts,tsx,js,jsx} : Changes affecting MCP Prompts (like adding tags, importing, etc.) must be adopted, applied, and tested consistently
Applied to files:
docs/development/upgrade-guide.mdxsrc/fastmcp/prompts/function_prompt.pysrc/fastmcp/prompts/__init__.pysrc/fastmcp/prompts/prompt.py
📚 Learning: 2026-01-12T16:24:54.978Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: .cursor/rules/core-mcp-objects.mdc:0-0
Timestamp: 2026-01-12T16:24:54.978Z
Learning: Applies to src/tools/**/*.{ts,tsx,js,jsx} : Changes affecting MCP Tools (like adding tags, importing, etc.) must be adopted, applied, and tested consistently
Applied to files:
docs/development/upgrade-guide.mdxsrc/fastmcp/tools/tool.pysrc/fastmcp/tools/function_tool.pysrc/fastmcp/tools/__init__.py
📚 Learning: 2026-01-12T16:25:10.972Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T16:25:10.972Z
Learning: Applies to src/**/__init__.py : Be intentional about re-exports - don't blindly re-export everything to parent namespaces; only re-export fundamental types to fastmcp.*
Applied to files:
src/fastmcp/server/sampling/sampling_tool.pysrc/fastmcp/tools/tool_transform.pysrc/fastmcp/tools/tool.pysrc/fastmcp/resources/resource.pysrc/fastmcp/tools/function_tool.pysrc/fastmcp/resources/__init__.pysrc/fastmcp/tools/__init__.pysrc/fastmcp/prompts/__init__.pysrc/fastmcp/prompts/prompt.py
📚 Learning: 2026-01-12T16:24:54.978Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: .cursor/rules/core-mcp-objects.mdc:0-0
Timestamp: 2026-01-12T16:24:54.978Z
Learning: Applies to src/resources/**/*.{ts,tsx,js,jsx} : Changes affecting MCP Resources (like adding tags, importing, etc.) must be adopted, applied, and tested consistently
Applied to files:
src/fastmcp/resources/resource.pysrc/fastmcp/resources/__init__.py
📚 Learning: 2026-01-12T16:24:54.978Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: .cursor/rules/core-mcp-objects.mdc:0-0
Timestamp: 2026-01-12T16:24:54.978Z
Learning: Maintain consistency across all four MCP object types (Tools, Resources, Resource Templates, and Prompts) when implementing similar features
Applied to files:
src/fastmcp/server/providers/local_provider.py
🧬 Code graph analysis (10)
src/fastmcp/decorators.py (5)
src/fastmcp/prompts/function_prompt.py (1)
PromptMeta(56-67)src/fastmcp/resources/function_resource.py (1)
ResourceMeta(43-57)src/fastmcp/server/tasks/config.py (1)
TaskConfig(42-152)src/fastmcp/tools/function_tool.py (1)
ToolMeta(72-87)src/fastmcp/utilities/components.py (1)
FastMCPMeta(21-22)
src/fastmcp/server/sampling/sampling_tool.py (1)
src/fastmcp/tools/function_tool.py (1)
ParsedFunction(117-256)
src/fastmcp/tools/tool.py (2)
src/fastmcp/tools/function_tool.py (3)
FunctionTool(259-462)from_function(125-256)from_function(285-417)src/fastmcp/tools/tool_transform.py (1)
ArgTransform(96-207)
src/fastmcp/resources/function_resource.py (6)
src/fastmcp/decorators.py (1)
resolve_task_config(17-19)src/fastmcp/resources/resource.py (3)
Resource(209-410)from_function(234-267)read(288-298)src/fastmcp/server/dependencies.py (1)
transform_context_annotations(131-247)src/fastmcp/server/tasks/config.py (4)
TaskConfig(42-152)from_bool(80-89)validate_function(99-152)supports_tasks(91-97)src/fastmcp/utilities/types.py (1)
get_fn_name(34-35)src/fastmcp/resources/template.py (1)
ResourceTemplate(101-316)
src/fastmcp/prompts/function_prompt.py (5)
src/fastmcp/decorators.py (1)
resolve_task_config(17-19)src/fastmcp/prompts/prompt.py (7)
Prompt(189-393)PromptArgument(95-104)PromptResult(107-186)from_function(229-261)render(263-274)convert_result(276-310)register_with_docket(366-370)src/fastmcp/server/dependencies.py (2)
transform_context_annotations(131-247)without_injected_parameters(433-491)src/fastmcp/server/tasks/config.py (2)
TaskConfig(42-152)supports_tasks(91-97)src/fastmcp/utilities/json_schema.py (1)
compress_schema(364-401)
src/fastmcp/resources/resource.py (1)
src/fastmcp/resources/function_resource.py (2)
FunctionResource(60-210)from_function(76-184)
src/fastmcp/tools/function_tool.py (10)
src/fastmcp/server/dependencies.py (1)
transform_context_annotations(131-247)src/fastmcp/server/tasks/config.py (4)
TaskConfig(42-152)supports_tasks(91-97)from_bool(80-89)validate_function(99-152)src/fastmcp/server/providers/local_provider.py (4)
tool(456-473)tool(476-493)tool(499-682)decorator(747-813)src/fastmcp/tools/tool.py (6)
Tool(123-387)ToolResult(62-120)from_function(188-222)to_mcp_tool(159-185)run(224-234)convert_result(236-274)src/fastmcp/utilities/json_schema.py (1)
compress_schema(364-401)src/fastmcp/utilities/types.py (3)
Audio(307-362)File(365-448)replace_type(451-485)src/fastmcp/resources/function_resource.py (2)
from_function(76-184)decorator(302-311)src/fastmcp/prompts/prompt.py (2)
from_function(229-261)convert_result(276-310)src/fastmcp/server/sampling/sampling_tool.py (2)
from_function(76-109)run(46-61)src/fastmcp/server/context.py (1)
debug(518-532)
src/fastmcp/server/providers/local_provider.py (5)
src/fastmcp/prompts/function_prompt.py (8)
FunctionPrompt(70-333)prompt(337-337)prompt(339-349)prompt(351-362)prompt(365-444)from_function(76-223)PromptMeta(56-67)decorator(419-428)src/fastmcp/prompts/prompt.py (2)
Prompt(189-393)from_function(229-261)src/fastmcp/resources/resource.py (2)
Resource(209-410)from_function(234-267)src/fastmcp/resources/template.py (3)
ResourceTemplate(101-316)from_function(128-155)from_function(451-576)src/fastmcp/decorators.py (1)
get_fastmcp_meta(29-41)
src/fastmcp/resources/__init__.py (3)
src/fastmcp/resources/function_resource.py (3)
FunctionResource(60-210)ResourceMeta(43-57)resource(213-313)src/fastmcp/server/providers/local_provider.py (1)
resource(684-815)src/fastmcp/server/server.py (1)
resource(1996-2080)
src/fastmcp/prompts/prompt.py (1)
src/fastmcp/prompts/function_prompt.py (2)
FunctionPrompt(70-333)from_function(76-223)
🪛 GitHub Actions: Run static analysis
src/fastmcp/tools/tool_transform.py
[error] 954-954: LOQ: file size limit exceeded (954 > 952).
src/fastmcp/server/server.py
[error] 2799-2799: LOQ: file size limit exceeded (2799 > 2682).
src/fastmcp/tools/function_tool.py
[error] 604-604: LOQ: file size limit exceeded (604 > 500).
src/fastmcp/server/providers/local_provider.py
[error] 997-997: LOQ: file size limit exceeded (997 > 738).
🪛 Ruff (0.14.10)
src/fastmcp/tools/tool.py
481-481: Avoid specifying long messages outside the exception class
(TRY003)
src/fastmcp/resources/function_resource.py
125-128: Avoid specifying long messages outside the exception class
(TRY003)
133-133: Avoid specifying long messages outside the exception class
(TRY003)
236-239: Avoid specifying long messages outside the exception class
(TRY003)
src/fastmcp/prompts/function_prompt.py
112-115: Avoid specifying long messages outside the exception class
(TRY003)
135-135: Avoid specifying long messages outside the exception class
(TRY003)
140-140: Avoid specifying long messages outside the exception class
(TRY003)
142-142: Avoid specifying long messages outside the exception class
(TRY003)
200-202: try-except-pass detected, consider logging the exception
(S110)
200-200: Do not catch blind exception: Exception
(BLE001)
259-262: Avoid specifying long messages outside the exception class
(TRY003)
280-280: Avoid specifying long messages outside the exception class
(TRY003)
298-298: Avoid specifying long messages outside the exception class
(TRY003)
383-386: Avoid specifying long messages outside the exception class
(TRY003)
434-434: Avoid specifying long messages outside the exception class
(TRY003)
439-439: Avoid specifying long messages outside the exception class
(TRY003)
src/fastmcp/resources/resource.py
443-443: Avoid specifying long messages outside the exception class
(TRY003)
src/fastmcp/tools/function_tool.py
137-137: Avoid specifying long messages outside the exception class
(TRY003)
139-141: Avoid specifying long messages outside the exception class
(TRY003)
147-149: Avoid specifying long messages outside the exception class
(TRY003)
152-154: Avoid specifying long messages outside the exception class
(TRY003)
199-201: try-except-pass detected, consider logging the exception
(S110)
199-199: Do not catch blind exception: Exception
(BLE001)
335-338: Avoid specifying long messages outside the exception class
(TRY003)
378-378: Avoid specifying long messages outside the exception class
(TRY003)
398-401: Avoid specifying long messages outside the exception class
(TRY003)
527-530: Avoid specifying long messages outside the exception class
(TRY003)
584-584: Avoid specifying long messages outside the exception class
(TRY003)
589-589: Avoid specifying long messages outside the exception class
(TRY003)
src/fastmcp/server/providers/local_provider.py
272-275: Avoid specifying long messages outside the exception class
(TRY003)
314-317: Avoid specifying long messages outside the exception class
(TRY003)
588-599: Avoid specifying long messages outside the exception class
(TRY003)
739-743: Avoid specifying long messages outside the exception class
(TRY003)
755-766: Avoid specifying long messages outside the exception class
(TRY003)
905-908: Avoid specifying long messages outside the exception class
(TRY003)
920-931: Avoid specifying long messages outside the exception class
(TRY003)
976-979: Avoid specifying long messages outside the exception class
(TRY003)
984-984: Avoid specifying long messages outside the exception class
(TRY003)
src/fastmcp/prompts/prompt.py
425-425: Avoid specifying long messages outside the exception class
(TRY003)
🔇 Additional comments (26)
src/fastmcp/server/sampling/sampling_tool.py (1)
12-12: LGTM!The import path update correctly reflects the refactoring of
ParsedFunctionto its dedicatedfunction_toolmodule. The usage remains unchanged and consistent with the new module location.src/fastmcp/tools/tool_transform.py (1)
18-19: Import restructuring is correct.The split import correctly sources
ParsedFunctionfrom its new dedicated module while keepingTool,ToolResult, and_convert_to_contentfrom the originaltoolmodule.docs/development/upgrade-guide.mdx (1)
17-55: Documentation accurately documents the breaking change and provides correct configuration examples.The section effectively communicates the decorator behavior change with:
- Appropriate Warning component for visibility
- Before/After code examples using CodeGroup showing the behavioral difference
- Clear rationale explaining why functions remain functions
- Both configuration methods correctly documented:
- Programmatic:
fastmcp.settings.decorator_mode = "object"- Environment variable:
FASTMCP_DECORATOR_MODE=object(auto-generated by pydantic_settings from the Settings field)docs/development/v3-notes/v3-features.mdx (1)
241-271: LGTM! Clear and comprehensive documentation of the decorator behavior change.The documentation effectively:
- Explains the new v3 default behavior with a runnable example
- Provides clear rationale ("Functions stay callable", "Matches Flask, FastAPI, Typer")
- Documents both migration paths (environment variable and programmatic setting)
- Appropriately documents the breaking change in both the feature section and breaking changes section
Also applies to: 396-419
src/fastmcp/tools/__init__.py (1)
1-14: LGTM! Intentional and well-organized public API exports.The exports are appropriately scoped:
FunctionTool,ParsedFunction,ToolMeta,toolfrom the new dedicated moduleTool,ToolResultfrom the base tool module- All exports are fundamental types that users need for the metadata-driven decorator patterns
This aligns with the coding guideline to be intentional about re-exports. Based on learnings.
src/fastmcp/decorators.py (1)
29-41: LGTM! Robust metadata extraction with proper edge case handling.The implementation correctly handles:
- Direct attribute access for decorated functions
- Bound methods via
__func__for instance method support- Wrapped functions via
inspect.unwrapfor compatibility with other decorators (e.g.,@functools.wraps)- The
ValueErrorcatch on line 39 correctly handles the edge case whereinspect.unwrapencounters an infinite wrapper chainsrc/fastmcp/tools/tool.py (2)
187-222: LGTM! Clean delegation pattern with lazy import.The
from_functionclassmethod correctly:
- Uses a lazy import to avoid circular dependencies
- Delegates all parameters to
FunctionTool.from_function- Maintains the same public API signature for backwards compatibility
460-481: Well-implemented deprecation shim.The
__getattr__hook provides a clean migration path:
- Deprecation warnings are controlled by
fastmcp.settings.deprecation_warnings- Correct
stacklevel=2ensures warnings point to the caller's location- Falls back to
AttributeErrorfor unknown attributesThe static analysis hint (TRY003) about the long message in the
AttributeErroris a false positive—this is the standard Python pattern for module-level__getattr__.src/fastmcp/resources/__init__.py (1)
1-25: LGTM! Consistent with tools module structure.The import reorganization follows the same pattern as
tools/__init__.py:
- Function-specific types (
FunctionResource,ResourceMeta,resource) from the dedicatedfunction_resourcemodule- Base types (
Resource,ResourceContent,ResourceResult) from theresourcemoduleResourceMetais appropriately added to public exports for the metadata-driven decorator patternsBased on learnings, this is intentional about re-exports.
src/fastmcp/server/server.py (3)
69-70: LGTM! Import reorganization aligns with module restructuring.The imports correctly source types from their new dedicated modules:
FunctionPromptfromprompts.function_promptPromptResultfromprompts.promptFunctionToolfromtools.function_tool- Other tool types from
tools.toolAlso applies to: 89-90
1811-1823: LGTM! API expansion to accept decorated functions.The
add_tool,add_resource, andadd_promptmethods now correctly accept both component instances and decorated functions (Callable[..., Any]), enabling the new decorator pattern where functions retain their callable nature.The docstrings are updated to reflect this dual-input capability.
Also applies to: 1972-1983, 2082-2091
2010-2010: LGTM! Return type correctly reflects decorator mode behavior.The
resourcedecorator's return typeCallable[[AnyFunction], Resource | ResourceTemplate | AnyFunction]correctly indicates that indecorator_mode="function", the original function is returned, while indecorator_mode="object", a component is returned.Also applies to: 2077-2078
src/fastmcp/prompts/prompt.py (2)
228-261: LGTM! Clean delegation pattern forfrom_function.The conversion to a classmethod that delegates to
FunctionPrompt.from_functionis well-structured. The lazy import inside the method body avoids circular imports while maintaining the public API.
396-425: Well-implemented deprecation shim with controlled warnings.The
__getattr__implementation correctly:
- Uses
fastmcp.settings.deprecation_warningsto control warning emission- Provides clear migration guidance in the warning message
- Falls through to
AttributeErrorfor unknown attributesOne minor observation: the
stacklevel=2is appropriate here since the call originates from the module-level attribute access.src/fastmcp/resources/function_resource.py (1)
60-73: LGTM! Clean FunctionResource implementation.The
FunctionResourceclass is well-structured with:
- Clear docstring explaining lazy loading behavior
- Proper async handling in
read()with recursive Resource support- Correct docket registration pattern
Also applies to: 186-200
src/fastmcp/server/providers/local_provider.py (2)
187-216: LGTM!add_toolproperly handles both Tool objects and decorated functions.The implementation correctly:
- Checks for existing Tool instances first
- Extracts metadata via
get_fastmcp_meta- Falls back to
Tool.from_functionfor plain functions without metadata
290-318: LGTM!add_promptmirrors theadd_toolpattern correctly.Consistent implementation with proper metadata extraction and fallback to
Prompt.from_function.src/fastmcp/resources/resource.py (2)
233-267: LGTM! Consistent delegation pattern forfrom_function.The classmethod properly delegates to
FunctionResource.from_functionwith all parameters passed through. This matches the pattern established inprompt.py.
413-443: LGTM! Deprecation shim consistent with other modules.The
__getattr__implementation follows the same pattern asprompt.py, providing controlled deprecation warnings and proper fallback to the new module location.src/fastmcp/prompts/function_prompt.py (3)
70-223: Well-structuredFunctionPromptimplementation.The
from_functionclassmethod correctly:
- Enforces mutual exclusion between metadata and individual parameters
- Validates function signatures (no *args/**kwargs, named lambdas)
- Normalizes TaskConfig with proper validation
- Generates PromptArgument list with JSON schema hints for non-string types
- Properly handles callable classes and staticmethods
225-298: LGTM!_convert_string_argumentsandrenderimplementation.The type conversion logic properly:
- Attempts JSON parsing first for complex types
- Falls back to direct validation
- Provides informative error messages on failure
The
rendermethod correctly validates required arguments and handles async functions.
365-444: LGTM! Standalonepromptdecorator with proper mode switching.The decorator implementation:
- Supports all invocation patterns (
@prompt,@prompt(),@prompt("name"))- Guards against classmethod decoration order issues
- Properly switches between object mode (deprecated) and function mode
- Attaches metadata to the original function in function mode
src/fastmcp/tools/function_tool.py (4)
116-256: Well-structuredParsedFunctionimplementation.The
from_functionclassmethod correctly:
- Validates function signatures (no *args/**kwargs)
- Validates exclude_args against function parameters
- Handles callable classes and staticmethods
- Generates input/output schemas with proper compression
- Wraps non-object output schemas to comply with MCP requirements
259-417:FunctionTool.from_functionis well-implemented.The implementation correctly:
- Enforces mutual exclusion between metadata and individual parameters
- Emits deprecation warnings for
serializerandexclude_args- Normalizes TaskConfig with validation
- Validates output schema is an object type per MCP spec
502-594: LGTM! Standalonetooldecorator consistent with other decorators.The implementation follows the same pattern as
promptandresourcedecorators with proper mode switching and metadata attachment.
419-427: The current implementation is correct.TypeAdapter.validate_python()on an async function actually invokes the function and returns a coroutine object—it does not merely validate schema and return the input dictionary.The flow is: (1)
validate_python(arguments)callswrapper_fn(**arguments), which executes the wrapped function and returns a coroutine, (2)inspect.isawaitable(result)detects the coroutine, (3)await resultexecutes it to completion and retrieves the actual return value, (4)convert_result()processes the final result.The proposed fix would incorrectly attempt to unpack a coroutine object as keyword arguments and invoke the function a second time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fb4f1e9f5a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| meta=meta.meta, | ||
| task=resolved_task, | ||
| exclude_args=meta.exclude_args, | ||
| serializer=meta.serializer, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forward decorator auth in filesystem discovery
When filesystem discovery rebuilds components from __fastmcp__ metadata, it doesn’t pass meta.auth into Tool.from_function (and the same omission occurs for resources/prompts in this function). As a result, any auth checks declared in decorators are silently dropped for modules discovered via FileSystemProvider, allowing unauthenticated access in deployments that rely on decorator-level auth. Please forward meta.auth when constructing Tool/Resource/ResourceTemplate/Prompt objects here.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/fastmcp/tools/tool.py (1)
50-52: Stale comment: "Re-export from function_tool module"This comment suggests static re-exports will follow, but the actual re-export mechanism is via
__getattr__at the end of the file. Consider removing or clarifying this comment to avoid confusion.Suggested fix
-# Re-export from function_tool module - logger = get_logger(__name__)src/fastmcp/server/providers/filesystem_discovery.py (1)
222-239: Consider usingresolve_task_configfor consistency.The inline
meta.task if meta.task is not None else Falseduplicates the logic inresolve_task_configfromfastmcp.decorators. Using the utility would improve consistency with other parts of the codebase.Suggested refactor
+ from fastmcp.decorators import resolve_task_config + if isinstance(meta, ToolMeta): - resolved_task = meta.task if meta.task is not None else False + resolved_task = resolve_task_config(meta.task) tool = Tool.from_function(Apply similar changes for
ResourceMetaandPromptMetahandling below.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
tests/deprecated/test_function_component_imports.pyis excluded by none and included by none
📒 Files selected for processing (6)
src/fastmcp/prompts/__init__.pysrc/fastmcp/resources/__init__.pysrc/fastmcp/resources/function_resource.pysrc/fastmcp/server/providers/filesystem_discovery.pysrc/fastmcp/tools/__init__.pysrc/fastmcp/tools/tool.py
🚧 Files skipped from review as they are similar to previous changes (1)
- src/fastmcp/resources/init.py
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.py: Python source code must use Python ≥3.10 with full type annotations
Never use bareexcept- be specific with exception types
Prioritize readable, understandable code - clarity over cleverness; avoid obfuscated or confusing patterns
Follow existing patterns and maintain consistency across the codebase
Files:
src/fastmcp/resources/function_resource.pysrc/fastmcp/tools/__init__.pysrc/fastmcp/tools/tool.pysrc/fastmcp/server/providers/filesystem_discovery.pysrc/fastmcp/prompts/__init__.py
src/**/__init__.py
📄 CodeRabbit inference engine (AGENTS.md)
Be intentional about re-exports - don't blindly re-export everything to parent namespaces; only re-export fundamental types to fastmcp.*
Files:
src/fastmcp/tools/__init__.pysrc/fastmcp/prompts/__init__.py
🧠 Learnings (3)
📚 Learning: 2026-01-12T16:25:10.972Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T16:25:10.972Z
Learning: Applies to src/**/__init__.py : Be intentional about re-exports - don't blindly re-export everything to parent namespaces; only re-export fundamental types to fastmcp.*
Applied to files:
src/fastmcp/tools/__init__.pysrc/fastmcp/tools/tool.pysrc/fastmcp/prompts/__init__.py
📚 Learning: 2026-01-12T16:24:54.978Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: .cursor/rules/core-mcp-objects.mdc:0-0
Timestamp: 2026-01-12T16:24:54.978Z
Learning: Applies to src/tools/**/*.{ts,tsx,js,jsx} : Changes affecting MCP Tools (like adding tags, importing, etc.) must be adopted, applied, and tested consistently
Applied to files:
src/fastmcp/tools/__init__.pysrc/fastmcp/tools/tool.py
📚 Learning: 2026-01-12T16:24:54.978Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: .cursor/rules/core-mcp-objects.mdc:0-0
Timestamp: 2026-01-12T16:24:54.978Z
Learning: Applies to src/prompts/**/*.{ts,tsx,js,jsx} : Changes affecting MCP Prompts (like adding tags, importing, etc.) must be adopted, applied, and tested consistently
Applied to files:
src/fastmcp/prompts/__init__.py
🧬 Code graph analysis (5)
src/fastmcp/resources/function_resource.py (6)
src/fastmcp/decorators.py (1)
resolve_task_config(17-19)src/fastmcp/resources/resource.py (2)
Resource(209-410)from_function(234-267)src/fastmcp/server/dependencies.py (2)
transform_context_annotations(131-247)without_injected_parameters(433-491)src/fastmcp/server/tasks/config.py (4)
TaskConfig(42-152)from_bool(80-89)validate_function(99-152)supports_tasks(91-97)src/fastmcp/utilities/types.py (1)
get_fn_name(34-35)src/fastmcp/resources/template.py (1)
ResourceTemplate(101-316)
src/fastmcp/tools/__init__.py (3)
src/fastmcp/tools/function_tool.py (5)
FunctionTool(259-462)tool(466-466)tool(468-482)tool(484-499)tool(502-594)src/fastmcp/tools/tool.py (2)
Tool(123-387)ToolResult(62-120)src/fastmcp/tools/tool_transform.py (2)
forward(39-66)forward_raw(69-92)
src/fastmcp/tools/tool.py (1)
src/fastmcp/tools/function_tool.py (3)
FunctionTool(259-462)from_function(125-256)from_function(285-417)
src/fastmcp/server/providers/filesystem_discovery.py (5)
src/fastmcp/decorators.py (1)
get_fastmcp_meta(29-41)src/fastmcp/prompts/function_prompt.py (5)
PromptMeta(56-67)prompt(337-337)prompt(339-349)prompt(351-362)prompt(365-444)src/fastmcp/resources/function_resource.py (2)
ResourceMeta(43-57)resource(211-311)src/fastmcp/server/dependencies.py (1)
without_injected_parameters(433-491)src/fastmcp/tools/function_tool.py (5)
ToolMeta(72-87)tool(466-466)tool(468-482)tool(484-499)tool(502-594)
src/fastmcp/prompts/__init__.py (2)
src/fastmcp/prompts/function_prompt.py (5)
FunctionPrompt(70-333)prompt(337-337)prompt(339-349)prompt(351-362)prompt(365-444)src/fastmcp/prompts/prompt.py (4)
Message(40-92)Prompt(189-393)PromptArgument(95-104)PromptResult(107-186)
🪛 Ruff (0.14.10)
src/fastmcp/resources/function_resource.py
125-128: Avoid specifying long messages outside the exception class
(TRY003)
133-133: Avoid specifying long messages outside the exception class
(TRY003)
234-237: Avoid specifying long messages outside the exception class
(TRY003)
src/fastmcp/tools/tool.py
482-482: 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). (1)
- GitHub Check: Run tests: Python 3.10 on windows-latest
🔇 Additional comments (15)
src/fastmcp/prompts/__init__.py (1)
1-12: LGTM!The re-exports are intentional and well-organized. Moving
FunctionPromptandpromptto the dedicatedfunction_promptmodule aligns with the PR's goal of consolidating function-wrapping implementations. AddingPromptArgumentto__all__improves API completeness.src/fastmcp/tools/tool.py (3)
187-222: LGTM!The delegation pattern is correct. Using a local import inside
from_functionavoids circular imports while keeping the base class API intact. This allows users to callTool.from_function()without knowing aboutFunctionTool.
460-482: LGTM!The
__getattr__shim correctly implements the deprecation path for backwards compatibility. Thestacklevel=2ensures warnings point to the caller's import site. This allows existing code importingFunctionTool,ParsedFunction, ortoolfrom this module to continue working while receiving deprecation notices.
457-457: LGTM!Reducing
__all__to onlyToolandToolResultcorrectly reflects the intended public API surface. Deprecated names remain accessible via__getattr__for backwards compatibility but are no longer advertised.src/fastmcp/tools/__init__.py (1)
1-12: LGTM!The package cleanly re-exports the fundamental tool types from their new locations.
FunctionToolandtoolfrom the newfunction_toolmodule,ToolandToolResultfrom the base module, andforward/forward_rawutilities fromtool_transform. This aligns with the PR's refactoring goals while maintaining a clean public API. Based on learnings, these re-exports are intentional and appropriate for fundamental types.src/fastmcp/server/providers/filesystem_discovery.py (3)
189-199: LGTM!The local imports inside
extract_componentscorrectly avoid circular import issues while providing access to the metadata types and utilities needed for the new decorator-based component extraction.
240-276: LGTM!The resource materialization logic correctly mirrors the
@resourcedecorator behavior: checking for URI placeholders and function parameters to decide betweenResourceTemplateandResource. This ensures consistent component creation regardless of whether decorators are used directly or discovered via filesystem.
277-290: LGTM!Prompt materialization correctly delegates to
Prompt.from_functionwith all metadata fields.src/fastmcp/resources/function_resource.py (7)
33-39: LGTM!The
DecoratedResourceprotocol correctly defines the interface for decorated resource functions with__fastmcp__metadata. Using@runtime_checkableenables isinstance checks at runtime.
42-57: LGTM!The
ResourceMetadataclass follows the same pattern asToolMetaandPromptMeta, providing a frozen, discriminated metadata container for decorated functions.
184-198: LGTM!The
readmethod correctly handles both sync and async functions, and the recursive read for nestedResourceresults enables composition patterns.
233-237: Good defensive check for common decorator misuse.Checking if
uriis a routine catches the common mistake of using@resourcewithout parentheses, providing a clear error message.
300-309: LGTM!The decorator correctly switches between legacy "object" mode (with deprecation warning) and the new "function" mode that attaches metadata. The
stacklevel=3ensures the warning points to the user's decorator usage.
282-298: LGTM!The
attach_metadatahelper correctly handles both regular functions and bound methods by accessing__func__when present. This ensures the__fastmcp__metadata survives method binding.
163-182: No action needed—the code correctly preserves the docstring.
transform_context_annotationsreturns the same function object (only updates__signature__), so wheninspect.getdoc(fn)is called on line 174, it retrieves the original function's docstring. Additionally,without_injected_parametersexplicitly preserves__doc__via assignment, ensuring the docstring is maintained throughout the transformation chain.
Remove standalone decorating-methods.mdx page and add "Using with Methods" subsection to tools.mdx with brief cross-references in prompts.mdx and resources.mdx. Update error message URLs to point to new location.
Test Failure AnalysisSummary: The static analysis job failed because 15 files exceed their configured line limits in Root Cause: The decorator refactoring introduced in this PR has increased the size of several files beyond their previously established limits. The Suggested Solution: Run uv run loq baseline
git add loq.toml
git commit -m "Update loq baseline for decorator refactoring"Detailed AnalysisThe following 15 files exceed their limits: The Related Files
Updated for workflow run 20942889881 - commit bc2a25c. Edited by marvin. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/fastmcp/prompts/function_prompt.py (1)
200-202: Silent exception swallowing may hide schema generation failures.The bare
except Exception: passsilently ignores all schema generation failures. While the intent is to gracefully degrade when schema generation fails, this could mask legitimate bugs.Consider logging at debug level to aid troubleshooting:
♻️ Suggested improvement
except Exception: - # If schema generation fails, skip enhancement - pass + # If schema generation fails, skip enhancement + logger.debug( + f"Could not generate schema for parameter '{param_name}'" + )src/fastmcp/server/providers/local_provider.py (1)
578-599: Helpful error message for unbound methods, but verify consistency across all three decorators.The error message is excellent—it shows exactly what the user should do. However, I notice the error messages in
tool,resource, andpromptdecorators all link to the same URL (/servers/tools#using-with-methods). For resources, this may be slightly confusing since there's now a dedicated section in resources.mdx.Consider updating the URL in the resource decorator (line 765) to point to
/servers/resources#using-with-methodsfor consistency.src/fastmcp/tools/function_tool.py (1)
193-201: Consider logging type hint resolution failures.Similar to the prompt module, silently swallowing exceptions during type hint resolution could hide issues. Since this is for output schema generation (which is important for MCP structured output), consider debug logging.
♻️ Suggested improvement
except Exception: - # If resolution fails, keep the string annotation - pass + # If resolution fails, keep the string annotation + logger.debug(f"Could not resolve return type annotation for {fn}")
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
docs/docs.jsondocs/patterns/decorating-methods.mdxdocs/servers/prompts.mdxdocs/servers/resources.mdxdocs/servers/tools.mdxsrc/fastmcp/prompts/function_prompt.pysrc/fastmcp/server/providers/local_provider.pysrc/fastmcp/tools/function_tool.py
💤 Files with no reviewable changes (2)
- docs/patterns/decorating-methods.mdx
- docs/docs.json
✅ Files skipped from review due to trivial changes (1)
- docs/servers/prompts.mdx
🧰 Additional context used
📓 Path-based instructions (2)
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/servers/resources.mdxdocs/servers/tools.mdx
src/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.py: Python source code must use Python ≥3.10 with full type annotations
Never use bareexcept- be specific with exception types
Prioritize readable, understandable code - clarity over cleverness; avoid obfuscated or confusing patterns
Follow existing patterns and maintain consistency across the codebase
Files:
src/fastmcp/server/providers/local_provider.pysrc/fastmcp/tools/function_tool.pysrc/fastmcp/prompts/function_prompt.py
🧠 Learnings (3)
📚 Learning: 2026-01-12T16:24:54.978Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: .cursor/rules/core-mcp-objects.mdc:0-0
Timestamp: 2026-01-12T16:24:54.978Z
Learning: Applies to src/tools/**/*.{ts,tsx,js,jsx} : Changes affecting MCP Tools (like adding tags, importing, etc.) must be adopted, applied, and tested consistently
Applied to files:
docs/servers/tools.mdxsrc/fastmcp/tools/function_tool.py
📚 Learning: 2026-01-12T16:24:54.978Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: .cursor/rules/core-mcp-objects.mdc:0-0
Timestamp: 2026-01-12T16:24:54.978Z
Learning: Maintain consistency across all four MCP object types (Tools, Resources, Resource Templates, and Prompts) when implementing similar features
Applied to files:
src/fastmcp/server/providers/local_provider.py
📚 Learning: 2026-01-12T16:24:54.978Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: .cursor/rules/core-mcp-objects.mdc:0-0
Timestamp: 2026-01-12T16:24:54.978Z
Learning: Applies to src/prompts/**/*.{ts,tsx,js,jsx} : Changes affecting MCP Prompts (like adding tags, importing, etc.) must be adopted, applied, and tested consistently
Applied to files:
src/fastmcp/prompts/function_prompt.py
🧬 Code graph analysis (3)
src/fastmcp/server/providers/local_provider.py (6)
src/fastmcp/prompts/function_prompt.py (7)
FunctionPrompt(70-333)prompt(337-337)prompt(339-349)prompt(351-362)prompt(365-444)from_function(76-223)decorator(419-428)src/fastmcp/prompts/prompt.py (2)
Prompt(189-393)from_function(229-261)src/fastmcp/resources/resource.py (2)
Resource(209-410)from_function(234-267)src/fastmcp/resources/template.py (3)
ResourceTemplate(101-316)from_function(128-155)from_function(451-576)src/fastmcp/tools/tool.py (2)
Tool(123-387)from_function(188-222)src/fastmcp/decorators.py (1)
get_fastmcp_meta(29-41)
src/fastmcp/tools/function_tool.py (6)
src/fastmcp/decorators.py (1)
resolve_task_config(17-19)src/fastmcp/server/dependencies.py (2)
transform_context_annotations(131-247)without_injected_parameters(433-491)src/fastmcp/server/tasks/config.py (4)
TaskConfig(42-152)supports_tasks(91-97)from_bool(80-89)validate_function(99-152)src/fastmcp/tools/tool.py (5)
Tool(123-387)ToolResult(62-120)from_function(188-222)to_mcp_tool(159-185)run(224-234)src/fastmcp/utilities/json_schema.py (1)
compress_schema(364-401)src/fastmcp/utilities/types.py (3)
Audio(307-362)File(365-448)Image(235-304)
src/fastmcp/prompts/function_prompt.py (6)
src/fastmcp/exceptions.py (1)
PromptError(22-23)src/fastmcp/prompts/prompt.py (8)
Prompt(189-393)PromptArgument(95-104)PromptResult(107-186)from_function(229-261)render(263-274)convert_result(276-310)register_with_docket(366-370)add_to_docket(372-393)src/fastmcp/server/dependencies.py (1)
transform_context_annotations(131-247)src/fastmcp/server/tasks/config.py (4)
TaskConfig(42-152)from_bool(80-89)validate_function(99-152)supports_tasks(91-97)src/fastmcp/utilities/json_schema.py (1)
compress_schema(364-401)src/fastmcp/utilities/types.py (1)
get_cached_typeadapter(45-117)
🪛 GitHub Actions: Run static analysis
docs/servers/resources.mdx
[error] 731-731: loq: Line 731 > 727 (violation detected)
docs/servers/tools.mdx
[error] 1040-1040: loq: Line 1040 > 1019 (violation detected)
src/fastmcp/server/providers/local_provider.py
[error] 997-997: loq: Line 997 > 738 (violation detected)
src/fastmcp/tools/function_tool.py
[error] 594-594: loq: Line 594 > 500 (violation detected)
🪛 Ruff (0.14.10)
src/fastmcp/server/providers/local_provider.py
272-275: Avoid specifying long messages outside the exception class
(TRY003)
314-317: Avoid specifying long messages outside the exception class
(TRY003)
588-599: Avoid specifying long messages outside the exception class
(TRY003)
739-743: Avoid specifying long messages outside the exception class
(TRY003)
755-766: Avoid specifying long messages outside the exception class
(TRY003)
905-908: Avoid specifying long messages outside the exception class
(TRY003)
920-931: Avoid specifying long messages outside the exception class
(TRY003)
976-979: Avoid specifying long messages outside the exception class
(TRY003)
984-984: Avoid specifying long messages outside the exception class
(TRY003)
src/fastmcp/tools/function_tool.py
137-137: Avoid specifying long messages outside the exception class
(TRY003)
139-141: Avoid specifying long messages outside the exception class
(TRY003)
147-149: Avoid specifying long messages outside the exception class
(TRY003)
152-154: Avoid specifying long messages outside the exception class
(TRY003)
199-201: try-except-pass detected, consider logging the exception
(S110)
199-199: Do not catch blind exception: Exception
(BLE001)
335-338: Avoid specifying long messages outside the exception class
(TRY003)
378-378: Avoid specifying long messages outside the exception class
(TRY003)
398-401: Avoid specifying long messages outside the exception class
(TRY003)
527-530: Avoid specifying long messages outside the exception class
(TRY003)
584-584: Avoid specifying long messages outside the exception class
(TRY003)
589-589: Avoid specifying long messages outside the exception class
(TRY003)
src/fastmcp/prompts/function_prompt.py
112-115: Avoid specifying long messages outside the exception class
(TRY003)
135-135: Avoid specifying long messages outside the exception class
(TRY003)
140-140: Avoid specifying long messages outside the exception class
(TRY003)
142-142: Avoid specifying long messages outside the exception class
(TRY003)
200-202: try-except-pass detected, consider logging the exception
(S110)
200-200: Do not catch blind exception: Exception
(BLE001)
259-262: Avoid specifying long messages outside the exception class
(TRY003)
280-280: Avoid specifying long messages outside the exception class
(TRY003)
298-298: Avoid specifying long messages outside the exception class
(TRY003)
383-386: Avoid specifying long messages outside the exception class
(TRY003)
434-434: Avoid specifying long messages outside the exception class
(TRY003)
439-439: 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 with lowest-direct dependencies
- GitHub Check: Run tests: Python 3.13 on ubuntu-latest
- GitHub Check: Run tests: Python 3.10 on windows-latest
🔇 Additional comments (18)
src/fastmcp/prompts/function_prompt.py (5)
1-44: LGTM! Well-organized imports and type definitions.The imports are properly organized with TYPE_CHECKING guards for conditional imports (Docket, Execution), and the type variable
Fis appropriately bounded toCallable[..., Any].
46-68: LGTM! Clean protocol and metadata definitions.The
DecoratedPromptprotocol with@runtime_checkablecorrectly defines the contract for decorated functions, and the frozenPromptMetadataclass provides immutable metadata storage with sensible defaults.
269-298: LGTM! Robust render implementation with proper error handling.The render method correctly validates required arguments, converts string arguments to expected types, handles awaitables, and wraps errors in
PromptErrorwith logging. The flow is clear and follows defensive programming patterns.
300-333: LGTM! Clean Docket integration.The
register_with_docketandadd_to_docketmethods properly check task support before registration and handle the key parameter correctly.
419-428: Stacklevel in deprecation warning may be incorrect for all call paths.The
stacklevel=4assumes a specific call depth. Depending on howdecoratoris called (directly vianame_or_fnbeing a routine vs. through the wrapper), the stack depth varies. This could result in the warning pointing to the wrong line.Consider verifying the warning points to the user's decorator usage in both invocation patterns:
@prompt(no parentheses)@prompt()or@prompt(name="x")docs/servers/resources.mdx (1)
135-138: LGTM! Clear cross-reference for method decoration pattern.The new subsection appropriately directs users to the Tools documentation for the detailed pattern, maintaining consistency across Tools, Resources, and Prompts documentation. The guidance is concise and actionable.
docs/servers/tools.mdx (1)
119-139: LGTM! Clear and complete example for method decoration.The documentation:
- Explains why
@mcp.tooldoesn't work directly with methods (self/clsappearing as parameters)- Provides a complete, runnable example with the Calculator class
- Shows the correct pattern: decorate with standalone
@tool, then register bound method withmcp.add_tool()- Comment on line 138 clarifies the schema outcome
This follows the MDX documentation guidelines for including complete, runnable code examples.
src/fastmcp/server/providers/local_provider.py (4)
187-216: LGTM! Clean handling of decorated functions in add_tool.The method correctly:
- Checks if input is already a Tool
- Extracts
__fastmcp__metadata usingget_fastmcp_meta- Falls back to
Tool.from_function(tool)for plain functions without metadata
222-276: LGTM! Comprehensive resource handling with proper template detection.The logic correctly distinguishes between:
- Resource (no URI params and no function params)
- ResourceTemplate (URI params like
{param}or function has parameters)The error message for non-decorated functions is helpful and actionable.
768-813: Consistent decorator mode handling for resources.The implementation correctly handles both
objectmode (legacy) and the new function-mode, properly distinguishing between Resource and ResourceTemplate based on URI/function parameters. The metadata attachment follows the same pattern as tools and prompts.
904-969: LGTM! Prompt decorator follows the established pattern.The implementation is consistent with the tool decorator, including:
- Classmethod detection with helpful error
- Unbound method detection
- Object-mode vs function-mode branching
- Proper metadata attachment
src/fastmcp/tools/function_tool.py (7)
62-88: LGTM! Clean protocol and metadata definitions.The
DecoratedToolprotocol andToolMetadataclass mirror the patterns infunction_prompt.py, maintaining consistency across the codebase. TheToolMetacorrectly includes all tool-specific fields likeoutput_schema,annotations, andexclude_args.
91-114: LGTM! Well-designed schema helpers.The
_WrappedResultgeneric wrapper elegantly handles MCP's requirement that output schemas be objects. The_is_object_schemafunction correctly identifies object types including self-referencing schemas with$ref.
203-225: Clever handling of unserializable MCP types.Using
replace_typewith_UnserializableTypeto prevent schema generation for internal types (Image, Audio, File, ToolResult, etc.) is a clean approach that avoids polluting output schemas with FastMCP-specific types.
284-417: LGTM! Comprehensive from_function implementation.The method:
- Properly validates mutual exclusion between
metadataand individual params- Emits deprecation warnings for
serializerandexclude_args- Validates lambda functions require explicit names
- Normalizes and validates TaskConfig
- Validates output schemas are object types per MCP spec
465-499: LGTM! Well-defined overloads for type safety.The three overloads correctly handle:
@tool(bare decorator on function)@tool("name", ...)(name as first positional argument)@tool(name="name", ...)(keyword arguments only)This provides excellent IDE support and type checking.
569-578: Deprecation warning stacklevel consideration.Similar to the prompt decorator, the
stacklevel=4may not be correct for all call paths. Whendecoratoris called directly (line 581), the stack is different than when called throughwrapper(line 592).Verify the warning points to the user's code in both scenarios:
@tool # direct path def fn1(): ... @tool() # wrapper path def fn2(): ...
419-427: ValidationError handling is properly implemented and documented.The
run()method'sValidationErrorfromtype_adapter.validate_python()is correctly handled by the server'scall_tool()method (insrc/fastmcp/server/server.py, lines 1348-1349), which explicitly catches bothValidationErrorandPydanticValidationError, logs the exception, and re-raises it. The method's docstring also documents this behavior. No action required.
Test Failure AnalysisSummary: The static analysis job failed because 15 files exceed their configured line count limits in the Root Cause: This PR adds the entire FastMCP codebase to the repository. While all formatting, linting, and type checking passed successfully, the Suggested Solution: Run uv run loq baseline
git add loq.toml
git commit -m "Update loq baseline for initial codebase commit"This will update the Detailed AnalysisThe All other pre-commit hooks passed successfully:
The workflow logs show this is purely a file size limit issue, not a code quality problem. Related Files
The |
Test Failure AnalysisSummary: The Windows Python 3.10 test is timing out during initialization of the Root Cause: PR #2856 introduced a new The stack trace shows:
Suggested Solution:
The immediate fix would be to modify
Detailed AnalysisFailing Test# tests/server/auth/providers/test_azure.py:542
def test_prepare_scopes_for_upstream_refresh_empty_scopes(self):
"""Test behavior with empty scopes list."""
provider = AzureProvider(
client_id="test_client",
client_secret="test_secret",
tenant_id="test-tenant",
base_url="https://myserver.com",
identifier_uri="api://my-api",
required_scopes=["read"],
additional_authorize_scopes=["User.Read", "openid"],
jwt_signing_key="test-secret",
)The timeout occurs during the Stack Trace ExcerptWhy Windows Only?Windows file system behavior, particularly with SQLite in Related Files
|
|
Wondrous. Interestingly, the biggest gain here is interoperability with Python's existing decorator ecosystem. Previously, FastMCP decorators weren't safely chainable with other third-party decorators. Now they are. This actually matters for @beartype. We explicitly support FastMCP by treating decorated callables as |
Decorators (
@tool,@resource,@prompt) now return the original function unchanged instead of transforming it into a component object. This aligns FastMCP with how decorators work in Flask, FastAPI, and Typer.Why this matters:
mcp.add_tool(obj.method)Breaking change: Code that treats decorated functions as
FunctionTool/FunctionResource/FunctionPromptobjects will break. SetFASTMCP_DECORATOR_MODE=objectfor v2 behavior.Closes #2292