Skip to content

Commit a0fe665

Browse files
authored
Merge pull request #14 from andylim-duo/upstream-03182026
Upstream 03182026
2 parents a1ce448 + fb5c657 commit a0fe665

17 files changed

Lines changed: 455 additions & 735 deletions

File tree

docs/api.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/hooks/gen_ref_pages.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Generate the code reference pages and navigation."""
2+
3+
from pathlib import Path
4+
5+
import mkdocs_gen_files
6+
7+
nav = mkdocs_gen_files.Nav()
8+
9+
root = Path(__file__).parent.parent.parent
10+
src = root / "src"
11+
12+
for path in sorted(src.rglob("*.py")):
13+
module_path = path.relative_to(src).with_suffix("")
14+
doc_path = path.relative_to(src).with_suffix(".md")
15+
full_doc_path = Path("api", doc_path)
16+
17+
parts = tuple(module_path.parts)
18+
19+
if parts[-1] == "__init__":
20+
parts = parts[:-1]
21+
doc_path = doc_path.with_name("index.md")
22+
full_doc_path = full_doc_path.with_name("index.md")
23+
elif parts[-1].startswith("_"):
24+
continue
25+
26+
nav[parts] = doc_path.as_posix()
27+
28+
with mkdocs_gen_files.open(full_doc_path, "w") as fd:
29+
ident = ".".join(parts)
30+
fd.write(f"::: {ident}")
31+
32+
mkdocs_gen_files.set_edit_path(full_doc_path, path.relative_to(root))
33+
34+
with mkdocs_gen_files.open("api/SUMMARY.md", "w") as nav_file:
35+
nav_file.writelines(nav.build_literate_nav())

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,4 @@ npx -y @modelcontextprotocol/inspector
6464

6565
## API Reference
6666

67-
Full API documentation is available in the [API Reference](api.md).
67+
Full API documentation is available in the [API Reference](api/mcp/index.md).

docs/migration.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,30 @@ result = await session.list_resources(params=PaginatedRequestParams(cursor="next
169169
result = await session.list_tools(params=PaginatedRequestParams(cursor="next_page_token"))
170170
```
171171

172+
### `ClientSession.get_server_capabilities()` replaced by `initialize_result` property
173+
174+
`ClientSession` now stores the full `InitializeResult` via an `initialize_result` property. This provides access to `server_info`, `capabilities`, `instructions`, and the negotiated `protocol_version` through a single property. The `get_server_capabilities()` method has been removed.
175+
176+
**Before (v1):**
177+
178+
```python
179+
capabilities = session.get_server_capabilities()
180+
# server_info, instructions, protocol_version were not stored — had to capture initialize() return value
181+
```
182+
183+
**After (v2):**
184+
185+
```python
186+
result = session.initialize_result
187+
if result is not None:
188+
capabilities = result.capabilities
189+
server_info = result.server_info
190+
instructions = result.instructions
191+
version = result.protocol_version
192+
```
193+
194+
The high-level `Client.initialize_result` returns the same `InitializeResult` but is non-nullable — initialization is guaranteed inside the context manager, so no `None` check is needed. This replaces v1's `Client.server_capabilities`; use `client.initialize_result.capabilities` instead.
195+
172196
### `McpError` renamed to `MCPError`
173197

174198
The `McpError` exception class has been renamed to `MCPError` for consistent naming with the MCP acronym style used throughout the SDK.
@@ -859,6 +883,6 @@ The lowlevel `Server` also now exposes a `session_manager` property to access th
859883

860884
If you encounter issues during migration:
861885

862-
1. Check the [API Reference](api.md) for updated method signatures
886+
1. Check the [API Reference](api/mcp/index.md) for updated method signatures
863887
2. Review the [examples](https://github.com/modelcontextprotocol/python-sdk/tree/main/examples) for updated usage patterns
864888
3. Open an issue on [GitHub](https://github.com/modelcontextprotocol/python-sdk/issues) if you find a bug or need further assistance

mkdocs.yml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ nav:
2525
- Introduction: experimental/tasks.md
2626
- Server Implementation: experimental/tasks-server.md
2727
- Client Usage: experimental/tasks-client.md
28-
- API Reference: api.md
28+
- API Reference: api/
2929

3030
theme:
3131
name: "material"
@@ -115,19 +115,22 @@ plugins:
115115
- social:
116116
enabled: !ENV [ENABLE_SOCIAL_CARDS, false]
117117
- glightbox
118+
- gen-files:
119+
scripts:
120+
- docs/hooks/gen_ref_pages.py
121+
- literate-nav:
122+
nav_file: SUMMARY.md
118123
- mkdocstrings:
119124
handlers:
120125
python:
121-
paths: [src/mcp]
126+
paths: [src]
122127
options:
123128
relative_crossrefs: true
124129
members_order: source
125130
separate_signature: true
126131
show_signature_annotations: true
127132
signature_crossrefs: true
128133
group_by_category: false
129-
# 3 because docs are in pages with an H2 just above them
130-
heading_level: 3
131134
inventories:
132135
- url: https://docs.python.org/3/objects.inv
133136
- url: https://docs.pydantic.dev/latest/objects.inv

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ dev = [
7474
]
7575
docs = [
7676
"mkdocs>=1.6.1",
77+
"mkdocs-gen-files>=0.5.0",
7778
"mkdocs-glightbox>=0.4.0",
79+
"mkdocs-literate-nav>=0.6.1",
7880
"mkdocs-material[imaging]>=9.5.45",
7981
"mkdocstrings-python>=2.0.1",
8082
]

src/mcp/client/client.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
EmptyResult,
2020
GetPromptResult,
2121
Implementation,
22+
InitializeResult,
2223
ListPromptsResult,
2324
ListResourcesResult,
2425
ListResourceTemplatesResult,
@@ -29,7 +30,6 @@
2930
ReadResourceResult,
3031
RequestParamsMeta,
3132
ResourceTemplateReference,
32-
ServerCapabilities,
3333
)
3434

3535

@@ -155,9 +155,16 @@ def session(self) -> ClientSession:
155155
return self._session
156156

157157
@property
158-
def server_capabilities(self) -> ServerCapabilities | None:
159-
"""The server capabilities received during initialization, or None if not yet initialized."""
160-
return self.session.get_server_capabilities()
158+
def initialize_result(self) -> InitializeResult:
159+
"""The server's InitializeResult.
160+
161+
Contains server_info, capabilities, instructions, and the negotiated protocol_version.
162+
Raises RuntimeError if accessed outside the context manager.
163+
"""
164+
result = self.session.initialize_result
165+
if result is None: # pragma: no cover
166+
raise RuntimeError("Client must be used within an async context manager")
167+
return result
161168

162169
async def send_ping(self, *, meta: RequestParamsMeta | None = None) -> EmptyResult:
163170
"""Send a ping request to the server."""

src/mcp/client/session.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def __init__(
131131
self._logging_callback = logging_callback or _default_logging_callback
132132
self._message_handler = message_handler or _default_message_handler
133133
self._tool_output_schemas: dict[str, dict[str, Any] | None] = {}
134-
self._server_capabilities: types.ServerCapabilities | None = None
134+
self._initialize_result: types.InitializeResult | None = None
135135
self._experimental_features: ExperimentalClientFeatures | None = None
136136

137137
# Experimental: Task handlers (use defaults if not provided)
@@ -185,18 +185,19 @@ async def initialize(self) -> types.InitializeResult:
185185
if result.protocol_version not in SUPPORTED_PROTOCOL_VERSIONS:
186186
raise RuntimeError(f"Unsupported protocol version from the server: {result.protocol_version}")
187187

188-
self._server_capabilities = result.capabilities
188+
self._initialize_result = result
189189

190190
await self.send_notification(types.InitializedNotification())
191191

192192
return result
193193

194-
def get_server_capabilities(self) -> types.ServerCapabilities | None:
195-
"""Return the server capabilities received during initialization.
194+
@property
195+
def initialize_result(self) -> types.InitializeResult | None:
196+
"""The server's InitializeResult. None until initialize() has been called.
196197
197-
Returns None if the session has not been initialized yet.
198+
Contains server_info, capabilities, instructions, and the negotiated protocol_version.
198199
"""
199-
return self._server_capabilities
200+
return self._initialize_result
200201

