Skip to content

Commit af38579

Browse files
committed
Add tasks/delete method
1 parent 3375c02 commit af38579

File tree

5 files changed

+80
-1
lines changed

5 files changed

+80
-1
lines changed

examples/shared/in_memory_task_store.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,17 @@ async def list_tasks(self, cursor: str | None = None) -> dict[str, Any]:
134134

135135
return {"tasks": tasks, "nextCursor": next_cursor}
136136

137+
async def delete_task(self, task_id: str) -> None:
138+
"""Delete a task from storage."""
139+
if task_id not in self._tasks:
140+
raise ValueError(f"Task with ID {task_id} not found")
141+
142+
# Cancel any scheduled cleanup
143+
self._cancel_cleanup(task_id)
144+
145+
# Remove the task
146+
self._tasks.pop(task_id)
147+
137148
def _schedule_cleanup(self, task_id: str, delay_seconds: float) -> None:
138149
"""Schedule automatic cleanup of a task after the specified delay."""
139150

src/mcp/client/session.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,15 @@ async def list_tasks(self, cursor: str | None = None) -> types.ListTasksResult:
579579
types.ListTasksResult,
580580
)
581581

582+
async def delete_task(self, task_id: str) -> types.EmptyResult:
583+
"""Delete a specific task."""
584+
return await self.send_request(
585+
types.ClientRequest(
586+
types.DeleteTaskRequest(method="tasks/delete", params=types.DeleteTaskParams(taskId=task_id))
587+
),
588+
types.EmptyResult,
589+
)
590+
582591
async def _received_request(self, responder: RequestResponder[types.ServerRequest, types.ClientResult]) -> None:
583592
ctx = RequestContext[ClientSession, Any](
584593
request_id=responder.request_id,

src/mcp/server/session.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,9 @@ async def _receive_loop(self) -> None:
144144
async with self._incoming_message_stream_writer:
145145
await super()._receive_loop()
146146

147-
async def _received_request(self, responder: RequestResponder[types.ClientRequest, types.ServerResult]):
147+
async def _received_request( # noqa: PLR0912
148+
self, responder: RequestResponder[types.ClientRequest, types.ServerResult]
149+
):
148150
# Handle task creation if task metadata is present
149151
if responder.request_meta and responder.request_meta.task and self._task_store:
150152
task_meta = responder.request_meta.task
@@ -275,6 +277,23 @@ async def _received_request(self, responder: RequestResponder[types.ClientReques
275277
await responder.respond(
276278
types.ErrorData(code=types.INVALID_REQUEST, message="Task store not configured")
277279
)
280+
case types.DeleteTaskRequest(params=params):
281+
# Handle delete task requests if task store is available
282+
if self._task_store:
283+
try:
284+
await self._task_store.delete_task(params.taskId)
285+
with responder:
286+
await responder.respond(types.ServerResult(types.EmptyResult(_meta={})))
287+
except Exception as e:
288+
with responder:
289+
await responder.respond(
290+
types.ErrorData(code=types.INVALID_PARAMS, message=f"Failed to delete task: {e}")
291+
)
292+
else:
293+
with responder:
294+
await responder.respond(
295+
types.ErrorData(code=types.INVALID_REQUEST, message="Task store not configured")
296+
)
278297
case _:
279298
if self._initialization_state != InitializationState.Initialized:
280299
raise RuntimeError("Received request before initialization was complete")
@@ -459,6 +478,15 @@ async def list_tasks(self, cursor: str | None = None) -> types.ListTasksResult:
459478
types.ListTasksResult,
460479
)
461480

481+
async def delete_task(self, task_id: str) -> types.EmptyResult:
482+
"""Delete a specific task."""
483+
return await self.send_request(
484+
types.ServerRequest(
485+
types.DeleteTaskRequest(method="tasks/delete", params=types.DeleteTaskParams(taskId=task_id))
486+
),
487+
types.EmptyResult,
488+
)
489+
462490
async def _handle_incoming(self, req: ServerRequestResponder) -> None:
463491
await self._incoming_message_stream_writer.send(req)
464492

src/mcp/shared/task.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@ async def list_tasks(self, cursor: str | None = None) -> dict[str, list[Task] |
9999
"""
100100
...
101101

102+
@abstractmethod
103+
async def delete_task(self, task_id: str) -> None:
104+
"""
105+
Delete a task from storage.
106+
107+
Args:
108+
task_id: The task identifier
109+
110+
Raises:
111+
Exception: If task not found
112+
"""
113+
...
114+
102115

103116
def is_terminal(status: TaskStatus) -> bool:
104117
"""

src/mcp/types.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,22 @@ class ListTasksResult(Result):
584584
model_config = ConfigDict(extra="allow")
585585

586586

587+
class DeleteTaskParams(RequestParams):
588+
"""Parameters for deleting a task."""
589+
590+
taskId: str
591+
"""The task identifier."""
592+
593+
model_config = ConfigDict(extra="allow")
594+
595+
596+
class DeleteTaskRequest(Request[DeleteTaskParams, Literal["tasks/delete"]]):
597+
"""A request to delete a specific task."""
598+
599+
method: Literal["tasks/delete"] = "tasks/delete"
600+
params: DeleteTaskParams
601+
602+
587603
class ListResourcesRequest(PaginatedRequest[Literal["resources/list"]]):
588604
"""Sent from the client to request a list of resources the server has."""
589605

@@ -1433,6 +1449,7 @@ class ClientRequest(
14331449
| GetTaskRequest
14341450
| GetTaskPayloadRequest
14351451
| ListTasksRequest
1452+
| DeleteTaskRequest
14361453
]
14371454
):
14381455
pass
@@ -1503,6 +1520,7 @@ class ServerRequest(
15031520
| GetTaskRequest
15041521
| GetTaskPayloadRequest
15051522
| ListTasksRequest
1523+
| DeleteTaskRequest
15061524
]
15071525
):
15081526
pass

0 commit comments

Comments
 (0)