Skip to content

Commit c81674c

Browse files
committed
Drop deprecated cursor parameter and ResourceReference class
Remove deprecated APIs: - cursor parameter from ClientSession list methods (list_resources, list_resource_templates, list_prompts, list_tools) - use params=PaginatedRequestParams(cursor=...) instead - ResourceReference class - use ResourceTemplateReference instead
1 parent 4d14107 commit c81674c

File tree

4 files changed

+21
-244
lines changed

4 files changed

+21
-244
lines changed

docs/migration.md

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -52,20 +52,25 @@ async with http_client:
5252

5353
The `headers`, `timeout`, `sse_read_timeout`, and `auth` parameters have been removed from `StreamableHTTPTransport`. Configure these on the `httpx.AsyncClient` instead (see example above).
5454

55-
### `Content` type alias removed
55+
### Removed type aliases and classes
5656

57-
The deprecated `Content` type alias has been removed. Use `ContentBlock` directly instead.
57+
The following deprecated type aliases and classes have been removed from `mcp.types`:
58+
59+
| Removed | Replacement |
60+
|---------|-------------|
61+
| `Content` | `ContentBlock` |
62+
| `ResourceReference` | `ResourceTemplateReference` |
5863

5964
**Before (v1):**
6065

6166
```python
62-
from mcp.types import Content
67+
from mcp.types import Content, ResourceReference
6368
```
6469

6570
**After (v2):**
6671

6772
```python
68-
from mcp.types import ContentBlock
73+
from mcp.types import ContentBlock, ResourceTemplateReference
6974
```
7075

