Skip to content

Commit 49a13ec

Browse files
authored
Add doc-strings (#251)
1 parent ceb6a82 commit 49a13ec

File tree

8 files changed

+226
-48
lines changed

8 files changed

+226
-48
lines changed

examples/servers/streamable-http-stateless/mcp_simple_streamablehttp_stateless/server.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
"""Simple MCP server example using streamable HTTP transport.
2+
3+
This module demonstrates a basic MCP server implementation using streamable HTTP
4+
transport with basic math operations (add and multiply).
5+
"""
6+
17
import contextlib
28
import logging
39
from collections.abc import AsyncIterator
@@ -31,6 +37,16 @@ def main(
3137
log_level: str,
3238
json_response: bool,
3339
) -> int:
40+
"""Run the MCP server with streamable HTTP transport.
41+
42+
Args:
43+
port: Port to listen on for HTTP requests.
44+
log_level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL).
45+
json_response: Whether to enable JSON responses instead of SSE streams.
46+
47+
Returns:
48+
Exit code (0 for success).
49+
"""
3450
# Configure logging
3551
logging.basicConfig(
3652
level=getattr(logging, log_level.upper()),
@@ -43,6 +59,18 @@ def main(
4359
async def call_tool(
4460
name: str, arguments: dict
4561
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
62+
"""Handle tool calls for math operations.
63+
64+
Args:
65+
name: Name of the tool to call.
66+
arguments: Dictionary of arguments for the tool.
67+
68+
Returns:
69+
List of content objects with the tool result.
70+
71+
Raises:
72+
ValueError: If the tool name is not recognized.
73+
"""
4674
if name == "add":
4775
return [
4876
types.TextContent(
@@ -62,6 +90,11 @@ async def call_tool(
6290

6391
@app.list_tools()
6492
async def list_tools() -> list[types.Tool]:
93+
"""List all available tools provided by this server.
94+
95+
Returns:
96+
List of tool definitions for add and multiply operations.
97+
"""
6598
return [
6699
types.Tool(
67100
name="add",
@@ -112,11 +145,25 @@ async def list_tools() -> list[types.Tool]:
112145
async def handle_streamable_http(
113146
scope: Scope, receive: Receive, send: Send
114147
) -> None:
148+
"""Handle streamable HTTP requests through the session manager.
149+
150+
Args:
151+
scope: ASGI scope object.
152+
receive: ASGI receive callable.
153+
send: ASGI send callable.
154+
"""
115155
await session_manager.handle_request(scope, receive, send)
116156

117157
@contextlib.asynccontextmanager
118158
async def lifespan(app: Starlette) -> AsyncIterator[None]:
119-
"""Context manager for session manager."""
159+
"""Context manager for session manager lifecycle.
160+
161+
Args:
162+
app: The Starlette application instance.
163+
164+
Yields:
165+
None during the application lifetime.
166+
"""
120167
async with session_manager.run():
121168
logger.info("Application started with StreamableHTTP session manager!")
122169
try:

langchain_mcp_adapters/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""LangChain MCP Adapters - Connect MCP servers with LangChain applications.
2+
3+
This package provides adapters to connect MCP (Model Context Protocol) servers
4+
with LangChain applications, converting MCP tools, prompts, and resources into
5+
LangChain-compatible formats.
6+
"""

langchain_mcp_adapters/client.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
"""Client for connecting to multiple MCP servers and loading LangChain-compatible resources.
2+
3+
This module provides the MultiServerMCPClient class for managing connections to multiple
4+
MCP servers and loading tools, prompts, and resources from them.
5+
"""
6+
17
import asyncio
28
from collections.abc import AsyncIterator
39
from contextlib import asynccontextmanager
@@ -169,6 +175,11 @@ async def get_resources(
169175
return await load_mcp_resources(session, uris=uris)
170176

171177
async def __aenter__(self) -> "MultiServerMCPClient":
178+
"""Async context manager entry point.
179+
180+
Raises:
181+
NotImplementedError: Context manager support has been removed.
182+
"""
172183
raise NotImplementedError(ASYNC_CONTEXT_MANAGER_ERROR)
173184

174185
def __aexit__(
@@ -177,6 +188,16 @@ def __aexit__(
177188
exc_val: BaseException | None,
178189
exc_tb: TracebackType | None,
179190
) -> None:
191+
"""Async context manager exit point.
192+
193+
Args:
194+
exc_type: Exception type if an exception occurred.
195+
exc_val: Exception value if an exception occurred.
196+
exc_tb: Exception traceback if an exception occurred.
197+
198+
Raises:
199+
NotImplementedError: Context manager support has been removed.
200+
"""
180201
raise NotImplementedError(ASYNC_CONTEXT_MANAGER_ERROR)
181202

182203

langchain_mcp_adapters/prompts.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
"""Prompts adapter for converting MCP prompts to LangChain messages.
2+
3+
This module provides functionality to convert MCP prompt messages into LangChain
4+
message objects, handling both user and assistant message types.
5+
"""
6+
17
from typing import Any
28

39
from langchain_core.messages import AIMessage, HumanMessage
@@ -35,7 +41,16 @@ async def load_mcp_prompt(
3541
*,
3642
arguments: dict[str, Any] | None = None,
3743
) -> list[HumanMessage | AIMessage]:
38-
"""Load MCP prompt and convert to LangChain messages."""
44+
"""Load MCP prompt and convert to LangChain messages.
45+
46+
Args:
47+
session: The MCP client session.
48+
name: Name of the prompt to load.
49+
arguments: Optional arguments to pass to the prompt.
50+
51+
Returns:
52+
A list of LangChain messages converted from the MCP prompt.
53+
"""
3954
response = await session.get_prompt(name, arguments)
4055
return [
4156
convert_mcp_prompt_message_to_langchain_message(message) for message in response.messages

langchain_mcp_adapters/resources.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
"""Resources adapter for converting MCP resources to LangChain Blobs.
2+
3+
This module provides functionality to convert MCP resources into LangChain Blob
4+
objects, handling both text and binary resource content types.
5+
"""
6+
17
import base64
28

39
from langchain_core.documents.base import Blob
@@ -31,12 +37,11 @@ async def get_mcp_resource(session: ClientSession, uri: str) -> list[Blob]:
3137
"""Fetch a single MCP resource and convert it to LangChain Blobs.
3238
3339
Args:
34-
session: MCP client session
35-
uri: URI of the resource to fetch
40+
session: MCP client session.
41+
uri: URI of the resource to fetch.
3642
3743
Returns:
38-
A list of LangChain Blobs
39-
44+
A list of LangChain Blobs.
4045
"""
4146
contents_result = await session.read_resource(uri)
4247
if not contents_result.contents or len(contents_result.contents) == 0:
@@ -55,16 +60,17 @@ async def load_mcp_resources(
5560
"""Load MCP resources and convert them to LangChain Blobs.
5661
5762
Args:
58-
session: MCP client session
59-
uris: List of URIs to load.
60-
If None, all resources will be loaded.
61-
NOTE: if you specify None, dynamic resources will NOT be loaded,
62-
as they need the parameters to be provided,
63-
and are ignored by MCP SDK's session.list_resources() method.
63+
session: MCP client session.
64+
uris: List of URIs to load. If None, all resources will be loaded.
65+
Note: Dynamic resources will NOT be loaded when None is specified,
66+
as they require parameters and are ignored by the MCP SDK's
67+
session.list_resources() method.
6468
6569
Returns:
66-
A list of LangChain Blobs
70+
A list of LangChain Blobs.
6771
72+
Raises:
73+
RuntimeError: If an error occurs while fetching a resource.
6874
"""
6975
blobs = []
7076

langchain_mcp_adapters/sessions.py

Lines changed: 62 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
"""Session management for different MCP transport types.
2+
3+
This module provides connection configurations and session management for various
4+
MCP transport types including stdio, SSE, WebSocket, and streamable HTTP.
5+
"""
6+
17
from __future__ import annotations
28

39
import os
@@ -30,15 +36,30 @@
3036

3137

3238
class McpHttpClientFactory(Protocol):
39+
"""Protocol for creating httpx.AsyncClient instances for MCP connections."""
40+
3341
def __call__(
3442
self,
3543
headers: dict[str, str] | None = None,
3644
timeout: httpx.Timeout | None = None,
3745
auth: httpx.Auth | None = None,
38-
) -> httpx.AsyncClient: ...
46+
) -> httpx.AsyncClient:
47+
"""Create an httpx.AsyncClient instance.
48+
49+
Args:
50+
headers: HTTP headers to include in requests.
51+
timeout: Request timeout configuration.
52+
auth: Authentication configuration.
53+
54+
Returns:
55+
Configured httpx.AsyncClient instance.
56+
"""
57+
...
3958

4059

4160
class StdioConnection(TypedDict):
61+
"""Configuration for stdio transport connections to MCP servers."""
62+
4263
transport: Literal["stdio"]
4364

4465
command: str
@@ -74,6 +95,8 @@ class StdioConnection(TypedDict):
7495

7596

7697
class SSEConnection(TypedDict):
98+
"""Configuration for Server-Sent Events (SSE) transport connections to MCP servers."""
99+
77100
transport: Literal["sse"]
78101

79102
url: str
@@ -107,9 +130,10 @@ class SSEConnection(TypedDict):
107130

108131

109132
class StreamableHttpConnection(TypedDict):
110-
transport: Literal["streamable_http"]
111133
"""Connection configuration for Streamable HTTP transport."""
112134

135+
transport: Literal["streamable_http"]
136+
113137
url: str
114138
"""The URL of the endpoint to connect to."""
115139

@@ -137,6 +161,8 @@ class StreamableHttpConnection(TypedDict):
137161

138162

139163
class WebsocketConnection(TypedDict):
164+
"""Configuration for WebSocket transport connections to MCP servers."""
165+
140166
transport: Literal["websocket"]
141167

142168
url: str
@@ -163,14 +189,16 @@ async def _create_stdio_session( # noqa: PLR0913
163189
"""Create a new session to an MCP server using stdio.
164190
165191
Args:
166-
command: Command to execute
167-
args: Arguments for the command
168-
env: Environment variables for the command
169-
cwd: Working directory for the command
170-
encoding: Character encoding
171-
encoding_error_handler: How to handle encoding errors
172-
session_kwargs: Additional keyword arguments to pass to the ClientSession
192+
command: Command to execute.
193+
args: Arguments for the command.
194+
env: Environment variables for the command.
195+
cwd: Working directory for the command.
196+
encoding: Character encoding.
197+
encoding_error_handler: How to handle encoding errors.
198+
session_kwargs: Additional keyword arguments to pass to the ClientSession.
173199
200+
Yields:
201+
An initialized ClientSession.
174202
"""
175203
# NOTE: execution commands (e.g., `uvx` / `npx`) require PATH envvar to be set.
176204
# To address this, we automatically inject existing PATH envvar into the `env` value,
@@ -210,14 +238,16 @@ async def _create_sse_session( # noqa: PLR0913
210238
"""Create a new session to an MCP server using SSE.
211239
212240
Args:
213-
url: URL of the SSE server
214-
headers: HTTP headers to send to the SSE endpoint
215-
timeout: HTTP timeout
216-
sse_read_timeout: SSE read timeout
217-
session_kwargs: Additional keyword arguments to pass to the ClientSession
218-
httpx_client_factory: Custom factory for httpx.AsyncClient (optional)
219-
auth: httpx.Auth | None = None
241+
url: URL of the SSE server.
242+
headers: HTTP headers to send to the SSE endpoint.
243+
timeout: HTTP timeout.
244+
sse_read_timeout: SSE read timeout.
245+
session_kwargs: Additional keyword arguments to pass to the ClientSession.
246+
httpx_client_factory: Custom factory for httpx.AsyncClient (optional).
247+
auth: Authentication for the HTTP client.
220248
249+
Yields:
250+
An initialized ClientSession.
221251
"""
222252
# Create and store the connection
223253
kwargs = {}
@@ -249,15 +279,17 @@ async def _create_streamable_http_session( # noqa: PLR0913
249279
"""Create a new session to an MCP server using Streamable HTTP.
250280
251281
Args:
252-
url: URL of the endpoint to connect to
253-
headers: HTTP headers to send to the endpoint
254-
timeout: HTTP timeout
255-
sse_read_timeout: How long (in seconds) the client will wait for a new event before disconnecting
256-
terminate_on_close: Whether to terminate the session on close
257-
session_kwargs: Additional keyword arguments to pass to the ClientSession
258-
httpx_client_factory: Custom factory for httpx.AsyncClient (optional)
259-
auth: httpx.Auth | None = None
282+
url: URL of the endpoint to connect to.
283+
headers: HTTP headers to send to the endpoint.
284+
timeout: HTTP timeout.
285+
sse_read_timeout: How long the client will wait for a new event before disconnecting.
286+
terminate_on_close: Whether to terminate the session on close.
287+
session_kwargs: Additional keyword arguments to pass to the ClientSession.
288+
httpx_client_factory: Custom factory for httpx.AsyncClient (optional).
289+
auth: Authentication for the HTTP client.
260290
291+
Yields:
292+
An initialized ClientSession.
261293
"""
262294
# Create and store the connection
263295
kwargs = {}
@@ -288,12 +320,14 @@ async def _create_websocket_session(
288320
"""Create a new session to an MCP server using Websockets.
289321
290322
Args:
291-
url: URL of the Websocket endpoint
292-
session_kwargs: Additional keyword arguments to pass to the ClientSession
323+
url: URL of the Websocket endpoint.
324+
session_kwargs: Additional keyword arguments to pass to the ClientSession.
293325
294-
Raises:
295-
ImportError: If websockets package is not installed
326+
Yields:
327+
An initialized ClientSession.
296328
329+
Raises:
330+
ImportError: If websockets package is not installed.
297331
"""
298332
try:
299333
from mcp.client.websocket import websocket_client

0 commit comments

Comments
 (0)