Skip to content

Commit 494eb11

Browse files
authored
[v1.x] Support Python 3.14 (#2769)
1 parent 6213787 commit 494eb11

13 files changed

Lines changed: 224 additions & 42 deletions

File tree

.github/workflows/shared.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
continue-on-error: true
3636
strategy:
3737
matrix:
38-
python-version: ["3.10", "3.11", "3.12", "3.13"]
38+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
3939
dep-resolution:
4040
- name: lowest-direct
4141
install-flags: "--upgrade --resolution lowest-direct"

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ When bumping a dependency version manually, update the constraint in `pyproject.
7272

7373
Security-relevant dependency updates (P0) are applied within 7 days of public disclosure and backported to active release branches.
7474

75-
The SDK currently supports Python 3.10 through 3.13. New CPython releases are supported within one minor SDK release of their stable release date.
75+
The SDK currently supports Python 3.10 through 3.14. New CPython releases are supported within one minor SDK release of their stable release date.
7676

7777
## Triage Process
7878

pyproject.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,23 @@ classifiers = [
2020
"Programming Language :: Python :: 3.11",
2121
"Programming Language :: Python :: 3.12",
2222
"Programming Language :: Python :: 3.13",
23+
"Programming Language :: Python :: 3.14",
2324
]
2425
dependencies = [
2526
"anyio>=4.5",
2627
"httpx>=0.27.1,<1.0.0",
2728
"httpx-sse>=0.4",
28-
"pydantic>=2.11.0,<3.0.0",
29-
"starlette>=0.27",
29+
"pydantic>=2.12.0,<3.0.0; python_version >= '3.14'",
30+
"pydantic>=2.11.0,<3.0.0; python_version < '3.14'",
31+
"starlette>=0.48.0; python_version >= '3.14'",
32+
"starlette>=0.27; python_version < '3.14'",
3033
"python-multipart>=0.0.9",
3134
"sse-starlette>=1.6.1",
3235
"pydantic-settings>=2.5.2",
3336
"uvicorn>=0.31.1; sys_platform != 'emscripten'",
3437
"jsonschema>=4.20.0",
35-
"pywin32>=310; sys_platform == 'win32'",
38+
"pywin32>=311; sys_platform == 'win32' and python_version >= '3.14'",
39+
"pywin32>=310; sys_platform == 'win32' and python_version < '3.14'",
3640
"pyjwt[crypto]>=2.10.1",
3741
"typing-extensions>=4.9.0",
3842
"typing-inspection>=0.4.1",
@@ -67,7 +71,7 @@ dev = [
6771
docs = [
6872
"mkdocs>=1.6.1",
6973
"mkdocs-glightbox>=0.4.0",
70-
"mkdocs-material[imaging]>=9.5.45",
74+
"mkdocs-material[imaging]>=9.6.19",
7175
"mkdocstrings-python>=1.12.2",
7276
]
7377

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def find_context_parameter(fn: Callable[..., Any]) -> str | None:
2525
# Get type hints to properly resolve string annotations
2626
try:
2727
hints = typing.get_type_hints(fn)
28-
except Exception:
28+
except Exception: # pragma: no cover
2929
# If we can't resolve type hints, we can't find the context parameter
3030
return None
3131

src/mcp/server/session.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,5 @@ async def _handle_incoming(self, req: ServerRequestResponder) -> None:
685685
await self._incoming_message_stream_writer.send(req)
686686

687687
@property
688-
def incoming_messages(
689-
self,
690-
) -> MemoryObjectReceiveStream[ServerRequestResponder]:
688+
def incoming_messages(self) -> MemoryObjectReceiveStream[ServerRequestResponder]:
691689
return self._incoming_message_stream_reader

tests/experimental/tasks/server/test_server.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ async def run_server():
312312
async with anyio.create_task_group() as tg:
313313

314314
async def handle_messages():
315-
async for message in server_session.incoming_messages:
315+
async for message in server_session.incoming_messages: # pragma: no cover
316316
await server._handle_message(message, server_session, {}, False)
317317

318318
tg.start_soon(handle_messages)
@@ -392,7 +392,7 @@ async def run_server():
392392
) as server_session:
393393
async with anyio.create_task_group() as tg:
394394

395-
async def handle_messages():
395+
async def handle_messages(): # pragma: no cover
396396
async for message in server_session.incoming_messages:
397397
await server._handle_message(message, server_session, {}, False)
398398

tests/server/test_lowlevel_input_validation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ async def run_server():
7070
async with anyio.create_task_group() as tg:
7171

7272
async def handle_messages():
73-
async for message in server_session.incoming_messages:
73+
async for message in server_session.incoming_messages: # pragma: no cover
7474
await server._handle_message(message, server_session, {}, False)
7575

7676
tg.start_soon(handle_messages)

tests/server/test_lowlevel_output_validation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ async def run_server():
7171
async with anyio.create_task_group() as tg:
7272

7373
async def handle_messages():
74-
async for message in server_session.incoming_messages:
74+
async for message in server_session.incoming_messages: # pragma: no cover
7575
await server._handle_message(message, server_session, {}, False)
7676

7777
tg.start_soon(handle_messages)

tests/server/test_lowlevel_tool_annotations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ async def run_server():
6767
async with anyio.create_task_group() as tg:
6868

6969
async def handle_messages():
70-
async for message in server_session.incoming_messages:
70+
async for message in server_session.incoming_messages: # pragma: no cover
7171
await server._handle_message(message, server_session, {}, False)
7272

7373
tg.start_soon(handle_messages)

tests/server/test_session.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -410,11 +410,8 @@ async def test_create_message_tool_result_validation():
410410

411411
# Case 8: empty messages list - skips validation entirely
412412
# Covers the `if messages:` branch (line 280->302)
413-
with anyio.move_on_after(0.01):
414-
await session.create_message(
415-
messages=[],
416-
max_tokens=100,
417-
)
413+
with anyio.move_on_after(0.01): # pragma: no cover
414+
await session.create_message(messages=[], max_tokens=100)
418415

419416

420417
@pytest.mark.anyio

0 commit comments

Comments
 (0)