* feat: add TokenCache utility and caching to GitHubTokenVerifier
Extract the caching machinery from IntrospectionTokenVerifier into a
shared TokenCache class in fastmcp.utilities.token_cache, then wire
it into both IntrospectionTokenVerifier and GitHubTokenVerifier.
* Remove dead constant, validate negative cache params
* Fix overwrite eviction bug, skip cache on scope lookup failure
* feat: support ImageContent and AudioContent in sampling handlers
Co-authored-by: Claude <noreply@anthropic.com>
* Validate image MIME types, fix silent drop in assistant list messages
* Reject image/audio in assistant messages with tool_calls
* Reject ImageContent in assistant messages for Anthropic
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix: suppress output schema for ToolResult subclass annotations
* use issubclass_safe/is_class_member_of_type for ToolResult subclass checks
* use parsed_fn.return_type for ToolResult check in transform fallback
* 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
* fix: enforce auth/visibility in ResourcesAsTools and PromptsAsTools for non-FastMCP providers
🤖 Co-authored-by: Claude <noreply@anthropic.com>
* fix: honor stdio auth bypass and correct transform ordering in provider wrappers
Co-authored-by: Claude <noreply@anthropic.com>
* fix: move context/dependencies imports into function to break circular import
* fix: route ResourcesAsTools/PromptsAsTools through ctx.fastmcp
Instead of manually reimplementing auth, visibility, and session
transforms in the transform layer, tool functions now call
ctx.fastmcp.read_resource() / ctx.fastmcp.render_prompt() which
routes through the server's full middleware chain. This matches
the pattern CodeMode uses with ctx.fastmcp.call_tool().
The isinstance(provider, FastMCP) branching is removed entirely.
* feat: add _scope parameter for provider-scoped listing
AggregateProvider can now filter which child providers to query when
listing components. ResourcesAsTools and PromptsAsTools use this to
scope listings to their configured provider while still routing
through ctx.fastmcp for full middleware coverage.
The scope matching walks wrapped providers, so a
WrappedProvider(Namespace, inner=MyProvider) matches if MyProvider
is in the scope list.
* test: add coverage for ResourcesAsTools scoped to a sub-server
* fix: delegate to super() when _scope is None, add AggregateProvider to scope matching
* simplify: remove _scope machinery, route everything through ctx.fastmcp
Reverts the _scope parameter from Provider/AggregateProvider/Server.
ResourcesAsTools and PromptsAsTools now simply route through
ctx.fastmcp for all operations. Apply to a FastMCP server instance
for proper auth/visibility/middleware coverage.
Tests rewritten to use FastMCP server directly instead of raw providers.
* warn when ResourcesAsTools/PromptsAsTools is applied to a non-FastMCP provider
* docs: explain that ResourcesAsTools/PromptsAsTools should wrap a FastMCP server
* raise TypeError instead of warning when applied to non-FastMCP provider
---------
Co-authored-by: Claude <noreply@anthropic.com>
Keycloak returns refresh_expires_in=0 for offline tokens (offline_access scope),
meaning "no fixed time-based expiry". The truthiness check on this value caused
the proxy to skip issuing a PROXY_RT, forcing browser re-auth every hour.
Closes#3509🤖 Generated with Claude Code
Co-authored-by: Marvin Context Protocol <41898282+Marvin Context Protocol@users.noreply.github.com>
Co-authored-by: Jeremiah Lowin <jlowin@users.noreply.github.com>
* fix: stop passing follow_redirects to httpx_client_factory
Remove the `follow_redirects=True` kwarg that was being forced onto
custom httpx_client_factory calls with a type: ignore suppression.
The McpHttpClientFactory protocol does not include follow_redirects,
so this was a protocol violation. httpx already strips Authorization
headers on cross-origin redirects via its _redirect_headers mechanism.
🤖 Co-authored-by: Claude <noreply@anthropic.com>
* fix: restore follow_redirects=True for custom httpx client factories
httpx already strips Authorization headers on cross-origin redirects,
so follow_redirects is safe to keep. Removing it broke redirect
handling for users providing custom factories.
* fix: remove vacuous test that never invoked connect_session
The test asserted on received_kwargs but never called connect_session,
so the factory was never invoked and the assertion was a no-op.
* fix: use AsyncClient with transport= instead of monkey-patching _transport
* fix: use IdP-granted scopes instead of client-requested scopes in OAuthProxy
* fix: use parse_scopes instead of split for IdP scope strings
Some providers (e.g. GitHub) return comma-delimited scopes like
"repo,gist" rather than the RFC 6749 space-delimited format.
* Merge origin/main into fix/oauth-proxy-use-idp-granted-scopes
* fix: remove unrelated transform and http.py changes from PR scope
* fix: remove accidentally staged worktree directories
* fix: prevent path traversal in skill download via malicious skill names
Co-authored-by: Claude <noreply@anthropic.com>
* fix: resolve skill_dir once and use consistently to prevent overwrite bypass
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat: make upstream_client_secret optional in OAuthProxy
Extract _create_upstream_oauth_client() factory method for subclass
override. Cookie signing falls back to JWT key material when no secret.
* fix: include client_id in revocation requests for public clients
* fix: use factory method for revocation auth
* fix: URL-encode path params in OpenAPI provider to prevent SSRF/path traversal
Co-authored-by: Claude <noreply@anthropic.com>
* Exempt too-long from core-category requirement in triage
* fix: also encode dots in path params to prevent bare .. traversal
* fix: only encode .. (not all dots) to preserve valid dotted values
* fix: encode all dots in path params to prevent single-dot normalization
* fix: check decoded path stays within prefix in double-encoding test
---------
Co-authored-by: Claude <noreply@anthropic.com>
- Use 10 PBKDF2 iterations in test_mode (vs 1M in production) for
JWT key derivation — cuts auth test setup from ~2.5s to <0.1s
- Add timeout(15) to subprocess-spawning tests (TestKeepAlive,
test_mcp_config) that exceed 5s under parallel CI load
- Remove pytestmark filterwarnings overrides in tests/deprecated/
that were leaking DeprecationWarning to test output
- Fix deprecated add_tool_transformation() usage in test_authorization
- Document new settings in settings.mdx
Add an is_dir() check after the existence check in
install_cursor_workspace() to provide a clear error message when
a file path is passed instead of a directory.
Fixes#3426
Co-authored-by: nightcityblade <nightcityblade@gmail.com>
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
* perf: expose minimum_check_interval, reduce task pickup latency
The Docket Worker polls for new tasks every minimum_check_interval
(previously hardcoded to 250ms in pydocket). Expose this setting so
users can tune it, default to 50ms, and override to 10ms in tests.
This cuts average task pickup latency from ~125ms to ~5ms per task.
* perf: reduce task test overhead and eliminate cross-test contamination
- Expose minimum_check_interval setting (default 50ms, 10ms in tests)
to reduce Docket Worker task pickup latency
- Isolate fakeredis per test via unique memory:// URLs to prevent
stale _async_blocking tasks from contaminating subsequent tests
- Make client disconnect timeout configurable (default 5s, 1s in tests)
- Add --durations=50 to CI for passive performance regression detection
- Remove 15s timeout band-aids from task test conftest files
- Add explicit @pytest.mark.timeout(10) to cancellation tests
- Fix deprecated FastMCP.as_proxy() usage in test_task_proxy.py
Fix context manager ordering in FastMCPTransport so the task group
(server run + subscriptions) is cancelled before the lifespan
(Docket Worker) tears down. Also break subscription loop on terminal
task states.
Closes#3498
* Add FastMCPApp — a Provider for composable MCP applications
* Wire Prefab callable resolver via to_json(tool_resolver=) parameter
* Remove inspect.signature compat check, use try/except until prefab 0.10.0
* Address review: fix add_tool registry gaps, normalize auth errors, bump prefab to 0.10.0
* Register global key after _add_component succeeds
* Simplify: extract decorator dispatch, use get_fastmcp_meta, expose get_global_tool
* Remove prek from Marvin workflows
These workflows run Claude to respond to /marvin mentions — linting
the repo is unnecessary and fails without renderer deps installed.
* Return ResolvedTool from callable resolver, add contacts example
The callable resolver now returns ResolvedTool (from prefab_ui) instead of a
plain string, carrying metadata like unwrap_result that the renderer needs to
correctly handle structuredContent envelopes. The unwrap_result flag is derived
from the tool's x-fastmcp-wrap-result output schema marker.
* Bump prefab-ui requirement to >=0.11.0
* Remove stale ty ignore comments now that prefab-ui 0.11 is published
* Add fastmcp dev apps command with browser UI preview
* Improve fastmcp dev apps: dropdown picker, reload flag, process cleanup
- Replace Tabs with Pages+Select for tool picker (Rx-based reactive state)
- Add --reload/--no-reload flag (default: True) to fastmcp dev apps
- Kill entire process group on shutdown so port 8000 is freed properly
- Suppress uvicorn websockets deprecation warning (websockets-sansio)
- Bump prefab-ui to >=0.11.1 (fixes get_renderer_head bug in 0.11.0)
- Add farewell tool to greet_server example for multi-tool testing
* Add docs for fastmcp dev apps command
* Fix orphaned server on startup failure, guard Unix-only signal handling
* Show tool title in picker, remove editable prefab source
* Bump prefab-ui to >=0.11.2
* Fail fast when prefab-ui is not installed
* Add apps/development docs, link from prefab and sidebar
* Fix optional field defaults, fail with non-zero on startup timeout
* feat: add `verify` parameter for SSL certificate configuration
* Propagate verify to OAuth preflight clients
* Propagate verify to pre-constructed OAuth instances
* Fix verify override not propagating to existing OAuth factory
* Warn when both httpx_client_factory and verify are provided
* Preserve user-provided OAuth factory when transport has verify
* Skip OAuth re-sync when transport has custom httpx_client_factory
When set to "external", the built-in consent screen is skipped
(same as False) but no security warning is logged, since consent
is handled externally by the upstream IdP.
Forwarded through all OAuthProxy subclasses: GoogleProvider,
GitHubProvider, AzureProvider, DiscordProvider, WorkOSProvider,
OIDCProxy, Auth0Provider, AWSCognitoProvider, and OCIProvider.
* Propagate x-fastmcp-wrap-result flag in tool result _meta
🤖 Generated with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
* Skip listTools round-trip when _meta has x-fastmcp-wrap-result
🤖 Generated with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
* Use namespaced meta key: {"fastmcp": {"wrap_result": true}}
🤖 Generated with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
* Clean up _parse_call_tool_result: hoist cast import, document local CallToolResult import, extract fastmcp_meta
🤖 Generated with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
* Merge _meta in tasks result handler instead of overwriting
🤖 Generated with Claude Code
* Preserve type validation in meta-based unwrap path
🤖 Generated with Claude Code
* Fix type validation for wrapped task results, guard non-dict meta
🤖 Generated with Claude Code
---------
Co-authored-by: Claude <noreply@anthropic.com>