@@ -953,6 +953,9 @@ async def iter_all_tools(self, *, meta: RequestParamsMeta | None = None) -> Asyn
953953
954954 Useful for streaming consumers that want to process tools without
955955 materializing the full list in memory.
956+
957+ Raises:
958+ RuntimeError: The server returned a pagination cursor that did not advance.
956959 """
957960 cursor : str | None = None
958961 while True :
@@ -961,6 +964,10 @@ async def iter_all_tools(self, *, meta: RequestParamsMeta | None = None) -> Asyn
961964 yield tool
962965 if result .next_cursor is None :
963966 return
967+ if result .next_cursor == cursor :
968+ raise RuntimeError (
969+ "Server returned a pagination cursor that did not advance; refusing to page forever."
970+ )
964971 cursor = result .next_cursor
965972
966973 async def list_all_tools (self , * , meta : RequestParamsMeta | None = None ) -> list [Tool ]:
@@ -969,54 +976,93 @@ async def list_all_tools(self, *, meta: RequestParamsMeta | None = None) -> list
969976 Unlike `list_tools`, which returns one page, this walks pagination
970977 until the server reports no further pages and returns the combined
971978 list.
979+
980+ Raises:
981+ RuntimeError: The server returned a pagination cursor that did not advance.
972982 """
973983 return [tool async for tool in self .iter_all_tools (meta = meta )]
974984
975985 async def iter_all_prompts (self , * , meta : RequestParamsMeta | None = None ) -> AsyncIterator [Prompt ]:
976- """Yield every prompt from the server, paging through `next_cursor`."""
986+ """Yield every prompt from the server, paging through `next_cursor`.
987+
988+ Raises:
989+ RuntimeError: The server returned a pagination cursor that did not advance.
990+ """
977991 cursor : str | None = None
978992 while True :
979993 result = await self .list_prompts (cursor = cursor , meta = meta )
980994 for prompt in result .prompts :
981995 yield prompt
982996 if result .next_cursor is None :
983997 return
998+ if result .next_cursor == cursor :
999+ raise RuntimeError (
1000+ "Server returned a pagination cursor that did not advance; refusing to page forever."
1001+ )
9841002 cursor = result .next_cursor
9851003
9861004 async def list_all_prompts (self , * , meta : RequestParamsMeta | None = None ) -> list [Prompt ]:
987- """List every prompt from the server, draining `next_cursor` across pages."""
1005+ """List every prompt from the server, draining `next_cursor` across pages.
1006+
1007+ Raises:
1008+ RuntimeError: The server returned a pagination cursor that did not advance.
1009+ """
9881010 return [prompt async for prompt in self .iter_all_prompts (meta = meta )]
9891011
9901012 async def iter_all_resources (self , * , meta : RequestParamsMeta | None = None ) -> AsyncIterator [Resource ]:
991- """Yield every resource from the server, paging through `next_cursor`."""
1013+ """Yield every resource from the server, paging through `next_cursor`.
1014+
1015+ Raises:
1016+ RuntimeError: The server returned a pagination cursor that did not advance.
1017+ """
9921018 cursor : str | None = None
9931019 while True :
9941020 result = await self .list_resources (cursor = cursor , meta = meta )
9951021 for resource in result .resources :
9961022 yield resource
9971023 if result .next_cursor is None :
9981024 return
1025+ if result .next_cursor == cursor :
1026+ raise RuntimeError (
1027+ "Server returned a pagination cursor that did not advance; refusing to page forever."
1028+ )
9991029 cursor = result .next_cursor
10001030
10011031 async def list_all_resources (self , * , meta : RequestParamsMeta | None = None ) -> list [Resource ]:
1002- """List every resource from the server, draining `next_cursor` across pages."""
1032+ """List every resource from the server, draining `next_cursor` across pages.
1033+
1034+ Raises:
1035+ RuntimeError: The server returned a pagination cursor that did not advance.
1036+ """
10031037 return [resource async for resource in self .iter_all_resources (meta = meta )]
10041038
10051039 async def iter_all_resource_templates (
10061040 self , * , meta : RequestParamsMeta | None = None
10071041 ) -> AsyncIterator [ResourceTemplate ]:
1008- """Yield every resource template from the server, paging through `next_cursor`."""
1042+ """Yield every resource template from the server, paging through `next_cursor`.
1043+
1044+ Raises:
1045+ RuntimeError: The server returned a pagination cursor that did not advance.
1046+ """
10091047 cursor : str | None = None
10101048 while True :
10111049 result = await self .list_resource_templates (cursor = cursor , meta = meta )
10121050 for template in result .resource_templates :
10131051 yield template
10141052 if result .next_cursor is None :
10151053 return
1054+ if result .next_cursor == cursor :
1055+ raise RuntimeError (
1056+ "Server returned a pagination cursor that did not advance; refusing to page forever."
1057+ )
10161058 cursor = result .next_cursor
10171059
10181060 async def list_all_resource_templates (self , * , meta : RequestParamsMeta | None = None ) -> list [ResourceTemplate ]:
1019- """List every resource template from the server, draining `next_cursor` across pages."""
1061+ """List every resource template from the server, draining `next_cursor` across pages.
1062+
1063+ Raises:
1064+ RuntimeError: The server returned a pagination cursor that did not advance.
1065+ """
10201066 return [template async for template in self .iter_all_resource_templates (meta = meta )]
10211067
10221068 @deprecated ("The roots capability is deprecated as of 2026-07-28 (SEP-2577)." , category = MCPDeprecationWarning )
0 commit comments