Skip to content

Commit de89457

Browse files
fix: send params as empty object for list methods without cursor (modelcontextprotocol#1453)
1 parent cd7253c commit de89457

File tree

4 files changed

+301
-180
lines changed

4 files changed

+301
-180
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,7 +1840,7 @@ import asyncio
18401840

18411841
from mcp.client.session import ClientSession
18421842
from mcp.client.stdio import StdioServerParameters, stdio_client
1843-
from mcp.types import Resource
1843+
from mcp.types import PaginatedRequestParams, Resource
18441844

18451845

18461846
async def list_all_resources() -> None:
@@ -1857,7 +1857,7 @@ async def list_all_resources() -> None:
18571857

18581858
while True:
18591859
# Fetch a page of resources
1860-
result = await session.list_resources(cursor=cursor)
1860+
result = await session.list_resources(params=PaginatedRequestParams(cursor=cursor))
18611861
all_resources.extend(result.resources)
18621862

18631863
print(f"Fetched {len(result.resources)} resources")

examples/snippets/clients/pagination_client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from mcp.client.session import ClientSession
88
from mcp.client.stdio import StdioServerParameters, stdio_client
9-
from mcp.types import Resource
9+
from mcp.types import PaginatedRequestParams, Resource
1010

1111

1212
async def list_all_resources() -> None:
@@ -23,7 +23,7 @@ async def list_all_resources() -> None:
2323

2424
while True:
2525
# Fetch a page of resources
26-
result = await session.list_resources(cursor=cursor)
26+
result = await session.list_resources(params=PaginatedRequestParams(cursor=cursor))
2727
all_resources.extend(result.resources)
2828

2929
print(f"Fetched {len(result.resources)} resources")

src/mcp/client/session.py

Lines changed: 136 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import logging
22
from datetime import timedelta
3-
from typing import Any, Protocol
3+
from typing import Any, Protocol, overload
44

55
import anyio.lowlevel
66
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
77
from jsonschema import SchemaError, ValidationError, validate
88
from pydantic import AnyUrl, TypeAdapter
9+
from typing_extensions import deprecated
910

1011
import mcp.types as types
1112
from mcp.shared.context import RequestContext
@@ -212,25 +213,79 @@ async def set_logging_level(self, level: types.LoggingLevel) -> types.EmptyResul
212213
types.EmptyResult,
213214
)
214215

215-
async def list_resources(self, cursor: str | None = None) -> types.ListResourcesResult:
216-
"""Send a resources/list request."""
216+
@overload
217+
@deprecated("Use list_resources(params=PaginatedRequestParams(...)) instead")
218+
async def list_resources(self, cursor: str | None) -> types.ListResourcesResult: ...
219+
220+
@overload
221+
async def list_resources(self, *, params: types.PaginatedRequestParams | None) -> types.ListResourcesResult: ...
222+
223+
@overload
224+
async def list_resources(self) -> types.ListResourcesResult: ...
225+
226+
async def list_resources(
227+
self,
228+
cursor: str | None = None,
229+
*,
230+
params: types.PaginatedRequestParams | None = None,
231+
) -> types.ListResourcesResult:
232+
"""Send a resources/list request.
233+
234+
Args:
235+
cursor: Simple cursor string for pagination (deprecated, use params instead)
236+
params: Full pagination parameters including cursor and any future fields
237+
"""
238+
if params is not None and cursor is not None:
239+
raise ValueError("Cannot specify both cursor and params")
240+
241+
if params is not None:
242+
request_params = params
243+
elif cursor is not None:
244+
request_params = types.PaginatedRequestParams(cursor=cursor)
245+
else:
246+
request_params = None
247+
217248
return await self.send_request(
218-
types.ClientRequest(
219-
types.ListResourcesRequest(
220-
params=types.PaginatedRequestParams(cursor=cursor) if cursor is not None else None,
221-
)
222-
),
249+
types.ClientRequest(types.ListResourcesRequest(params=request_params)),
223250
types.ListResourcesResult,
224251
)
225252

