fastmcp-tasks 4.0.0a2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastmcp_tasks-4.0.0a2/.gitignore +80 -0
- fastmcp_tasks-4.0.0a2/PKG-INFO +107 -0
- fastmcp_tasks-4.0.0a2/README.md +83 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/__init__.py +20 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/client.py +567 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/client_models.py +130 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/components.py +182 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/context.py +571 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/creation.py +245 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/dependencies.py +184 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/extension.py +299 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/handlers.py +433 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/input_loop.py +200 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/input_store.py +505 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/keys.py +206 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/lifespan.py +108 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/models.py +197 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/py.typed +1 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/settings.py +165 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/wire_production.py +111 -0
- fastmcp_tasks-4.0.0a2/fastmcp_tasks/worker_cli.py +146 -0
- fastmcp_tasks-4.0.0a2/pyproject.toml +68 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
wheels/
|
|
8
|
+
*.egg-info/
|
|
9
|
+
*.egg
|
|
10
|
+
MANIFEST
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.loq_cache
|
|
13
|
+
.coverage
|
|
14
|
+
htmlcov/
|
|
15
|
+
.tox/
|
|
16
|
+
nosetests.xml
|
|
17
|
+
coverage.xml
|
|
18
|
+
*.cover
|
|
19
|
+
|
|
20
|
+
# Virtual environments
|
|
21
|
+
.venv
|
|
22
|
+
venv/
|
|
23
|
+
env/
|
|
24
|
+
ENV/
|
|
25
|
+
.env
|
|
26
|
+
|
|
27
|
+
# System files
|
|
28
|
+
.DS_Store
|
|
29
|
+
|
|
30
|
+
# Version file
|
|
31
|
+
src/fastmcp/_version.py
|
|
32
|
+
|
|
33
|
+
# Editors and IDEs
|
|
34
|
+
.cursorrules
|
|
35
|
+
.vscode/
|
|
36
|
+
.idea/
|
|
37
|
+
*.swp
|
|
38
|
+
*.swo
|
|
39
|
+
*~
|
|
40
|
+
.project
|
|
41
|
+
.pydevproject
|
|
42
|
+
.settings/
|
|
43
|
+
|
|
44
|
+
# Jupyter Notebook
|
|
45
|
+
.ipynb_checkpoints
|
|
46
|
+
|
|
47
|
+
# Type checking
|
|
48
|
+
.mypy_cache/
|
|
49
|
+
.dmypy.json
|
|
50
|
+
dmypy.json
|
|
51
|
+
.pyre/
|
|
52
|
+
.pytype/
|
|
53
|
+
|
|
54
|
+
# Local development
|
|
55
|
+
.python-version
|
|
56
|
+
.envrc
|
|
57
|
+
.envrc.private
|
|
58
|
+
.direnv/
|
|
59
|
+
|
|
60
|
+
# Logs and databases
|
|
61
|
+
*.log
|
|
62
|
+
*.sqlite
|
|
63
|
+
*.db
|
|
64
|
+
*.ddb
|
|
65
|
+
|
|
66
|
+
# Claude worktree management
|
|
67
|
+
.claude-wt/worktrees
|
|
68
|
+
.claude/worktrees/
|
|
69
|
+
|
|
70
|
+
# Agents
|
|
71
|
+
/PLAN.md
|
|
72
|
+
/TODO.md
|
|
73
|
+
/STATUS.md
|
|
74
|
+
plans/
|
|
75
|
+
|
|
76
|
+
# Common FastMCP test files
|
|
77
|
+
/test.py
|
|
78
|
+
/server.py
|
|
79
|
+
/client.py
|
|
80
|
+
/test.json
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastmcp-tasks
|
|
3
|
+
Version: 4.0.0a2
|
|
4
|
+
Summary: Background task execution for FastMCP servers via the io.modelcontextprotocol/tasks extension (SEP-2663).
|
|
5
|
+
Project-URL: Homepage, https://gofastmcp.com
|
|
6
|
+
Project-URL: Repository, https://github.com/PrefectHQ/fastmcp
|
|
7
|
+
Project-URL: Documentation, https://gofastmcp.com
|
|
8
|
+
Author: Jeremiah Lowin
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Keywords: background tasks,fastmcp,fastmcp tasks,mcp,model context protocol
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: burner-redis<0.1.7; sys_platform == 'win32'
|
|
21
|
+
Requires-Dist: fastmcp-slim[server]==4.0.0a2
|
|
22
|
+
Requires-Dist: pydocket>=0.20.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# fastmcp-tasks
|
|
26
|
+
|
|
27
|
+
A complete implementation of background tasks for the Model Context Protocol — the `io.modelcontextprotocol/tasks` extension defined in [SEP-2663](https://github.com/modelcontextprotocol/ext-tasks).
|
|
28
|
+
|
|
29
|
+
The MCP tasks extension is a Final SEP, but as of this writing it ships in the ecosystem as a schema and a prose specification — no language SDK provides a working runtime for it. `fastmcp-tasks` is, to our knowledge, the first: a full server-side implementation of the protocol, built on the durable execution engine ([docket](https://github.com/chrisguidry/docket)) that FastMCP has run in production since v3. If you want to actually *run* MCP background tasks today, this is the implementation.
|
|
30
|
+
|
|
31
|
+
## What background tasks are
|
|
32
|
+
|
|
33
|
+
Most tool calls are synchronous: the client sends `tools/call` and holds the request open until the tool returns. That breaks down for work that takes minutes or hours — a long analysis, a batch job, a slow external API. The tasks extension lets a server answer such a call *immediately* with a durable task handle, then run the work in the background while the client polls for completion on its own schedule.
|
|
34
|
+
|
|
35
|
+
The model is poll-based and stateless by construction, which is what makes it survive disconnects, server restarts, and load balancers:
|
|
36
|
+
|
|
37
|
+
1. A client that supports tasks issues a normal `tools/call` with a per-request opt-in.
|
|
38
|
+
2. The server decides whether to run it as a task. If it does, it returns a `CreateTaskResult` carrying a server-generated task id — right away, before the work starts.
|
|
39
|
+
3. The client polls `tasks/get` until the task reaches a terminal state, then reads the result inlined in the response.
|
|
40
|
+
4. `tasks/cancel` requests cancellation; `tasks/update` answers any input the task asks for mid-run.
|
|
41
|
+
|
|
42
|
+
The server owns the task's durable state, so the client can poll across independent requests — from any process, after a crash, through any replica — with no session affinity required.
|
|
43
|
+
|
|
44
|
+
## Usage
|
|
45
|
+
|
|
46
|
+
Install it as the `tasks` extra on FastMCP:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uv pip install "fastmcp[tasks]"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Register the extension on your server and mark the tools that may run as tasks. The extension is where the backend is configured — point it at Redis for a distributed deployment, or leave it on the in-memory default for a single process:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from fastmcp import FastMCP
|
|
56
|
+
from fastmcp_tasks import TasksExtension
|
|
57
|
+
|
|
58
|
+
mcp = FastMCP("Analytics")
|
|
59
|
+
mcp.add_extension(TasksExtension(url="redis://localhost:6379/0"))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@mcp.tool(task=True)
|
|
63
|
+
async def analyze(dataset: str) -> str:
|
|
64
|
+
# Long-running work. The client gets a task handle immediately and
|
|
65
|
+
# polls for the result; this runs in a background worker.
|
|
66
|
+
...
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`task=True` is a declaration of intent — this tool *may* run as a task — while the server, per the spec, decides per call whether to actually task it. Use `TaskConfig` for finer control:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from fastmcp.utilities.tasks import TaskConfig
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@mcp.tool(task=TaskConfig(mode="required"))
|
|
76
|
+
async def must_run_async(n: int) -> int:
|
|
77
|
+
# Always runs as a task; a client that has not opted in is told so.
|
|
78
|
+
...
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Registering `TasksExtension` is required to serve `task=True` tools — the tool declares intent, the extension provides the engine. A `task=True` tool on a server with no tasks extension registered fails loudly at startup rather than silently running inline.
|
|
82
|
+
|
|
83
|
+
### Running out-of-process workers
|
|
84
|
+
|
|
85
|
+
For distributed deployments backed by Redis, run dedicated worker processes alongside your server:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
python -m fastmcp_tasks.worker_cli worker server.py
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Workers and servers that share a backend URL and queue name share a task queue, so you can scale execution independently of your request-serving frontends.
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
The backend is configured on the extension. Every option also has a `FASTMCP_DOCKET_*` environment variable, so an env-configured deployment can construct `TasksExtension()` with no arguments:
|
|
96
|
+
|
|
97
|
+
| Option | Env var | Default | Description |
|
|
98
|
+
| --- | --- | --- | --- |
|
|
99
|
+
| `url` | `FASTMCP_DOCKET_URL` | `memory://` | Backend URL. `memory://` for single-process; `redis://host:port/db` for distributed workers. |
|
|
100
|
+
| `name` | `FASTMCP_DOCKET_NAME` | `fastmcp` | Queue name. Servers and workers sharing a name and URL share a queue. |
|
|
101
|
+
| `concurrency` | `FASTMCP_DOCKET_CONCURRENCY` | `10` | Maximum concurrent tasks per worker. |
|
|
102
|
+
|
|
103
|
+
See the [FastMCP task documentation](https://gofastmcp.com/servers/tasks) for the full reference.
|
|
104
|
+
|
|
105
|
+
## Status
|
|
106
|
+
|
|
107
|
+
The tasks extension is an experimental MCP extension, and `fastmcp-tasks` tracks its draft schema. The protocol's shape is settled — SEP-2663 is Final — but field-level details may still move; this package versions independently so it can follow the schema without waiting on a FastMCP release.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# fastmcp-tasks
|
|
2
|
+
|
|
3
|
+
A complete implementation of background tasks for the Model Context Protocol — the `io.modelcontextprotocol/tasks` extension defined in [SEP-2663](https://github.com/modelcontextprotocol/ext-tasks).
|
|
4
|
+
|
|
5
|
+
The MCP tasks extension is a Final SEP, but as of this writing it ships in the ecosystem as a schema and a prose specification — no language SDK provides a working runtime for it. `fastmcp-tasks` is, to our knowledge, the first: a full server-side implementation of the protocol, built on the durable execution engine ([docket](https://github.com/chrisguidry/docket)) that FastMCP has run in production since v3. If you want to actually *run* MCP background tasks today, this is the implementation.
|
|
6
|
+
|
|
7
|
+
## What background tasks are
|
|
8
|
+
|
|
9
|
+
Most tool calls are synchronous: the client sends `tools/call` and holds the request open until the tool returns. That breaks down for work that takes minutes or hours — a long analysis, a batch job, a slow external API. The tasks extension lets a server answer such a call *immediately* with a durable task handle, then run the work in the background while the client polls for completion on its own schedule.
|
|
10
|
+
|
|
11
|
+
The model is poll-based and stateless by construction, which is what makes it survive disconnects, server restarts, and load balancers:
|
|
12
|
+
|
|
13
|
+
1. A client that supports tasks issues a normal `tools/call` with a per-request opt-in.
|
|
14
|
+
2. The server decides whether to run it as a task. If it does, it returns a `CreateTaskResult` carrying a server-generated task id — right away, before the work starts.
|
|
15
|
+
3. The client polls `tasks/get` until the task reaches a terminal state, then reads the result inlined in the response.
|
|
16
|
+
4. `tasks/cancel` requests cancellation; `tasks/update` answers any input the task asks for mid-run.
|
|
17
|
+
|
|
18
|
+
The server owns the task's durable state, so the client can poll across independent requests — from any process, after a crash, through any replica — with no session affinity required.
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Install it as the `tasks` extra on FastMCP:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
uv pip install "fastmcp[tasks]"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Register the extension on your server and mark the tools that may run as tasks. The extension is where the backend is configured — point it at Redis for a distributed deployment, or leave it on the in-memory default for a single process:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from fastmcp import FastMCP
|
|
32
|
+
from fastmcp_tasks import TasksExtension
|
|
33
|
+
|
|
34
|
+
mcp = FastMCP("Analytics")
|
|
35
|
+
mcp.add_extension(TasksExtension(url="redis://localhost:6379/0"))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@mcp.tool(task=True)
|
|
39
|
+
async def analyze(dataset: str) -> str:
|
|
40
|
+
# Long-running work. The client gets a task handle immediately and
|
|
41
|
+
# polls for the result; this runs in a background worker.
|
|
42
|
+
...
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`task=True` is a declaration of intent — this tool *may* run as a task — while the server, per the spec, decides per call whether to actually task it. Use `TaskConfig` for finer control:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from fastmcp.utilities.tasks import TaskConfig
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@mcp.tool(task=TaskConfig(mode="required"))
|
|
52
|
+
async def must_run_async(n: int) -> int:
|
|
53
|
+
# Always runs as a task; a client that has not opted in is told so.
|
|
54
|
+
...
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Registering `TasksExtension` is required to serve `task=True` tools — the tool declares intent, the extension provides the engine. A `task=True` tool on a server with no tasks extension registered fails loudly at startup rather than silently running inline.
|
|
58
|
+
|
|
59
|
+
### Running out-of-process workers
|
|
60
|
+
|
|
61
|
+
For distributed deployments backed by Redis, run dedicated worker processes alongside your server:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
python -m fastmcp_tasks.worker_cli worker server.py
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Workers and servers that share a backend URL and queue name share a task queue, so you can scale execution independently of your request-serving frontends.
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
The backend is configured on the extension. Every option also has a `FASTMCP_DOCKET_*` environment variable, so an env-configured deployment can construct `TasksExtension()` with no arguments:
|
|
72
|
+
|
|
73
|
+
| Option | Env var | Default | Description |
|
|
74
|
+
| --- | --- | --- | --- |
|
|
75
|
+
| `url` | `FASTMCP_DOCKET_URL` | `memory://` | Backend URL. `memory://` for single-process; `redis://host:port/db` for distributed workers. |
|
|
76
|
+
| `name` | `FASTMCP_DOCKET_NAME` | `fastmcp` | Queue name. Servers and workers sharing a name and URL share a queue. |
|
|
77
|
+
| `concurrency` | `FASTMCP_DOCKET_CONCURRENCY` | `10` | Maximum concurrent tasks per worker. |
|
|
78
|
+
|
|
79
|
+
See the [FastMCP task documentation](https://gofastmcp.com/servers/tasks) for the full reference.
|
|
80
|
+
|
|
81
|
+
## Status
|
|
82
|
+
|
|
83
|
+
The tasks extension is an experimental MCP extension, and `fastmcp-tasks` tracks its draft schema. The protocol's shape is settled — SEP-2663 is Final — but field-level details may still move; this package versions independently so it can follow the schema without waiting on a FastMCP release.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Background task execution for FastMCP via the SEP-2663 tasks extension."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
from fastmcp.client.extension_hooks import register_internal_client_extension_factory
|
|
6
|
+
from fastmcp_tasks.client import ToolTask, _build_tasks_client_extension, call_tool_task
|
|
7
|
+
from fastmcp_tasks.extension import TasksExtension
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
__version__ = version("fastmcp-tasks")
|
|
11
|
+
except PackageNotFoundError:
|
|
12
|
+
__version__ = "0.0.0"
|
|
13
|
+
|
|
14
|
+
# Register the client half so every FastMCP `Client` transparently drives a
|
|
15
|
+
# task-serving backend's background tasks (see `fastmcp_tasks.client`). Importing
|
|
16
|
+
# this package — which any task deployment does, server or client side — is what
|
|
17
|
+
# turns on client task support.
|
|
18
|
+
register_internal_client_extension_factory(_build_tasks_client_extension)
|
|
19
|
+
|
|
20
|
+
__all__ = ["TasksExtension", "ToolTask", "call_tool_task", "__version__"]
|