* fix: recover StdioTransport after subprocess exits
🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: improve Windows reliability for stdio crash recovery
🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: filesystem provider import machinery
- Temporary sys.path entries (both package and non-package mode) now removed
immediately after exec_module via try/finally, eliminating permanent process-wide pollution
- Non-package files use bare stem as sys.modules key only if unclaimed; falls back
to private hash-based key to prevent stdlib shadowing (e.g. json.py clobbering json)
- Reload of private-key modules uses spec.loader.exec_module directly instead of
importlib.reload, which cannot find files by their private synthetic name
- _find_package_root gains stop_at parameter; discover_and_import passes provider_root
to prevent package root discovery from escaping above the provider boundary
Closes#3625 (issues 2, 3, 6)
🤖 Generated with Claude Code
* fix: use contextlib.suppress for SIM105 linting
🤖 Generated with Claude Code
* test: add import machinery regression tests
🤖 Generated with Claude Code
* fix: resolve provider_root before path comparison; improve tests
- Resolve provider_root in import_module_from_file so the stop_at boundary
in _find_package_root works correctly when provider_root is a relative path
(e.g. FileSystemProvider(Path("./mcp"))) — previously the resolved file_path
and unresolved stop_at.parent would never compare equal
- Fix test_stdlib_not_shadowed: use unconditional finally to restore sys.modules["json"]
- Strengthen test_same_stem_files: assert mod_a is not mod_b and that sys.modules["helpers"]
was not clobbered by the second import
- Replace direct _find_package_root unit test with an integration test through
import_module_from_file(provider_root=...) that also verifies the module name
and that tmp_path is not added to sys.path
🤖 Generated with Claude Code
Adds Provider.get_app_tool(app_name, tool_name) — a dedicated method for
finding app-visible tools by their original name, bypassing transforms.
AggregateProvider queries children, WrappedProvider delegates to inner,
FastMCPProvider delegates to nested server. The default implementation
checks _get_tool and matches meta.fastmcp.app.
This replaces the process-level _APP_TOOLS registry. Tool routing now
works through the provider tree, which exists in every process — no
shared state needed for horizontal scaling.
* Transparently refresh upstream token in OAuthProxy.load_access_token()
When upstream token validation fails during load_access_token, attempt
to refresh using the stored refresh token before returning None. This
prevents premature 401s that force clients into expensive full re-auth
flows when the upstream token expires.
Co-authored-by: Claude <noreply@anthropic.com>
* Gate transparent refresh on token expiry, add advisory lock
Only attempt upstream refresh when the token is actually expired, not
on any validation failure (scope mismatch, revocation, etc.). Add
per-token advisory lock to prevent concurrent async tasks from racing
to refresh the same upstream token.
* Re-check expiry inside lock, reload from storage after refresh failure
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Replace UUID global keys with (app_name, tool_name) registry
Collapses three module-level registries (_APP_TOOL_REGISTRY,
_FN_TO_GLOBAL_KEY, _NAME_TO_GLOBAL_KEY) into one: _APP_TOOLS keyed by
(app_name, tool_name). Removes UUID generation, global key stamping in
metadata, and the complex resolver that mapped callables and strings
through multiple fallback paths.
The server now reads _meta.fastmcp.app from the MCP request (set by the
Prefab renderer) and routes directly to the named app's tool. Two apps
with the same tool name are disambiguated by app name, not by UUID.
The resolver is simplified to pass-through: CallTool("save") serializes
as "save", and the server resolves it at call time using the app context.
* Read app name from _meta.prefab.app to match Prefab renderer
* Inject _meta.fastmcp.app into @app.ui() structured content
The @app.ui() decorator stores the FastMCPApp name in the tool's metadata.
When the tool result is serialized, _prefab_to_json injects it as
_meta.fastmcp.app in the structured content. The Prefab renderer reads
this on init and echoes it back as _meta.fastmcp.app on every
callServerTool call, completing the routing loop.
* 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.
* Comprehensive MCP Apps docs, string CallTool resolution, bump prefab-ui >=0.13.0
Rewrites the apps documentation as a learning journey: overview → Prefab apps
→ FastMCPApp → patterns → dev tools → custom HTML. Adds a new FastMCPApp page
covering composable apps with @app.tool()/@app.ui(), CallTool, forms, actions,
and composition. Teaches Rx() and set_initial_state() as the primary state API.
Adds string-based CallTool resolution so CallTool("save_contact") resolves to
the tool's global key, matching callable ref behavior. Requires prefab-ui 0.13.0
which passes strings through the tool resolver.
* Detect ambiguous string CallTool resolution across apps
* Simplify string name registry to plain dict (last-write-wins)
* 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