Use 120 characters instead of 88 (#856)

This commit is contained in:
Marcelo Trylesinski 2025-06-11 02:45:50 -07:00 • committed by GitHub
commit 543961968c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 687 additions and 2142 deletions

View file

@ -45,9 +45,7 @@ class OAuthClientMetadata(BaseModel):
# token_endpoint_auth_method: this implementation only supports none &
# client_secret_post;
# ie: we do not support client_secret_basic
token_endpoint_auth_method: Literal["none", "client_secret_post"] = (
"client_secret_post"
)
token_endpoint_auth_method: Literal["none", "client_secret_post"] = "client_secret_post"
# grant_types: this implementation only supports authorization_code & refresh_token
grant_types: list[Literal["authorization_code", "refresh_token"]] = [
"authorization_code",
@ -84,17 +82,12 @@ class OAuthClientMetadata(BaseModel):
if redirect_uri is not None:
# Validate redirect_uri against client's registered redirect URIs
if redirect_uri not in self.redirect_uris:
raise InvalidRedirectUriError(
f"Redirect URI '{redirect_uri}' not registered for client"
)
raise InvalidRedirectUriError(f"Redirect URI '{redirect_uri}' not registered for client")
return redirect_uri
elif len(self.redirect_uris) == 1:
return self.redirect_uris[0]
else:
raise InvalidRedirectUriError(
"redirect_uri must be specified when client "
"has multiple registered URIs"
)
raise InvalidRedirectUriError("redirect_uri must be specified when client " "has multiple registered URIs")
class OAuthClientInformationFull(OAuthClientMetadata):

View file

@ -11,26 +11,15 @@ import anyio
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
import mcp.types as types
from mcp.client.session import (
ClientSession,
ListRootsFnT,
LoggingFnT,
MessageHandlerFnT,
SamplingFnT,
)
from mcp.client.session import ClientSession, ListRootsFnT, LoggingFnT, MessageHandlerFnT, SamplingFnT
from mcp.server import Server
from mcp.shared.message import SessionMessage
MessageStream = tuple[
MemoryObjectReceiveStream[SessionMessage | Exception],
MemoryObjectSendStream[SessionMessage],
]
MessageStream = tuple[MemoryObjectReceiveStream[SessionMessage | Exception], MemoryObjectSendStream[SessionMessage]]
@asynccontextmanager
async def create_client_server_memory_streams() -> (
AsyncGenerator[tuple[MessageStream, MessageStream], None]
):
async def create_client_server_memory_streams() -> AsyncGenerator[tuple[MessageStream, MessageStream], None]:
"""
Creates a pair of bidirectional memory streams for client-server communication.
@ -39,12 +28,8 @@ async def create_client_server_memory_streams() -> (
(read_stream, write_stream)
"""
# Create streams for both directions
server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[
SessionMessage | Exception
](1)
client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[
SessionMessage | Exception
](1)
server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[SessionMessage | Exception](1)
client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage | Exception](1)
client_streams = (server_to_client_receive, client_to_server_send)
server_streams = (client_to_server_receive, server_to_client_send)

View file

@ -20,9 +20,7 @@ class ClientMessageMetadata:
"""Metadata specific to client messages."""
resumption_token: ResumptionToken | None = None
on_resumption_token_update: Callable[[ResumptionToken], Awaitable[None]] | None = (
None
)
on_resumption_token_update: Callable[[ResumptionToken], Awaitable[None]] | None = None
@dataclass

View file

@ -23,22 +23,8 @@ class Progress(BaseModel):
@dataclass
class ProgressContext(
Generic[
SendRequestT,
SendNotificationT,
SendResultT,
ReceiveRequestT,
ReceiveNotificationT,
]
):
session: BaseSession[
SendRequestT,
SendNotificationT,
SendResultT,
ReceiveRequestT,
ReceiveNotificationT,
]
class ProgressContext(Generic[SendRequestT, SendNotificationT, SendResultT, ReceiveRequestT, ReceiveNotificationT]):
session: BaseSession[SendRequestT, SendNotificationT, SendResultT, ReceiveRequestT, ReceiveNotificationT]
progress_token: ProgressToken
total: float | None
current: float = field(default=0.0, init=False)
@ -54,24 +40,12 @@ class ProgressContext(
@contextmanager
def progress(
ctx: RequestContext[
BaseSession[
SendRequestT,
SendNotificationT,
SendResultT,
ReceiveRequestT,
ReceiveNotificationT,
],
BaseSession[SendRequestT, SendNotificationT, SendResultT, ReceiveRequestT, ReceiveNotificationT],
LifespanContextT,
],
total: float | None = None,
) -> Generator[
ProgressContext[
SendRequestT,
SendNotificationT,
SendResultT,
ReceiveRequestT,
ReceiveNotificationT,
],
ProgressContext[SendRequestT, SendNotificationT, SendResultT, ReceiveRequestT, ReceiveNotificationT],
None,
]:
if ctx.meta is None or ctx.meta.progressToken is None:

View file

@ -38,9 +38,7 @@ SendResultT = TypeVar("SendResultT", ClientResult, ServerResult)
SendNotificationT = TypeVar("SendNotificationT", ClientNotification, ServerNotification)
ReceiveRequestT = TypeVar("ReceiveRequestT", ClientRequest, ServerRequest)
ReceiveResultT = TypeVar("ReceiveResultT", bound=BaseModel)
ReceiveNotificationT = TypeVar(
"ReceiveNotificationT", ClientNotification, ServerNotification
)
ReceiveNotificationT = TypeVar("ReceiveNotificationT", ClientNotification, ServerNotification)
RequestId = str | int
@ -48,9 +46,7 @@ RequestId = str | int
class ProgressFnT(Protocol):
"""Protocol for progress notification callbacks."""
async def __call__(
self, progress: float, total: float | None, message: str | None
) -> None: ...
async def __call__(self, progress: float, total: float | None, message: str | None) -> None: ...
class RequestResponder(Generic[ReceiveRequestT, SendResultT]):
@ -177,9 +173,7 @@ class BaseSession(
messages when entered.
"""
_response_streams: dict[
RequestId, MemoryObjectSendStream[JSONRPCResponse | JSONRPCError]
]
_response_streams: dict[RequestId, MemoryObjectSendStream[JSONRPCResponse | JSONRPCError]]
_request_id: int
_in_flight: dict[RequestId, RequestResponder[ReceiveRequestT, SendResultT]]
_progress_callbacks: dict[RequestId, ProgressFnT]
@ -242,9 +236,7 @@ class BaseSession(
request_id = self._request_id
self._request_id = request_id + 1
response_stream, response_stream_reader = anyio.create_memory_object_stream[
JSONRPCResponse | JSONRPCError
](1)
response_stream, response_stream_reader = anyio.create_memory_object_stream[JSONRPCResponse | JSONRPCError](1)
self._response_streams[request_id] = response_stream
# Set up progress token if progress callback is provided
@ -266,11 +258,7 @@ class BaseSession(
**request_data,
)
await self._write_stream.send(
SessionMessage(
message=JSONRPCMessage(jsonrpc_request), metadata=metadata
)
)
await self._write_stream.send(SessionMessage(message=JSONRPCMessage(jsonrpc_request), metadata=metadata))
# request read timeout takes precedence over session read timeout
timeout = None
@ -322,15 +310,11 @@ class BaseSession(
)
session_message = SessionMessage(
message=JSONRPCMessage(jsonrpc_notification),
metadata=ServerMessageMetadata(related_request_id=related_request_id)
if related_request_id
else None,
metadata=ServerMessageMetadata(related_request_id=related_request_id) if related_request_id else None,
)
await self._write_stream.send(session_message)
async def _send_response(
self, request_id: RequestId, response: SendResultT | ErrorData
) -> None:
async def _send_response(self, request_id: RequestId, response: SendResultT | ErrorData) -> None:
if isinstance(response, ErrorData):
jsonrpc_error = JSONRPCError(jsonrpc="2.0", id=request_id, error=response)
session_message = SessionMessage(message=JSONRPCMessage(jsonrpc_error))
@ -339,9 +323,7 @@ class BaseSession(
jsonrpc_response = JSONRPCResponse(
jsonrpc="2.0",
id=request_id,
result=response.model_dump(
by_alias=True, mode="json", exclude_none=True
),
result=response.model_dump(by_alias=True, mode="json", exclude_none=True),
)
session_message = SessionMessage(message=JSONRPCMessage(jsonrpc_response))
await self._write_stream.send(session_message)
@ -357,19 +339,14 @@ class BaseSession(
elif isinstance(message.message.root, JSONRPCRequest):
try:
validated_request = self._receive_request_type.model_validate(
message.message.root.model_dump(
by_alias=True, mode="json", exclude_none=True
)
message.message.root.model_dump(by_alias=True, mode="json", exclude_none=True)
)
responder = RequestResponder(
request_id=message.message.root.id,
request_meta=validated_request.root.params.meta
if validated_request.root.params
else None,
request_meta=validated_request.root.params.meta if validated_request.root.params else None,
request=validated_request,
session=self,
on_complete=lambda r: self._in_flight.pop(
r.request_id, None),
on_complete=lambda r: self._in_flight.pop(r.request_id, None),
message_metadata=message.metadata,
)
self._in_flight[responder.request_id] = responder
@ -381,9 +358,7 @@ class BaseSession(
# For request validation errors, send a proper JSON-RPC error
# response instead of crashing the server
logging.warning(f"Failed to validate request: {e}")
logging.debug(
f"Message that failed validation: {message.message.root}"
)
logging.debug(f"Message that failed validation: {message.message.root}")
error_response = JSONRPCError(
jsonrpc="2.0",
id=message.message.root.id,
@ -393,16 +368,13 @@ class BaseSession(
data="",
),
)
session_message = SessionMessage(
message=JSONRPCMessage(error_response))
session_message = SessionMessage(message=JSONRPCMessage(error_response))
await self._write_stream.send(session_message)
elif isinstance(message.message.root, JSONRPCNotification):
try:
notification = self._receive_notification_type.model_validate(
message.message.root.model_dump(
by_alias=True, mode="json", exclude_none=True
)
message.message.root.model_dump(by_alias=True, mode="json", exclude_none=True)
)
# Handle cancellation notifications
if isinstance(notification.root, CancelledNotification):
@ -427,8 +399,7 @@ class BaseSession(
except Exception as e:
# For other validation errors, log and continue
logging.warning(
f"Failed to validate notification: {e}. "
f"Message was: {message.message.root}"
f"Failed to validate notification: {e}. " f"Message was: {message.message.root}"
)
else: # Response or error
stream = self._response_streams.pop(message.message.root.id, None)
@ -436,10 +407,7 @@ class BaseSession(
await stream.send(message.message.root)
else:
await self._handle_incoming(
RuntimeError(
"Received response with an unknown "
f"request ID: {message}"
)
RuntimeError("Received response with an unknown " f"request ID: {message}")
)
# after the read stream is closed, we need to send errors
@ -450,9 +418,7 @@ class BaseSession(
await stream.aclose()
self._response_streams.clear()
async def _received_request(
self, responder: RequestResponder[ReceiveRequestT, SendResultT]
) -> None:
async def _received_request(self, responder: RequestResponder[ReceiveRequestT, SendResultT]) -> None:
"""
Can be overridden by subclasses to handle a request without needing to
listen on the message stream.
@ -481,9 +447,7 @@ class BaseSession(
async def _handle_incoming(
self,
req: RequestResponder[ReceiveRequestT, SendResultT]
| ReceiveNotificationT
| Exception,
req: RequestResponder[ReceiveRequestT, SendResultT] | ReceiveNotificationT | Exception,
) -> None:
"""A generic handler for incoming messages. Overwritten by subclasses."""
pass