Commit graph

2,649 commits

Author SHA1 Message Date
Jeremiah Lowin
cb9fc0ca58 Add release notes for v2.14.2 and v2.14.3 2026-01-12 16:52:51 -05:00
Jeremiah Lowin
e6005703e7
Fix HTTP transport timeout defaulting to 5 seconds (#2848) v2.14.3
Fixes #2842, fixes #2845
2026-01-12 12:18:59 -05:00
Chris Guidry
9e86dbcabb
Merge pull request #2843 from jlowin/debug-task-lifecycle
Fix ContextVar propagation for ASGI-mounted servers with tasks
2026-01-12 10:38:44 -05:00
Chris Guidry
964b23b071
Merge branch 'release/2.x' into debug-task-lifecycle 2026-01-12 10:32:57 -05:00
Chris Guidry
c127dd979f Remove debug logging, keep minimal ContextVar fix
Removes all the verbose debug logging added during diagnosis while
preserving the essential fix: Context.__aenter__ sets _current_docket
and _current_worker from server instance attributes. This ensures
ContextVars work in ASGI environments where lifespan and request
handlers run in sibling async contexts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 10:21:04 -05:00
Chris Guidry
7b24bd58c8 Make all task handlers consistent with debug logging
All three handlers (tool, prompt, resource) now have identical patterns:
- Debug logging for docket access, Redis writes, docket.add, subscriptions
- Try/except with traceback logging around Redis and docket operations
- Consistent error messages with instance_id

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 10:00:42 -05:00
Chris Guidry
687889c598 Simplify ContextVar management - trust Context to set them at request time
Remove redundant ContextVar handling:
- _lifespan_manager no longer re-sets ContextVars in early-return branch
- Handler fallback logic removed (no more `if docket is None: docket = server._docket`)

The authoritative place for request-context ContextVars is now Context.__aenter__,
which sets _current_docket and _current_worker from server instance attributes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 09:59:11 -05:00
Jeremiah Lowin
df5765cef3
Use pip instead of uv pip in upgrade instructions (#2841) 2026-01-10 18:15:28 -05:00
Jeremiah Lowin
7628c4380f
Add CLI update notifications (#2839) 2026-01-10 18:11:40 -05:00
Chris Guidry
5cea6ba575 Bump pydocket to >=0.16.6 for py-key-value Redis username workaround
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 17:10:53 -05:00
Chris Guidry
6824d56aec Bump pydocket to >=0.16.5 for Redis ACL fix
pydocket 0.16.5 fixes an issue where worker_group_name was passed as
a KEY instead of ARGV in Lua scripts, causing ACL failures when Redis
users are restricted to key patterns.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 15:06:02 -05:00
Chris Guidry
c72b5dd7f0 Add detailed logging around docket.add() and subscription tasks
Tracing where the Redis ACL error occurs - the initial Redis writes
succeed but error happens somewhere after.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 13:37:09 -05:00
Chris Guidry
726976a99f Add verbose Redis error logging with full traceback
When Redis operations fail, log the full traceback to help diagnose
ACL and permission issues in production environments.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 13:28:52 -05:00
Chris Guidry
6e8c60b65e Add verbose logging to Context for debugging Lambda ContextVar issue
Adds detailed logging to Context.__aenter__ and __aexit__ to track:
- When Context is entered/exited
- Values of server._docket and server._worker
- ContextVar values before and after setting
- Token values for debugging reset issues

This will help diagnose why ContextVars might not propagate in Lambda.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 13:05:57 -05:00
Chris Guidry
b32f7f5f99 Set docket/worker ContextVars at request time in Context
Instead of relying on ContextVar propagation from lifespan (which fails
in Lambda), set _current_docket and _current_worker when entering a
Context for each request. This ensures user dependencies like
CurrentDocket() and CurrentWorker() work in all environments.

The values come from server._docket and server._worker which are always
available after lifespan initialization.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 13:03:52 -05:00
Chris Guidry
4c169a80de Add server._docket fallback for Lambda ContextVar issue
ContextVars set during lifespan don't propagate to request handlers
in Lambda (works fine locally). As a workaround, fall back to using
server._docket when the ContextVar returns None.

This is a Lambda-specific issue - possibly related to how Lambda Web
Adapter or Lambda's asyncio runtime handles context propagation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 13:02:32 -05:00
Chris Guidry
fc4d0114db Fix ContextVar propagation for nested ASGI lifespan calls
When FastMCP runs with uvicorn, the lifespan is entered twice:
1. FastMCP's outer context (during http_app setup)
2. Starlette's ASGI lifespan (which request handlers inherit from)

The second call was skipping ContextVar setup because _lifespan_result_set
was already True. This caused _current_docket.get() to return None in
request handlers even though server._docket was correctly set.

Fix: Always set ContextVars when entering _lifespan_manager, using the
already-initialized values from self._docket and self._worker.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 11:47:01 -05:00
Chris Guidry
8e927fbfed Add debug logging for task lifecycle 2026-01-09 11:27:15 -05:00
Chris Guidry
3df88260eb
Prefix Redis keys with docket name for ACL isolation (#2812)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 19:04:15 -05:00
Jeremiah Lowin
ae255277cc
Backport OAuth token storage TTL fix to release/2.x (#2798)
Fixes #2670, #2682
2026-01-06 17:46:58 -05:00
Jeremiah Lowin
e3a4e596fc
Add debug logging for OAuth token expiry diagnostics (#2789) 2025-12-31 13:37:53 -05:00
Adam Azzam
99832a9faf
Merge pull request #2787 from jlowin/confernece-to-2.x-branch v2.14.2
conference to 2.x branch
2025-12-30 22:09:15 -06:00
Adam Azzam
7fd365c868 Update docs.json 2025-12-30 21:41:01 -05:00
Jeremiah Lowin
9cf9aa9b37
Lazy import DiskStore to avoid sqlite3 dependency on import (#2785) 2025-12-30 19:20:10 -05:00
Jeremiah Lowin
1b637522d1
Fix base_url fallback when url is not set (#2776) (#2782)
Co-authored-by: Taisei Mima <bhbstar.me@gmail.com>
fix for httpx.URL("") being truthy but stringifying to empty string.
2025-12-30 17:51:57 -05:00
Jeremiah Lowin
33ff356c0f
Fix titled enum elicitation schema to comply with MCP spec (#2774) 2025-12-29 09:46:20 -05:00
Jeremiah Lowin
820f74e8ed
[BugFix] Fix openapi_version Check So 3.1 Is Included (#2768) (#2769)
Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com>
2025-12-28 07:39:21 -05:00
Jeremiah Lowin
bbf6c200ee
Update CLI banner with FastMCP 3.0 notice (#2765) 2025-12-26 22:13:05 -05:00
Jeremiah Lowin
97327893bb
Fix OAuth Proxy resource parameter validation (#2763) 2025-12-26 21:24:08 -05:00
Jeremiah Lowin
6bade1cbd9
Add auth_route parameter to SupabaseProvider (#2760)
Co-authored-by: Eloi Zalczer <eloi@entropia.io>
2025-12-26 16:23:41 -05:00
Jeremiah Lowin
4963b516c2
Fix: resolve root-level $ref in outputSchema for MCP spec compliance (#2720) (#2727)
Co-authored-by: lif <1835304752@qq.com>
2025-12-25 08:53:52 -05:00
Jeremiah Lowin
7f56291204
Add changelog entries for v2.13.1 through v2.14.1 (#2724) 2025-12-25 08:22:24 -05:00
Jeremiah Lowin
ee9ee777c5
Add v3 breaking changes notice to README and docs (#2713) 2025-12-24 16:04:46 -05:00
Jeremiah Lowin
39c4855580
Pin MCP under 2 (#2709) 2025-12-24 15:28:31 -05:00
Jeremiah Lowin
88349bd68f
Fix Prefect website URL in docs footer (#2705) 2025-12-24 08:30:26 -05:00
Chris Guidry
53b609f262
Merge pull request #2700 from jlowin/2679-task-cancel-fix-2.x
Bump pydocket to 0.16.3 to fix worker cleanup race condition
2025-12-23 18:54:32 -05:00
Chris Guidry
34112a17df Bump pydocket to 0.16.3 to fix worker cleanup race condition
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>
2025-12-23 18:45:42 -05:00
Jeremiah Lowin
5daabf0b84
Fix test cleanup for uvicorn 0.39+ context isolation (#2696) 2025-12-23 18:40:20 -05:00
Jeremiah Lowin
7a46e2130b
Let FastMCPError propagate unchanged from managers (#2697) 2025-12-23 18:29:36 -05:00
Jeremiah Lowin
bf60ac4e44 Fix task execution for tools with custom names (#2645)
Uses pydocket 0.16.0's `names=` parameter for explicit registration keys:
- Tools/prompts: registered by `.key`
- Resources/templates: registered by `.name`

Removes `_create_named_fn_wrapper` function.

Closes #2642
2025-12-23 18:05:29 -05:00
Chris Guidry
afb22c4a74 Let FastMCPError propagate from dependencies
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>
2025-12-23 18:00:40 -05:00
Rafi Olaverria
6a434e4005 fix: check the cause of the tool error (#2674) 2025-12-23 18:00:25 -05:00
Jeremiah Lowin
2f561ec98d
Deprecate exclude_args in favor of Depends() (#2621) v2.14.1
* Deprecate exclude_args in favor of Depends()

* Add version badge to Hiding Parameters section
2025-12-14 21:24:08 -05:00
Jeremiah Lowin
076ec0c84b
Adopt streamable_http_client API from MCP SDK (#2620)
* Adopt streamable_http_client API from MCP SDK

- Update import to use new streamable_http_client function
- Convert httpx_client_factory to httpx.AsyncClient before passing to new API
- Maintain backward compatibility by continuing to accept factories
- Add deprecation warning for sse_read_timeout parameter

The new API accepts httpx.AsyncClient directly instead of factories.
We continue accepting factories for OAuth compatibility, converting
them to clients at the boundary with the MCP SDK.

* Fix timeout type conversion for streamable_http_client

Convert read_timeout_seconds from timedelta to float before passing
to httpx, matching the pattern used in the SSE transport.

* Enable redirect following in httpx client

* Fix httpx client resource leak
2025-12-14 21:18:01 -05:00
Jeremiah Lowin
b8ae95a4bb
Add tool_names parameter to mount() for name overrides (#2619)
* Add tool_names parameter to mount() for name overrides

* Fix Docket registration to use tool_names overrides
2025-12-14 20:56:42 -05:00
Jeremiah Lowin
577f4d1bdf
Consolidate sampling examples and fix tool_choice bug (#2618)
* Fix tool_choice to always require tools when result_type is set

* Consolidate sampling examples with rich output

* Replace eval() with explicit add/multiply tools
2025-12-14 20:47:00 -05:00
Jeremiah Lowin
c91c43e280
Add AnthropicSamplingHandler (#2617)
* Add AnthropicSamplingHandler

Adds a sampling handler for the Anthropic API at
fastmcp.client.sampling.handlers.anthropic, alongside the existing
OpenAI handler. Includes full support for tool calling.

Install with: pip install fastmcp[anthropic]

* Update default model

* Update sampling docs to cover both OpenAI and Anthropic handlers

* Use AsyncAnthropic, fix falsy value handling, handle tool_choice none

* Propagate isError to Anthropic, join multiple text blocks, fix docs
2025-12-14 16:07:22 -05:00
Jeremiah Lowin
da77cfa73f
Unify SamplingHandler and promote OpenAI handler (#2616)
* Unify SamplingHandler and promote OpenAI handler

Consolidates ServerSamplingHandler and ClientSamplingHandler into a single
SamplingHandler type alias. Moves OpenAISamplingHandler from experimental
to fastmcp.client.sampling.handlers.openai as the canonical location.

Backwards compatibility maintained for imports from experimental.

* Remove unreachable code paths in OpenAI handler

* Fix docstring and use elif for mutually exclusive branches
2025-12-14 15:22:43 -05:00
Jeremiah Lowin
41ec7ee06d
SEP-1577: Sampling with tools (#2551)
* 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>
2025-12-14 13:51:05 -05:00
Jeremiah Lowin
0cd3690aef
Consolidate session state reset logic and improve cancellation cleanup (#2615) 2025-12-14 09:11:30 -05:00