diff --git a/docs/python-sdk-pages.json b/docs/python-sdk-pages.json index 704b28e4f9..b16a3c2abf 100644 --- a/docs/python-sdk-pages.json +++ b/docs/python-sdk-pages.json @@ -1,5 +1,4 @@ [ - "python-sdk/fastmcp-apps", "python-sdk/fastmcp-cli", "python-sdk/fastmcp-client", "python-sdk/fastmcp-decorators", @@ -13,6 +12,19 @@ "python-sdk/fastmcp-telemetry", "python-sdk/fastmcp-tools", "python-sdk/fastmcp-types", + { + "group": "fastmcp.apps", + "pages": [ + "python-sdk/fastmcp-apps-__init__", + "python-sdk/fastmcp-apps-app", + "python-sdk/fastmcp-apps-approval", + "python-sdk/fastmcp-apps-choice", + "python-sdk/fastmcp-apps-config", + "python-sdk/fastmcp-apps-file_upload", + "python-sdk/fastmcp-apps-form", + "python-sdk/fastmcp-apps-generative" + ] + }, { "group": "fastmcp.experimental", "pages": [ @@ -39,6 +51,7 @@ "python-sdk/fastmcp-utilities-__init__", "python-sdk/fastmcp-utilities-async_utils", "python-sdk/fastmcp-utilities-auth", + "python-sdk/fastmcp-utilities-authorization", "python-sdk/fastmcp-utilities-cli", "python-sdk/fastmcp-utilities-components", "python-sdk/fastmcp-utilities-docstring_parsing", @@ -82,6 +95,7 @@ "python-sdk/fastmcp-utilities-openapi", "python-sdk/fastmcp-utilities-pagination", "python-sdk/fastmcp-utilities-skills", + "python-sdk/fastmcp-utilities-tasks", "python-sdk/fastmcp-utilities-tests", "python-sdk/fastmcp-utilities-timeout", "python-sdk/fastmcp-utilities-token_cache", diff --git a/docs/python-sdk/fastmcp-apps.mdx b/docs/python-sdk/fastmcp-apps-__init__.mdx similarity index 89% rename from docs/python-sdk/fastmcp-apps.mdx rename to docs/python-sdk/fastmcp-apps-__init__.mdx index 58bd246561..5f69a4b594 100644 --- a/docs/python-sdk/fastmcp-apps.mdx +++ b/docs/python-sdk/fastmcp-apps-__init__.mdx @@ -1,6 +1,6 @@ --- -title: apps -sidebarTitle: apps +title: __init__ +sidebarTitle: __init__ --- # `fastmcp.apps` diff --git a/docs/python-sdk/fastmcp-apps-app.mdx b/docs/python-sdk/fastmcp-apps-app.mdx new file mode 100644 index 0000000000..4b10923094 --- /dev/null +++ b/docs/python-sdk/fastmcp-apps-app.mdx @@ -0,0 +1,146 @@ +--- +title: app +sidebarTitle: app +--- + +# `fastmcp.apps.app` + + +FastMCPApp — a Provider that represents a composable MCP application. + +FastMCPApp binds entry-point tools (model calls these) together with backend +tools (the UI calls these via CallTool). Backend tools are tagged with +``meta["fastmcp"]["app"]`` so they can be found through the provider chain +even when transforms (namespace, visibility, etc.) have renamed or hidden +them — the server sets a context var that tells ``Provider.get_tool`` to +fall back to a direct lookup for app-visible tools. + +Usage:: + + from fastmcp import FastMCP, FastMCPApp + + app = FastMCPApp("Dashboard") + + @app.ui() + def show_dashboard() -> Component: + return Column(...) + + @app.tool() + def save_contact(name: str, email: str) -> str: + return name + + server = FastMCP("Platform") + server.add_provider(app) + + +## Classes + +### `FastMCPApp` + + +A Provider that represents an MCP application. + +Binds together entry-point tools (``@app.ui``), backend tools +(``@app.tool``), and the Prefab renderer resource. Backend tools +are tagged with ``meta["fastmcp"]["app"]`` so ``Provider.get_tool`` +can find them by original name even when transforms have been applied. + + +**Methods:** + +#### `tool` + +```python +tool(self, name_or_fn: F) -> F +``` + +#### `tool` + +```python +tool(self, name_or_fn: str | None = None) -> Callable[[F], F] +``` + +#### `tool` + +```python +tool(self, name_or_fn: str | AnyFunction | None = None) -> Any +``` + +Register a backend tool that the UI calls via CallTool. + +Backend tools default to ``visibility=["app"]``. Pass ``model=True`` +to also expose the tool to the model (``visibility=["app", "model"]``). + +Supports multiple calling patterns:: + + @app.tool + def save(name: str): ... + + @app.tool() + def save(name: str): ... + + @app.tool("custom_name") + def save(name: str): ... + + +#### `ui` + +```python +ui(self, name_or_fn: F) -> F +``` + +#### `ui` + +```python +ui(self, name_or_fn: str | None = None) -> Callable[[F], F] +``` + +#### `ui` + +```python +ui(self, name_or_fn: str | AnyFunction | None = None) -> Any +``` + +Register a UI entry-point tool that the model calls. + +Entry-point tools default to ``visibility=["model"]`` and auto-wire +the Prefab renderer resource and CSP. They are tagged with the app +name so structured content includes ``_meta.fastmcp.app``. + +Supports multiple calling patterns:: + + @app.ui + def dashboard() -> Component: ... + + @app.ui() + def dashboard() -> Component: ... + + @app.ui("my_dashboard") + def dashboard() -> Component: ... + + +#### `add_tool` + +```python +add_tool(self, tool: Tool | Callable[..., Any]) -> Tool +``` + +Add a tool to this app programmatically. + +The tool is tagged with this app's name for routing. + + +#### `lifespan` + +```python +lifespan(self) -> AsyncIterator[None] +``` + +#### `run` + +```python +run(self, transport: Literal['stdio', 'http', 'sse', 'streamable-http'] | None = None, **kwargs: Any) -> None +``` + +Create a temporary FastMCP server and run this app standalone. + diff --git a/docs/python-sdk/fastmcp-apps-approval.mdx b/docs/python-sdk/fastmcp-apps-approval.mdx new file mode 100644 index 0000000000..81285a76d7 --- /dev/null +++ b/docs/python-sdk/fastmcp-apps-approval.mdx @@ -0,0 +1,58 @@ +--- +title: approval +sidebarTitle: approval +--- + +# `fastmcp.apps.approval` + + +Approval — a Provider that adds human-in-the-loop approval to any server. + +The LLM presents a summary of what it's about to do, and the user +approves or rejects via buttons. The result is sent back into the +conversation as a message, prompting the LLM's next turn. + +Requires ``fastmcp[apps]`` (prefab-ui). + +Usage:: + + from fastmcp import FastMCP + from fastmcp.apps.approval import Approval + + mcp = FastMCP("My Server") + mcp.add_provider(Approval()) + + +## Classes + +### `Approval` + + +A Provider that adds human-in-the-loop approval to a server. + +The LLM calls the ``request_approval`` tool with a summary and +optional details. The user sees an approval card with Approve and +Reject buttons. Clicking either sends a message back into the +conversation (via ``SendMessage``), triggering the LLM's next turn. + +The message appears as if the user sent it, so the LLM sees +something like ``'"Deploy v3.2 to production" is APPROVED'``. + +Example:: + + from fastmcp import FastMCP + from fastmcp.apps.approval import Approval + + mcp = FastMCP("My Server") + mcp.add_provider(Approval()) + +Customized:: + + Approval( + title="Deploy Gate", + approve_text="Ship it", + approve_variant="default", + reject_text="Abort", + reject_variant="destructive", + ) + diff --git a/docs/python-sdk/fastmcp-apps-choice.mdx b/docs/python-sdk/fastmcp-apps-choice.mdx new file mode 100644 index 0000000000..8b7572622d --- /dev/null +++ b/docs/python-sdk/fastmcp-apps-choice.mdx @@ -0,0 +1,44 @@ +--- +title: choice +sidebarTitle: choice +--- + +# `fastmcp.apps.choice` + + +Choice — a Provider that lets the user pick from a set of options. + +The LLM presents options, the user clicks one, and the selection +flows back into the conversation as a message. + +Requires ``fastmcp[apps]`` (prefab-ui). + +Usage:: + + from fastmcp import FastMCP + from fastmcp.apps.choice import Choice + + mcp = FastMCP("My Server") + mcp.add_provider(Choice()) + + +## Classes + +### `Choice` + + +A Provider that lets the user choose from a set of options. + +The LLM calls ``choose`` with a prompt and a list of options. +The user sees a card with one button per option. Clicking a button +sends the selection back into the conversation via ``SendMessage``, +triggering the LLM's next turn. + +Example:: + + from fastmcp import FastMCP + from fastmcp.apps.choice import Choice + + mcp = FastMCP("My Server") + mcp.add_provider(Choice()) + diff --git a/docs/python-sdk/fastmcp-apps-config.mdx b/docs/python-sdk/fastmcp-apps-config.mdx new file mode 100644 index 0000000000..74828bbdd5 --- /dev/null +++ b/docs/python-sdk/fastmcp-apps-config.mdx @@ -0,0 +1,90 @@ +--- +title: config +sidebarTitle: config +--- + +# `fastmcp.apps.config` + + +MCP Apps support — extension negotiation and typed UI metadata models. + +Provides constants and Pydantic models for the MCP Apps extension +(io.modelcontextprotocol/ui), enabling tools and resources to carry +UI metadata for clients that support interactive app rendering. + + +## Functions + +### `app_config_to_meta_dict` + +```python +app_config_to_meta_dict(app: AppConfig | dict[str, Any]) -> dict[str, Any] +``` + + +Convert an AppConfig or dict to the wire-format dict for ``meta["ui"]``. + + +## Classes + +### `ResourceCSP` + + +Content Security Policy for MCP App resources. + +Declares which external origins the app is allowed to connect to or +load resources from. Hosts use these declarations to build the +``Content-Security-Policy`` header for the sandboxed iframe. + + +### `ResourcePermissions` + + +Iframe sandbox permissions for MCP App resources. + +Each field, when set (typically to ``{}``), requests that the host +grant the corresponding Permission Policy feature to the sandboxed +iframe. Hosts MAY honour these; apps should use JS feature detection +as a fallback. + + +### `AppConfig` + + +Configuration for MCP App tools and resources. + +Controls how a tool or resource participates in the MCP Apps extension. +On tools, ``resource_uri`` and ``visibility`` specify which UI resource +to render and where the tool appears. On resources, those fields must +be left unset (the resource itself is the UI). + +All fields use ``exclude_none`` serialization so only explicitly-set +values appear on the wire. Aliases match the MCP Apps wire format +(camelCase). + + +### `PrefabAppConfig` + + +App configuration for Prefab tools with sensible defaults. + +Like ``app=True`` but customizable. Auto-wires the Prefab renderer +URI and merges the renderer's CSP with any additional domains you +specify. The renderer resource is registered automatically. + +Example:: + + @mcp.tool(app=PrefabAppConfig()) # same as app=True + + @mcp.tool(app=PrefabAppConfig( + csp=ResourceCSP(frame_domains=["https://example.com"]), + )) + + +**Methods:** + +#### `model_post_init` + +```python +model_post_init(self, __context: Any) -> None +``` diff --git a/docs/python-sdk/fastmcp-apps-file_upload.mdx b/docs/python-sdk/fastmcp-apps-file_upload.mdx new file mode 100644 index 0000000000..878cbae32b --- /dev/null +++ b/docs/python-sdk/fastmcp-apps-file_upload.mdx @@ -0,0 +1,144 @@ +--- +title: file_upload +sidebarTitle: file_upload +--- + +# `fastmcp.apps.file_upload` + + +FileUpload — a Provider that adds drag-and-drop file upload to any server. + +Lets users upload files directly to the server through an interactive UI, +bypassing the LLM context window entirely. The LLM can then read and work +with uploaded files through model-visible tools. + +Requires ``fastmcp[apps]`` (prefab-ui). + +Usage:: + + from fastmcp import FastMCP + from fastmcp.apps import FileUpload + + mcp = FastMCP("My Server") + mcp.add_provider(FileUpload()) + +For custom persistence, override the storage methods:: + + class S3Upload(FileUpload): + def on_store(self, files, ctx): + # write to S3, return summaries + ... + + def on_list(self, ctx): + # list from S3 + ... + + def on_read(self, name, ctx): + # read from S3 + ... + + +## Classes + +### `FileUpload` + + +A Provider that adds file upload capabilities to a server. + +Registers a drag-and-drop UI tool, a backend storage tool, and +model-visible tools for listing and reading uploaded files. + +Files are scoped by MCP session and stored in memory by default. +Override ``on_store``, ``on_list``, and ``on_read`` for custom +persistence (filesystem, S3, database, etc.). Each method receives +the current ``Context``, giving access to session ID, auth tokens, +and request metadata for partitioning and authorization. + +**Session scoping:** The default storage uses ``ctx.session_id`` to +isolate files by session. This works with stdio, SSE, and stateful +HTTP transports. In **stateless HTTP** mode, each request creates a +new session, so files won't persist across requests. For stateless +deployments, override the storage methods to partition by a stable +identifier from the auth context:: + + class UserScopedUpload(FileUpload): + def on_store(self, files, ctx): + user_id = ctx.access_token["sub"] + ... + +Example:: + + from fastmcp import FastMCP + from fastmcp.apps.file_upload import FileUpload + + mcp = FastMCP("My Server") + mcp.add_provider(FileUpload()) + + +**Methods:** + +#### `on_store` + +```python +on_store(self, files: list[dict[str, Any]], ctx: Context) -> list[dict[str, Any]] +``` + +Store uploaded files and return summaries. + +**Args:** +- `files`: List of file dicts, each with ``name``, ``size``, +``type``, and ``data`` (base64-encoded content). +- `ctx`: The current request context. Use for session ID, +auth tokens, or any metadata needed for partitioning. + +Override this method for custom persistence. The default +implementation stores files in memory, scoped by +``_get_scope_key(ctx)``. + +**Returns:** +- List of file summary dicts (``name``, ``type``, ``size``, +- ``size_display``, ``uploaded_at``). + + +#### `on_list` + +```python +on_list(self, ctx: Context) -> list[dict[str, Any]] +``` + +List all stored files. + +**Args:** +- `ctx`: The current request context. + +Override this method for custom persistence. The default +implementation returns files from the current scope. + +**Returns:** +- List of file summary dicts. + + +#### `on_read` + +```python +on_read(self, name: str, ctx: Context) -> dict[str, Any] +``` + +Read a file's contents by name. + +**Args:** +- `name`: The filename to read. +- `ctx`: The current request context. + +Override this method for custom persistence. The default +implementation reads from the current scope's in-memory store. +Text files are decoded from base64; binary files return a +truncated base64 preview. + +**Returns:** +- Dict with file metadata and ``content`` (text) or +- ``content_base64`` (binary preview). + +**Raises:** +- `ValueError`: If the file is not found. + diff --git a/docs/python-sdk/fastmcp-apps-form.mdx b/docs/python-sdk/fastmcp-apps-form.mdx new file mode 100644 index 0000000000..c99110c7b1 --- /dev/null +++ b/docs/python-sdk/fastmcp-apps-form.mdx @@ -0,0 +1,69 @@ +--- +title: form +sidebarTitle: form +--- + +# `fastmcp.apps.form` + + +FormInput — a Provider that collects structured input from the user. + +Define a Pydantic model for the data you need, and ``FormInput`` +generates a form UI. The user fills it out, the submission is +validated, and an optional callback processes the result. + +Requires ``fastmcp[apps]`` (prefab-ui). + +Usage:: + + from pydantic import BaseModel + from fastmcp import FastMCP + from fastmcp.apps.form import FormInput + + class ShippingAddress(BaseModel): + street: str + city: str + state: str + zip_code: str + + mcp = FastMCP("My Server") + mcp.add_provider(FormInput(model=ShippingAddress)) + + +## Classes + +### `FormInput` + + +A Provider that collects structured input via a Pydantic model. + +Define a model for the data you need, and ``FormInput`` generates +a form from it using ``Form.from_model()``. Field types, labels, +descriptions, and validation are all derived from the model. + +Optionally provide an ``on_submit`` callback to process the +validated data. The callback receives a model instance and returns +a string that goes back to the LLM. Without a callback, the +validated JSON is sent directly. + +Example:: + + from pydantic import BaseModel + from fastmcp import FastMCP + from fastmcp.apps.form import FormInput + + class Contact(BaseModel): + name: str + email: str + + mcp = FastMCP("My Server") + mcp.add_provider(FormInput(model=Contact)) + +With a callback:: + + def save_contact(contact: Contact) -> str: + db.insert(contact.model_dump()) + return f"Saved {contact.name}" + + mcp.add_provider(FormInput(model=Contact, on_submit=save_contact)) + diff --git a/docs/python-sdk/fastmcp-apps-generative.mdx b/docs/python-sdk/fastmcp-apps-generative.mdx new file mode 100644 index 0000000000..bb5756b966 --- /dev/null +++ b/docs/python-sdk/fastmcp-apps-generative.mdx @@ -0,0 +1,56 @@ +--- +title: generative +sidebarTitle: generative +--- + +# `fastmcp.apps.generative` + + +GenerativeUI — a Provider that adds LLM-generated UI capabilities. + +Registers tools and resources from ``prefab_ui.generative`` so that an +LLM can write Prefab Python code, execute it in a sandbox, and render +the result as a streaming interactive UI. + +Requires ``fastmcp[apps]`` (prefab-ui). + +Usage:: + + from fastmcp import FastMCP + from fastmcp.apps.generative import GenerativeUI + + mcp = FastMCP("My Server") + mcp.add_provider(GenerativeUI()) + + +## Classes + +### `GenerativeUI` + + +A Provider that adds generative UI capabilities to a server. + +Registers: + +- A ``generate_ui`` tool that accepts Prefab Python code, executes + it in a Pyodide sandbox, and returns the rendered PrefabApp. + Supports streaming via ``ontoolinputpartial``. +- A ``components`` tool that searches the Prefab component library. +- The generative renderer resource with CSP for Pyodide CDN access. + +Example:: + + from fastmcp import FastMCP + from fastmcp.apps.generative import GenerativeUI + + mcp = FastMCP("My Server") + mcp.add_provider(GenerativeUI()) + + +**Methods:** + +#### `lifespan` + +```python +lifespan(self) -> AsyncIterator[None] +``` diff --git a/docs/python-sdk/fastmcp-experimental-transforms-code_mode.mdx b/docs/python-sdk/fastmcp-experimental-transforms-code_mode.mdx index ae98a1a4da..6d634b6ea1 100644 --- a/docs/python-sdk/fastmcp-experimental-transforms-code_mode.mdx +++ b/docs/python-sdk/fastmcp-experimental-transforms-code_mode.mdx @@ -7,7 +7,7 @@ sidebarTitle: code_mode ## Classes -### `SandboxProvider` +### `SandboxProvider` Interface for executing LLM-generated Python code in a sandbox. @@ -20,13 +20,13 @@ sandbox — never with plain ``exec()``. Use ``MontySandboxProvider`` **Methods:** -#### `run` +#### `run` ```python run(self, code: str) -> Any ``` -### `MontySandboxProvider` +### `MontySandboxProvider` Sandbox provider backed by `pydantic-monty`. @@ -38,16 +38,22 @@ Sandbox provider backed by `pydantic-monty`. ``gc_interval`` (int). All are optional; omit a key to leave that limit uncapped. +When the argument is omitted entirely, a conservative baseline +is applied (``max_duration_secs=30``, ``max_memory=100 MB``) so +the out-of-box configuration is not unbounded. Pass +``limits=None`` to explicitly run without any limits, or a dict +to set your own. + **Methods:** -#### `run` +#### `run` ```python run(self, code: str) -> Any ``` -### `Search` +### `Search` Discovery tool factory that searches the catalog by query. @@ -64,7 +70,7 @@ Defaults to BM25 ranking. The LLM can override this per call. ``None`` means no limit. -### `GetSchemas` +### `GetSchemas` Discovery tool factory that returns schemas for tools by name. @@ -78,7 +84,7 @@ types, and required markers. ``"full"`` returns the complete JSON schema. -### `GetTags` +### `GetTags` Discovery tool factory that lists tool tags from the catalog. @@ -93,7 +99,7 @@ without tags appear under ``"untagged"``. ``"full"`` lists all tools under each tag. -### `ListTools` +### `ListTools` Discovery tool factory that lists all tools in the catalog. @@ -106,7 +112,7 @@ Discovery tool factory that lists all tools in the catalog. ``"full"`` returns the complete JSON schema. -### `CodeMode` +### `CodeMode` Transform that collapses all tools into discovery + execute meta-tools. @@ -123,13 +129,13 @@ environment with ``call_tool(name, params)`` in scope. **Methods:** -#### `transform_tools` +#### `transform_tools` ```python transform_tools(self, tools: Sequence[Tool]) -> Sequence[Tool] ``` -#### `get_tool` +#### `get_tool` ```python get_tool(self, name: str, call_next: GetToolNext) -> Tool | None diff --git a/docs/python-sdk/fastmcp-mcp_config.mdx b/docs/python-sdk/fastmcp-mcp_config.mdx index 8d0c4a83e8..0302d92707 100644 --- a/docs/python-sdk/fastmcp-mcp_config.mdx +++ b/docs/python-sdk/fastmcp-mcp_config.mdx @@ -42,7 +42,7 @@ infer_transport_type_from_url(url: str | AnyUrl) -> Literal['http', 'sse'] Infer the appropriate transport type from the given URL. -### `update_config_file` +### `update_config_file` ```python update_config_file(file_path: Path, server_name: str, server_config: CanonicalMCPServerTypes) -> None @@ -167,7 +167,7 @@ from_file(cls, file_path: Path) -> Self Load configuration from JSON file. -### `CanonicalMCPConfig` +### `CanonicalMCPConfig` Canonical MCP configuration format. @@ -178,7 +178,7 @@ The format is designed to be client-agnostic and extensible for future use cases **Methods:** -#### `add_server` +#### `add_server` ```python add_server(self, name: str, server: CanonicalMCPServerTypes) -> None diff --git a/docs/python-sdk/fastmcp-utilities-authorization.mdx b/docs/python-sdk/fastmcp-utilities-authorization.mdx new file mode 100644 index 0000000000..f70c442831 --- /dev/null +++ b/docs/python-sdk/fastmcp-utilities-authorization.mdx @@ -0,0 +1,70 @@ +--- +title: authorization +sidebarTitle: authorization +--- + +# `fastmcp.utilities.authorization` + + +Authorization checks for FastMCP components. + +Auth checks are callables that receive an ``AuthContext`` and return True to +allow access or False to deny it. They can also raise ``AuthorizationError`` to +deny with a custom message; other exceptions are masked and treated as denial. + + +## Functions + +### `require_scopes` + +```python +require_scopes(*scopes: str) -> AuthCheck +``` + + +Require all of the given OAuth scopes. + + +### `restrict_tag` + +```python +restrict_tag(tag: str) -> AuthCheck +``` + + +Require scopes when the accessed component has a specific tag. + + +### `run_auth_checks` + +```python +run_auth_checks(checks: AuthCheck | list[AuthCheck], ctx: AuthContext) -> bool +``` + + +Run auth checks with AND logic. + + +## Classes + +### `AuthContext` + + +Context passed to auth check callables. + +**Attributes:** +- `token`: The current access token, or None if unauthenticated. +- `component`: The tool, resource, resource template, or prompt being accessed. +- `tool`: Backwards-compatible alias for component when it is a Tool. + + +**Methods:** + +#### `tool` + +```python +tool(self) -> Tool | None +``` + +Backwards-compatible access to the component as a Tool. + diff --git a/docs/python-sdk/fastmcp-utilities-json_schema.mdx b/docs/python-sdk/fastmcp-utilities-json_schema.mdx index 53655abd49..ca24bc283c 100644 --- a/docs/python-sdk/fastmcp-utilities-json_schema.mdx +++ b/docs/python-sdk/fastmcp-utilities-json_schema.mdx @@ -62,7 +62,7 @@ the referenced definition while preserving $defs for nested references. - if no resolution is needed -### `compress_schema` +### `compress_schema` ```python compress_schema(schema: dict[str, Any], prune_params: list[str] | None = None, prune_additional_properties: bool = False, prune_titles: bool = False, dereference: bool = False) -> dict[str, Any] diff --git a/docs/python-sdk/fastmcp-utilities-tasks.mdx b/docs/python-sdk/fastmcp-utilities-tasks.mdx new file mode 100644 index 0000000000..ed455626eb --- /dev/null +++ b/docs/python-sdk/fastmcp-utilities-tasks.mdx @@ -0,0 +1,62 @@ +--- +title: tasks +sidebarTitle: tasks +--- + +# `fastmcp.utilities.tasks` + + +Task configuration primitives for FastMCP components. + +## Classes + +### `TaskMeta` + + +Metadata for task-augmented execution requests. + +**Attributes:** +- `ttl`: Client-requested TTL in milliseconds. If None, uses server default. +- `fn_key`: Docket routing key. Auto-derived from component name if None. + + +### `TaskConfig` + + +Configuration for MCP background task execution. + +Controls how a component handles task-augmented requests: + +- ``forbidden``: Component does not support task execution. +- ``optional``: Component supports both synchronous and task execution. +- ``required``: Component requires task execution. + + +**Methods:** + +#### `from_bool` + +```python +from_bool(cls, value: bool) -> TaskConfig +``` + +Convert a boolean task flag to a TaskConfig. + + +#### `supports_tasks` + +```python +supports_tasks(self) -> bool +``` + +Check if this component supports task execution. + + +#### `validate_function` + +```python +validate_function(self, fn: Callable[..., Any], name: str) -> None +``` + +Validate that a function is compatible with this task config. + diff --git a/docs/python-sdk/fastmcp-utilities-versions.mdx b/docs/python-sdk/fastmcp-utilities-versions.mdx index 0e390aef90..1eaa6391ac 100644 --- a/docs/python-sdk/fastmcp-utilities-versions.mdx +++ b/docs/python-sdk/fastmcp-utilities-versions.mdx @@ -22,7 +22,7 @@ Examples: ## Functions -### `parse_version_key` +### `parse_version_key` ```python parse_version_key(version: str | None) -> VersionKey @@ -38,10 +38,10 @@ Parse a version string into a sortable key. - A VersionKey suitable for sorting. -### `version_sort_key` +### `version_sort_key` ```python -version_sort_key(component: FastMCPComponent) -> VersionKey +version_sort_key(component: FastMCPComponent) -> tuple[VersionKey, str] ``` @@ -49,14 +49,22 @@ Get a sort key for a component based on its version. Use with sorted() or max() to order components by version. +The key is a `(VersionKey, raw)` tuple. The `VersionKey` orders by PEP 440 +semantics (or lexicographically for non-PEP 440 strings); the raw version +string is a deterministic tie-breaker so that two components whose versions +are PEP 440-equivalent but spelled differently (e.g. `"1"` and `"1.0"`) are +ordered reproducibly instead of by registration order. The raw tie-breaker +only affects equivalent-version ties and never the primary version order, +so range/equality matching (which uses `VersionKey` directly) is unchanged. + **Args:** - `component`: The component to get a sort key for. **Returns:** -- A sortable VersionKey. +- A deterministic, sortable `(VersionKey, raw)` tuple. -### `compare_versions` +### `compare_versions` ```python compare_versions(a: str | None, b: str | None) -> int @@ -73,7 +81,7 @@ Compare two version strings. - -1 if a < b, 0 if a == b, 1 if a > b. -### `is_version_greater` +### `is_version_greater` ```python is_version_greater(a: str | None, b: str | None) -> bool @@ -90,7 +98,7 @@ Check if version a is greater than version b. - True if a > b, False otherwise. -### `max_version` +### `max_version` ```python max_version(a: str | None, b: str | None) -> str | None @@ -107,7 +115,7 @@ Return the greater of two versions. - The greater version, or None if both are None. -### `min_version` +### `min_version` ```python min_version(a: str | None, b: str | None) -> str | None @@ -124,7 +132,7 @@ Return the lesser of two versions. - The lesser version, or None if both are None. -### `dedupe_with_versions` +### `dedupe_with_versions` ```python dedupe_with_versions(components: Sequence[C], key_fn: Callable[[C], str]) -> list[C] @@ -159,11 +167,18 @@ match any spec. - `gte`: If set, only versions >= this value match. - `lt`: If set, only versions < this value match. - `eq`: If set, only this exact version matches (gte/lt ignored). +Matching is PEP 440-normalized and `v`-prefix insensitive, so +`eq="v1.0"` matches a component versioned `"1.0"`, and `eq="1.0"` +matches `"1"` (PEP 440 treats `1` and `1.0` as the same version). +If a server registers two PEP 440-equivalent spellings of the +same component (e.g. both `"1"` and `"1.0"`), they are the same +version under this spec; selection among them is deterministic +(see `version_sort_key`), not registration-order dependent. **Methods:** -#### `matches` +#### `matches` ```python matches(self, version: str | None) -> bool @@ -182,7 +197,7 @@ from version-specific rules. - True if the version matches the spec. -#### `intersect` +#### `intersect` ```python intersect(self, other: VersionSpec | None) -> VersionSpec @@ -201,7 +216,7 @@ the intersection validates "1.0" is in range and returns the exact spec. - A VersionSpec that matches only versions satisfying both specs. -### `VersionKey` +### `VersionKey` A comparable version key that handles None, PEP 440 versions, and strings.