pydocket 0.16.3 fixes a race condition in `_worker_loop` where cancellation
arriving between `_worker_done.clear()` and the try block would cause
`_worker_done.set()` to never run, blocking `Worker.__aexit__` forever.
Also fixes:
- Simplified `_docket_lifespan` cleanup (timeout wrapper no longer needed)
- Fixed `nested_server` test fixture to use graceful uvicorn shutdown
- Fixed uv transport tests to use local fastmcp in dev mode
Closes#2679🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a test that verifies task cancellation actually interrupts running
coroutines (they receive CancelledError) rather than just marking the task
as cancelled in Redis while the coroutine continues to completion.
This requires pydocket >= 0.16.2 which added best-effort cancellation via
Redis pub/sub signaling to workers.
Closes#2679🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Move OpenAPI to providers/openapi/ submodule
Migrates the OpenAPI implementation to the provider pattern:
- Creates src/fastmcp/server/providers/openapi/ submodule with provider.py,
components.py, and routing.py
- Converts server/openapi/ to deprecated re-export stubs
- FastMCPOpenAPI remains as deprecated wrapper that uses OpenAPIProvider
- Updates experimental/server/openapi to import from new canonical location
* Update tests and FastMCP methods to use OpenAPIProvider
- Update FastMCP.from_openapi() and from_fastapi() to use OpenAPIProvider
directly, returning FastMCP instead of deprecated FastMCPOpenAPI
- Move tests from tests/server/openapi/ to tests/server/providers/openapi/
- Update all test imports to use new canonical location
- Add tests/deprecated/openapi/ for backward compatibility testing
- Update tests/client/test_openapi.py to use new imports
* Fix deprecation warning tests and address CodeRabbit feedback
- Use importlib.reload() to ensure deprecation warnings fire in tests
- Change logger.error to logger.exception for better stack traces
* Refactor FastMCPProxy into ProxyProvider
Move proxy functionality from custom manager classes to the Provider pattern:
- Create ProxyProvider that implements the Provider interface
- Move all proxy code to src/fastmcp/server/providers/proxy.py
- Keep FastMCPProxy as a convenience wrapper using ProxyProvider
- Add deprecation warning when importing from old location
- Convert handler classmethods to module-level functions
- Remove redundant get_* methods (base class defaults work)
* Remove unused Components class, simplify TaskComponents()
* Add poll_interval to TaskConfig
Allow users to configure polling interval per component via
TaskConfig(poll_interval=timedelta(...)). Default is 5 seconds.
* Update snapshots for poll_interval field
* Add version badge to poll_interval docs
* Add defensive handling for Redis data and align default poll intervals
* Replace type: ignore[attr-defined] with isinstance assertions in tests
* Fix isinstance assertions in failing tests
- Fix enum test to check for ResponseEnum instead of str
- Fix binary resource test to check for BlobResourceContents instead of TextResourceContents
- Fix Root type tests to check attributes directly instead of isinstance checks
* Fix type errors without using type: ignore
- Remove execution methods from TransformingProvider (only handles transformations)
- Add execution methods to base Provider class with default implementations
- Fix type narrowing in tests using cast() instead of type: ignore
- Fix PromptResult type handling in prompt render tests
- Fix type narrowing in middleware test for arguments and structured_content
* Add supports_tasks() method to replace string mode checks
Consolidates task config mode checks into a readable method on TaskConfig.
Instead of `task_config.mode == "forbidden"` or `task_config.mode != "forbidden"`,
code now uses `task_config.supports_tasks()` for clearer intent.
Updated 20 instances across the codebase and added type assertions in tests
to resolve type checker warnings.
* Update test to match new error message
* Add test_custom_subclass_tasks.py
* Refactor provider execution: delegate to middleware via wrapper components
- Remove execution methods (call_tool, read_resource, etc.) from Provider base
- Add FastMCPProvider* wrapper classes that delegate to child server middleware
- Move task routing to Tool._run() using contextvars (_task_metadata, _tool_call_key)
- Add convert_to_tool_result(result, output_schema) utility for Docket results
- Add convert_to_prompt_result() utility for prompt task results
- Pass namespaced key via add_to_docket(name=) for mounted tool lookup
* Standardize add_to_docket() with fn_key/task_key parameters
All components now use explicit fn_key (function lookup) and task_key
(result storage) parameters instead of relying on implicit key handling.
This fixes mounted component task execution where the MCP-visible key
differs from the Docket-registered function name.
* Add middleware chain tests for three-level mount hierarchy
Tests verify middleware runs at parent, child, and grandchild levels
for tools, resources, prompts, and resource templates.
* WIP: Provider refactor - unified submit_to_docket, template _read() in progress
Work in progress on refactoring execution to use component _read()/_run()/_render() methods.
Template background tasks not yet working - needs fix for Docket key lookup.
* Fix conversion functions to take full component for attribute access
Pass Tool/Prompt/Resource/Template to conversion functions instead of
individual attributes, ensuring access to serializer, output_schema,
mime_type, etc. Also fixes mixed-content output schema validation.
* Refactor: unified convert_result() methods and check_background_task helper
- Add convert_result() instance methods to all component types (Tool, Prompt, Resource, ResourceTemplate)
- Extract duplicated task routing logic into check_background_task() helper
- Fix type annotations on FastMCPProviderResource.read() and FastMCPProviderPrompt.render()
- Update protocol.py to use component.convert_result() uniformly
* Update tests to use namespace= instead of deprecated prefix= parameter
* Use CreateTaskResult for background task creation
Move result conversion logic to components (convert_result methods) and
return proper CreateTaskResult SDK type from task handlers. Consolidates
MCP protocol handler overrides into server.py with documentation.
* Address CodeRabbit nitpicks
- Add type annotation for resource parameter in handle_resource_as_task
- Move RootModel import to module level in client.py
* Document intentionally unused task_meta parameters
Prefix with underscore to suppress lint warnings. Client TTL will be
configurable via TaskConfig in the future; keeping parameter for API stability.
Refactors docket/background task support to be encapsulated within each
component rather than requiring external coordination:
- Move task_config to FastMCPComponent base class (default: forbidden)
- Add register_with_docket(docket) method that components use to register
themselves, checking task_config internally
- Add add_to_docket() method that handles component-specific calling
conventions (splatted kwargs vs positional dict)
- Simplify server registration to just call component.register_with_docket()
- Update task handlers to use component.add_to_docket()
This enables custom Tool/Resource/Prompt subclasses to support background
tasks by setting task_config and optionally overriding the docket methods.
* Refactor MountedProvider into FastMCPProvider + TransformingProvider
Split the monolithic MountedProvider into two focused components:
- FastMCPProvider: wraps a FastMCP server as a provider
- TransformingProvider: applies namespace/rename transformations to any provider
Add with_transforms() method to Provider base class for fluent API.
Rename mount() prefix parameter to namespace (deprecate prefix).
* Reuse compiled URI_PATTERN in deprecated import_server
* Simplify .key as computed property
Keep .key as the standard lookup interface for all components but
implement it as a computed property instead of a stored field.
- Remove _key private attribute and custom model_copy(key=...)
- .key returns .name for tools/prompts, str(.uri) for resources,
.uri_template for templates
- Use .key universally for component lookups in managers
- MountedProvider: prefix URIs only for resources/templates, not names
- Docket registration: tools/prompts use .key, resources use .name
(matches fn.__name__ for function lookup)
* Simplify .key as computed property
Keep .key as the standard lookup interface for all components but
implement it as a computed property instead of a stored field.
- Remove _key private attribute and custom model_copy(key=...)
- .key returns .name for tools/prompts, str(.uri) for resources,
.uri_template for templates
- Use .key universally for component lookups and Docket registration
- MountedProvider: prefix URIs only for resources/templates, not names
- Add _backend_* fields to proxy classes to preserve original identifiers
for backend calls when prefixed via import_server
* Standardize .key as computed property
- .key is now a read-only computed property:
- Tools/Prompts: returns .name
- Resources: returns str(.uri)
- Templates: returns .uri_template
- Prefixing uses model_copy(update={...}) to change underlying field
- Resource/template names are NOT prefixed, only URIs
- Move import_server tests to tests/deprecated/
When a tool was registered with a custom name different from its function
name, task execution would fail because Docket registered the function by
its `__name__` but the handler looked it up by the tool's configured name.
This switches to using Docket's new `names=` parameter (pydocket 0.16.0)
to register functions with their proper lookup keys, and removes the
`_create_named_fn_wrapper` hack that was used for mounted servers.
Closes#2642🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a dependency raises ToolError or other FastMCPError subclasses, they
were getting wrapped in RuntimeError with a generic "Failed to resolve
dependency" message. This made it hard to use ToolError for validation
in dependencies.
Now FastMCPError subclasses propagate unchanged, matching the pattern
used elsewhere in the codebase.
Closes#2633🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Simplify Provider interface and consolidate docket registration
- Remove get_http_routes from Provider (unused)
- Remove ProviderLifespanConfig, _base_lifespan, _register_tasks
- Remove supports_tasks flag from Provider.__init__
- Consolidate all docket registration in server._docket_lifespan()
- Simplify lifespan() to take no parameters
- Move MountedProvider to separate module
* Fix control flow in ComponentService resource methods
* Move providers to server/providers
* Ensure MountedProvider get_* methods go through middleware
* Fix get_resource to only return concrete resources
Reverts template-checking in get_resource that broke task execution.
Tasks need access to the original template, not instantiated resources.
* Move prefix utilities into mounted.py, deprecate import_server
- Add resource prefix functions (add/remove/has_resource_prefix) to mounted.py
- Deprecate import_server with warning to use mount() instead
- Add tool_names uniqueness validation in MountedProvider
* Fix provider iteration order and remove dead _is_mounted flag
- Remove unused _is_mounted flag (MountedProvider.lifespan() calls _lifespan
not _lifespan_manager, so the flag was never checked)
- Fix provider iteration: change reversed() to forward order in execution
methods (_call_tool, _read_resource_middleware, _get_prompt_content_middleware)
to match documented "first non-None wins" semantics
- Fix ComponentService to handle prefix-less mounted servers using
_strip_tool_prefix()/_strip_resource_prefix() methods
- Update conflict resolution tests to expect first-registered provider wins
- Add regression tests for Docket behavior and prefix-less ComponentService
* Add TaskComponents type and exception handling for provider task registration
- Create TaskComponents dataclass with FunctionTool/FunctionResource/etc. types
for proper typing of get_tasks() return value
- Add try/except wrapper around provider.get_tasks() in _docket_lifespan for
consistent error handling (warn + continue or raise based on settings)
- Remove type: ignore comments from server.py task registration loop