|  | 
| 47 | 47 |     - [Mounting to an Existing ASGI Server](#mounting-to-an-existing-asgi-server) | 
| 48 | 48 |   - [Advanced Usage](#advanced-usage) | 
| 49 | 49 |     - [Low-Level Server](#low-level-server) | 
|  | 50 | +    - [Pagination (Advanced)](#pagination-advanced) | 
| 50 | 51 |     - [Writing MCP Clients](#writing-mcp-clients) | 
| 51 | 52 |     - [Client Display Utilities](#client-display-utilities) | 
| 52 | 53 |     - [OAuth Authentication for Clients](#oauth-authentication-for-clients) | 
| @@ -1530,6 +1531,125 @@ Tools can return data in three ways: | 
| 1530 | 1531 | 
 | 
| 1531 | 1532 | When an `outputSchema` is defined, the server automatically validates the structured output against the schema. This ensures type safety and helps catch errors early. | 
| 1532 | 1533 | 
 | 
|  | 1534 | +### Pagination (Advanced) | 
|  | 1535 | + | 
|  | 1536 | +For servers that need to handle large datasets, the low-level server provides paginated versions of list operations. This is an optional optimization - most servers won't need pagination unless they're dealing with hundreds or thousands of items. | 
|  | 1537 | + | 
|  | 1538 | +#### Server-side Implementation | 
|  | 1539 | + | 
|  | 1540 | +<!-- snippet-source examples/snippets/servers/pagination_example.py --> | 
|  | 1541 | +```python | 
|  | 1542 | +""" | 
|  | 1543 | +Example of implementing pagination with MCP server decorators. | 
|  | 1544 | +""" | 
|  | 1545 | + | 
|  | 1546 | +import mcp.types as types | 
|  | 1547 | +from mcp.server.lowlevel import Server | 
|  | 1548 | +from pydantic import AnyUrl | 
|  | 1549 | + | 
|  | 1550 | +# Initialize the server | 
|  | 1551 | +server = Server("paginated-server") | 
|  | 1552 | + | 
|  | 1553 | +# Sample data to paginate | 
|  | 1554 | +ITEMS = [f"Item {i}" for i in range(1, 101)]  # 100 items | 
|  | 1555 | + | 
|  | 1556 | + | 
|  | 1557 | +@server.list_resources_paginated() | 
|  | 1558 | +async def list_resources_paginated(cursor: types.Cursor | None) -> types.ListResourcesResult: | 
|  | 1559 | +    """List resources with pagination support.""" | 
|  | 1560 | +    page_size = 10 | 
|  | 1561 | +     | 
|  | 1562 | +    # Parse cursor to get offset | 
|  | 1563 | +    start = 0 if cursor is None else int(cursor) | 
|  | 1564 | +    end = start + page_size | 
|  | 1565 | +     | 
|  | 1566 | +    # Get page of resources | 
|  | 1567 | +    page_items = [ | 
|  | 1568 | +        types.Resource( | 
|  | 1569 | +            uri=AnyUrl(f"resource://items/{item}"), | 
|  | 1570 | +            name=item, | 
|  | 1571 | +            description=f"Description for {item}" | 
|  | 1572 | +        ) | 
|  | 1573 | +        for item in ITEMS[start:end] | 
|  | 1574 | +    ] | 
|  | 1575 | +     | 
|  | 1576 | +    # Determine next cursor | 
|  | 1577 | +    next_cursor = str(end) if end < len(ITEMS) else None | 
|  | 1578 | +     | 
|  | 1579 | +    return types.ListResourcesResult( | 
|  | 1580 | +        resources=page_items, | 
|  | 1581 | +        nextCursor=next_cursor | 
|  | 1582 | +    ) | 
|  | 1583 | +``` | 
|  | 1584 | + | 
|  | 1585 | +_Full example: [examples/snippets/servers/pagination_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/pagination_example.py)_ | 
|  | 1586 | +<!-- /snippet-source --> | 
|  | 1587 | + | 
|  | 1588 | +Similar decorators are available for all list operations: | 
|  | 1589 | + | 
|  | 1590 | +- `@server.list_tools_paginated()` - for paginating tools | 
|  | 1591 | +- `@server.list_resources_paginated()` - for paginating resources   | 
|  | 1592 | +- `@server.list_prompts_paginated()` - for paginating prompts | 
|  | 1593 | + | 
|  | 1594 | +#### Client-side Consumption | 
|  | 1595 | + | 
|  | 1596 | +<!-- snippet-source examples/snippets/clients/pagination_client.py --> | 
|  | 1597 | +```python | 
|  | 1598 | +""" | 
|  | 1599 | +Example of consuming paginated MCP endpoints from a client. | 
|  | 1600 | +""" | 
|  | 1601 | + | 
|  | 1602 | +import asyncio | 
|  | 1603 | +from mcp.client.session import ClientSession | 
|  | 1604 | +from mcp.client.stdio import StdioServerParameters, stdio_client | 
|  | 1605 | + | 
|  | 1606 | + | 
|  | 1607 | +async def list_all_resources(): | 
|  | 1608 | +    """Fetch all resources using pagination.""" | 
|  | 1609 | +    async with stdio_client( | 
|  | 1610 | +        StdioServerParameters(command="uv", args=["run", "mcp-simple-pagination"]) | 
|  | 1611 | +    ) as (read, write): | 
|  | 1612 | +        async with ClientSession(read, write) as session: | 
|  | 1613 | +            await session.initialize() | 
|  | 1614 | +             | 
|  | 1615 | +            all_resources = [] | 
|  | 1616 | +            cursor = None | 
|  | 1617 | +             | 
|  | 1618 | +            while True: | 
|  | 1619 | +                # Fetch a page of resources | 
|  | 1620 | +                result = await session.list_resources(cursor=cursor) | 
|  | 1621 | +                all_resources.extend(result.resources) | 
|  | 1622 | +                 | 
|  | 1623 | +                print(f"Fetched {len(result.resources)} resources") | 
|  | 1624 | +                 | 
|  | 1625 | +                # Check if there are more pages | 
|  | 1626 | +                if result.nextCursor: | 
|  | 1627 | +                    cursor = result.nextCursor | 
|  | 1628 | +                else: | 
|  | 1629 | +                    break | 
|  | 1630 | +             | 
|  | 1631 | +            print(f"Total resources: {len(all_resources)}") | 
|  | 1632 | +            return all_resources | 
|  | 1633 | + | 
|  | 1634 | + | 
|  | 1635 | +if __name__ == "__main__": | 
|  | 1636 | +    asyncio.run(list_all_resources()) | 
|  | 1637 | +``` | 
|  | 1638 | + | 
|  | 1639 | +_Full example: [examples/snippets/clients/pagination_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/pagination_client.py)_ | 
|  | 1640 | +<!-- /snippet-source --> | 
|  | 1641 | + | 
|  | 1642 | +#### Key Points | 
|  | 1643 | + | 
|  | 1644 | +- **Cursors are opaque strings** - the server defines the format (numeric offsets, timestamps, etc.) | 
|  | 1645 | +- **Return `nextCursor=None`** when there are no more pages | 
|  | 1646 | +- **Backward compatible** - clients that don't support pagination will still work (they'll just get the first page) | 
|  | 1647 | +- **Flexible page sizes** - Each endpoint can define its own page size based on data characteristics | 
|  | 1648 | + | 
|  | 1649 | +> **NOTE**: The paginated decorators (`list_tools_paginated()`, `list_resources_paginated()`, `list_prompts_paginated()`) are mutually exclusive with their non-paginated counterparts and cannot be used together on the same server instance. | 
|  | 1650 | +
 | 
|  | 1651 | +See the [simple-pagination example](examples/servers/simple-pagination) for a complete implementation. | 
|  | 1652 | + | 
| 1533 | 1653 | ### Writing MCP Clients | 
| 1534 | 1654 | 
 | 
| 1535 | 1655 | The SDK provides a high-level client interface for connecting to MCP servers using various [transports](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports): | 
|  | 
0 commit comments