@@ -595,6 +595,9 @@ async def iter_all_tools(self, *, meta: RequestParamsMeta | None = None) -> Asyn
595595
596596 Useful for streaming consumers that want to process tools without
597597 materializing the full list in memory.
598+
599+ Raises:
600+ RuntimeError: The server returned a pagination cursor that did not advance.
598601 """
599602 cursor : str | None = None
600603 while True :
@@ -603,6 +606,10 @@ async def iter_all_tools(self, *, meta: RequestParamsMeta | None = None) -> Asyn
603606 yield tool
604607 if result .next_cursor is None :
605608 return
609+ if result .next_cursor == cursor :
610+ raise RuntimeError (
611+ "Server returned a pagination cursor that did not advance; refusing to page forever."
612+ )
606613 cursor = result .next_cursor
607614
608615 async def list_all_tools (self , * , meta : RequestParamsMeta | None = None ) -> list [Tool ]:
@@ -611,54 +618,93 @@ async def list_all_tools(self, *, meta: RequestParamsMeta | None = None) -> list
611618 Unlike `list_tools`, which returns one page, this walks pagination
612619 until the server reports no further pages and returns the combined
613620 list.
621+
622+ Raises:
623+ RuntimeError: The server returned a pagination cursor that did not advance.
614624 """
615625 return [tool async for tool in self .iter_all_tools (meta = meta )]
616626
617627 async def iter_all_prompts (self , * , meta : RequestParamsMeta | None = None ) -> AsyncIterator [Prompt ]:
618- """Yield every prompt from the server, paging through `next_cursor`."""
628+ """Yield every prompt from the server, paging through `next_cursor`.
629+
630+ Raises:
631+ RuntimeError: The server returned a pagination cursor that did not advance.
632+ """
619633 cursor : str | None = None
620634 while True :
621635 result = await self .list_prompts (cursor = cursor , meta = meta )
622636 for prompt in result .prompts :
623637 yield prompt
624638 if result .next_cursor is None :
625639 return
640+ if result .next_cursor == cursor :
641+ raise RuntimeError (
642+ "Server returned a pagination cursor that did not advance; refusing to page forever."
643+ )
626644 cursor = result .next_cursor
627645
628646 async def list_all_prompts (self , * , meta : RequestParamsMeta | None = None ) -> list [Prompt ]:
629- """List every prompt from the server, draining `next_cursor` across pages."""
647+ """List every prompt from the server, draining `next_cursor` across pages.
648+
649+ Raises:
650+ RuntimeError: The server returned a pagination cursor that did not advance.
651+ """
630652 return [prompt async for prompt in self .iter_all_prompts (meta = meta )]
631653
632654 async def iter_all_resources (self , * , meta : RequestParamsMeta | None = None ) -> AsyncIterator [Resource ]:
633- """Yield every resource from the server, paging through `next_cursor`."""
655+ """Yield every resource from the server, paging through `next_cursor`.
656+
657+ Raises:
658+ RuntimeError: The server returned a pagination cursor that did not advance.
659+ """
634660 cursor : str | None = None
635661 while True :
636662 result = await self .list_resources (cursor = cursor , meta = meta )
637663 for resource in result .resources :
638664 yield resource
639665 if result .next_cursor is None :
640666 return
667+ if result .next_cursor == cursor :
668+ raise RuntimeError (
669+ "Server returned a pagination cursor that did not advance; refusing to page forever."
670+ )
641671 cursor = result .next_cursor
642672
643673 async def list_all_resources (self , * , meta : RequestParamsMeta | None = None ) -> list [Resource ]:
644- """List every resource from the server, draining `next_cursor` across pages."""
674+ """List every resource from the server, draining `next_cursor` across pages.
675+
676+ Raises:
677+ RuntimeError: The server returned a pagination cursor that did not advance.
678+ """
645679 return [resource async for resource in self .iter_all_resources (meta = meta )]
646680
647681 async def iter_all_resource_templates (
648682 self , * , meta : RequestParamsMeta | None = None
649683 ) -> AsyncIterator [ResourceTemplate ]:
650- """Yield every resource template from the server, paging through `next_cursor`."""
684+ """Yield every resource template from the server, paging through `next_cursor`.
685+
686+ Raises:
687+ RuntimeError: The server returned a pagination cursor that did not advance.
688+ """
651689 cursor : str | None = None
652690 while True :
653691 result = await self .list_resource_templates (cursor = cursor , meta = meta )
654692 for template in result .resource_templates :
655693 yield template
656694 if result .next_cursor is None :
657695 return
696+ if result .next_cursor == cursor :
697+ raise RuntimeError (
698+ "Server returned a pagination cursor that did not advance; refusing to page forever."
699+ )
658700 cursor = result .next_cursor
659701
660702 async def list_all_resource_templates (self , * , meta : RequestParamsMeta | None = None ) -> list [ResourceTemplate ]:
661- """List every resource template from the server, draining `next_cursor` across pages."""
703+ """List every resource template from the server, draining `next_cursor` across pages.
704+
705+ Raises:
706+ RuntimeError: The server returned a pagination cursor that did not advance.
707+ """
662708 return [template async for template in self .iter_all_resource_templates (meta = meta )]
663709
664710 @deprecated ("The roots capability is deprecated as of 2026-07-28 (SEP-2577)." , category = MCPDeprecationWarning )
0 commit comments