* feat: Add encoding parameter to FileResource
- Add optional encoding field (str | None, default None) to FileResource.
- Pass encoding through to read_text() for cross-platform text file reading.
- Preserve backward compatibility by defaulting to system encoding.
* test: Add tests for FileResource encoding parameter
- Test UTF-8 reading with explicit encoding for non-ASCII content.
- Test backward compatibility when no encoding is specified.
- Test that encoding is ignored for binary file reads.
- Test Latin-1 reading with matching encoding.
* docs: Document FileResource encoding parameter
- Add encoding="utf-8" to FileResource example in resource classes guide.
- Update FileResource description to mention encoding support.
* feat: Change FileResource encoding default from None to utf-8
- Default to utf-8 instead of system encoding to prevent cross-platform footgun.
- Update field description to reflect new default.
- Update test to verify default encoding is utf-8 with non-ASCII content.
- Remove redundant encoding="utf-8" from docs example since it is now the default.
* 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>
* 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: cache component lists in ProxyProvider to avoid redundant backend connections
Every call_tool through a proxy was triggering _list_tools() to resolve
the tool by name, opening a full MCP session just for the lookup, then
opening a second session for the actual execution. This caches component
lists on the ProxyProvider with a configurable TTL (default 300s),
cutting backend handshakes in half for repeated calls.
* docs: document component caching and session reuse for proxy providers
* fix: add sleep in cache TTL test for Windows clock resolution
* docs: clarify cache scope and dynamic backend guidance
* Add tests for two-stage pattern, empty full-detail results, empty inputs
* Add ListTools, search limit, catalog size annotation; split tests
Co-authored-by: Claude <noreply@anthropic.com>
* Remove BM25 internal cap so Search.limit is the sole truncation point
* Pass default_limit to BM25 instead of arbitrary high cap
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Decompose CodeMode into composable discovery tools
CodeMode now owns only the execute sandbox. Discovery tools (search,
get_schema, etc.) are composable via the discovery_tools parameter.
Each is a Callable[[GetToolCatalog], Tool] factory.
Ships SearchTool (lightweight name+description results) and SchemaTool
(brief markdown or full JSON schemas by tool name) as built-in defaults.
* Rename to Search/GetSchemas/Tags, add tag filtering, fix bugs
- Rename SearchTool→Search, SchemaTool→GetSchemas, Categories→Tags
- Add tags parameter to Search for LLM-side tag filtering
- Add Tags discovery tool for browsing tools by tag
- Fix shared singleton default factories (now per-instance)
- Fix get_schema full mode returning invalid JSON on partial matches
- Fix "untagged" filter inconsistency between Tags and Search
- Split serialization tests to comply with loq line limit
- Rewrite docs for conceptual clarity
* Add three-tier detail levels, remove default_arguments, rename Tags→GetTags, rewrite docs
* Clean up __all__ exports, return valid JSON for empty full-detail results
* 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>
* Add MultiAuth for composing multiple token verification sources
🤖 Generated with Claude Code
https://claude.ai/code/session_01WwKYDCqjM2FqYwY5ZNVvjb
* Fix ruff lint/format in MultiAuth tests
🤖 Generated with Claude Code
https://claude.ai/code/session_01WwKYDCqjM2FqYwY5ZNVvjb
* Fix MultiAuth well-known route delegation and empty scopes handling
🤖 Generated with Claude Code
https://claude.ai/code/session_01WwKYDCqjM2FqYwY5ZNVvjb
* Harden MultiAuth: exception resilience, mcp_path propagation, test coverage
- verify_token now catches exceptions from individual sources and
continues to the next, so one broken verifier can't take down the
whole chain
- set_mcp_path propagates to verifiers, not just the server
- Fix jwks_url→jwks_uri typo in class docstring
- Add tests for raising verifiers, valid-token HTTP acceptance,
and set_mcp_path propagation
* Clean up MultiAuth: precompute sources, deduplicate test helpers
* Fix version badges to 3.1.0
---------
Co-authored-by: Claude <noreply@anthropic.com>
* code mode
* update uv.lock for monty optional dep
🤖 Generated with Claude Code
* retry CI
* Address PR review comments on CodeMode transform
🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix ty unresolved-attribute error on search_helper
🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* more idiomacy
* harden
* fix docs
* harden
* fix red CI
* Refactor CodeMode to use CatalogTransform base class
Removes the duplicate ContextVar bypass pattern in favor of the shared
CatalogTransform machinery. Also fixes a pre-existing bug where
`from __future__ import annotations` caused NameError for Annotated
in nested function scopes at runtime.
* Remove redundant _get_visible_tools wrapper in CodeMode
* Rewrite CodeMode docs with proper motivation and structure
* Fix type narrowing in collision test
* Stop unwrapping tool results in CodeMode's call_tool
call_tool() inside execute blocks now returns structured content as-is,
preserving the {"result": value} wrapping. This means the output schema
shown in search results accurately describes what call_tool() returns,
so LLMs can trust the schema when writing code.
Also adds examples/code_mode/ with a server and narrated client demo.
* Simplify call_tool return type: dict | str
* Fix example client to unwrap structured results
* Let server resolve tool versions instead of pinning first match
* Rewrite CodeMode docs to match current behavior
* Rename optional extra from monty to code-mode
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
Fix description of "FastMCP Constructor Parameters": Remove parameters `on_duplicate_tools`, `on_duplicate_resources` and `on_duplicate_prompts`, which are no longer accepted by FastMCP(). Add the new parameter `on_duplicate` and its description.
* feat: Add search transforms for tool discovery
RegexSearchTransform and BM25SearchTransform collapse large tool
catalogs into a search interface so LLMs discover tools on demand
instead of receiving the full listing.
* chore: Update SDK documentation
* fix: call_tool recursion guard, atomic BM25 rebuild, hash includes descriptions
* Extract CatalogTransform base class for catalog-aware transforms
Transforms that replace list_tools() with synthetic components (like
search) need to read the real catalog at call time without triggering
their own replacement logic. CatalogTransform handles the re-entrant
bypass via per-instance ContextVar, exposing transform_tools() as the
subclass hook and get_tool_catalog() for catalog access.
* Add search transform examples for regex and BM25
* Add README for search transform examples
* Polish search example clients with rich output
* Remove hardcoded tool counts from search example subtitles
* Clarify that review bot feedback should be evaluated on its merits
* Expand search transform docs with proper hierarchy
---------
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
The `key` parameter was removed from `add_resource()` in the 2.x era and no longer exists in the implementation. Removes all references and the "Custom Resource Keys" section from both the current and v2 docs.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Nc1qEJ1rKaRRxB5h6Qu5V3
Co-authored-by: Claude <noreply@anthropic.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 consent binding cookie to prevent confused deputy attacks (GHSA-rww4-4w9c-7733)
The OAuthProxy's consent page verified user intent but didn't bind the
consenting browser to the IdP callback. An attacker could intercept the
upstream authorization URL after consent and send it to a victim, whose
browser would complete the flow without having the consent cookie.
This adds a signed consent binding cookie set during consent approval
(both manual and auto-approve paths) and verified in the IdP callback
handler. A different browser won't have this cookie and gets a 403.
* Use startswith for URL assertion in consent binding test
* Store consent bindings as per-transaction map to support parallel flows
* Only accept __Host- consent binding cookie on HTTPS
* chore: Update SDK documentation
---------
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>