Skip to content

Conversation

@jlowin
Copy link
Owner

@jlowin jlowin commented Dec 7, 2025

Exposes the full MCP task execution modes via TaskConfig instead of just task=True/False (bool still works though!)

The primary user-facing impact of this change is the ability to create MCP components (e.g. tools) that require background task execution as opposed to whatever the client wants.

from fastmcp import FastMCP, TaskConfig

mcp = FastMCP("MyServer")

@mcp.tool(task=TaskConfig(mode="optional"))   # supports both sync and background
async def flexible(): ...

@mcp.tool(task=TaskConfig(mode="required"))   # error if client doesn't request task  
async def must_be_background(): ...

@mcp.tool(task=TaskConfig(mode="forbidden"))  # error if client requests task
async def sync_only(): ...

Boolean shortcuts still work: task=Truemode="optional", task=Falsemode="forbidden".

Key changes:

  • New TaskConfig dataclass in src/fastmcp/server/tasks/config.py
  • Model classes use task_config: TaskConfig field (decorators still use task= for ergonomics)
  • Server enforces modes: returns -32601 for required without task or forbidden with task
  • TaskConfig.validate_function() centralizes the async function check

Internally, task details are stored on these new TaskConfig objects, anticipating both future MCP-task-specific config as well as the ability to pass Docket-specific config without accessing function dependencies.

cc @chrisguidry

Expose the full MCP task execution modes (forbidden/optional/required)
via TaskConfig instead of just boolean task=True/False.
@marvin-context-protocol marvin-context-protocol bot added enhancement Improvement to existing functionality. For issues and smaller PR improvements. server Related to FastMCP server implementation or server-side functionality. documentation Updates to docs, examples, or guides. Primary change is documentation-related. labels Dec 7, 2025
@jlowin jlowin requested a review from chrisguidry December 7, 2025 02:03
@jlowin jlowin added this to the MCP 11/25/25 milestone Dec 7, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 7, 2025

Walkthrough

This PR introduces TaskConfig, a new configuration structure for managing background task execution across the FastMCP framework (implementing SEP-1686). The change replaces boolean task fields with a structured task_config field throughout the codebase, including in tools, resources, prompts, and templates. TaskConfig defines three execution modes: "forbidden", "optional", and "required". Public API signatures are updated to accept task parameters as bool | TaskConfig | None. Task handling logic is refactored to inspect task_config.mode instead of boolean checks. Documentation is expanded with examples and guidance on server-wide defaults and mode usage. A new module src/fastmcp/server/tasks/config.py provides the TaskConfig and TaskMode implementations.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.97% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The PR description lacks required sections from the template, including issue reference, self-review confirmation, testing details, and documentation updates. Add the following to the PR description: issue number link, confirmation of manual testing and test additions, documentation update verification, self-review and readiness checkboxes per the template.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly summarizes the main change: introducing TaskConfig to handle SEP-1686 execution modes, replacing the previous boolean task flag approach.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-task-config-modes

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.

Copy link
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: 0

🧹 Nitpick comments (3)
src/fastmcp/server/tasks/config.py (1)

78-83: Consider handling classmethod in unwrap logic.

The unwrap logic handles staticmethod but not classmethod. If someone decorates a classmethod with task execution, the iscoroutinefunction check may fail.

         # Unwrap callable classes and staticmethods
         fn_to_check = fn
         if not inspect.isroutine(fn) and callable(fn):
             fn_to_check = fn.__call__
         if isinstance(fn_to_check, staticmethod):
             fn_to_check = fn_to_check.__func__
+        if isinstance(fn_to_check, classmethod):
+            fn_to_check = fn_to_check.__func__
docs/servers/tasks.mdx (1)

90-93: Consider renaming example function for clarity.

The function sync_only is declared as async def, which may confuse readers. Consider renaming to no_background or immediate_only to better convey that it executes without background task support rather than implying it's a synchronous function.

 # No task support (default when task=False or omitted)
 @mcp.tool(task=TaskConfig(mode="forbidden"))
-async def sync_only() -> str:
+async def no_background() -> str:
     return "Never runs as background task"
src/fastmcp/server/server.py (1)

596-622: Mode enforcement logic is correct but duplicated.

The mode enforcement pattern is correctly implemented:

  1. mode="required" + no task metadata → error
  2. mode="forbidden" + task metadata → error
  3. Task metadata present + mode allows → route to background handler

However, this same pattern is repeated in three handlers (resources, prompts, tools). Consider extracting to a helper function for maintainability.

Example helper extraction:

