@@ -241,6 +241,9 @@ def _build_call_tool_adapter(
241241 if not active :
242242 return _CallToolResultAdapter
243243 tags = frozenset (active )
244+ core_arm = "core"
245+ while core_arm in tags : # the routing sentinel must never collide with a claimed tag
246+ core_arm += "-"
244247
245248 def _route (value : Any ) -> str :
246249 # pydantic hands the discriminator either the raw inbound dict or an
@@ -251,9 +254,9 @@ def _route(value: Any) -> str:
251254 tag = cast ("dict[str, Any]" , value ).get ("resultType" )
252255 else :
253256 tag = getattr (value , "result_type" , None )
254- return tag if isinstance (tag , str ) and tag in tags else "core"
257+ return tag if isinstance (tag , str ) and tag in tags else core_arm
255258
256- arms : list [Any ] = [Annotated [types .CallToolResult | types .InputRequiredResult , Tag ("core" )]]
259+ arms : list [Any ] = [Annotated [types .CallToolResult | types .InputRequiredResult , Tag (core_arm )]]
257260 arms += [Annotated [claim .model , Tag (tag )] for tag , claim in active .items ()]
258261 # reduce(or_, ...) builds the Union dynamically; PEP-646 star-unpack needs py3.11+.
259262 return TypeAdapter (Annotated [reduce (or_ , arms ), Discriminator (_route )])
@@ -270,7 +273,7 @@ def _index_claims(
270273 advertised extension and no wire tag may be claimed twice.
271274 """
272275 indexed : dict [str , tuple [ResultClaim [Any ], ...]] = {}
273- seen : set [tuple [ str , str ] ] = set ()
276+ seen : set [str ] = set ()
274277 for identifier , claims in (result_claims or {}).items ():
275278 if extensions is None or identifier not in extensions :
276279 raise ValueError (
@@ -283,10 +286,9 @@ def _index_claims(
283286 "extension from the capability ad at every version — omit the key instead"
284287 )
285288 for claim in claims :
286- key = (claim .method , claim .result_type )
287- if key in seen :
288- raise ValueError (f"duplicate result claim for { claim .method !r} resultType { claim .result_type !r} " )
289- seen .add (key )
289+ if claim .result_type in seen :
290+ raise ValueError (f"duplicate result claim for resultType { claim .result_type !r} " )
291+ seen .add (claim .result_type )
290292 indexed [identifier ] = tuple (claims )
291293 return indexed
292294
@@ -411,8 +413,10 @@ async def __aenter__(self) -> Self:
411413 # Shield the group's own scope (a new one would break LIFO exit)
412414 # so a pending outer cancellation cannot re-fire inside __aexit__.
413415 task_group .cancel_scope .shield = True
414- await task_group .__aexit__ (None , None , None )
415- self ._close_binding_queues ()
416+ try :
417+ await task_group .__aexit__ (None , None , None )
418+ finally :
419+ self ._close_binding_queues ()
416420 raise
417421 return self
418422
@@ -425,8 +429,10 @@ async def __aexit__(
425429 # Exit must not block: cancel the dispatcher, binding consumers, and in-flight callbacks.
426430 assert self ._task_group is not None
427431 self ._task_group .cancel_scope .cancel ()
428- result = await self ._task_group .__aexit__ (exc_type , exc_val , exc_tb )
429- self ._close_binding_queues ()
432+ try :
433+ result = await self ._task_group .__aexit__ (exc_type , exc_val , exc_tb )
434+ finally :
435+ self ._close_binding_queues ()
430436 await resync_tracer ()
431437 return result
432438
@@ -975,15 +981,15 @@ async def call_tool(
975981 allow_input_required: When ``False`` (default), an `InputRequiredResult`
976982 from the server raises `RuntimeError`; when ``True``, it is returned
977983 so the caller can resolve the requests and retry.
978- allow_claimed: When `` False` ` (default), a claimed (extension) result
979- shape raises `UnexpectedClaimedResult`; when `` True` `, the parsed
984+ allow_claimed: When `False` (default), a claimed (extension) result
985+ shape raises `UnexpectedClaimedResult`; when `True`, the parsed
980986 claim model is returned for the caller to handle.
981987
982988 Raises:
983989 RuntimeError: If the server returns an `InputRequiredResult` and
984990 ``allow_input_required`` is ``False``.
985991 UnexpectedClaimedResult: If a claimed result shape parses and
986- `` allow_claimed`` is `` False` `; carries the parsed value.
992+ `allow_claimed` is `False`; carries the parsed value.
987993 """
988994 result = await self .send_request (
989995 types .CallToolRequest (
0 commit comments