201202
@property
202203
def experimental(self) -> ExperimentalClientFeatures:

src/mcp/server/session.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ async def send_progress_notification(
496496
related_request_id,
497497
)
498498

499-
async def send_resource_list_changed(self) -> None: # pragma: no cover
499+
async def send_resource_list_changed(self) -> None:
500500
"""Send a resource list changed notification."""
501501
await self.send_notification(types.ResourceListChangedNotification())
502502

src/mcp/server/websocket.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from mcp.shared.message import SessionMessage
1111

1212

13-
@asynccontextmanager # pragma: no cover
13+
@asynccontextmanager
1414
async def websocket_server(scope: Scope, receive: Receive, send: Send):
1515
"""WebSocket server transport for MCP. This is an ASGI application, suitable for use
1616
with a framework like Starlette and a server like Hypercorn.
@@ -34,13 +34,13 @@ async def ws_reader():
3434
async for msg in websocket.iter_text():
3535
try:
3636
client_message = types.jsonrpc_message_adapter.validate_json(msg, by_name=False)
37-
except ValidationError as exc:
37+
except ValidationError as exc: # pragma: no cover
3838
await read_stream_writer.send(exc)
3939
continue
4040

4141
session_message = SessionMessage(client_message)
4242
await read_stream_writer.send(session_message)
43-
except anyio.ClosedResourceError:
43+
except anyio.ClosedResourceError: # pragma: no cover
4444
await websocket.close()
4545

4646
async def ws_writer():
@@ -49,7 +49,7 @@ async def ws_writer():
4949
async for session_message in write_stream_reader:
5050
obj = session_message.message.model_dump_json(by_alias=True, exclude_unset=True)
5151
await websocket.send_text(obj)
52-
except anyio.ClosedResourceError:
52+
except anyio.ClosedResourceError: # pragma: no cover
5353
await websocket.close()
5454

5555
async with anyio.create_task_group() as tg:

0 commit comments

Comments
 (0)