Skip to content

Commit 4150b2d

Browse files
committed
feat: add on_* handler kwargs to enable_tasks for custom task handlers
Allow users to override default task handlers by passing on_get_task, on_task_result, on_list_tasks, and on_cancel_task to enable_tasks(). User-provided handlers are registered first; defaults fill in the rest.
1 parent 9f0ae6c commit 4150b2d

File tree

3 files changed

+45
-14
lines changed

3 files changed

+45
-14
lines changed

docs/migration.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ from mcp.server import ServerRequestContext
594594

595595
The experimental decorator methods on `ExperimentalHandlers` (`@server.experimental.list_tasks()`, `@server.experimental.get_task()`, etc.) have been removed.
596596

597-
Default task handlers are still registered automatically via `server.experimental.enable_tasks()`.
597+
Default task handlers are still registered automatically via `server.experimental.enable_tasks()`. Custom handlers can be passed as `on_*` kwargs to override specific defaults.
598598

599599
**Before (v1):**
600600

@@ -610,13 +610,16 @@ async def custom_get_task(request: GetTaskRequest) -> GetTaskResult:
610610
**After (v2):**
611611

612612
```python
613-
from mcp.server.lowlevel import Server
613+
from mcp.server import Server, ServerRequestContext
614614
from mcp.types import GetTaskRequestParams, GetTaskResult
615615

616+
617+
async def custom_get_task(ctx: ServerRequestContext, params: GetTaskRequestParams) -> GetTaskResult:
618+
...
619+
620+
616621
server = Server("my-server")
617-
server.experimental.enable_tasks(task_store)
618-
# Default handlers are registered automatically.
619-
# Custom task handlers are not yet supported via the constructor.
622+
server.experimental.enable_tasks(on_get_task=custom_get_task)
620623
```
621624

622625
## Deprecations

src/mcp/server/experimental/task_result_handler.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,14 @@ class TaskResultHandler:
4444
5. Returns the final result
4545
4646
Usage:
47-
handler = TaskResultHandler(task_store, message_queue)
48-
4947
async def handle_task_result(
5048
ctx: ServerRequestContext, params: GetTaskPayloadRequestParams
5149
) -> GetTaskPayloadResult:
52-
assert ctx.request_id is not None
53-
return await handler.handle(
54-
GetTaskPayloadRequest(params=params), ctx.session, ctx.request_id
55-
)
50+
...
5651
57-
server._add_request_handler("tasks/result", handle_task_result)
52+
server.experimental.enable_tasks(
53+
on_task_result=handle_task_result,
54+
)
5855
"""
5956

6057
def __init__(

src/mcp/server/lowlevel/experimental.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,35 @@ def enable_tasks(
7878
self,
7979
store: TaskStore | None = None,
8080
queue: TaskMessageQueue | None = None,
81+
*,
82+
on_get_task: Callable[[ServerRequestContext[Any, Any], GetTaskRequestParams], Awaitable[GetTaskResult]]
83+
| None = None,
84+
on_task_result: Callable[
85+
[ServerRequestContext[Any, Any], GetTaskPayloadRequestParams], Awaitable[GetTaskPayloadResult]
86+
]
87+
| None = None,
88+
on_list_tasks: Callable[
89+
[ServerRequestContext[Any, Any], PaginatedRequestParams | None], Awaitable[ListTasksResult]
90+
]
91+
| None = None,
92+
on_cancel_task: Callable[
93+
[ServerRequestContext[Any, Any], CancelTaskRequestParams], Awaitable[CancelTaskResult]
94+
]
95+
| None = None,
8196
) -> TaskSupport:
8297
"""Enable experimental task support.
8398
84-
This sets up the task infrastructure and auto-registers default handlers
85-
for tasks/get, tasks/result, tasks/list, and tasks/cancel.
99+
This sets up the task infrastructure and registers handlers for
100+
tasks/get, tasks/result, tasks/list, and tasks/cancel. Custom handlers
101+
can be provided via the on_* kwargs; any not provided will use defaults.
86102
87103
Args:
88104
store: Custom TaskStore implementation (defaults to InMemoryTaskStore)
89105
queue: Custom TaskMessageQueue implementation (defaults to InMemoryTaskMessageQueue)
106+
on_get_task: Custom handler for tasks/get
107+
on_task_result: Custom handler for tasks/result
108+
on_list_tasks: Custom handler for tasks/list
109+
on_cancel_task: Custom handler for tasks/cancel
90110
91111
Returns:
92112
The TaskSupport configuration object
@@ -110,6 +130,17 @@ def enable_tasks(
110130

111131
self._task_support = TaskSupport(store=store, queue=queue)
112132

133+
# Register user-provided handlers
134+
if on_get_task is not None:
135+
self._add_request_handler("tasks/get", on_get_task)
136+
if on_task_result is not None:
137+
self._add_request_handler("tasks/result", on_task_result)
138+
if on_list_tasks is not None:
139+
self._add_request_handler("tasks/list", on_list_tasks)
140+
if on_cancel_task is not None:
141+
self._add_request_handler("tasks/cancel", on_cancel_task)
142+
143+
# Fill in defaults for any not provided
113144
if not self._has_handler("tasks/get"):
114145

115146
async def _default_get_task(

0 commit comments

Comments
 (0)