@@ -107,6 +107,52 @@ def __init__(
107107 def client_params (self ) -> types .InitializeRequestParams | None :
108108 return self ._client_params
109109
110+ def _check_tasks_capability (
111+ self , required : types .ClientTasksCapability , client : types .ClientTasksCapability
112+ ) -> bool :
113+ """Check if client supports required tasks capabilities."""
114+ if required .requests is None :
115+ return True
116+ if client .requests is None :
117+ return False
118+
119+ req_cap = required .requests
120+ client_req_cap = client .requests
121+
122+ # Check sampling requests
123+ if req_cap .sampling is not None and (
124+ client_req_cap .sampling is None
125+ or (req_cap .sampling .createMessage and not client_req_cap .sampling .createMessage )
126+ ):
127+ return False
128+
129+ # Check elicitation requests
130+ if req_cap .elicitation is not None and (
131+ client_req_cap .elicitation is None or (req_cap .elicitation .create and not client_req_cap .elicitation .create )
132+ ):
133+ return False
134+
135+ # Check roots requests
136+ if req_cap .roots is not None and (
137+ client_req_cap .roots is None or (req_cap .roots .list and not client_req_cap .roots .list )
138+ ):
139+ return False
140+
141+ # Check tasks operations
142+ if req_cap .tasks is not None :
143+ if client_req_cap .tasks is None :
144+ return False
145+ tasks_checks = [
146+ not req_cap .tasks .get or client_req_cap .tasks .get ,
147+ not req_cap .tasks .list or client_req_cap .tasks .list ,
148+ not req_cap .tasks .result or client_req_cap .tasks .result ,
149+ not req_cap .tasks .delete or client_req_cap .tasks .delete ,
150+ ]
151+ if not all (tasks_checks ):
152+ return False
153+
154+ return True
155+
110156 def check_client_capability (self , capability : types .ClientCapabilities ) -> bool :
111157 """Check if the client supports a specific capability."""
112158 if self ._client_params is None :
@@ -138,6 +184,12 @@ def check_client_capability(self, capability: types.ClientCapabilities) -> bool:
138184 if exp_key not in client_caps .experimental or client_caps .experimental [exp_key ] != exp_value :
139185 return False
140186
187+ if capability .tasks is not None :
188+ if client_caps .tasks is None :
189+ return False
190+ if not self ._check_tasks_capability (capability .tasks , client_caps .tasks ):
191+ return False
192+
141193 return True
142194
143195 async def _receive_loop (self ) -> None :
@@ -193,8 +245,17 @@ async def _received_request( # noqa: PLR0912
193245 # Ping requests are allowed at any time
194246 pass
195247 case types .GetTaskRequest (params = params ):
248+ # Check if client has announced tasks capability
249+ if self ._client_params is None or self ._client_params .capabilities .tasks is None :
250+ with responder :
251+ await responder .respond (
252+ types .ErrorData (
253+ code = types .INVALID_REQUEST ,
254+ message = "Client has not announced tasks capability" ,
255+ )
256+ )
196257 # Handle get task requests if task store is available
197- if self ._task_store :
258+ elif self ._task_store :
198259 task = await self ._task_store .get_task (params .taskId )
199260 if task is None :
200261 with responder :
@@ -220,8 +281,17 @@ async def _received_request( # noqa: PLR0912
220281 types .ErrorData (code = types .INVALID_REQUEST , message = "Task store not configured" )
221282 )
222283 case types .GetTaskPayloadRequest (params = params ):
284+ # Check if client has announced tasks capability
285+ if self ._client_params is None or self ._client_params .capabilities .tasks is None :
286+ with responder :
287+ await responder .respond (
288+ types .ErrorData (
289+ code = types .INVALID_REQUEST ,
290+ message = "Client has not announced tasks capability" ,
291+ )
292+ )
223293 # Handle get task result requests if task store is available
224- if self ._task_store :
294+ elif self ._task_store :
225295 task = await self ._task_store .get_task (params .taskId )
226296 if task is None :
227297 with responder :
@@ -253,8 +323,17 @@ async def _received_request( # noqa: PLR0912
253323 types .ErrorData (code = types .INVALID_REQUEST , message = "Task store not configured" )
254324 )
255325 case types .ListTasksRequest (params = params ):
326+ # Check if client has announced tasks capability
327+ if self ._client_params is None or self ._client_params .capabilities .tasks is None :
328+ with responder :
329+ await responder .respond (
330+ types .ErrorData (
331+ code = types .INVALID_REQUEST ,
332+ message = "Client has not announced tasks capability" ,
333+ )
334+ )
256335 # Handle list tasks requests if task store is available
257- if self ._task_store :
336+ elif self ._task_store :
258337 try :
259338 result = await self ._task_store .list_tasks (params .cursor if params else None )
260339 with responder :
@@ -278,8 +357,17 @@ async def _received_request( # noqa: PLR0912
278357 types .ErrorData (code = types .INVALID_REQUEST , message = "Task store not configured" )
279358 )
280359 case types .DeleteTaskRequest (params = params ):
360+ # Check if client has announced tasks capability
361+ if self ._client_params is None or self ._client_params .capabilities .tasks is None :
362+ with responder :
363+ await responder .respond (
364+ types .ErrorData (
365+ code = types .INVALID_REQUEST ,
366+ message = "Client has not announced tasks capability" ,
367+ )
368+ )
281369 # Handle delete task requests if task store is available
282- if self ._task_store :
370+ elif self ._task_store :
283371 try :
284372 await self ._task_store .delete_task (params .taskId )
285373 with responder :
0 commit comments