Refine fastmcp-slim packaging (#4125)

* Refine fastmcp-slim packaging

* Format install hints
This commit is contained in:
Jeremiah Lowin 2026-05-12 10:11:57 -04:00 committed by GitHub
commit ee48a0fd6e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 163 additions and 161 deletions

View file

@ -145,7 +145,14 @@ jobs:
import fastmcp
import fastmcp.settings
assert not any(ep.name == "fastmcp" for ep in entry_points(group="console_scripts"))
assert any(ep.name == "fastmcp" for ep in entry_points(group="console_scripts"))
try:
from fastmcp.cli import app
except ImportError as exc:
assert "FastMCP CLI support is not installed" in str(exc)
else:
raise AssertionError(f"bare fastmcp-slim unexpectedly imported CLI app {app!r}")
try:
fastmcp.FastMCP
@ -167,7 +174,14 @@ jobs:
from fastmcp.client.transports import StdioTransport, StreamableHttpTransport
from fastmcp.mcp_config import MCPConfig
assert not any(ep.name == "fastmcp" for ep in entry_points(group="console_scripts"))
assert any(ep.name == "fastmcp" for ep in entry_points(group="console_scripts"))
try:
from fastmcp.cli import app
except ImportError as exc:
assert "FastMCP CLI support is not installed" in str(exc)
else:
raise AssertionError(f"client-only slim unexpectedly imported CLI app {app!r}")
assert Client("https://example.com/mcp")
assert StreamableHttpTransport("https://example.com/mcp")
@ -188,9 +202,18 @@ jobs:
SLIM_WHEEL=$(ls /tmp/fastmcp-dist/fastmcp_slim-*.whl)
uv pip install --python /tmp/fastmcp-slim-server-smoke/bin/python "${SLIM_WHEEL}[server]"
/tmp/fastmcp-slim-server-smoke/bin/python - <<'PY'
from importlib.metadata import entry_points
from fastmcp import FastMCP
from fastmcp.cli import app
assert any(
ep.name == "fastmcp" and ep.value == "fastmcp.cli:app"
for ep in entry_points(group="console_scripts")
)
mcp = FastMCP("smoke")
assert app is not None
assert mcp.name == "smoke"
PY
@ -201,11 +224,16 @@ jobs:
uv pip install --python /tmp/fastmcp-full-smoke/bin/python --find-links /tmp/fastmcp-dist "$FULL_WHEEL"
/tmp/fastmcp-full-smoke/bin/python - <<'PY'
from importlib.metadata import entry_points
from importlib.metadata import requires
from fastmcp import Client, FastMCP
from fastmcp.client.client import CallToolResult
from fastmcp.exceptions import ToolError
fastmcp_reqs = requires("fastmcp") or []
assert any("fastmcp-slim[client,server]" in req for req in fastmcp_reqs)
assert not any("fastmcp-slim[full" in req for req in fastmcp_reqs)
assert any(
ep.name == "fastmcp" and ep.value == "fastmcp.cli:app"
for ep in entry_points(group="console_scripts")

View file

@ -5,6 +5,7 @@ import warnings
from importlib.metadata import PackageNotFoundError, version as _version
from typing import TYPE_CHECKING
from fastmcp import _install_hints
from fastmcp.settings import Settings
from fastmcp.utilities.logging import configure_logging as _configure_logging
@ -48,40 +49,28 @@ def __getattr__(name: str) -> object:
try:
from fastmcp.client import Client
except ImportError as exc:
raise ImportError(
"FastMCP client support is not installed. Install "
"`fastmcp-slim[client]` or `fastmcp`."
) from exc
raise ImportError(_install_hints.CLIENT_SUPPORT) from exc
return Client
if name == "Context":
try:
from fastmcp.server.context import Context
except ImportError as exc:
raise ImportError(
"FastMCP server support is not installed. Install "
"`fastmcp-slim[server]` or `fastmcp`."
) from exc
raise ImportError(_install_hints.SERVER_SUPPORT) from exc
return Context
if name == "FastMCP":
try:
from fastmcp.server.server import FastMCP
except ImportError as exc:
raise ImportError(
"FastMCP server support is not installed. Install "
"`fastmcp-slim[server]` or `fastmcp`."
) from exc
raise ImportError(_install_hints.SERVER_SUPPORT) from exc
return FastMCP
if name == "FastMCPApp":
try:
from fastmcp.apps.app import FastMCPApp
except ImportError as exc:
raise ImportError(
"FastMCP app support is not installed. Install "
"`fastmcp-slim[server,apps]` or `fastmcp[apps]`."
) from exc
raise ImportError(_install_hints.APP_SUPPORT) from exc
return FastMCPApp
if name == "FastMCPDeprecationWarning":
@ -92,18 +81,12 @@ def __getattr__(name: str) -> object:
try:
return importlib.import_module("fastmcp.client")
except ImportError as exc:
raise ImportError(
"FastMCP client support is not installed. Install "
"`fastmcp-slim[client]` or `fastmcp`."
) from exc
raise ImportError(_install_hints.CLIENT_SUPPORT) from exc
if name == "server":
try:
return importlib.import_module("fastmcp.server")
except ImportError as exc:
raise ImportError(
"FastMCP server support is not installed. Install "
"`fastmcp-slim[server]` or `fastmcp`."
) from exc
raise ImportError(_install_hints.SERVER_SUPPORT) from exc
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

View file

@ -0,0 +1,25 @@
CLIENT_SUPPORT = (
"FastMCP client support is not installed. Install `fastmcp` or "
"`fastmcp-slim[client]`."
)
SERVER_SUPPORT = (
"FastMCP server support is not installed. Install `fastmcp` or "
"`fastmcp-slim[server]`."
)
APP_SUPPORT = (
"FastMCP app support is not installed. Install `fastmcp[apps]` or "
"`fastmcp-slim[server,apps]`."
)
CLI_SUPPORT = (
"FastMCP CLI support is not installed. Install `fastmcp` or `fastmcp-slim[server]`."
)
def full_package(feature: str) -> str:
return (
f"{feature} require the full `fastmcp` package. "
"Install it with `pip install fastmcp`."
)

View file

@ -1,3 +1,8 @@
"""FastMCP CLI package."""
from .cli import app
try:
from .cli import app
except ImportError as exc:
from fastmcp import _install_hints
raise ImportError(_install_hints.CLI_SUPPORT) from exc

View file

@ -1,5 +1,5 @@
"""FastMCP CLI as a runnable package"""
from .cli import app
from . import app
app()

View file

@ -1,3 +1,5 @@
from fastmcp import _install_hints
try:
from .auth import OAuth, BearerAuth
from .client import Client
@ -14,10 +16,7 @@ try:
UvxStdioTransport,
)
except ImportError as exc:
raise ImportError(
"FastMCP client support is not installed. Install "
"`fastmcp-slim[client]` or `fastmcp`."
) from exc
raise ImportError(_install_hints.CLIENT_SUPPORT) from exc
__all__ = [
"BearerAuth",

View file

@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Any
from mcp import ClientSession
from typing_extensions import Unpack
from fastmcp import _install_hints
from fastmcp.client.transports.base import ClientTransport, SessionKwargs
from fastmcp.client.transports.memory import FastMCPTransport
from fastmcp.mcp_config import (
@ -105,8 +106,7 @@ class MCPConfigTransport(ClientTransport):
from fastmcp.server.server import FastMCP
except ImportError as exc:
raise ImportError(
"MCP configs with multiple servers require the full `fastmcp` "
"package for now. Install it with `pip install fastmcp`."
_install_hints.full_package("MCP configs with multiple servers")
) from exc
timeout = session_kwargs.get("read_timeout_seconds")

View file

@ -9,6 +9,7 @@ from mcp.server.fastmcp import FastMCP as FastMCP1Server
from mcp.shared.memory import create_client_server_memory_streams
from typing_extensions import Unpack
from fastmcp import _install_hints
from fastmcp.client.transports.base import ClientTransport, SessionKwargs
if TYPE_CHECKING:
@ -103,10 +104,7 @@ async def _enter_server_lifespan(
FastMCP2 = None
if FastMCP2 is None and not isinstance(server, FastMCP1Server):
raise ImportError(
"In-memory FastMCP transports require the full `fastmcp` package. "
"Install it with `pip install fastmcp`."
)
raise ImportError(_install_hints.full_package("In-memory FastMCP transports"))
if FastMCP2 is not None and isinstance(server, FastMCP2):
async with server._lifespan_manager():

View file

@ -40,6 +40,8 @@ from pydantic import (
)
from typing_extensions import Self, override
from fastmcp import _install_hints
if TYPE_CHECKING:
from fastmcp.client.transports import (
ClientTransport,
@ -129,8 +131,9 @@ class _TransformingMCPServerMixin(BaseModel):
from fastmcp.server.transforms import ToolTransform
except ImportError as exc:
raise ImportError(
"MCP configs that use FastMCP-specific tool transforms or tag filters "
"require the full `fastmcp` package. Install it with `pip install fastmcp`."
_install_hints.full_package(
"MCP configs that use FastMCP-specific tool transforms or tag filters"
)
) from exc
transport = cast("ClientTransport", super().to_transport()) # ty: ignore[unresolved-attribute]
@ -154,8 +157,9 @@ class _TransformingMCPServerMixin(BaseModel):
from fastmcp.client.transports import FastMCPTransport
except ImportError as exc:
raise ImportError(
"MCP configs that use FastMCP-specific tool transforms or tag filters "
"require the full `fastmcp` package. Install it with `pip install fastmcp`."
_install_hints.full_package(
"MCP configs that use FastMCP-specific tool transforms or tag filters"
)
) from exc
return FastMCPTransport(mcp=self._to_server_and_underlying_transport()[0])

View file

@ -1,13 +1,12 @@
import importlib
from fastmcp import _install_hints
try:
from .context import Context
from .server import FastMCP, create_proxy
except ImportError as exc:
raise ImportError(
"FastMCP server support is not installed. Install "
"`fastmcp-slim[server]` or `fastmcp`."
) from exc
raise ImportError(_install_hints.SERVER_SUPPORT) from exc
def __getattr__(name: str) -> object:

View file

@ -1,6 +1,6 @@
[project]
name = "fastmcp-slim"
dynamic = ["version"]
dynamic = ["version", "optional-dependencies"]
description = "The dependency-slim FastMCP package."
authors = [{ name = "Jeremiah Lowin" }]
dependencies = [
@ -36,32 +36,60 @@ classifiers = [
"Typing :: Typed",
]
[project.optional-dependencies]
[project.urls]
Homepage = "https://gofastmcp.com"
Repository = "https://github.com/PrefectHQ/fastmcp"
Documentation = "https://gofastmcp.com"
[project.scripts]
fastmcp = "fastmcp.cli:app"
[build-system]
requires = ["hatchling", "uv-dynamic-versioning>=0.7.0"]
build-backend = "hatchling.build"
[tool.hatch.version]
source = "uv-dynamic-versioning"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["fastmcp"]
[tool.uv-dynamic-versioning]
vcs = "git"
style = "pep440"
bump = true
fallback-version = "0.0.0"
[tool.hatch.metadata.hooks.uv-dynamic-versioning.optional-dependencies]
anthropic = ["anthropic>=0.48.0"]
apps = ["prefab-ui>=0.18.0"]
# PyJWT floor: transitive via msal; CVE-2026-32597 affects <= 2.11.0
azure = ["azure-identity>=1.16.0", "PyJWT>=2.12.0"]
client = [
"fastmcp-slim[mcp]=={{ version }}",
"authlib>=1.6.11",
"exceptiongroup>=1.2.2",
"httpx>=0.28.1,<1.0",
"mcp>=1.24.0,<2.0",
"opentelemetry-api>=1.20.0",
"py-key-value-aio[filetree,keyring,memory]>=0.4.4,<0.5.0",
]
code-mode = ["pydantic-monty==0.0.16"]
gemini = ["google-genai>=1.18.0", "jsonref>=1.1.0"]
full = [
mcp = [
"exceptiongroup>=1.2.2",
"httpx>=0.28.1,<1.0",
"mcp>=1.24.0,<2.0",
"opentelemetry-api>=1.20.0",
]
openai = ["openai>=1.102.0"]
server = [
"fastmcp-slim[mcp]=={{ version }}",
"authlib>=1.6.11",
"cyclopts>=4.0.0",
"exceptiongroup>=1.2.2",
"griffelib>=2.0.0",
"httpx>=0.28.1,<1.0",
"jsonref>=1.1.0",
"jsonschema-path>=0.3.4",
"mcp>=1.24.0,<2.0",
"openapi-pydantic>=0.5.1",
"opentelemetry-api>=1.20.0",
"packaging>=24.0",
"py-key-value-aio[filetree,keyring,memory]>=0.4.4,<0.5.0",
"pyperclip>=1.9.0",
@ -72,46 +100,4 @@ full = [
"watchfiles>=1.0.0",
"websockets>=15.0.1",
]
openai = ["openai>=1.102.0"]
server = [
"authlib>=1.6.11",
"exceptiongroup>=1.2.2",
"griffelib>=2.0.0",
"httpx>=0.28.1,<1.0",
"jsonref>=1.1.0",
"jsonschema-path>=0.3.4",
"mcp>=1.24.0,<2.0",
"openapi-pydantic>=0.5.1",
"opentelemetry-api>=1.20.0",
"packaging>=24.0",
"py-key-value-aio[filetree,keyring,memory]>=0.4.4,<0.5.0",
"python-multipart>=0.0.26",
"pyyaml>=6.0,<7.0",
"uncalled-for>=0.2.0",
"uvicorn>=0.35",
"watchfiles>=1.0.0",
"websockets>=15.0.1",
]
tasks = ["pydocket>=0.20.0"]
[project.urls]
Homepage = "https://gofastmcp.com"
Repository = "https://github.com/PrefectHQ/fastmcp"
Documentation = "https://gofastmcp.com"
[build-system]
requires = ["hatchling", "uv-dynamic-versioning>=0.7.0"]
build-backend = "hatchling.build"
[tool.hatch.version]
source = "uv-dynamic-versioning"
[tool.hatch.build.targets.wheel]
packages = ["fastmcp"]
[tool.uv-dynamic-versioning]
vcs = "git"
style = "pep440"
bump = true
fallback-version = "0.0.0"

View file

@ -31,9 +31,6 @@ Homepage = "https://gofastmcp.com"
Repository = "https://github.com/PrefectHQ/fastmcp"
Documentation = "https://gofastmcp.com"
[project.scripts]
fastmcp = "fastmcp.cli:app"
[build-system]
requires = ["hatchling", "uv-dynamic-versioning>=0.7.0"]
build-backend = "hatchling.build"
@ -43,21 +40,25 @@ source = "uv-dynamic-versioning"
[tool.hatch.build.targets.wheel]
bypass-selection = true
only-include = []
exclude = ["/*"]
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.metadata.hooks.uv-dynamic-versioning]
dependencies = ["fastmcp-slim[full]=={{ version }}"]
dependencies = [
"fastmcp-slim[client,server]=={{ version }}",
]
[tool.hatch.metadata.hooks.uv-dynamic-versioning.optional-dependencies]
anthropic = ["fastmcp-slim[full,anthropic]=={{ version }}"]
apps = ["fastmcp-slim[full,apps]=={{ version }}"]
azure = ["fastmcp-slim[full,azure]=={{ version }}"]
code-mode = ["fastmcp-slim[full,code-mode]=={{ version }}"]
gemini = ["fastmcp-slim[full,gemini]=={{ version }}"]
openai = ["fastmcp-slim[full,openai]=={{ version }}"]
tasks = ["fastmcp-slim[full,tasks]=={{ version }}"]
anthropic = ["fastmcp-slim[anthropic]=={{ version }}"]
apps = ["fastmcp-slim[apps]=={{ version }}"]
azure = ["fastmcp-slim[azure]=={{ version }}"]
code-mode = ["fastmcp-slim[code-mode]=={{ version }}"]
gemini = ["fastmcp-slim[gemini]=={{ version }}"]
openai = ["fastmcp-slim[openai]=={{ version }}"]
tasks = ["fastmcp-slim[tasks]=={{ version }}"]
[tool.uv-dynamic-versioning]
vcs = "git"

100
uv.lock generated
View file

@ -830,30 +830,30 @@ wheels = [
name = "fastmcp"
source = { editable = "." }
dependencies = [
{ name = "fastmcp-slim", extra = ["full"] },
{ name = "fastmcp-slim", extra = ["client", "server"] },
]
[package.optional-dependencies]
anthropic = [
{ name = "fastmcp-slim", extra = ["anthropic", "full"] },
{ name = "fastmcp-slim", extra = ["anthropic"] },
]
apps = [
{ name = "fastmcp-slim", extra = ["apps", "full"] },
{ name = "fastmcp-slim", extra = ["apps"] },
]
azure = [
{ name = "fastmcp-slim", extra = ["azure", "full"] },
{ name = "fastmcp-slim", extra = ["azure"] },
]
code-mode = [
{ name = "fastmcp-slim", extra = ["code-mode", "full"] },
{ name = "fastmcp-slim", extra = ["code-mode"] },
]
gemini = [
{ name = "fastmcp-slim", extra = ["full", "gemini"] },
{ name = "fastmcp-slim", extra = ["gemini"] },
]
openai = [
{ name = "fastmcp-slim", extra = ["full", "openai"] },
{ name = "fastmcp-slim", extra = ["openai"] },
]
tasks = [
{ name = "fastmcp-slim", extra = ["full", "tasks"] },
{ name = "fastmcp-slim", extra = ["tasks"] },
]
[package.dev-dependencies]
@ -890,14 +890,14 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "fastmcp-slim", extras = ["anthropic", "full"], marker = "extra == 'anthropic'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["apps", "full"], marker = "extra == 'apps'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["azure", "full"], marker = "extra == 'azure'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["code-mode", "full"], marker = "extra == 'code-mode'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["full"], editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["full", "gemini"], marker = "extra == 'gemini'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["full", "openai"], marker = "extra == 'openai'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["full", "tasks"], marker = "extra == 'tasks'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["anthropic"], marker = "extra == 'anthropic'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["apps"], marker = "extra == 'apps'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["azure"], marker = "extra == 'azure'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["client", "server"], editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["code-mode"], marker = "extra == 'code-mode'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["gemini"], marker = "extra == 'gemini'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["openai"], marker = "extra == 'openai'", editable = "fastmcp_slim" },
{ name = "fastmcp-slim", extras = ["tasks"], marker = "extra == 'tasks'", editable = "fastmcp_slim" },
]
provides-extras = ["anthropic", "apps", "azure", "code-mode", "gemini", "openai", "tasks"]
@ -965,7 +965,20 @@ client = [
code-mode = [
{ name = "pydantic-monty" },
]
full = [
gemini = [
{ name = "google-genai" },
{ name = "jsonref" },
]
mcp = [
{ name = "exceptiongroup" },
{ name = "httpx" },
{ name = "mcp" },
{ name = "opentelemetry-api" },
]
openai = [
{ name = "openai" },
]
server = [
{ name = "authlib" },
{ name = "cyclopts" },
{ name = "exceptiongroup" },
@ -986,32 +999,6 @@ full = [
{ name = "watchfiles" },
{ name = "websockets" },
]
gemini = [
{ name = "google-genai" },
{ name = "jsonref" },
]
openai = [
{ name = "openai" },
]
server = [
{ name = "authlib" },
{ name = "exceptiongroup" },
{ name = "griffelib" },
{ name = "httpx" },
{ name = "jsonref" },
{ name = "jsonschema-path" },
{ name = "mcp" },
{ name = "openapi-pydantic" },
{ name = "opentelemetry-api" },
{ name = "packaging" },
{ name = "py-key-value-aio", extra = ["filetree", "keyring", "memory"] },
{ name = "python-multipart" },
{ name = "pyyaml" },
{ name = "uncalled-for" },
{ name = "uvicorn" },
{ name = "watchfiles" },
{ name = "websockets" },
]
tasks = [
{ name = "pydocket" },
]
@ -1020,63 +1007,50 @@ tasks = [
requires-dist = [
{ name = "anthropic", marker = "extra == 'anthropic'", specifier = ">=0.48.0" },
{ name = "authlib", marker = "extra == 'client'", specifier = ">=1.6.11" },
{ name = "authlib", marker = "extra == 'full'", specifier = ">=1.6.11" },
{ name = "authlib", marker = "extra == 'server'", specifier = ">=1.6.11" },
{ name = "azure-identity", marker = "extra == 'azure'", specifier = ">=1.16.0" },
{ name = "cyclopts", marker = "extra == 'full'", specifier = ">=4.0.0" },
{ name = "cyclopts", marker = "extra == 'server'", specifier = ">=4.0.0" },
{ name = "exceptiongroup", marker = "extra == 'client'", specifier = ">=1.2.2" },
{ name = "exceptiongroup", marker = "extra == 'full'", specifier = ">=1.2.2" },
{ name = "exceptiongroup", marker = "extra == 'mcp'", specifier = ">=1.2.2" },
{ name = "exceptiongroup", marker = "extra == 'server'", specifier = ">=1.2.2" },
{ name = "google-genai", marker = "extra == 'gemini'", specifier = ">=1.18.0" },
{ name = "griffelib", marker = "extra == 'full'", specifier = ">=2.0.0" },
{ name = "griffelib", marker = "extra == 'server'", specifier = ">=2.0.0" },
{ name = "httpx", marker = "extra == 'client'", specifier = ">=0.28.1,<1.0" },
{ name = "httpx", marker = "extra == 'full'", specifier = ">=0.28.1,<1.0" },
{ name = "httpx", marker = "extra == 'mcp'", specifier = ">=0.28.1,<1.0" },
{ name = "httpx", marker = "extra == 'server'", specifier = ">=0.28.1,<1.0" },
{ name = "jsonref", marker = "extra == 'full'", specifier = ">=1.1.0" },
{ name = "jsonref", marker = "extra == 'gemini'", specifier = ">=1.1.0" },
{ name = "jsonref", marker = "extra == 'server'", specifier = ">=1.1.0" },
{ name = "jsonschema-path", marker = "extra == 'full'", specifier = ">=0.3.4" },
{ name = "jsonschema-path", marker = "extra == 'server'", specifier = ">=0.3.4" },
{ name = "mcp", marker = "extra == 'client'", specifier = ">=1.24.0,<2.0" },
{ name = "mcp", marker = "extra == 'full'", specifier = ">=1.24.0,<2.0" },
{ name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.24.0,<2.0" },
{ name = "mcp", marker = "extra == 'server'", specifier = ">=1.24.0,<2.0" },
{ name = "openai", marker = "extra == 'openai'", specifier = ">=1.102.0" },
{ name = "openapi-pydantic", marker = "extra == 'full'", specifier = ">=0.5.1" },
{ name = "openapi-pydantic", marker = "extra == 'server'", specifier = ">=0.5.1" },
{ name = "opentelemetry-api", marker = "extra == 'client'", specifier = ">=1.20.0" },
{ name = "opentelemetry-api", marker = "extra == 'full'", specifier = ">=1.20.0" },
{ name = "opentelemetry-api", marker = "extra == 'mcp'", specifier = ">=1.20.0" },
{ name = "opentelemetry-api", marker = "extra == 'server'", specifier = ">=1.20.0" },
{ name = "packaging", marker = "extra == 'full'", specifier = ">=24.0" },
{ name = "packaging", marker = "extra == 'server'", specifier = ">=24.0" },
{ name = "platformdirs", specifier = ">=4.0.0" },
{ name = "prefab-ui", marker = "extra == 'apps'", specifier = ">=0.18.0" },
{ name = "py-key-value-aio", extras = ["filetree", "keyring", "memory"], marker = "extra == 'client'", specifier = ">=0.4.4,<0.5.0" },
{ name = "py-key-value-aio", extras = ["filetree", "keyring", "memory"], marker = "extra == 'full'", specifier = ">=0.4.4,<0.5.0" },
{ name = "py-key-value-aio", extras = ["filetree", "keyring", "memory"], marker = "extra == 'server'", specifier = ">=0.4.4,<0.5.0" },
{ name = "pydantic", extras = ["email"], specifier = ">=2.11.7" },
{ name = "pydantic-monty", marker = "extra == 'code-mode'", specifier = "==0.0.16" },
{ name = "pydantic-settings", specifier = ">=2.0.0" },
{ name = "pydocket", marker = "extra == 'tasks'", specifier = ">=0.20.0" },
{ name = "pyjwt", marker = "extra == 'azure'", specifier = ">=2.12.0" },
{ name = "pyperclip", marker = "extra == 'full'", specifier = ">=1.9.0" },
{ name = "pyperclip", marker = "extra == 'server'", specifier = ">=1.9.0" },
{ name = "python-dotenv", specifier = ">=1.1.0" },
{ name = "python-multipart", marker = "extra == 'full'", specifier = ">=0.0.26" },
{ name = "python-multipart", marker = "extra == 'server'", specifier = ">=0.0.26" },
{ name = "pyyaml", marker = "extra == 'full'", specifier = ">=6.0,<7.0" },
{ name = "pyyaml", marker = "extra == 'server'", specifier = ">=6.0,<7.0" },
{ name = "rich", specifier = ">=13.9.4" },
{ name = "typing-extensions", specifier = ">=4.0.0" },
{ name = "uncalled-for", marker = "extra == 'full'", specifier = ">=0.2.0" },
{ name = "uncalled-for", marker = "extra == 'server'", specifier = ">=0.2.0" },
{ name = "uvicorn", marker = "extra == 'full'", specifier = ">=0.35" },
{ name = "uvicorn", marker = "extra == 'server'", specifier = ">=0.35" },
{ name = "watchfiles", marker = "extra == 'full'", specifier = ">=1.0.0" },
{ name = "watchfiles", marker = "extra == 'server'", specifier = ">=1.0.0" },
{ name = "websockets", marker = "extra == 'full'", specifier = ">=15.0.1" },
{ name = "websockets", marker = "extra == 'server'", specifier = ">=15.0.1" },
]
provides-extras = ["anthropic", "apps", "azure", "client", "code-mode", "full", "gemini", "openai", "server", "tasks"]
provides-extras = ["anthropic", "apps", "azure", "client", "code-mode", "gemini", "mcp", "openai", "server", "tasks"]
[[package]]
name = "google-auth"