From 242850c0f3de9106eec43ebd3a35aad5dccb647b Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Tue, 21 Jul 2026 20:44:54 -0400 Subject: [PATCH] Scaffold fastmcp-tasks workspace package Co-Authored-By: Claude --- fastmcp_slim/pyproject.toml | 1 - fastmcp_tasks/README.md | 9 ++++ fastmcp_tasks/fastmcp_tasks/__init__.py | 10 +++++ fastmcp_tasks/fastmcp_tasks/py.typed | 1 + fastmcp_tasks/pyproject.toml | 57 +++++++++++++++++++++++++ pyproject.toml | 9 ++-- uv.lock | 27 ++++++++---- 7 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 fastmcp_tasks/README.md create mode 100644 fastmcp_tasks/fastmcp_tasks/__init__.py create mode 100644 fastmcp_tasks/fastmcp_tasks/py.typed create mode 100644 fastmcp_tasks/pyproject.toml diff --git a/fastmcp_slim/pyproject.toml b/fastmcp_slim/pyproject.toml index bb78b47a2..e23dfca8c 100644 --- a/fastmcp_slim/pyproject.toml +++ b/fastmcp_slim/pyproject.toml @@ -108,4 +108,3 @@ server = [ "watchfiles>=1.0.0", "websockets>=15.0.1", ] -tasks = ["pydocket>=0.20.0"] diff --git a/fastmcp_tasks/README.md b/fastmcp_tasks/README.md new file mode 100644 index 000000000..53c9f0902 --- /dev/null +++ b/fastmcp_tasks/README.md @@ -0,0 +1,9 @@ +# fastmcp-tasks + +`fastmcp-tasks` provides background task execution for FastMCP servers via the `io.modelcontextprotocol/tasks` extension ([SEP-2663](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2663)). + +It bundles the task-queue dependencies (powered by [docket](https://github.com/chrisguidry/docket)) that FastMCP's `tasks` extra requires. Install it alongside [FastMCP](https://gofastmcp.com) to run long-lived tools as background tasks instead of blocking a request for their full duration. + +```bash +uv pip install "fastmcp[tasks]" +``` diff --git a/fastmcp_tasks/fastmcp_tasks/__init__.py b/fastmcp_tasks/fastmcp_tasks/__init__.py new file mode 100644 index 000000000..9880ae3b6 --- /dev/null +++ b/fastmcp_tasks/fastmcp_tasks/__init__.py @@ -0,0 +1,10 @@ +"""Background task execution for FastMCP via the SEP-2663 tasks extension.""" + +from importlib.metadata import PackageNotFoundError, version + +try: + __version__ = version("fastmcp-tasks") +except PackageNotFoundError: + __version__ = "0.0.0" + +__all__ = ["__version__"] diff --git a/fastmcp_tasks/fastmcp_tasks/py.typed b/fastmcp_tasks/fastmcp_tasks/py.typed new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/fastmcp_tasks/fastmcp_tasks/py.typed @@ -0,0 +1 @@ + diff --git a/fastmcp_tasks/pyproject.toml b/fastmcp_tasks/pyproject.toml new file mode 100644 index 000000000..bed6d05f0 --- /dev/null +++ b/fastmcp_tasks/pyproject.toml @@ -0,0 +1,57 @@ +[project] +name = "fastmcp-tasks" +dynamic = ["version", "dependencies"] +description = "Background task execution for FastMCP servers via the io.modelcontextprotocol/tasks extension (SEP-2663)." +authors = [{ name = "Jeremiah Lowin" }] + +requires-python = ">=3.10" +readme = "README.md" +license = "Apache-2.0" + +keywords = [ + "mcp", + "fastmcp tasks", + "background tasks", + "model context protocol", + "fastmcp", +] +classifiers = [ + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Topic :: Scientific/Engineering :: Artificial Intelligence", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Typing :: Typed", +] + +[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.metadata] +allow-direct-references = true + +[tool.hatch.build.targets.wheel] +packages = ["fastmcp_tasks"] + +[tool.uv-dynamic-versioning] +vcs = "git" +style = "pep440" +bump = true +fallback-version = "0.0.0" + +[tool.hatch.metadata.hooks.uv-dynamic-versioning] +dependencies = [ + "fastmcp-slim[server]=={{ version }}", + "pydocket>=0.20.0", +] diff --git a/pyproject.toml b/pyproject.toml index 281bc9ef8..71bad7539 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,7 +58,7 @@ 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 }}"] +tasks = ["fastmcp-tasks=={{ version }}"] [tool.uv-dynamic-versioning] vcs = "git" @@ -67,7 +67,7 @@ bump = true fallback-version = "0.0.0" [tool.uv.workspace] -members = ["fastmcp_slim", "fastmcp_remote"] +members = ["fastmcp_slim", "fastmcp_remote", "fastmcp_tasks"] [tool.uv] default-groups = ["dev"] @@ -108,6 +108,7 @@ dev = [ fastmcp = { workspace = true } fastmcp-slim = { workspace = true } fastmcp-remote = { workspace = true } +fastmcp-tasks = { workspace = true } [tool.pytest.ini_options] asyncio_mode = "auto" @@ -129,7 +130,7 @@ markers = [ "subprocess_heavy: marks tests that spawn a fresh Python interpreter which imports FastMCP. Each one costs a full interpreter's memory and startup, so they run serially alongside client_process tests rather than competing with parallel xdist workers.", "conformance: marks MCP conformance tests (require Node.js/npx)", ] -pythonpath = ["fastmcp_slim", "fastmcp_remote"] +pythonpath = ["fastmcp_slim", "fastmcp_remote", "fastmcp_tasks"] testpaths = ["tests"] python_files = ["test_*.py", "*_test.py"] python_classes = ["Test*"] @@ -137,7 +138,7 @@ python_functions = ["test_*"] addopts = ["--inline-snapshot=disable"] [tool.ty.src] -include = ["fastmcp_slim", "fastmcp_remote", "tests", "examples"] +include = ["fastmcp_slim", "fastmcp_remote", "fastmcp_tasks", "tests", "examples"] exclude = [ "**/node_modules", "**/__pycache__", diff --git a/uv.lock b/uv.lock index 640c1a367..a671a51ed 100644 --- a/uv.lock +++ b/uv.lock @@ -10,7 +10,7 @@ resolution-markers = [ ] [options] -exclude-newer = "2026-07-07T19:26:14.279827Z" +exclude-newer = "2026-07-15T00:39:08.277536Z" exclude-newer-span = "P1W" [options.exclude-newer-package] @@ -26,6 +26,7 @@ members = [ "fastmcp", "fastmcp-remote", "fastmcp-slim", + "fastmcp-tasks", ] [[package]] @@ -864,7 +865,7 @@ openai = [ { name = "fastmcp-slim", extra = ["openai"] }, ] tasks = [ - { name = "fastmcp-slim", extra = ["tasks"] }, + { name = "fastmcp-tasks" }, ] [package.dev-dependencies] @@ -908,7 +909,7 @@ requires-dist = [ { 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" }, + { name = "fastmcp-tasks", marker = "extra == 'tasks'", editable = "fastmcp_tasks" }, ] provides-extras = ["anthropic", "apps", "azure", "code-mode", "gemini", "openai", "tasks"] @@ -1025,9 +1026,6 @@ server = [ { name = "watchfiles" }, { name = "websockets" }, ] -tasks = [ - { name = "pydocket" }, -] [package.metadata] requires-dist = [ @@ -1065,7 +1063,6 @@ requires-dist = [ { name = "pydantic", extras = ["email"], specifier = ">=2.12.0" }, { name = "pydantic-monty", marker = "extra == 'code-mode'", specifier = "==0.0.17" }, { 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 == 'server'", specifier = ">=1.9.0" }, { name = "python-dotenv", specifier = ">=1.1.0" }, @@ -1081,7 +1078,21 @@ requires-dist = [ { name = "watchfiles", marker = "extra == 'server'", specifier = ">=1.0.0" }, { name = "websockets", marker = "extra == 'server'", specifier = ">=15.0.1" }, ] -provides-extras = ["anthropic", "apps", "azure", "client", "code-mode", "gemini", "mcp", "openai", "server", "tasks"] +provides-extras = ["anthropic", "apps", "azure", "client", "code-mode", "gemini", "mcp", "openai", "server"] + +[[package]] +name = "fastmcp-tasks" +source = { editable = "fastmcp_tasks" } +dependencies = [ + { name = "fastmcp-slim", extra = ["server"] }, + { name = "pydocket" }, +] + +[package.metadata] +requires-dist = [ + { name = "fastmcp-slim", extras = ["server"], editable = "fastmcp_slim" }, + { name = "pydocket", specifier = ">=0.20.0" }, +] [[package]] name = "google-auth"