* pin pydantic-monty to 0.0.8
* rename tool/prompt/resource base modules to avoid decorator name shadow
* add sys.modules shims for old submodule import paths
* preserve original module paths in deprecation warnings
* clarify when sys.modules shims can be removed
* Replace vendored DI with uncalled-for
FastMCP vendored a minimal DI engine extracted from Docket (~164 lines)
with try/except fallback patterns everywhere. The `uncalled-for` package
is a clean, typed extraction of this same system, and since Docket will
also depend on it (chrisguidry/docket#353), `uncalled_for.Dependency`
becomes the single canonical base class.
This deletes the `_vendor/docket_di/` directory, replaces all the
try/except import patterns with direct `uncalled_for` imports, and
updates the `Dependency.execution` → `current_execution` ContextVar
references to match the Docket branch. The `Progress` class now
delegates to an internal impl and returns `self` from `__aenter__`
(matching Docket's pattern) so that ty's generic resolution works
without `type: ignore` suppressions.
Temporarily points pydocket at the `use-uncalled-for` branch so both
sides can be validated together in CI.
🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Re-export Dependency from fastmcp.dependencies
Internal code like azure.py should import from the fastmcp namespace
rather than reaching into uncalled_for directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Import Dependency from fastmcp namespace in tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add generic type parameters to Dependency subclasses
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Mention uncalled-for in DI docs
The DI engine now comes from uncalled-for, so the docs should credit
it alongside Docket. Also updates the Docket docs link to docket.lol.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Point docket dependency at main
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Bump uncalled-for pin to >=0.2.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix uncalled-for imports for 0.2.0 API changes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Support Shared() dependencies without docket
Enters a SharedContext at server lifetime so that Shared() dependencies
from uncalled-for resolve once and are cached across tool/resource/prompt
calls. When running with docket, the Worker already handles this; this
covers the non-docket path and direct call_tool() usage.
Also re-exports Shared from fastmcp.dependencies.
Closes#3251
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Bump docket lockfile to latest main
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Remove duplicate test classes from rebase conflict resolution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Point docket dependency at pydocket>=0.18.0 release
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Pair SharedContext __aenter__ with __aexit__ in Context lifecycle
The old `_ensure_shared_context` on the server called `__aenter__()` on a
lazy `SharedContext` but never `__aexit__()`, leaking the exit stack and
its resources. Moved the SharedContext management into Context's own
enter/exit so it's properly paired: when docket is available the lifespan
handles it, otherwise Context creates and cleans up a per-request one.
Updated Shared() tests to use Client (which runs the lifespan) rather
than calling server methods directly, since cross-request sharing
requires a lifespan.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Hoist SharedContext import to module level
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Fix ty 0.0.19 type errors
🤖 Generated with Claude Code
* Fix ruff formatting in sampling/run.py
🤖 Generated with Claude Code
https://claude.ai/code/session_01GWzbyF1vHvVeS4yJ5bhScf
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Fix ty ignore syntax in OpenAPI provider
* Fix flaky rate limiting and ping timing tests
* Assert rate limit error message in flaky test fix
* Catch only ToolError in rate limiting test
* Fix non-serializable state lost between middleware and tools
Inherit _request_state dict from parent Context in __aenter__ so
middleware and tool contexts share the same in-memory state.
Closes#3228
* chore: Update SDK documentation
---------
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
* Update repository references from jlowin/fastmcp to prefecthq/fastmcp
* Retrigger CI after repo transfer
* chore: Update SDK documentation
* Only run deep triage on bug issues for jlowin
---------
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
* 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 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
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.
* MCP → SDK (vocab change only)
* WIP: Sampling API with SamplingResult[T] and result_type
* SEP-1577: Sampling with tools
- Add tools and result_type parameters to ctx.sample()
- Update OpenAI handler for tool content types
- Client advertises sampling.tools capability by default
- Collect tool results into single message with list content
* Fix tool result content handling in OpenAI handler
* Remove @sampling_tool decorator - pass functions directly to sample()
Functions passed to ctx.sample(tools=[...]) are now auto-converted
via SamplingTool.from_function(). Users can still use that method
directly for custom name/description overrides.
* Remove auto-conversion of MCP tools to sampling tools
Users want MCP tools passed to ctx.sample() to go through the full MCP
machinery (middleware, native responses) rather than being auto-converted
to direct function calls. Now only SamplingTool and plain callables are
accepted - passing a FastMCP Tool raises a clear TypeError.
Also bumps mcp dependency to >=1.24.0 for required sampling features.
* Refactor sampling API: replace sample_iter() with sample_step()
Replace the mutable SampleRun/sample_iter() pattern with a simpler stateless
sample_step() function. sample_step() makes a single LLM call and returns a
SampleStep with the response and history. sample() now loops sample_step()
internally.
Key changes:
- Add sample_step() for fine-grained control over the sampling loop
- Remove SampleRun class and sample_iter() method
- Structured output uses tool description only (no prompt modification)
- execute_tools parameter controls automatic vs manual tool execution
* Address CodeRabbit nitpicks
* Address CodeRabbit review feedback for sampling tools
- Fix temperature=0.0 being dropped due to falsy evaluation
- Add ToolChoice.name support for forcing specific tools
- Replace assert statements with explicit RuntimeError checks
- Add mask_error_details parameter to sample()/sample_step() with ToolError escape hatch
- Fix hasattr patterns with proper isinstance checks
- Document mask_error_details and add OpenAI prerequisites to docs
* Address additional CodeRabbit review feedback
- Catch ValidationError specifically instead of bare Exception
- Update result_type docs to mention dataclasses and basic types
- Raise ValueError for unknown tool_choice modes
- Validate sampling_handler_behavior to catch typos
- Remove ToolChoice.name handling (not part of MCP spec)
- Validate tool_choice string in sample_step()
* Review fixes for sampling tools PR
- Remove internal functions from sampling __init__.py exports
- Remove fragile is_text property, use not is_tool_use instead
- Inline call_client into context.py, remove from run.py
- Fix SamplingMessage docs to use TextContent
- Handle result.text being None in doc examples
- Simplify client sampling docs to recommend OpenAISamplingHandler
- Add sampling_capabilities override documentation
- Raise iteration limit from 50 to 100
- Remove _parse_model_preferences duplication
- Use AsyncOpenAI in OpenAISamplingHandler
- Fix tool_choice docstring
* Fix OpenAI handler tests to use AsyncOpenAI
* Address remaining CodeRabbit review comments
- Fix message ordering in OpenAI handler: tool results now correctly
follow assistant message with tool_calls
- sample_step() now always includes assistant message in history
- Raise ValueError on JSON parse errors instead of silent {}
- Add has_sampling capability check when behavior is None
- Raise RuntimeError when structured output receives text response
- Wrap primitive result_type schemas in object wrapper
- Fix docs example using invalid SamplingMessage construction
- Add comprehensive client_sampling_test.py example
* Add return type annotation to OpenAISamplingHandler.__init__
* Use explicit 'is not None' check for sampling_capabilities defaulting
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Bill Easton <strawgate@users.noreply.github.com>
* feat: make ResourceContent the canonical internal type for resources
Add Resource._read() private method that always returns ResourceContent,
maintaining backwards compatibility for custom resources returning str/bytes
from read(). Includes deprecation warning when str/bytes is returned.
* fix: address review feedback for ResourceContent
- Remove ResourceContent from root exports (import from fastmcp.resources)
- Fix FunctionResource.read() return type to str | bytes | ResourceContent
- Decode base64 blobs in proxy when receiving from remote servers
- Preserve meta in ProxyResource cached content
* fix: add empty result guards in proxy resource reads
* feat: handle error from the initialize middleware
In some situation, the initialize middleware can check the status of the
server and decide to raise an error.
Example use case: in a FastMCPProxy, an initialization middleware
overrides the on_initialize method and connect to the underlying proxied
client. When client respond with error, I want to pass this error to the
client.
* docs update
* test: use McpError assertions now that exception propagation is fixed
- Update tests to catch McpError specifically instead of generic Exception
- Remove commented-out code in low_level.py
---------
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
* Implement MCP background tasks (SEP-1686) using Docket
Adds support for background task execution via the MCP task protocol,
powered by Docket for task queue management.
- Tools, resources, and prompts can be marked with `task=True` to run async
- Progress dependency for tracking task progress
- CurrentDocket and CurrentWorker dependencies for advanced use cases
- Client API with `.call_tool(..., task=True)` returns task handles
- Task status notifications via subscriptions
- CLI worker command for distributed task processing
Configuration via environment:
- FASTMCP_ENABLE_DOCKET=true
- FASTMCP_ENABLE_TASKS=true
- FASTMCP_DOCKET_URL=redis://... (or memory:// for single-process)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix tasks example import (TaskStatusResponse → GetTaskResult)
The example was using a non-existent TaskStatusResponse type.
Updated to use mcp.types.GetTaskResult which is what the
on_status_change callback actually receives.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix env var name in Docket error messages
The error messages referenced FASTMCP_EXPERIMENTAL_ENABLE_DOCKET but the
actual setting is FASTMCP_ENABLE_DOCKET.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove deprecated code re-added from pre-#2329 branch
- Remove ExtendedEnvSettingsSource (FASTMCP_SERVER_ prefix support)
- Remove dependencies parameter from FastMCP.__init__
* Replace fakeredis git pin with PyPI release
* Remove redundant fakeredis dev dep (pulled via pydocket)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
- Bump mcp SDK to >=1.23.1
- Add `client_secret_basic` authentication support (SDK PR #1334)
- TokenHandler now wraps SDK's handle() to transform `unauthorized_client`
to `invalid_client` on 401 responses per OAuth 2.1 spec
- Update `sample()` return type to use SDK's SamplingMessageContentBlock
- Update test expectations for new SDK fields (`task`, `_meta`)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Wrap responder.respond() to capture the InitializeResult before it's
sent to the write stream, then return it through the middleware chain.
This allows middleware (e.g., logging) to access the server's initialize
response, not just the client's request.
* Add meta to ToolResult
* add this at the client level and test the full integration
* add example
* slipped through linting somehow
---------
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
* Add compatibility tools contrib module
Implements four standalone tools that expose resources and prompts
as callable tools for clients that only support the tools capability.
Features:
- list_resources: List all available resources
- get_resource: Read a resource by URI
- list_prompts: List all available prompts
- get_prompt: Get a prompt with optional arguments
The tools use Context to access the server instance and can be easily
added to any FastMCP server using the add_compatibility_tools helper
or by adding individual tool instances directly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: William Easton <strawgate@users.noreply.github.com>
* Simplify compatibility tools to return raw MCP protocol objects
Return raw MCP protocol objects (ListResourcesResult, ReadResourceResult,
ListPromptsResult, GetPromptResult) instead of custom dictionaries. This
makes the tools simpler and more predictable by directly exposing what
the client methods return.
Co-authored-by: William Easton <strawgate@users.noreply.github.com>
* Add tool injection middleware
* cleanup contrib module
* More clean-up
* Clean up tool injection middleware.
* Update src/fastmcp/server/middleware/tool_injection.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Add tool injection docs
* Small cleanup of prompt middleware
* PR Feedback
* Fix tool injection tests
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: William Easton <strawgate@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>