|
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