7176
### `args` parameter removed from `ClientSessionGroup.call_tool()`
@@ -111,22 +116,6 @@ result = await session.list_resources(params=PaginatedRequestParams(cursor="next
111116
result = await session.list_tools(params=PaginatedRequestParams(cursor="next_page_token"))
112117
```
113118

114-
### `ResourceReference` class removed
115-
116-
The deprecated `ResourceReference` class has been removed. Use `ResourceTemplateReference` directly instead.
117-
118-
**Before (v1):**
119-
120-
```python
121-
from mcp.types import ResourceReference
122-
```
123-
124-
**After (v2):**
125-
126-
```python
127-
from mcp.types import ResourceTemplateReference
128-
```
129-
130119
## Deprecations
131120

132121
<!-- Add deprecations below -->

src/mcp/client/session.py

Lines changed: 12 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import logging
2-
from typing import Any, Protocol, overload
2+
from typing import Any, Protocol
33

44
import anyio.lowlevel
55
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
66
from pydantic import AnyUrl, TypeAdapter
7-
from typing_extensions import deprecated
87

98
import mcp.types as types
109
from mcp.client.experimental import ExperimentalClientFeatures
@@ -256,112 +255,48 @@ async def set_logging_level(self, level: types.LoggingLevel) -> types.EmptyResul
256255
types.EmptyResult,
257256
)
258257

259-
@overload
260-
@deprecated("Use list_resources(params=PaginatedRequestParams(...)) instead")
261-
async def list_resources(self, cursor: str | None) -> types.ListResourcesResult: ...
262-
263-
@overload
264-
async def list_resources(self, *, params: types.PaginatedRequestParams | None) -> types.ListResourcesResult: ...
265-
266-
@overload
267-
async def list_resources(self) -> types.ListResourcesResult: ...
268-
269-
async def list_resources(
270-
self,
271-
cursor: str | None = None,
272-
*,
273-
params: types.PaginatedRequestParams | None = None,
274-
) -> types.ListResourcesResult:
258+
async def list_resources(self, *, params: types.PaginatedRequestParams | None = None) -> types.ListResourcesResult:
275259
"""Send a resources/list request.
276260
277261
Args:
278-
cursor: Simple cursor string for pagination (deprecated, use params instead)
279262
params: Full pagination parameters including cursor and any future fields
280263
"""
281-
if params is not None and cursor is not None:
282-
raise ValueError("Cannot specify both cursor and params")
283-
284-
if params is not None:
285-
request_params = params
286-
elif cursor is not None:
287-
request_params = types.PaginatedRequestParams(cursor=cursor)
288-
else:
289-
request_params = None
290-
291264
return await self.send_request(
292-
types.ClientRequest(types.ListResourcesRequest(params=request_params)),
265+
types.ClientRequest(types.ListResourcesRequest(params=params)),
293266
types.ListResourcesResult,
294267
)
295268

296-
@overload
297-
@deprecated("Use list_resource_templates(params=PaginatedRequestParams(...)) instead")
298-
async def list_resource_templates(self, cursor: str | None) -> types.ListResourceTemplatesResult: ...
299-
300-
@overload
301269
async def list_resource_templates(
302-
self, *, params: types.PaginatedRequestParams | None
303-
) -> types.ListResourceTemplatesResult: ...
304-
305-
@overload
306-
async def list_resource_templates(self) -> types.ListResourceTemplatesResult: ...
307-
308-
async def list_resource_templates(
309-
self,
310-
cursor: str | None = None,
311-
*,
312-
params: types.PaginatedRequestParams | None = None,
270+
self, *, params: types.PaginatedRequestParams | None = None
313271
) -> types.ListResourceTemplatesResult:
314272
"""Send a resources/templates/list request.
315273
316274
Args:
317-
cursor: Simple cursor string for pagination (deprecated, use params instead)
318275
params: Full pagination parameters including cursor and any future fields
319276
"""
320-
if params is not None and cursor is not None:
321-
raise ValueError("Cannot specify both cursor and params")
322-
323-
if params is not None:
324-
request_params = params
325-
elif cursor is not None:
326-
request_params = types.PaginatedRequestParams(cursor=cursor)
327-
else:
328-
request_params = None
329-
330277
return await self.send_request(
331-
types.ClientRequest(types.ListResourceTemplatesRequest(params=request_params)),
278+
types.ClientRequest(types.ListResourceTemplatesRequest(params=params)),
332279
types.ListResourceTemplatesResult,
333280
)
334281

335282
async def read_resource(self, uri: AnyUrl) -> types.ReadResourceResult:
336283
"""Send a resources/read request."""
337284
return await self.send_request(
338-
types.ClientRequest(
339-
types.ReadResourceRequest(
340-
params=types.ReadResourceRequestParams(uri=uri),
341-
)
342-
),
285+
types.ClientRequest(types.ReadResourceRequest(params=types.ReadResourceRequestParams(uri=uri))),
343286
types.ReadResourceResult,
344287
)
345288

346289
async def subscribe_resource(self, uri: AnyUrl) -> types.EmptyResult:
347290
"""Send a resources/subscribe request."""
348291
return await self.send_request( # pragma: no cover
349-
types.ClientRequest(
350-
types.SubscribeRequest(
351-
params=types.SubscribeRequestParams(uri=uri),
352-
)
353-
),
292+
types.ClientRequest(types.SubscribeRequest(params=types.SubscribeRequestParams(uri=uri))),
354293
types.EmptyResult,
355294
)
356295

357296
async def unsubscribe_resource(self, uri: AnyUrl) -> types.EmptyResult:
358297
"""Send a resources/unsubscribe request."""
359298
return await self.send_request( # pragma: no cover
360-
types.ClientRequest(
361-
types.UnsubscribeRequest(
362-
params=types.UnsubscribeRequestParams(uri=uri),
363-
)
364-
),
299+
types.ClientRequest(types.UnsubscribeRequest(params=types.UnsubscribeRequestParams(uri=uri))),
365300
types.EmptyResult,
366301
)
367302

@@ -422,40 +357,14 @@ async def _validate_tool_result(self, name: str, result: types.CallToolResult) -
422357
except SchemaError as e: # pragma: no cover
423358
raise RuntimeError(f"Invalid schema for tool {name}: {e}") # pragma: no cover
424359

425-
@overload
426-
@deprecated("Use list_prompts(params=PaginatedRequestParams(...)) instead")
427-
async def list_prompts(self, cursor: str | None) -> types.ListPromptsResult: ...
428-
429-
@overload
430-
async def list_prompts(self, *, params: types.PaginatedRequestParams | None) -> types.ListPromptsResult: ...
431-
432-
@overload
433-
async def list_prompts(self) -> types.ListPromptsResult: ...
434-
435-
async def list_prompts(
436-
self,
437-
cursor: str | None = None,
438-
*,
439-
params: types.PaginatedRequestParams | None = None,
440-
) -> types.ListPromptsResult:
360+
async def list_prompts(self, *, params: types.PaginatedRequestParams | None = None) -> types.ListPromptsResult:
441361
"""Send a prompts/list request.
442362
443363
Args:
444-
cursor: Simple cursor string for pagination (deprecated, use params instead)
445364
params: Full pagination parameters including cursor and any future fields
446365
"""
447-
if params is not None and cursor is not None:
448-
raise ValueError("Cannot specify both cursor and params")
449-
450-
if params is not None:
451-
request_params = params
452-
elif cursor is not None:
453-
request_params = types.PaginatedRequestParams(cursor=cursor)
454-
else:
455-
request_params = None
456-
457366
return await self.send_request(
458-
types.ClientRequest(types.ListPromptsRequest(params=request_params)),
367+
types.ClientRequest(types.ListPromptsRequest(params=params)),
459368
types.ListPromptsResult,
460369
)
461370

@@ -494,40 +403,15 @@ async def complete(
494403
types.CompleteResult,
495404
)
496405

497-
@overload
498-
@deprecated("Use list_tools(params=PaginatedRequestParams(...)) instead")
499-
async def list_tools(self, cursor: str | None) -> types.ListToolsResult: ...
500-
501-
@overload
502-
async def list_tools(self, *, params: types.PaginatedRequestParams | None) -> types.ListToolsResult: ...
503-
504-
@overload
505-
async def list_tools(self) -> types.ListToolsResult: ...
506-
507-
async def list_tools(
508-
self,
509-
cursor: str | None = None,
510-
*,
511-
params: types.PaginatedRequestParams | None = None,
512-
) -> types.ListToolsResult:
406+
async def list_tools(self, *, params: types.PaginatedRequestParams | None = None) -> types.ListToolsResult:
513407
"""Send a tools/list request.
514408
515409
Args:
516410
cursor: Simple cursor string for pagination (deprecated, use params instead)
517411
params: Full pagination parameters including cursor and any future fields
518412
"""
519-
if params is not None and cursor is not None:
520-
raise ValueError("Cannot specify both cursor and params")
521-
522-
if params is not None:
523-
request_params = params
524-
elif cursor is not None:
525-
request_params = types.PaginatedRequestParams(cursor=cursor)
526-
else:
527-
request_params = None
528-
529413
result = await self.send_request(
530-
types.ClientRequest(types.ListToolsRequest(params=request_params)),
414+
types.ClientRequest(types.ListToolsRequest(params=params)),
531415
types.ListToolsResult,
532416
)
533417

src/mcp/types.py

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

77
from pydantic import BaseModel, ConfigDict, Field, FileUrl, RootModel
88
from pydantic.networks import AnyUrl, UrlConstraints
9-
from typing_extensions import deprecated
109

1110
LATEST_PROTOCOL_VERSION = "2025-11-25"
1211

@@ -1587,11 +1586,6 @@ class ResourceTemplateReference(BaseModel):
15871586
model_config = ConfigDict(extra="allow")
15881587

15891588

1590-
@deprecated("`ResourceReference` is deprecated, you should use `ResourceTemplateReference`.")
1591-
class ResourceReference(ResourceTemplateReference):
1592-
pass
1593-
1594-
15951589
class PromptReference(BaseModel):
15961590
"""Identifies a prompt."""
15971591

tests/client/test_list_methods_cursor.py

Lines changed: 0 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -46,65 +46,6 @@ async def test_template(name: str) -> str: # pragma: no cover
4646
return server
4747

4848

49-
@pytest.mark.parametrize(
50-
"method_name,request_method",
51-
[
52-
("list_tools", "tools/list"),
53-
("list_resources", "resources/list"),
54-
("list_prompts", "prompts/list"),
55-
("list_resource_templates", "resources/templates/list"),
56-
],
57-
)
58-
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
59-
async def test_list_methods_cursor_parameter(
60-
stream_spy: Callable[[], StreamSpyCollection],
61-
full_featured_server: FastMCP,
62-
method_name: str,
63-
request_method: str,
64-
):
65-
"""Test that the cursor parameter is accepted and correctly passed to the server.
66-
67-
Covers: list_tools, list_resources, list_prompts, list_resource_templates
68-
69-
See: https://modelcontextprotocol.io/specification/2025-03-26/server/utilities/pagination#request-format
70-
"""
71-
async with create_session(full_featured_server._mcp_server) as client_session:
72-
spies = stream_spy()
73-
74-
# Test without cursor parameter (omitted)
75-
method = getattr(client_session, method_name)
76-
_ = await method()
77-
requests = spies.get_client_requests(method=request_method)
78-
assert len(requests) == 1
79-
assert requests[0].params is None
80-
81-
spies.clear()
82-
83-
# Test with cursor=None
84-
_ = await method(cursor=None)
85-
requests = spies.get_client_requests(method=request_method)
86-
assert len(requests) == 1
87-
assert requests[0].params is None
88-
89-
spies.clear()
90-
91-
# Test with cursor as string
92-
_ = await method(cursor="some_cursor_value")
93-
requests = spies.get_client_requests(method=request_method)
94-
assert len(requests) == 1
95-
assert requests[0].params is not None
96-
assert requests[0].params["cursor"] == "some_cursor_value"
97-
98-
spies.clear()
99-
100-
# Test with empty string cursor
101-
_ = await method(cursor="")
102-
requests = spies.get_client_requests(method=request_method)
103-
assert len(requests) == 1
104-
assert requests[0].params is not None
105-
assert requests[0].params["cursor"] == ""
106-
107-
10849
@pytest.mark.parametrize(
10950
"method_name,request_method",
11051
[
@@ -164,37 +105,6 @@ async def test_list_methods_params_parameter(
164105
assert requests[0].params["cursor"] == "some_cursor_value"
165106

166107

167-
@pytest.mark.parametrize(
168-
"method_name",
169-
[
170-
"list_tools",
171-
"list_resources",
172-
"list_prompts",
173-
"list_resource_templates",
174-
],
175-
)
176-
async def test_list_methods_raises_error_when_both_cursor_and_params_provided(
177-
full_featured_server: FastMCP,
178-
method_name: str,
179-
):
180-
"""Test that providing both cursor and params raises ValueError.
181-
182-
Covers: list_tools, list_resources, list_prompts, list_resource_templates
183-
184-
When both cursor and params are provided, a ValueError should be raised
185-
to prevent ambiguity.
186-
"""
187-
async with create_session(full_featured_server._mcp_server) as client_session:
188-
method = getattr(client_session, method_name)
189-
190-
# Call with both cursor and params - should raise ValueError
191-
with pytest.raises(ValueError, match="Cannot specify both cursor and params"):
192-
await method(
193-
cursor="old_cursor",
194-
params=types.PaginatedRequestParams(cursor="new_cursor"),
195-
)
196-
197-
198108
async def test_list_tools_with_strict_server_validation():
199109
"""Test that list_tools works with strict servers require a params field,
200110
even if it is empty.

0 commit comments

Comments
 (0)