def _check_task_mode(
    mode: str,
    task_meta: Any,
    component_type: str,
    name: str,
) -> None:
    """Validate task mode constraints, raising McpError on violation."""
    if mode == "required" and not task_meta:
        raise McpError(
            ErrorData(
                code=METHOD_NOT_FOUND,
                message=f"{component_type} '{name}' requires task-augmented execution",
            )
        )
    if mode == "forbidden" and task_meta:
        raise McpError(
            ErrorData(
                code=METHOD_NOT_FOUND,
                message=f"{component_type} '{name}' does not support task-augmented execution",
            )
        )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8771f29 and a231ea4.

⛔ Files ignored due to path filters (9)
  • tests/client/tasks/test_task_result_caching.py is excluded by none and included by none
  • tests/server/tasks/test_server_tasks_parameter.py is excluded by none and included by none
  • tests/server/tasks/test_sync_function_task_disabled.py is excluded by none and included by none
  • tests/server/tasks/test_task_config_modes.py is excluded by none and included by none
  • tests/server/tasks/test_task_prompts.py is excluded by none and included by none
  • tests/server/tasks/test_task_resources.py is excluded by none and included by none
  • tests/server/tasks/test_task_tools.py is excluded by none and included by none
  • tests/server/test_tool_annotations.py is excluded by none and included by none
  • tests/tools/test_tool.py is excluded by none and included by none
📒 Files selected for processing (10)
  • docs/servers/tasks.mdx (2 hunks)
  • src/fastmcp/__init__.py (2 hunks)
  • src/fastmcp/prompts/prompt.py (6 hunks)
  • src/fastmcp/resources/resource.py (5 hunks)
  • src/fastmcp/resources/template.py (7 hunks)
  • src/fastmcp/server/server.py (16 hunks)
  • src/fastmcp/server/tasks/__init__.py (2 hunks)
  • src/fastmcp/server/tasks/config.py (1 hunks)
  • src/fastmcp/server/tasks/converters.py (1 hunks)
  • src/fastmcp/tools/tool.py (7 hunks)
🧰 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/tasks.mdx
src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.py: Python source code must use Python ≥3.10 with full type annotations
Never use bare except - be specific with exception types
Prioritize readable, understandable code - clarity over cleverness; avoid obfuscated or confusing patterns even if shorter
Follow existing patterns and maintain consistency in code organization and style

Files:

  • src/fastmcp/server/tasks/config.py
  • src/fastmcp/server/tasks/__init__.py
  • src/fastmcp/server/tasks/converters.py
  • src/fastmcp/__init__.py
  • src/fastmcp/resources/resource.py
  • src/fastmcp/tools/tool.py
  • src/fastmcp/server/server.py
  • src/fastmcp/resources/template.py
  • src/fastmcp/prompts/prompt.py
🧠 Learnings (1)
📚 Learning: 2025-12-04T00:17:41.238Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T00:17:41.238Z
Learning: Applies to tests/**/*.py : Pass FastMCP servers directly to clients for testing using in-memory transport; only use HTTP transport when explicitly testing network features

Applied to files:

  • src/fastmcp/__init__.py
🧬 Code graph analysis (7)
src/fastmcp/server/tasks/__init__.py (1)
src/fastmcp/server/tasks/config.py (1)
  • TaskConfig (19-89)
src/fastmcp/server/tasks/converters.py (1)
src/fastmcp/tools/tool.py (2)
  • ToolResult (74-120)
  • _convert_to_content (611-637)
src/fastmcp/__init__.py (2)
src/fastmcp/server/context.py (1)
  • fastmcp (152-157)
src/fastmcp/server/tasks/config.py (1)
  • TaskConfig (19-89)
src/fastmcp/resources/resource.py (2)
src/fastmcp/server/tasks/config.py (3)
  • TaskConfig (19-89)
  • from_bool (51-60)
  • validate_function (62-89)
src/fastmcp/utilities/types.py (1)
  • get_fn_name (34-35)
src/fastmcp/tools/tool.py (1)
src/fastmcp/server/tasks/config.py (3)
  • TaskConfig (19-89)
  • from_bool (51-60)
  • validate_function (62-89)
src/fastmcp/resources/template.py (1)
src/fastmcp/server/tasks/config.py (3)
  • TaskConfig (19-89)
  • from_bool (51-60)
  • validate_function (62-89)
src/fastmcp/prompts/prompt.py (1)
src/fastmcp/server/tasks/config.py (3)
  • TaskConfig (19-89)
  • from_bool (51-60)
  • validate_function (62-89)
🪛 Ruff (0.14.7)
src/fastmcp/server/tasks/config.py

86-89: Avoid specifying long messages outside the exception class

(TRY003)

src/fastmcp/tools/tool.py