226-
async def list_resource_templates(self, cursor: str | None = None) -> types.ListResourceTemplatesResult:
227-
"""Send a resources/templates/list request."""
253+
@overload
254+
@deprecated("Use list_resource_templates(params=PaginatedRequestParams(...)) instead")
255+
async def list_resource_templates(self, cursor: str | None) -> types.ListResourceTemplatesResult: ...
256+
257+
@overload
258+
async def list_resource_templates(
259+
self, *, params: types.PaginatedRequestParams | None
260+
) -> types.ListResourceTemplatesResult: ...
261+
262+
@overload
263+
async def list_resource_templates(self) -> types.ListResourceTemplatesResult: ...
264+
265+
async def list_resource_templates(
266+
self,
267+
cursor: str | None = None,
268+
*,
269+
params: types.PaginatedRequestParams | None = None,
270+
) -> types.ListResourceTemplatesResult:
271+
"""Send a resources/templates/list request.
272+
273+
Args:
274+
cursor: Simple cursor string for pagination (deprecated, use params instead)
275+
params: Full pagination parameters including cursor and any future fields
276+
"""
277+
if params is not None and cursor is not None:
278+
raise ValueError("Cannot specify both cursor and params")
279+
280+
if params is not None:
281+
request_params = params
282+
elif cursor is not None:
283+
request_params = types.PaginatedRequestParams(cursor=cursor)
284+
else:
285+
request_params = None
286+
228287
return await self.send_request(
229-
types.ClientRequest(
230-
types.ListResourceTemplatesRequest(
231-
params=types.PaginatedRequestParams(cursor=cursor) if cursor is not None else None,
232-
)
233-
),
288+
types.ClientRequest(types.ListResourceTemplatesRequest(params=request_params)),
234289
types.ListResourceTemplatesResult,
235290
)
236291

@@ -317,14 +372,40 @@ async def _validate_tool_result(self, name: str, result: types.CallToolResult) -
317372
except SchemaError as e:
318373
raise RuntimeError(f"Invalid schema for tool {name}: {e}")
319374

320-
async def list_prompts(self, cursor: str | None = None) -> types.ListPromptsResult:
321-
"""Send a prompts/list request."""
375+
@overload
376+
@deprecated("Use list_prompts(params=PaginatedRequestParams(...)) instead")
377+
async def list_prompts(self, cursor: str | None) -> types.ListPromptsResult: ...
378+
379+
@overload
380+
async def list_prompts(self, *, params: types.PaginatedRequestParams | None) -> types.ListPromptsResult: ...
381+
382+
@overload
383+
async def list_prompts(self) -> types.ListPromptsResult: ...
384+
385+
async def list_prompts(
386+
self,
387+
cursor: str | None = None,
388+
*,
389+
params: types.PaginatedRequestParams | None = None,
390+
) -> types.ListPromptsResult:
391+
"""Send a prompts/list request.
392+
393+
Args:
394+
cursor: Simple cursor string for pagination (deprecated, use params instead)
395+
params: Full pagination parameters including cursor and any future fields
396+
"""
397+
if params is not None and cursor is not None:
398+
raise ValueError("Cannot specify both cursor and params")
399+
400+
if params is not None:
401+
request_params = params
402+
elif cursor is not None:
403+
request_params = types.PaginatedRequestParams(cursor=cursor)
404+
else:
405+
request_params = None
406+
322407
return await self.send_request(
323-
types.ClientRequest(
324-
types.ListPromptsRequest(
325-
params=types.PaginatedRequestParams(cursor=cursor) if cursor is not None else None,
326-
)
327-
),
408+
types.ClientRequest(types.ListPromptsRequest(params=request_params)),
328409
types.ListPromptsResult,
329410
)
330411

@@ -363,14 +444,40 @@ async def complete(
363444
types.CompleteResult,
364445
)
365446

366-
async def list_tools(self, cursor: str | None = None) -> types.ListToolsResult:
367-
"""Send a tools/list request."""
447+
@overload
448+
@deprecated("Use list_tools(params=PaginatedRequestParams(...)) instead")
449+
async def list_tools(self, cursor: str | None) -> types.ListToolsResult: ...
450+
451+
@overload
452+
async def list_tools(self, *, params: types.PaginatedRequestParams | None) -> types.ListToolsResult: ...
453+
454+
@overload
455+
async def list_tools(self) -> types.ListToolsResult: ...
456+
457+
async def list_tools(
458+
self,
459+
cursor: str | None = None,
460+
*,
461+
params: types.PaginatedRequestParams | None = None,
462+
) -> types.ListToolsResult:
463+
"""Send a tools/list request.
464+
465+
Args:
466+
cursor: Simple cursor string for pagination (deprecated, use params instead)
467+
params: Full pagination parameters including cursor and any future fields
468+
"""
469+
if params is not None and cursor is not None:
470+
raise ValueError("Cannot specify both cursor and params")
471+
472+
if params is not None:
473+
request_params = params
474+
elif cursor is not None:
475+
request_params = types.PaginatedRequestParams(cursor=cursor)
476+
else:
477+
request_params = None
478+
368479
result = await self.send_request(
369-
types.ClientRequest(
370-
types.ListToolsRequest(
371-
params=types.PaginatedRequestParams(cursor=cursor) if cursor is not None else None,
372-
)
373-
),
480+
types.ClientRequest(types.ListToolsRequest(params=request_params)),
374481
types.ListToolsResult,
375482
)
376483

0 commit comments

Comments
 (0)