chore: 添加虚拟环境到仓库
- 添加 backend_service/venv 虚拟环境 - 包含所有Python依赖包 - 注意:虚拟环境约393MB,包含12655个文件
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The MCP module in AgentScope, that provides fine-grained control over
|
||||
the MCP servers."""
|
||||
|
||||
from ._client_base import MCPClientBase
|
||||
from ._mcp_function import MCPToolFunction
|
||||
from ._stateful_client_base import StatefulClientBase
|
||||
from ._stdio_stateful_client import StdIOStatefulClient
|
||||
from ._http_stateless_client import HttpStatelessClient
|
||||
from ._http_stateful_client import HttpStatefulClient
|
||||
|
||||
|
||||
__all__ = [
|
||||
"MCPToolFunction",
|
||||
"MCPClientBase",
|
||||
"StatefulClientBase",
|
||||
"StdIOStatefulClient",
|
||||
"HttpStatelessClient",
|
||||
"HttpStatefulClient",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,95 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The base class for MCP clients in AgentScope."""
|
||||
from abc import abstractmethod
|
||||
from typing import Callable, List
|
||||
|
||||
import mcp.types
|
||||
|
||||
from .._logging import logger
|
||||
from ..message import ImageBlock, Base64Source, AudioBlock, TextBlock
|
||||
|
||||
|
||||
class MCPClientBase:
|
||||
"""Base class for MCP clients."""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
"""Initialize the MCP client with a name.
|
||||
|
||||
Args:
|
||||
name (`str`):
|
||||
The name to identify the MCP server, which should be unique
|
||||
across the MCP servers.
|
||||
"""
|
||||
self.name = name
|
||||
|
||||
@abstractmethod
|
||||
async def get_callable_function(
|
||||
self,
|
||||
func_name: str,
|
||||
wrap_tool_result: bool = True,
|
||||
) -> Callable:
|
||||
"""Get a tool function by its name."""
|
||||
|
||||
@staticmethod
|
||||
def _convert_mcp_content_to_as_blocks(
|
||||
mcp_content_blocks: list,
|
||||
) -> List[TextBlock | ImageBlock | AudioBlock]:
|
||||
"""Convert MCP content to AgentScope blocks."""
|
||||
|
||||
as_content: list = []
|
||||
for content in mcp_content_blocks:
|
||||
if isinstance(content, mcp.types.TextContent):
|
||||
as_content.append(
|
||||
TextBlock(
|
||||
type="text",
|
||||
text=content.text,
|
||||
),
|
||||
)
|
||||
elif isinstance(content, mcp.types.ImageContent):
|
||||
as_content.append(
|
||||
ImageBlock(
|
||||
type="image",
|
||||
source=Base64Source(
|
||||
type="base64",
|
||||
media_type=content.mimeType,
|
||||
data=content.data,
|
||||
),
|
||||
),
|
||||
)
|
||||
elif isinstance(content, mcp.types.AudioContent):
|
||||
as_content.append(
|
||||
AudioBlock(
|
||||
type="audio",
|
||||
source=Base64Source(
|
||||
type="base64",
|
||||
media_type=content.mimeType,
|
||||
data=content.data,
|
||||
),
|
||||
),
|
||||
)
|
||||
elif isinstance(content, mcp.types.EmbeddedResource):
|
||||
if isinstance(
|
||||
content.resource,
|
||||
mcp.types.TextResourceContents,
|
||||
):
|
||||
as_content.append(
|
||||
TextBlock(
|
||||
type="text",
|
||||
text=content.resource.model_dump_json(indent=2),
|
||||
),
|
||||
)
|
||||
else:
|
||||
# TODO: support the BlobResourceContents in the future,
|
||||
# which is a base64-encoded string representing the
|
||||
# binary data
|
||||
logger.error(
|
||||
"Unsupported EmbeddedResource content type: %s. "
|
||||
"Skipping this content.",
|
||||
type(content.resource),
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
"Unsupported content type: %s. Skipping this content.",
|
||||
type(content),
|
||||
)
|
||||
return as_content
|
||||
@@ -0,0 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The MCP stateful HTTP client module in AgentScope."""
|
||||
from typing import Any, Literal
|
||||
|
||||
from mcp.client.sse import sse_client
|
||||
from mcp.client.streamable_http import streamablehttp_client
|
||||
|
||||
from ._stateful_client_base import StatefulClientBase
|
||||
|
||||
|
||||
class HttpStatefulClient(StatefulClientBase):
|
||||
"""The stateful sse/streamable HTTP MCP client implementation in
|
||||
AgentScope.
|
||||
|
||||
.. tip:: The stateful client is recommended for MCP servers that need to
|
||||
maintain session states, e.g. web browsers or other interactive
|
||||
MCP servers.
|
||||
|
||||
.. note:: The stateful client will maintain one session across multiple
|
||||
tool calls, until the client is closed by explicitly calling the
|
||||
`close()` method.
|
||||
|
||||
.. note:: When multiple HttpStatefulClient instances are connected,
|
||||
they should be closed following the Last In First Out (LIFO) principle
|
||||
to avoid potential errors. Always close the most recently registered
|
||||
client first, then work backwards to the first one.
|
||||
For more details, please refer to this `issue
|
||||
<https://github.com/modelcontextprotocol/python-sdk/issues/577>`_.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
transport: Literal["streamable_http", "sse"],
|
||||
url: str,
|
||||
headers: dict[str, str] | None = None,
|
||||
timeout: float = 30,
|
||||
sse_read_timeout: float = 60 * 5,
|
||||
**client_kwargs: Any,
|
||||
) -> None:
|
||||
"""Initialize the streamable HTTP MCP client.
|
||||
|
||||
Args:
|
||||
name (`str`):
|
||||
The name to identify the MCP server, which should be unique
|
||||
across the MCP servers.
|
||||
transport (`Literal["streamable_http", "sse"]`):
|
||||
The transport type of MCP server. Generally, the URL of sse
|
||||
transport should end with `/sse`, while the streamable HTTP
|
||||
URL ends with `/mcp`.
|
||||
url (`str`):
|
||||
The URL to the MCP server.
|
||||
headers (`dict[str, str] | None`, optional):
|
||||
Additional headers to include in the HTTP request.
|
||||
timeout (`float`, optional):
|
||||
The timeout for the HTTP request in seconds. Defaults to 30.
|
||||
sse_read_timeout (`float`, optional):
|
||||
The timeout for reading Server-Sent Events (SSE) in seconds.
|
||||
Defaults to 300 (5 minutes).
|
||||
**client_kwargs (`Any`):
|
||||
The additional keyword arguments to pass to the streamable
|
||||
HTTP client.
|
||||
"""
|
||||
super().__init__(name=name)
|
||||
|
||||
assert transport in ["streamable_http", "sse"]
|
||||
self.transport = transport
|
||||
|
||||
if self.transport == "streamable_http":
|
||||
self.client = streamablehttp_client(
|
||||
url=url,
|
||||
headers=headers,
|
||||
timeout=timeout,
|
||||
sse_read_timeout=sse_read_timeout,
|
||||
**client_kwargs,
|
||||
)
|
||||
else:
|
||||
self.client = sse_client(
|
||||
url=url,
|
||||
headers=headers,
|
||||
timeout=timeout,
|
||||
sse_read_timeout=sse_read_timeout,
|
||||
**client_kwargs,
|
||||
)
|
||||
@@ -0,0 +1,148 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The MCP streamable HTTP server."""
|
||||
from contextlib import _AsyncGeneratorContextManager
|
||||
from typing import Any, Callable, Awaitable, Literal, List
|
||||
|
||||
import mcp.types
|
||||
from mcp import ClientSession
|
||||
from mcp.client.sse import sse_client
|
||||
from mcp.client.streamable_http import streamablehttp_client
|
||||
|
||||
from . import MCPToolFunction
|
||||
from ._client_base import MCPClientBase
|
||||
from ..tool import ToolResponse
|
||||
|
||||
|
||||
class HttpStatelessClient(MCPClientBase):
|
||||
"""The sse/streamable HTTP MCP client implementation in AgentScope.
|
||||
|
||||
.. note:: Note this client is stateless, meaning it won't maintain the
|
||||
session state across multiple tool calls. Each tool call will start a
|
||||
new session and close it after the call is done.
|
||||
|
||||
"""
|
||||
|
||||
stateful: bool = False
|
||||
"""Whether the MCP server is stateful, meaning it will maintain the
|
||||
session state across multiple tool calls, or stateless, meaning it
|
||||
will start a new session for each tool call."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
transport: Literal["streamable_http", "sse"],
|
||||
url: str,
|
||||
headers: dict[str, str] | None = None,
|
||||
timeout: float = 30,
|
||||
sse_read_timeout: float = 60 * 5,
|
||||
**client_kwargs: Any,
|
||||
) -> None:
|
||||
"""Initialize the streamable HTTP MCP server.
|
||||
|
||||
Args:
|
||||
name (`str`):
|
||||
The name to identify the MCP server, which should be unique
|
||||
across the MCP servers.
|
||||
transport (`Literal["streamable_http", "sse"]`):
|
||||
The transport type of MCP server. Generally, the URL of sse
|
||||
transport should end with `/sse`, while the streamable HTTP
|
||||
URL ends with `/mcp`.
|
||||
url (`str`):
|
||||
The URL of the MCP server.
|
||||
headers (`dict[str, str] | None`, optional):
|
||||
Additional headers to include in the HTTP request.
|
||||
timeout (`float`, optional):
|
||||
The timeout for the HTTP request in seconds. Defaults to 30.
|
||||
sse_read_timeout (`float`, optional):
|
||||
The timeout for reading Server-Sent Events (SSE) in seconds.
|
||||
Defaults to 300 (5 minutes).
|
||||
**client_kwargs (`Any`):
|
||||
The additional keyword arguments to pass to the streamable
|
||||
HTTP client.
|
||||
"""
|
||||
super().__init__(name=name)
|
||||
|
||||
assert transport in ["streamable_http", "sse"]
|
||||
|
||||
self.transport = transport
|
||||
|
||||
self.client_config = {
|
||||
"url": url,
|
||||
"headers": headers or {},
|
||||
"timeout": timeout,
|
||||
"sse_read_timeout": sse_read_timeout,
|
||||
**client_kwargs,
|
||||
}
|
||||
|
||||
self._tools = None
|
||||
|
||||
def get_client(self) -> _AsyncGeneratorContextManager[Any]:
|
||||
"""The disposable MCP client object, which is a context manager."""
|
||||
if self.transport == "sse":
|
||||
return sse_client(**self.client_config)
|
||||
|
||||
if self.transport == "streamable_http":
|
||||
return streamablehttp_client(**self.client_config)
|
||||
|
||||
raise ValueError(
|
||||
f"Unsupported transport type: {self.transport}. "
|
||||
"Supported types are 'sse' and 'streamable_http'.",
|
||||
)
|
||||
|
||||
async def get_callable_function(
|
||||
self,
|
||||
func_name: str,
|
||||
wrap_tool_result: bool = True,
|
||||
) -> Callable[..., Awaitable[mcp.types.CallToolResult | ToolResponse]]:
|
||||
"""Get a tool function by its name.
|
||||
|
||||
Args:
|
||||
func_name (`str`):
|
||||
The name of the tool function.
|
||||
wrap_tool_result (`bool`, defaults to `True`):
|
||||
Whether to wrap the tool result into agentscope's
|
||||
`ToolResponse` object. If `False`, the raw result type
|
||||
`mcp.types.CallToolResult` will be returned.
|
||||
|
||||
Returns:
|
||||
`Callable[..., Awaitable[mcp.types.CallToolResult | \
|
||||
ToolResponse]]`:
|
||||
An async tool function that returns either
|
||||
`mcp.types.CallToolResult` or `ToolResponse` when called.
|
||||
"""
|
||||
|
||||
if self._tools is None:
|
||||
await self.list_tools()
|
||||
|
||||
target_tool = None
|
||||
for tool in self._tools:
|
||||
if tool.name == func_name:
|
||||
target_tool = tool
|
||||
break
|
||||
|
||||
if target_tool is None:
|
||||
raise ValueError(
|
||||
f"Tool '{func_name}' not found in the MCP server ",
|
||||
)
|
||||
|
||||
return MCPToolFunction(
|
||||
mcp_name=self.name,
|
||||
tool=target_tool,
|
||||
wrap_tool_result=wrap_tool_result,
|
||||
client_gen=self.get_client,
|
||||
)
|
||||
|
||||
async def list_tools(self) -> List[mcp.types.Tool]:
|
||||
"""List all tools available on the MCP server.
|
||||
|
||||
Returns:
|
||||
`mcp.types.ListToolsResult`:
|
||||
The result containing the list of tools.
|
||||
"""
|
||||
async with self.get_client() as cli:
|
||||
read_stream, write_stream = cli[0], cli[1]
|
||||
async with ClientSession(read_stream, write_stream) as session:
|
||||
await session.initialize()
|
||||
res = await session.list_tools()
|
||||
self._tools = res.tools
|
||||
return res.tools
|
||||
@@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The MCP tool function class in AgentScope."""
|
||||
from contextlib import _AsyncGeneratorContextManager
|
||||
from typing import Any, Callable
|
||||
|
||||
import mcp
|
||||
from mcp import ClientSession
|
||||
|
||||
from ._client_base import MCPClientBase
|
||||
from .._utils._common import _extract_json_schema_from_mcp_tool
|
||||
from ..tool import ToolResponse
|
||||
|
||||
|
||||
class MCPToolFunction:
|
||||
"""An MCP tool function class that can be called directly."""
|
||||
|
||||
name: str
|
||||
"""The name of the tool function."""
|
||||
|
||||
description: str
|
||||
"""The description of the tool function."""
|
||||
|
||||
json_schema: dict[str, Any]
|
||||
"""JSON schema of the tool function"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
mcp_name: str,
|
||||
tool: mcp.types.Tool,
|
||||
wrap_tool_result: bool,
|
||||
client_gen: Callable[..., _AsyncGeneratorContextManager[Any]]
|
||||
| None = None,
|
||||
session: ClientSession | None = None,
|
||||
) -> None:
|
||||
"""Initialize the MCP function."""
|
||||
self.mcp_name = mcp_name
|
||||
self.name = tool.name
|
||||
self.description = tool.description
|
||||
self.json_schema = _extract_json_schema_from_mcp_tool(tool)
|
||||
self.wrap_tool_result = wrap_tool_result
|
||||
|
||||
# Cannot be None at the same time
|
||||
if (
|
||||
client_gen is None
|
||||
and session is None
|
||||
or (client_gen is not None and session is not None)
|
||||
):
|
||||
raise ValueError(
|
||||
"Either client or session must be provided, but not both.",
|
||||
)
|
||||
|
||||
self.client_gen = client_gen
|
||||
self.session = session
|
||||
|
||||
async def __call__(
|
||||
self,
|
||||
**kwargs: Any,
|
||||
) -> mcp.types.CallToolResult | ToolResponse:
|
||||
"""Call the MCP tool function with the given arguments, and return
|
||||
the result."""
|
||||
if self.client_gen:
|
||||
async with self.client_gen() as cli:
|
||||
read_stream, write_stream = cli[0], cli[1]
|
||||
async with ClientSession(read_stream, write_stream) as session:
|
||||
await session.initialize()
|
||||
res = await session.call_tool(
|
||||
self.name,
|
||||
arguments=kwargs,
|
||||
)
|
||||
|
||||
else:
|
||||
res = await self.session.call_tool(
|
||||
self.name,
|
||||
arguments=kwargs,
|
||||
)
|
||||
|
||||
if self.wrap_tool_result:
|
||||
as_content = MCPClientBase._convert_mcp_content_to_as_blocks(
|
||||
res.content,
|
||||
)
|
||||
return ToolResponse(
|
||||
content=as_content,
|
||||
metadata=res.meta,
|
||||
)
|
||||
|
||||
return res
|
||||
@@ -0,0 +1,166 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The base MCP stateful client class in AgentScope, that provides basic
|
||||
functionality for stateful MCP clients."""
|
||||
from abc import ABC
|
||||
from contextlib import AsyncExitStack
|
||||
from typing import List
|
||||
|
||||
import mcp
|
||||
from mcp import ClientSession
|
||||
|
||||
from ._client_base import MCPClientBase
|
||||
from ._mcp_function import MCPToolFunction
|
||||
from .._logging import logger
|
||||
|
||||
|
||||
class StatefulClientBase(MCPClientBase, ABC):
|
||||
"""The base class for stateful MCP clients in AgentScope, which maintains
|
||||
the session state across multiple tool calls.
|
||||
|
||||
The developers should use `connect()` and `close()` methods to manage
|
||||
the client lifecycle.
|
||||
"""
|
||||
|
||||
is_connected: bool
|
||||
"""If connected to the MCP server"""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
"""Initialize the stateful MCP client.
|
||||
|
||||
Args:
|
||||
name (`str`):
|
||||
The name to identify the MCP server, which should be unique
|
||||
across the MCP servers.
|
||||
"""
|
||||
|
||||
super().__init__(name=name)
|
||||
|
||||
self.client = None
|
||||
self.stack = None
|
||||
self.session = None
|
||||
self.is_connected = False
|
||||
|
||||
# Cache the tools to avoid fetching them multiple times
|
||||
self._cached_tools = None
|
||||
|
||||
async def connect(self) -> None:
|
||||
"""Connect to MCP server."""
|
||||
if self.is_connected:
|
||||
raise RuntimeError(
|
||||
"The MCP server is already connected. Call close() "
|
||||
"before connecting again.",
|
||||
)
|
||||
|
||||
self.stack = AsyncExitStack()
|
||||
|
||||
try:
|
||||
context = await self.stack.enter_async_context(
|
||||
self.client,
|
||||
)
|
||||
read_stream, write_stream = context[0], context[1]
|
||||
self.session = ClientSession(read_stream, write_stream)
|
||||
await self.stack.enter_async_context(self.session)
|
||||
await self.session.initialize()
|
||||
|
||||
self.is_connected = True
|
||||
logger.info("MCP client connected.")
|
||||
except Exception:
|
||||
await self.stack.aclose()
|
||||
self.stack = None
|
||||
raise
|
||||
|
||||
async def close(self) -> None:
|
||||
"""Clean up the MCP client resources. You must call this method when
|
||||
your application is done."""
|
||||
if not self.is_connected:
|
||||
raise RuntimeError(
|
||||
"The MCP server is not connected. Call connect() before "
|
||||
"closing.",
|
||||
)
|
||||
|
||||
try:
|
||||
await self.stack.aclose()
|
||||
logger.info("MCP client closed.")
|
||||
except Exception as e:
|
||||
logger.warning("Error during MCP client cleanup: %s", e)
|
||||
finally:
|
||||
self.stack = None
|
||||
self.session = None
|
||||
self.is_connected = False
|
||||
|
||||
async def list_tools(self) -> List[mcp.types.Tool]:
|
||||
"""Get all available tools from the server.
|
||||
|
||||
Returns:
|
||||
`mcp.types.ListToolsResult`:
|
||||
A list of available MCP tools.
|
||||
"""
|
||||
self._validate_connection()
|
||||
|
||||
res = await self.session.list_tools()
|
||||
|
||||
# Cache the tools for later use
|
||||
self._cached_tools = res.tools
|
||||
return res.tools
|
||||
|
||||
async def get_callable_function(
|
||||
self,
|
||||
func_name: str,
|
||||
wrap_tool_result: bool = True,
|
||||
) -> MCPToolFunction:
|
||||
"""Get an async tool function from the MCP server by its name, so
|
||||
that you can call it directly, wrap it into your own function, or
|
||||
anyway you like.
|
||||
|
||||
.. note:: Currently, only the text, image, and audio results are
|
||||
supported in this function.
|
||||
|
||||
Args:
|
||||
func_name (`str`):
|
||||
The name of the tool function to get.
|
||||
wrap_tool_result (`bool`):
|
||||
Whether to wrap the tool result into agentscope's
|
||||
`ToolResponse` object. If `False`, the raw result type
|
||||
`mcp.types.CallToolResult` will be returned.
|
||||
|
||||
Returns:
|
||||
`MCPToolFunction`:
|
||||
A callable async function that returns either
|
||||
`mcp.types.CallToolResult` or `ToolResponse` when called.
|
||||
"""
|
||||
self._validate_connection()
|
||||
|
||||
if self._cached_tools is None:
|
||||
await self.list_tools()
|
||||
|
||||
target_tool = None
|
||||
for tool in self._cached_tools:
|
||||
if tool.name == func_name:
|
||||
target_tool = tool
|
||||
break
|
||||
|
||||
if target_tool is None:
|
||||
raise ValueError(
|
||||
f"Tool '{func_name}' not found in the MCP server",
|
||||
)
|
||||
|
||||
return MCPToolFunction(
|
||||
mcp_name=self.name,
|
||||
tool=target_tool,
|
||||
wrap_tool_result=wrap_tool_result,
|
||||
session=self.session,
|
||||
)
|
||||
|
||||
def _validate_connection(self) -> None:
|
||||
"""Validate the connection to the MCP server."""
|
||||
if not self.is_connected:
|
||||
raise RuntimeError(
|
||||
"The connection is not established. Call connect() "
|
||||
"before using the client.",
|
||||
)
|
||||
|
||||
if not self.session:
|
||||
raise RuntimeError(
|
||||
"The session is not initialized. Call connect() "
|
||||
"before using the client.",
|
||||
)
|
||||
@@ -0,0 +1,77 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The StdIO MCP server implementation in AgentScope, which provides
|
||||
function-level fine-grained control over the MCP servers using standard IO."""
|
||||
from typing import Literal
|
||||
|
||||
from mcp import stdio_client, StdioServerParameters
|
||||
|
||||
from ._stateful_client_base import StatefulClientBase
|
||||
|
||||
|
||||
class StdIOStatefulClient(StatefulClientBase):
|
||||
"""A client class that sets up and manage StdIO MCP server connections, and
|
||||
provides function-level fine-grained control over the MCP servers.
|
||||
|
||||
.. tip:: The stateful client is recommended for MCP servers that need to
|
||||
maintain session states, e.g. web browsers or other interactive
|
||||
MCP servers.
|
||||
|
||||
.. note:: The stateful client will maintain one session across multiple
|
||||
tool calls, until the client is closed by explicitly calling the
|
||||
`close()` method.
|
||||
|
||||
.. note:: When multiple StdIOStatefulClient instances are connected,
|
||||
they should be closed following the Last In First Out (LIFO) principle
|
||||
to avoid potential errors. Always close the most recently registered
|
||||
client first, then work backwards to the first one.
|
||||
For more details, please refer to this `issue
|
||||
<https://github.com/modelcontextprotocol/python-sdk/issues/577>`_.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
command: str,
|
||||
args: list[str] | None = None,
|
||||
env: dict[str, str] | None = None,
|
||||
cwd: str | None = None,
|
||||
encoding: str = "utf-8",
|
||||
encoding_error_handler: Literal[
|
||||
"strict",
|
||||
"ignore",
|
||||
"replace",
|
||||
] = "strict",
|
||||
) -> None:
|
||||
"""Initialize the MCP server with std IO.
|
||||
|
||||
Args:
|
||||
name (`str`):
|
||||
The name to identify the MCP server, which should be unique
|
||||
across the MCP servers.
|
||||
command (`str`):
|
||||
The executable to run to start the server.
|
||||
args (`list[str] | None`, optional):
|
||||
Command line arguments to pass to the executable.
|
||||
env (`dict[str, str] | None`, optional):
|
||||
The environment to use when spawning the process.
|
||||
cwd (`str | None`, optional):
|
||||
The working directory to use when spawning the process.
|
||||
encoding (`str`, optional):
|
||||
The text encoding used when sending/receiving messages to the
|
||||
server. Defaults to "utf-8".
|
||||
encoding_error_handler (`Literal["strict", "ignore", "replace"]`, \
|
||||
defaults to "strict"):
|
||||
The text encoding error handler.
|
||||
"""
|
||||
super().__init__(name=name)
|
||||
|
||||
self.client = stdio_client(
|
||||
StdioServerParameters(
|
||||
command=command,
|
||||
args=args or [],
|
||||
env=env,
|
||||
cwd=cwd,
|
||||
encoding=encoding,
|
||||
encoding_error_handler=encoding_error_handler,
|
||||
),
|
||||
)
|
||||
Reference in New Issue
Block a user