diff --git a/pyproject.toml b/pyproject.toml index 83a37da9..50a93903 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,4 +83,4 @@ target-version = "py310" members = ["examples/servers/*"] [tool.uv.sources] -mcp = { workspace = true } +mcp = { workspace = true } \ No newline at end of file diff --git a/src/mcp/client/stdio.py b/src/mcp/client/stdio.py index e79a816e..2eaa3475 100644 --- a/src/mcp/client/stdio.py +++ b/src/mcp/client/stdio.py @@ -1,6 +1,7 @@ import os import sys from contextlib import asynccontextmanager +from typing import Literal import anyio import anyio.lowlevel @@ -65,6 +66,21 @@ class StdioServerParameters(BaseModel): If not specified, the result of get_default_environment() will be used. """ + encoding: str = "utf-8" + """ + The text encoding used when sending/receiving messages to the server + + defaults to utf-8 + """ + + encoding_error_handler: Literal["strict", "ignore", "replace"] = "strict" + """ + The text encoding error handler. + + See https://docs.python.org/3/library/codecs.html#codec-base-classes for + explanations of possible values + """ + @asynccontextmanager async def stdio_client(server: StdioServerParameters): @@ -93,7 +109,11 @@ async def stdio_client(server: StdioServerParameters): try: async with read_stream_writer: buffer = "" - async for chunk in TextReceiveStream(process.stdout): + async for chunk in TextReceiveStream( + process.stdout, + encoding=server.encoding, + errors=server.encoding_error_handler, + ): lines = (buffer + chunk).split("\n") buffer = lines.pop() @@ -115,7 +135,12 @@ async def stdio_client(server: StdioServerParameters): async with write_stream_reader: async for message in write_stream_reader: json = message.model_dump_json(by_alias=True, exclude_none=True) - await process.stdin.send((json + "\n").encode()) + await process.stdin.send( + (json + "\n").encode( + encoding=server.encoding, + errors=server.encoding_error_handler, + ) + ) except anyio.ClosedResourceError: await anyio.lowlevel.checkpoint() diff --git a/src/mcp/server/lowlevel/server.py b/src/mcp/server/lowlevel/server.py index a0dd033d..4c5dc04f 100644 --- a/src/mcp/server/lowlevel/server.py +++ b/src/mcp/server/lowlevel/server.py @@ -101,8 +101,9 @@ class NotificationOptions: class Server: - def __init__(self, name: str): + def __init__(self, name: str, version: str | None = None): self.name = name + self.version = version self.request_handlers: dict[ type, Callable[..., Awaitable[types.ServerResult]] ] = { @@ -133,7 +134,7 @@ class Server: return InitializationOptions( server_name=self.name, - server_version=pkg_version("mcp"), + server_version=self.version if self.version else pkg_version("mcp"), capabilities=self.get_capabilities( notification_options or NotificationOptions(), experimental_capabilities or {}, diff --git a/src/mcp/shared/exceptions.py b/src/mcp/shared/exceptions.py index d8855b8d..97a1c09a 100644 --- a/src/mcp/shared/exceptions.py +++ b/src/mcp/shared/exceptions.py @@ -7,3 +7,8 @@ class McpError(Exception): """ error: ErrorData + + def __init__(self, error: ErrorData): + """Initialize McpError.""" + super().__init__(error.message) + self.error = error