Skip to content

Commit 0d7d84d

Browse files
Merge branch 'modelcontextprotocol:main' into main
2 parents 7ae3026 + c47c767 commit 0d7d84d

File tree

11 files changed

+184
-28
lines changed

11 files changed

+184
-28
lines changed

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,32 @@
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)
5060
- [Writing MCP Clients](#writing-mcp-clients)
5161
- [Client Display Utilities](#client-display-utilities)
5262
- [OAuth Authentication for Clients](#oauth-authentication-for-clients)
@@ -400,7 +410,7 @@ def get_weather(city: str) -> WeatherData:
400410
"""Get weather for a city - returns structured data."""
401411
# Simulated weather data
402412
return WeatherData(
403-
temperature=72.5,
413+
temperature=22.5,
404414
humidity=45.0,
405415
condition="sunny",
406416
wind_speed=5.2,
@@ -2137,6 +2147,7 @@ MCP servers declare capabilities during initialization:
21372147

21382148
## Documentation
21392149

2150+
- [API Reference](https://modelcontextprotocol.github.io/python-sdk/api/)
21402151
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
21412152
- [Model Context Protocol specification](https://spec.modelcontextprotocol.io)
21422153
- [Officially supported servers](https://github.com/modelcontextprotocol/servers)

examples/servers/simple-resource/mcp_simple_resource/server.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import click
33
import mcp.types as types
44
from mcp.server.lowlevel import Server
5+
from mcp.server.lowlevel.helper_types import ReadResourceContents
56
from pydantic import AnyUrl, FileUrl
67
from starlette.requests import Request
78

@@ -46,15 +47,15 @@ async def list_resources() -> list[types.Resource]:
4647
]
4748

4849
@app.read_resource()
49-
async def read_resource(uri: AnyUrl) -> str | bytes:
50+
async def read_resource(uri: AnyUrl):
5051
if uri.path is None:
5152
raise ValueError(f"Invalid resource path: {uri}")
5253
name = uri.path.replace(".txt", "").lstrip("/")
5354

5455
if name not in SAMPLE_RESOURCES:
5556
raise ValueError(f"Unknown resource: {uri}")
5657

57-
return SAMPLE_RESOURCES[name]["content"]
58+
return [ReadResourceContents(content=SAMPLE_RESOURCES[name]["content"], mime_type="text/plain")]
5859

5960
if transport == "sse":
6061
from mcp.server.sse import SseServerTransport

examples/snippets/servers/structured_output.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def get_weather(city: str) -> WeatherData:
2424
"""Get weather for a city - returns structured data."""
2525
# Simulated weather data
2626
return WeatherData(
27-
temperature=72.5,
27+
temperature=22.5,
2828
humidity=45.0,
2929
condition="sunny",
3030
wind_speed=5.2,

pyproject.toml

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,36 @@ executionEnvironments = [
102102
{ root = "examples/servers", reportUnusedFunction = false },
103103
]
104104

105-
[tool.ruff.lint]
106-
select = ["C4", "E", "F", "I", "PERF", "UP"]
107-
ignore = ["PERF203"]
108-
109105
[tool.ruff]
110106
line-length = 120
111107
target-version = "py310"
112108
extend-exclude = ["README.md"]
113109

110+
[tool.ruff.lint]
111+
select = [
112+
"C4", # flake8-comprehensions
113+
"C90", # mccabe
114+
"E", # pycodestyle
115+
"F", # pyflakes
116+
"I", # isort
117+
"PERF", # Perflint
118+
"PL", # Pylint
119+
"UP", # pyupgrade
120+
]
121+
ignore = ["PERF203", "PLC0415", "PLR0402"]
122+
mccabe.max-complexity = 24 # Default is 10
123+
114124
[tool.ruff.lint.per-file-ignores]
115125
"__init__.py" = ["F401"]
116126
"tests/server/fastmcp/test_func_metadata.py" = ["E501"]
127+
"tests/shared/test_progress_notifications.py" = ["PLW0603"]
128+
129+
[tool.ruff.lint.pylint]
130+
allow-magic-value-types = ["bytes", "float", "int", "str"]
131+
max-args = 23 # Default is 5
132+
max-branches = 23 # Default is 12
133+
max-returns = 13 # Default is 6
134+
max-statements = 102 # Default is 50
117135

118136
[tool.uv.workspace]
119137
members = ["examples/servers/*", "examples/snippets"]

src/mcp/server/fastmcp/server.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,8 @@ def __init__(
182182
raise ValueError("Cannot specify both auth_server_provider and token_verifier")
183183
if not auth_server_provider and not token_verifier:
184184
raise ValueError("Must specify either auth_server_provider or token_verifier when auth is enabled")
185-
else:
186-
if auth_server_provider or token_verifier:
187-
raise ValueError("Cannot specify auth_server_provider or token_verifier without auth settings")
185+
elif auth_server_provider or token_verifier:
186+
raise ValueError("Cannot specify auth_server_provider or token_verifier without auth settings")
188187

189188
self._auth_server_provider = auth_server_provider
190189
self._token_verifier = token_verifier

src/mcp/server/fastmcp/utilities/func_metadata.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,14 @@ def pre_parse_json(self, data: dict[str, Any]) -> dict[str, Any]:
139139
if field_info.alias:
140140
key_to_field_info[field_info.alias] = field_info
141141

142-
for data_key in data.keys():
142+
for data_key, data_value in data.items():
143143
if data_key not in key_to_field_info:
144144
continue
145145

146146
field_info = key_to_field_info[data_key]
147-
if isinstance(data[data_key], str) and field_info.annotation is not str:
147+
if isinstance(data_value, str) and field_info.annotation is not str:
148148
try:
149-
pre_parsed = json.loads(data[data_key])
149+
pre_parsed = json.loads(data_value)
150150
except json.JSONDecodeError:
151151
continue # Not JSON - skip
152152
if isinstance(pre_parsed, str | int | float):

src/mcp/server/lowlevel/server.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ async def main():
8585
from mcp.server.lowlevel.helper_types import ReadResourceContents
8686
from mcp.server.models import InitializationOptions
8787
from mcp.server.session import ServerSession
88-
from mcp.server.stdio import stdio_server as stdio_server
8988
from mcp.shared.context import RequestContext
9089
from mcp.shared.exceptions import McpError
9190
from mcp.shared.message import ServerMessageMetadata, SessionMessage

src/mcp/server/session.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ async def _received_request(self, responder: RequestResponder[types.ClientReques
161161
)
162162
)
163163
)
164+
case types.PingRequest():
165+
# Ping requests are allowed at any time
166+
pass
164167
case _:
165168
if self._initialization_state != InitializationState.Initialized:
166169
raise RuntimeError("Received request before initialization was complete")

src/mcp/server/streamable_http.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -838,17 +838,16 @@ async def message_router():
838838
# If this response is for an existing request stream,
839839
# send it there
840840
target_request_id = response_id
841-
else:
842-
# Extract related_request_id from meta if it exists
843-
if (
844-
session_message.metadata is not None
845-
and isinstance(
846-
session_message.metadata,
847-
ServerMessageMetadata,
848-
)
849-
and session_message.metadata.related_request_id is not None
850-
):
851-
target_request_id = str(session_message.metadata.related_request_id)
841+
# Extract related_request_id from meta if it exists
842+
elif (
843+
session_message.metadata is not None
844+
and isinstance(
845+
session_message.metadata,
846+
ServerMessageMetadata,
847+
)
848+
and session_message.metadata.related_request_id is not None
849+
):
850+
target_request_id = str(session_message.metadata.related_request_id)
852851

853852
request_stream_id = target_request_id if target_request_id is not None else GET_STREAM_KEY
854853

tests/server/fastmcp/test_integration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ async def test_structured_output(server_transport: str, server_url: str) -> None
693693

694694
# Check that the result contains expected weather data
695695
result_text = weather_result.content[0].text
696-
assert "72.5" in result_text # temperature
696+
assert "22.5" in result_text # temperature
697697
assert "sunny" in result_text # condition
698698
assert "45" in result_text # humidity
699699
assert "5.2" in result_text # wind_speed

0 commit comments

Comments
 (0)