Skip to content

Commit 0708565

Browse files
authored
Merge branch 'modelcontextprotocol:main' into dogacan/mcp-python-sdk/fix-oauth-scope-handling
2 parents 9718486 + 61399b3 commit 0708565

File tree

76 files changed

+3745
-513
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+3745
-513
lines changed

.gitattribute

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Generated
2+
uv.lock linguist-generated=true

.github/CODEOWNERS

Lines changed: 0 additions & 23 deletions
This file was deleted.

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ coverage.xml
5252
*.py,cover
5353
.hypothesis/
5454
.pytest_cache/
55+
.ruff_cache/
5556
cover/
5657

5758
# Translations
@@ -168,3 +169,6 @@ cython_debug/
168169
.vscode/
169170
.windsurfrules
170171
**/CLAUDE.local.md
172+
173+
# claude code
174+
.claude/

.pre-commit-config.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,22 @@ repos:
2525
hooks:
2626
- id: ruff-format
2727
name: Ruff Format
28-
entry: uv run ruff
28+
entry: uv run --frozen ruff
2929
args: [format]
3030
language: system
3131
types: [python]
3232
pass_filenames: false
3333
- id: ruff
3434
name: Ruff
35-
entry: uv run ruff
35+
entry: uv run --frozen ruff
3636
args: ["check", "--fix", "--exit-non-zero-on-fix"]
3737
types: [python]
3838
language: system
3939
pass_filenames: false
4040
exclude: ^README\.md$
4141
- id: pyright
4242
name: pyright
43-
entry: uv run pyright
43+
entry: uv run --frozen pyright
4444
language: system
4545
types: [python]
4646
pass_filenames: false
@@ -52,7 +52,7 @@ repos:
5252
pass_filenames: false
5353
- id: readme-snippets
5454
name: Check README snippets are up to date
55-
entry: uv run scripts/update_readme_snippets.py --check
55+
entry: uv run --frozen python scripts/update_readme_snippets.py --check
5656
language: system
5757
files: ^(README\.md|examples/.*\.py|scripts/update_readme_snippets\.py)$
5858
pass_filenames: false

CLAUDE.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ This document contains critical information about working with this codebase. Fo
4848
the problem it tries to solve, and how it is solved. Don't go into the specifics of the
4949
code unless it adds clarity.
5050

51-
- Always add `jerome3o-anthropic` and `jspahrsummers` as reviewer.
52-
5351
- NEVER ever mention a `co-authored-by` or similar aspects. In particular, never
5452
mention the tool used to create the commit message or PR.
5553

README.md

Lines changed: 168 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
[![MIT licensed][mit-badge]][mit-url]
99
[![Python Version][python-badge]][python-url]
1010
[![Documentation][docs-badge]][docs-url]
11+
[![Protocol][protocol-badge]][protocol-url]
1112
[![Specification][spec-badge]][spec-url]
12-
[![GitHub Discussions][discussions-badge]][discussions-url]
1313

1414
</div>
1515

@@ -31,22 +31,33 @@
3131
- [Prompts](#prompts)
3232
- [Images](#images)
3333
- [Context](#context)
34+
- [Getting Context in Functions](#getting-context-in-functions)
35+
- [Context Properties and Methods](#context-properties-and-methods)
3436
- [Completions](#completions)
3537
- [Elicitation](#elicitation)
3638
- [Sampling](#sampling)
3739
- [Logging and Notifications](#logging-and-notifications)
3840
- [Authentication](#authentication)
3941
- [FastMCP Properties](#fastmcp-properties)
40-
- [Session Properties](#session-properties-and-methods)
42+
- [Session Properties and Methods](#session-properties-and-methods)
4143
- [Request Context Properties](#request-context-properties)
4244
- [Running Your Server](#running-your-server)
4345
- [Development Mode](#development-mode)
4446
- [Claude Desktop Integration](#claude-desktop-integration)
4547
- [Direct Execution](#direct-execution)
4648
- [Streamable HTTP Transport](#streamable-http-transport)
49+
- [CORS Configuration for Browser-Based Clients](#cors-configuration-for-browser-based-clients)
4750
- [Mounting to an Existing ASGI Server](#mounting-to-an-existing-asgi-server)
51+
- [StreamableHTTP servers](#streamablehttp-servers)
52+
- [Basic mounting](#basic-mounting)
53+
- [Host-based routing](#host-based-routing)
54+
- [Multiple servers with path configuration](#multiple-servers-with-path-configuration)
55+
- [Path configuration at initialization](#path-configuration-at-initialization)
56+
- [SSE servers](#sse-servers)
4857
- [Advanced Usage](#advanced-usage)
4958
- [Low-Level Server](#low-level-server)
59+
- [Structured Output Support](#structured-output-support)
60+
- [Pagination (Advanced)](#pagination-advanced)
5061
- [Writing MCP Clients](#writing-mcp-clients)
5162
- [Client Display Utilities](#client-display-utilities)
5263
- [OAuth Authentication for Clients](#oauth-authentication-for-clients)
@@ -63,12 +74,12 @@
6374
[mit-url]: https://github.com/modelcontextprotocol/python-sdk/blob/main/LICENSE
6475
[python-badge]: https://img.shields.io/pypi/pyversions/mcp.svg
6576
[python-url]: https://www.python.org/downloads/
66-
[docs-badge]: https://img.shields.io/badge/docs-modelcontextprotocol.io-blue.svg
67-
[docs-url]: https://modelcontextprotocol.io
77+
[docs-badge]: https://img.shields.io/badge/docs-python--sdk-blue.svg
78+
[docs-url]: https://modelcontextprotocol.github.io/python-sdk/
79+
[protocol-badge]: https://img.shields.io/badge/protocol-modelcontextprotocol.io-blue.svg
80+
[protocol-url]: https://modelcontextprotocol.io
6881
[spec-badge]: https://img.shields.io/badge/spec-spec.modelcontextprotocol.io-blue.svg
6982
[spec-url]: https://spec.modelcontextprotocol.io
70-
[discussions-badge]: https://img.shields.io/github/discussions/modelcontextprotocol/python-sdk
71-
[discussions-url]: https://github.com/modelcontextprotocol/python-sdk/discussions
7283

7384
## Overview
7485

@@ -400,7 +411,7 @@ def get_weather(city: str) -> WeatherData:
400411
"""Get weather for a city - returns structured data."""
401412
# Simulated weather data
402413
return WeatherData(
403-
temperature=72.5,
414+
temperature=22.5,
404415
humidity=45.0,
405416
condition="sunny",
406417
wind_speed=5.2,
@@ -505,6 +516,41 @@ def debug_error(error: str) -> list[base.Message]:
505516
_Full example: [examples/snippets/servers/basic_prompt.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_prompt.py)_
506517
<!-- /snippet-source -->
507518

519+
### Icons
520+
521+
MCP servers can provide icons for UI display. Icons can be added to the server implementation, tools, resources, and prompts:
522+
523+
```python
524+
from mcp.server.fastmcp import FastMCP, Icon
525+
526+
# Create an icon from a file path or URL
527+
icon = Icon(
528+
src="icon.png",
529+
mimeType="image/png",
530+
sizes="64x64"
531+
)
532+
533+
# Add icons to server
534+
mcp = FastMCP(
535+
"My Server",
536+
website_url="https://example.com",
537+
icons=[icon]
538+
)
539+
540+
# Add icons to tools, resources, and prompts
541+
@mcp.tool(icons=[icon])
542+
def my_tool():
543+
"""Tool with an icon."""
544+
return "result"
545+
546+
@mcp.resource("demo://resource", icons=[icon])
547+
def my_resource():
548+
"""Resource with an icon."""
549+
return "content"
550+
```
551+
552+
_Full example: [examples/fastmcp/icons_demo.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/fastmcp/icons_demo.py)_
553+
508554
### Images
509555

510556
FastMCP provides an `Image` class that automatically handles image data:
@@ -736,6 +782,8 @@ async def book_table(date: str, time: str, party_size: int, ctx: Context[ServerS
736782
_Full example: [examples/snippets/servers/elicitation.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/elicitation.py)_
737783
<!-- /snippet-source -->
738784

785+
Elicitation schemas support default values for all field types. Default values are automatically included in the JSON schema sent to clients, allowing them to pre-populate forms.
786+
739787
The `elicit()` method returns an `ElicitationResult` with:
740788

741789
- `action`: "accept", "decline", or "cancel"
@@ -885,6 +933,8 @@ The FastMCP server instance accessible via `ctx.fastmcp` provides access to serv
885933

886934
- `ctx.fastmcp.name` - The server's name as defined during initialization
887935
- `ctx.fastmcp.instructions` - Server instructions/description provided to clients
936+
- `ctx.fastmcp.website_url` - Optional website URL for the server
937+
- `ctx.fastmcp.icons` - Optional list of icons for UI display
888938
- `ctx.fastmcp.settings` - Complete server configuration object containing:
889939
- `debug` - Debug mode flag
890940
- `log_level` - Current logging level
@@ -1727,6 +1777,116 @@ Tools can return data in three ways:
17271777

17281778
When an `outputSchema` is defined, the server automatically validates the structured output against the schema. This ensures type safety and helps catch errors early.
17291779

1780+
### Pagination (Advanced)
1781+
1782+
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.
1783+
1784+
#### Server-side Implementation
1785+
1786+
<!-- snippet-source examples/snippets/servers/pagination_example.py -->
1787+
```python
1788+
"""
1789+
Example of implementing pagination with MCP server decorators.
1790+
"""
1791+
1792+
from pydantic import AnyUrl
1793+
1794+
import mcp.types as types
1795+
from mcp.server.lowlevel import Server
1796+
1797+
# Initialize the server
1798+
server = Server("paginated-server")
1799+
1800+
# Sample data to paginate
1801+
ITEMS = [f"Item {i}" for i in range(1, 101)] # 100 items
1802+
1803+
1804+
@server.list_resources()
1805+
async def list_resources_paginated(request: types.ListResourcesRequest) -> types.ListResourcesResult:
1806+
"""List resources with pagination support."""
1807+
page_size = 10
1808+
1809+
# Extract cursor from request params
1810+
cursor = request.params.cursor if request.params is not None else None
1811+
1812+
# Parse cursor to get offset
1813+
start = 0 if cursor is None else int(cursor)
1814+
end = start + page_size
1815+
1816+
# Get page of resources
1817+
page_items = [
1818+
types.Resource(uri=AnyUrl(f"resource://items/{item}"), name=item, description=f"Description for {item}")
1819+
for item in ITEMS[start:end]
1820+
]
1821+
1822+
# Determine next cursor
1823+
next_cursor = str(end) if end < len(ITEMS) else None
1824+
1825+
return types.ListResourcesResult(resources=page_items, nextCursor=next_cursor)
1826+
```
1827+
1828+
_Full example: [examples/snippets/servers/pagination_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/pagination_example.py)_
1829+
<!-- /snippet-source -->
1830+
1831+
#### Client-side Consumption
1832+
1833+
<!-- snippet-source examples/snippets/clients/pagination_client.py -->
1834+
```python
1835+
"""
1836+
Example of consuming paginated MCP endpoints from a client.
1837+
"""
1838+
1839+
import asyncio
1840+
1841+
from mcp.client.session import ClientSession
1842+
from mcp.client.stdio import StdioServerParameters, stdio_client
1843+
from mcp.types import Resource
1844+
1845+
1846+
async def list_all_resources() -> None:
1847+
"""Fetch all resources using pagination."""
1848+
async with stdio_client(StdioServerParameters(command="uv", args=["run", "mcp-simple-pagination"])) as (
1849+
read,
1850+
write,
1851+
):
1852+
async with ClientSession(read, write) as session:
1853+
await session.initialize()
1854+
1855+
all_resources: list[Resource] = []
1856+
cursor = None
1857+
1858+
while True:
1859+
# Fetch a page of resources
1860+
result = await session.list_resources(cursor=cursor)
1861+
all_resources.extend(result.resources)
1862+
1863+
print(f"Fetched {len(result.resources)} resources")
1864+
1865+
# Check if there are more pages
1866+
if result.nextCursor:
1867+
cursor = result.nextCursor
1868+
else:
1869+
break
1870+
1871+
print(f"Total resources: {len(all_resources)}")
1872+
1873+
1874+
if __name__ == "__main__":
1875+
asyncio.run(list_all_resources())
1876+
```
1877+
1878+
_Full example: [examples/snippets/clients/pagination_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/pagination_client.py)_
1879+
<!-- /snippet-source -->
1880+
1881+
#### Key Points
1882+
1883+
- **Cursors are opaque strings** - the server defines the format (numeric offsets, timestamps, etc.)
1884+
- **Return `nextCursor=None`** when there are no more pages
1885+
- **Backward compatible** - clients that don't support pagination will still work (they'll just get the first page)
1886+
- **Flexible page sizes** - Each endpoint can define its own page size based on data characteristics
1887+
1888+
See the [simple-pagination example](examples/servers/simple-pagination) for a complete implementation.
1889+
17301890
### Writing MCP Clients
17311891

17321892
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):
@@ -2137,6 +2297,7 @@ MCP servers declare capabilities during initialization:
21372297

21382298
## Documentation
21392299

2300+
- [API Reference](https://modelcontextprotocol.github.io/python-sdk/api/)
21402301
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
21412302
- [Model Context Protocol specification](https://spec.modelcontextprotocol.io)
21422303
- [Officially supported servers](https://github.com/modelcontextprotocol/servers)

docs/authorization.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Authorization
2+
3+
!!! warning "Under Construction"
4+
5+
This page is currently being written. Check back soon for complete documentation.

docs/concepts.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Concepts
2+
3+
!!! warning "Under Construction"
4+
5+
This page is currently being written. Check back soon for complete documentation.
6+
7+
<!--
8+
- Server vs Client
9+
- Three primitives (tools, resources, prompts)
10+
- Transports (stdio, SSE, streamable HTTP)
11+
- Context and sessions
12+
- Lifecycle and state
13+
-->

0 commit comments

Comments
 (0)