333-333: 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). (3)
  • GitHub Check: Run tests: Python 3.10 on windows-latest
  • GitHub Check: Run tests: Python 3.10 on ubuntu-latest
  • GitHub Check: Run tests with lowest-direct dependencies
🔇 Additional comments (19)
src/fastmcp/server/tasks/converters.py (1)

36-38: LGTM!

The in-function import with the documented rationale is an appropriate solution for breaking the circular import chain. The comment clearly explains the dependency cycle.

src/fastmcp/server/tasks/config.py (1)

18-48: LGTM!

The TaskConfig dataclass is well-designed with clear mode semantics and comprehensive docstring. The three execution modes align with SEP-1686 specification.

src/fastmcp/__init__.py (1)

17-17: LGTM!

TaskConfig is appropriately added to the public API, following the existing import/export pattern for FastMCP and Context.

Also applies to: 35-35

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

6-6: LGTM!

Both TaskConfig and TaskMode are correctly re-exported, enabling the import path shown in the docstring examples.

Also applies to: 30-31

docs/servers/tasks.mdx (1)

64-98: LGTM!

The Execution Modes section is well-structured with a clear behavior matrix table and practical code examples. The boolean shortcut mappings are documented accurately.

src/fastmcp/prompts/prompt.py (2)

203-210: LGTM!

The normalization logic correctly converts the task parameter to TaskConfig and validates the function. The default mode of "forbidden" aligns with the PR's backward-compatible design.


162-165: LGTM!

Using default_factory correctly prevents shared state between FunctionPrompt instances.

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

273-276: LGTM on TaskConfig field definition.

The task_config field is correctly defined with a default_factory for the TaskConfig(mode="forbidden") default, and the type annotation with Annotated and Field follows existing patterns in the codebase.


293-296: LGTM on MCP tool conversion logic.

The to_mcp_tool method correctly checks both task_config.mode != "forbidden" and "execution" not in overrides before setting ToolExecution(taskSupport=...). This ensures explicit overrides take precedence and forbidden mode doesn't advertise task support.


335-342: LGTM on TaskConfig normalization and validation.

The normalization logic correctly handles all three input cases (None, bool, TaskConfig) and validates the function compatibility afterward. The flow ensures task_config is always a properly validated TaskConfig instance before construction.

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

235-238: LGTM on TaskConfig field in FunctionResourceTemplate.

The field definition is consistent with FunctionTool.task_config - same type annotation, default factory, and description pattern.


375-382: Good: Validation happens before function unwrapping.

The task_config.validate_function(fn, func_name) call correctly validates the original function at line 382 before the function unwrapping logic at lines 384-389. This ensures async validation checks the actual function, not the unwrapped __call__ method.


254-257: Verify TaskConfig propagation to created Resource.

When create_resource calls Resource.from_function, it passes task=self.task_config. This correctly propagates the template's task configuration to the dynamically created resource.

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

174-177: LGTM on TaskConfig field in FunctionResource.

Consistent with the pattern established in FunctionTool and FunctionResourceTemplate.


199-208: LGTM on normalization and validation logic.

The logic correctly:

  1. Derives func_name early (line 199) for use in validation error messages
  2. Normalizes task to task_config (lines 201-207)
  3. Validates before wrapping (line 208 before line 211)
src/fastmcp/server/server.py (4)

408-436: LGTM on Docket registration filtering.

The registration now correctly filters components by task_config.mode != "forbidden" instead of a boolean flag. This ensures only components that support task execution are registered with Docket.


1826-1829: Type annotation for supports_task is correct.

The variable supports_task: bool | TaskConfig correctly reflects that the value can be either a boolean (from self._support_tasks_by_default) or a TaskConfig (from the task parameter). This is then passed to Tool.from_function which handles both types via normalization.


1377-1405: LGTM on tool call handler mode enforcement.

The mode enforcement logic for tools follows the same correct pattern as resources and prompts. The handler appropriately checks mode constraints before routing to either background task execution or synchronous execution.


682-713: LGTM on prompt handler mode enforcement.

The mode enforcement for prompts is consistent with the resource and tool handlers. The result is correctly wrapped in mcp.types.ServerResult before returning.

Copy link
Collaborator

@chrisguidry chrisguidry left a comment

Choose a reason for hiding this comment

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

Love it!

@chrisguidry chrisguidry merged commit 61108a0 into main Dec 8, 2025
12 checks passed
@chrisguidry chrisguidry deleted the add-task-config-modes branch December 8, 2025 14:42
@He-Pin
Copy link

He-Pin commented Dec 8, 2025

Cool

@olwethu-web
Copy link

Bravo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Updates to docs, examples, or guides. Primary change is documentation-related. enhancement Improvement to existing functionality. For issues and smaller PR improvements. server Related to FastMCP server implementation or server-side functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants