콘텐츠로 이동

MCP Servers

MCPServer

Bases: ABC

Base class for Model Context Protocol servers.

ソースコード位置: src/agents/mcp/server.py
class MCPServer(abc.ABC):
    """Base class for Model Context Protocol servers."""

    def __init__(
        self,
        use_structured_content: bool = False,
        require_approval: RequireApprovalSetting = None,
        failure_error_function: ToolErrorFunction | None | _UnsetType = _UNSET,
        tool_meta_resolver: MCPToolMetaResolver | None = None,
        custom_data_extractor: MCPToolCustomDataExtractor | None = None,
    ):
        """
        Args:
            use_structured_content: Whether to use `tool_result.structured_content` when calling an
                MCP tool. Defaults to False for backwards compatibility - most MCP servers still
                include the structured content in the `tool_result.content`, and using it by
                default will cause duplicate content. You can set this to True if you know the
                server will not duplicate the structured content in the `tool_result.content`.
            require_approval: Approval policy for tools on this server. Accepts "always"/"never",
                a dict of tool names to those values, a boolean, an object with always/never
                tool lists (mirroring TS requireApproval), or a sync/async callable that receives
                `(run_context, agent, tool)` and returns whether the tool call needs approval.
                Normalized into a needs_approval policy.
            failure_error_function: Optional function used to convert MCP tool failures into
                a model-visible error message. If explicitly set to None, tool errors will be
                raised instead of converted. If left unset, the agent-level configuration (or
                SDK default) will be used.
            tool_meta_resolver: Optional callable that produces MCP request metadata (`_meta`) for
                tool calls. It is invoked by the Agents SDK before calling `call_tool`.
            custom_data_extractor: Optional callable that produces SDK-only custom data for
                emitted MCP tool output items.
        """
        self.use_structured_content = use_structured_content
        self._needs_approval_policy = self._normalize_needs_approval(
            require_approval=require_approval
        )
        self._failure_error_function = failure_error_function
        self.tool_meta_resolver = tool_meta_resolver
        self.custom_data_extractor = custom_data_extractor

    @abc.abstractmethod
    async def connect(self):
        """Connect to the server. For example, this might mean spawning a subprocess or
        opening a network connection. The server is expected to remain connected until
        `cleanup()` is called.
        """
        pass

    @property
    @abc.abstractmethod
    def name(self) -> str:
        """A readable name for the server."""
        pass

    @property
    def _error_name(self) -> str:
        """Return a diagnostic server name with URL credentials removed."""
        return get_mcp_server_log_name(self.name)

    @abc.abstractmethod
    async def cleanup(self):
        """Cleanup the server. For example, this might mean closing a subprocess or
        closing a network connection.
        """
        pass

    @abc.abstractmethod
    async def list_tools(
        self,
        run_context: RunContextWrapper[Any] | None = None,
        agent: AgentBase | None = None,
    ) -> list[MCPTool]:
        """List the tools available on the server."""
        pass

    @abc.abstractmethod
    async def call_tool(
        self,
        tool_name: str,
        arguments: dict[str, Any] | None,
        meta: dict[str, Any] | None = None,
    ) -> CallToolResult:
        """Invoke a tool on the server."""
        pass

    @property
    def cached_tools(self) -> list[MCPTool] | None:
        """Return the most recently fetched tools list, if available.

        Implementations may return `None` when tools have not been fetched yet or caching is
        disabled.
        """

        return None

    @abc.abstractmethod
    async def list_prompts(
        self,
    ) -> ListPromptsResult:
        """List the prompts available on the server."""
        pass

    @abc.abstractmethod
    async def get_prompt(
        self, name: str, arguments: dict[str, Any] | None = None
    ) -> GetPromptResult:
        """Get a specific prompt from the server."""
        pass

    async def list_resources(self, cursor: str | None = None) -> ListResourcesResult:
        """List the resources available on the server.

        Args:
            cursor: An opaque pagination cursor returned in a previous
                :class:`~mcp.types.ListResourcesResult` as ``nextCursor``.  Pass it
                here to fetch the next page of results.  ``None`` fetches the first
                page.

        Returns a :class:`~mcp.types.ListResourcesResult`.  When the result contains
        a ``nextCursor`` field, call this method again with that cursor to retrieve
        the next page.  Subclasses that do not support resources may leave this
        unimplemented; it will raise :exc:`NotImplementedError` at call time.
        """
        raise NotImplementedError(
            f"MCP server '{self._error_name}' does not support list_resources. "
            "Override this method in your server implementation."
        )

    async def list_resource_templates(
        self, cursor: str | None = None
    ) -> ListResourceTemplatesResult:
        """List the resource templates available on the server.

        Args:
            cursor: An opaque pagination cursor returned in a previous
                :class:`~mcp.types.ListResourceTemplatesResult` as ``nextCursor``.
                Pass it here to fetch the next page of results.  ``None`` fetches
                the first page.

        Returns a :class:`~mcp.types.ListResourceTemplatesResult`.  When the result
        contains a ``nextCursor`` field, call this method again with that cursor to
        retrieve the next page.  Subclasses that do not support resource templates
        may leave this unimplemented; it will raise :exc:`NotImplementedError` at
        call time.
        """
        raise NotImplementedError(
            f"MCP server '{self._error_name}' does not support list_resource_templates. "
            "Override this method in your server implementation."
        )

    async def read_resource(self, uri: str) -> ReadResourceResult:
        """Read the contents of a specific resource by URI.

        Args:
            uri: The URI of the resource to read. See :class:`~pydantic.networks.AnyUrl`
                for the supported URI formats.

        Returns a :class:`~mcp.types.ReadResourceResult`.  Subclasses that do not
        support resources may leave this unimplemented; it will raise
        :exc:`NotImplementedError` at call time.
        """
        raise NotImplementedError(
            f"MCP server '{self._error_name}' does not support read_resource. "
            "Override this method in your server implementation."
        )

    @staticmethod
    def _normalize_needs_approval(
        *,
        require_approval: RequireApprovalSetting,
    ) -> (
        bool
        | dict[str, bool]
        | Callable[[RunContextWrapper[Any], AgentBase, MCPTool], MaybeAwaitable[bool]]
    ):
        """Normalize approval inputs to booleans or a name->bool map."""

        if require_approval is None:
            return False

        def _to_bool(value: object, *, location: str) -> bool:
            if value == "always":
                return True
            if value == "never":
                return False
            raise UserError(
                f"Invalid require_approval value at {location}: "
                f"expected 'always' or 'never', got {value!r}."
            )

        def _validate_tool_names(value: object, *, location: str) -> list[str]:
            if not isinstance(value, list):
                raise UserError(
                    f"Invalid require_approval tool_names at {location}: "
                    f"expected a list of strings, got {type(value).__name__}."
                )

            tool_names: list[str] = []
            for index, tool_name in enumerate(value):
                if not isinstance(tool_name, str):
                    raise UserError(
                        f"Invalid require_approval tool name at {location}[{index}]: "
                        f"expected a string, got {type(tool_name).__name__}."
                    )
                tool_names.append(tool_name)
            return tool_names

        def _get_tool_names_entry(value: object, *, policy: str) -> list[str]:
            if not isinstance(value, dict):
                raise UserError(
                    f"Invalid require_approval.{policy}: "
                    f"expected an object with tool_names, got {type(value).__name__}."
                )
            return _validate_tool_names(
                value.get("tool_names", []),
                location=f"require_approval.{policy}.tool_names",
            )

        def _is_tool_list_schema(value: object) -> bool:
            if not isinstance(value, dict):
                return False
            for key in ("always", "never"):
                if key not in value:
                    continue
                entry = value.get(key)
                if isinstance(entry, dict) and "tool_names" in entry:
                    return True
            return False

        if isinstance(require_approval, dict) and _is_tool_list_schema(require_approval):
            always_entry: RequireApprovalToolList | Any = require_approval.get("always", {})
            never_entry: RequireApprovalToolList | Any = require_approval.get("never", {})
            invalid_keys = sorted(set(require_approval) - {"always", "never"})
            if invalid_keys:
                raise UserError(
                    "Invalid require_approval tool list policy: "
                    f"unexpected keys {invalid_keys!r}; expected only 'always' and 'never'."
                )
            always_names = _get_tool_names_entry(always_entry, policy="always")
            never_names = _get_tool_names_entry(never_entry, policy="never")
            overlapping_names = sorted(set(always_names) & set(never_names))
            if overlapping_names:
                raise UserError(
                    "Invalid require_approval tool list policy: "
                    f"tool names cannot appear in both always and never: {overlapping_names!r}."
                )
            tool_list_mapping: dict[str, bool] = {}
            for name in always_names:
                tool_list_mapping[name] = True
            for name in never_names:
                tool_list_mapping[name] = False
            return tool_list_mapping

        if isinstance(require_approval, dict):
            tool_mapping: dict[str, bool] = {}
            for name, value in require_approval.items():
                if isinstance(value, bool):
                    tool_mapping[str(name)] = value
                else:
                    tool_mapping[str(name)] = _to_bool(
                        value, location=f"require_approval[{name!r}]"
                    )
            return tool_mapping

        if callable(require_approval):
            return require_approval

        if isinstance(require_approval, bool):
            return require_approval

        return _to_bool(require_approval, location="require_approval")

    def _get_needs_approval_for_tool(
        self,
        tool: MCPTool,
        agent: AgentBase | None,
    ) -> bool | Callable[[RunContextWrapper[Any], dict[str, Any], str], Awaitable[bool]]:
        """Return a FunctionTool.needs_approval value for a given MCP tool.

        Legacy callers may omit ``agent`` when using ``MCPUtil.to_function_tool()`` directly.
        When approval is configured with a callable policy and no agent is available, this method
        returns ``True`` to preserve the historical fail-closed behavior.
        """

        policy = self._needs_approval_policy

        if callable(policy):
            if agent is None:
                return True

            async def _needs_approval(
                run_context: RunContextWrapper[Any], _args: dict[str, Any], _call_id: str
            ) -> bool:
                result = policy(run_context, agent, tool)
                if inspect.isawaitable(result):
                    result = await result
                return bool(result)

            return _needs_approval

        if isinstance(policy, dict):
            return bool(policy.get(tool.name, False))

        return bool(policy)

    def _get_failure_error_function(
        self, agent_failure_error_function: ToolErrorFunction | None
    ) -> ToolErrorFunction | None:
        """Return the effective error handler for MCP tool failures."""
        if self._failure_error_function is _UNSET:
            return agent_failure_error_function
        return cast(ToolErrorFunction | None, self._failure_error_function)

name abstractmethod property

name: str

A readable name for the server.

cached_tools property

cached_tools: list[Tool] | None

Return the most recently fetched tools list, if available.

Implementations may return None when tools have not been fetched yet or caching is disabled.

__init__

__init__(
    use_structured_content: bool = False,
    require_approval: RequireApprovalSetting = None,
    failure_error_function: ToolErrorFunction
    | None
    | _UnsetType = _UNSET,
    tool_meta_resolver: MCPToolMetaResolver | None = None,
    custom_data_extractor: MCPToolCustomDataExtractor
    | None = None,
)

引数:

名前 タイプ デスクリプション デフォルト
use_structured_content bool

Whether to use tool_result.structured_content when calling an MCP tool. Defaults to False for backwards compatibility - most MCP servers still include the structured content in the tool_result.content, and using it by default will cause duplicate content. You can set this to True if you know the server will not duplicate the structured content in the tool_result.content.

False
require_approval RequireApprovalSetting

Approval policy for tools on this server. Accepts "always"/"never", a dict of tool names to those values, a boolean, an object with always/never tool lists (mirroring TS requireApproval), or a sync/async callable that receives (run_context, agent, tool) and returns whether the tool call needs approval. Normalized into a needs_approval policy.

None
failure_error_function ToolErrorFunction | None | _UnsetType

Optional function used to convert MCP tool failures into a model-visible error message. If explicitly set to None, tool errors will be raised instead of converted. If left unset, the agent-level configuration (or SDK default) will be used.

_UNSET
tool_meta_resolver MCPToolMetaResolver | None

Optional callable that produces MCP request metadata (_meta) for tool calls. It is invoked by the Agents SDK before calling call_tool.

None
custom_data_extractor MCPToolCustomDataExtractor | None

Optional callable that produces SDK-only custom data for emitted MCP tool output items.

None
ソースコード位置: src/agents/mcp/server.py
def __init__(
    self,
    use_structured_content: bool = False,
    require_approval: RequireApprovalSetting = None,
    failure_error_function: ToolErrorFunction | None | _UnsetType = _UNSET,
    tool_meta_resolver: MCPToolMetaResolver | None = None,
    custom_data_extractor: MCPToolCustomDataExtractor | None = None,
):
    """
    Args:
        use_structured_content: Whether to use `tool_result.structured_content` when calling an
            MCP tool. Defaults to False for backwards compatibility - most MCP servers still
            include the structured content in the `tool_result.content`, and using it by
            default will cause duplicate content. You can set this to True if you know the
            server will not duplicate the structured content in the `tool_result.content`.
        require_approval: Approval policy for tools on this server. Accepts "always"/"never",
            a dict of tool names to those values, a boolean, an object with always/never
            tool lists (mirroring TS requireApproval), or a sync/async callable that receives
            `(run_context, agent, tool)` and returns whether the tool call needs approval.
            Normalized into a needs_approval policy.
        failure_error_function: Optional function used to convert MCP tool failures into
            a model-visible error message. If explicitly set to None, tool errors will be
            raised instead of converted. If left unset, the agent-level configuration (or
            SDK default) will be used.
        tool_meta_resolver: Optional callable that produces MCP request metadata (`_meta`) for
            tool calls. It is invoked by the Agents SDK before calling `call_tool`.
        custom_data_extractor: Optional callable that produces SDK-only custom data for
            emitted MCP tool output items.
    """
    self.use_structured_content = use_structured_content
    self._needs_approval_policy = self._normalize_needs_approval(
        require_approval=require_approval
    )
    self._failure_error_function = failure_error_function
    self.tool_meta_resolver = tool_meta_resolver
    self.custom_data_extractor = custom_data_extractor

connect abstractmethod async

connect()

Connect to the server. For example, this might mean spawning a subprocess or opening a network connection. The server is expected to remain connected until cleanup() is called.

ソースコード位置: src/agents/mcp/server.py
@abc.abstractmethod
async def connect(self):
    """Connect to the server. For example, this might mean spawning a subprocess or
    opening a network connection. The server is expected to remain connected until
    `cleanup()` is called.
    """
    pass

cleanup abstractmethod async

cleanup()

Cleanup the server. For example, this might mean closing a subprocess or closing a network connection.

ソースコード位置: src/agents/mcp/server.py
@abc.abstractmethod
async def cleanup(self):
    """Cleanup the server. For example, this might mean closing a subprocess or
    closing a network connection.
    """
    pass

list_tools abstractmethod async

list_tools(
    run_context: RunContextWrapper[Any] | None = None,
    agent: AgentBase | None = None,
) -> list[Tool]

List the tools available on the server.

ソースコード位置: src/agents/mcp/server.py
@abc.abstractmethod
async def list_tools(
    self,
    run_context: RunContextWrapper[Any] | None = None,
    agent: AgentBase | None = None,
) -> list[MCPTool]:
    """List the tools available on the server."""
    pass

call_tool abstractmethod async

call_tool(
    tool_name: str,
    arguments: dict[str, Any] | None,
    meta: dict[str, Any] | None = None,
) -> CallToolResult

Invoke a tool on the server.

ソースコード位置: src/agents/mcp/server.py
@abc.abstractmethod
async def call_tool(
    self,
    tool_name: str,
    arguments: dict[str, Any] | None,
    meta: dict[str, Any] | None = None,
) -> CallToolResult:
    """Invoke a tool on the server."""
    pass

list_prompts abstractmethod async

list_prompts() -> ListPromptsResult

List the prompts available on the server.

ソースコード位置: src/agents/mcp/server.py
@abc.abstractmethod
async def list_prompts(
    self,
) -> ListPromptsResult:
    """List the prompts available on the server."""
    pass

get_prompt abstractmethod async

get_prompt(
    name: str, arguments: dict[str, Any] | None = None
) -> GetPromptResult

Get a specific prompt from the server.

ソースコード位置: src/agents/mcp/server.py
@abc.abstractmethod
async def get_prompt(
    self, name: str, arguments: dict[str, Any] | None = None
) -> GetPromptResult:
    """Get a specific prompt from the server."""
    pass

list_resources async

list_resources(
    cursor: str | None = None,
) -> ListResourcesResult

List the resources available on the server.

引数:

名前 タイプ デスクリプション デフォルト
cursor str | None

An opaque pagination cursor returned in a previous :class:~mcp.types.ListResourcesResult as nextCursor. Pass it here to fetch the next page of results. None fetches the first page.

None

Returns a :class:~mcp.types.ListResourcesResult. When the result contains a nextCursor field, call this method again with that cursor to retrieve the next page. Subclasses that do not support resources may leave this unimplemented; it will raise :exc:NotImplementedError at call time.

ソースコード位置: src/agents/mcp/server.py
async def list_resources(self, cursor: str | None = None) -> ListResourcesResult:
    """List the resources available on the server.

    Args:
        cursor: An opaque pagination cursor returned in a previous
            :class:`~mcp.types.ListResourcesResult` as ``nextCursor``.  Pass it
            here to fetch the next page of results.  ``None`` fetches the first
            page.

    Returns a :class:`~mcp.types.ListResourcesResult`.  When the result contains
    a ``nextCursor`` field, call this method again with that cursor to retrieve
    the next page.  Subclasses that do not support resources may leave this
    unimplemented; it will raise :exc:`NotImplementedError` at call time.
    """
    raise NotImplementedError(
        f"MCP server '{self._error_name}' does not support list_resources. "
        "Override this method in your server implementation."
    )

list_resource_templates async

list_resource_templates(
    cursor: str | None = None,
) -> ListResourceTemplatesResult

List the resource templates available on the server.

引数:

名前 タイプ デスクリプション デフォルト
cursor str | None

An opaque pagination cursor returned in a previous :class:~mcp.types.ListResourceTemplatesResult as nextCursor. Pass it here to fetch the next page of results. None fetches the first page.

None

Returns a :class:~mcp.types.ListResourceTemplatesResult. When the result contains a nextCursor field, call this method again with that cursor to retrieve the next page. Subclasses that do not support resource templates may leave this unimplemented; it will raise :exc:NotImplementedError at call time.

ソースコード位置: src/agents/mcp/server.py
async def list_resource_templates(
    self, cursor: str | None = None
) -> ListResourceTemplatesResult:
    """List the resource templates available on the server.

    Args:
        cursor: An opaque pagination cursor returned in a previous
            :class:`~mcp.types.ListResourceTemplatesResult` as ``nextCursor``.
            Pass it here to fetch the next page of results.  ``None`` fetches
            the first page.

    Returns a :class:`~mcp.types.ListResourceTemplatesResult`.  When the result
    contains a ``nextCursor`` field, call this method again with that cursor to
    retrieve the next page.  Subclasses that do not support resource templates
    may leave this unimplemented; it will raise :exc:`NotImplementedError` at
    call time.
    """
    raise NotImplementedError(
        f"MCP server '{self._error_name}' does not support list_resource_templates. "
        "Override this method in your server implementation."
    )

read_resource async

read_resource(uri: str) -> ReadResourceResult

Read the contents of a specific resource by URI.

引数:

名前 タイプ デスクリプション デフォルト
uri str

The URI of the resource to read. See :class:~pydantic.networks.AnyUrl for the supported URI formats.

必須

Returns a :class:~mcp.types.ReadResourceResult. Subclasses that do not support resources may leave this unimplemented; it will raise :exc:NotImplementedError at call time.

ソースコード位置: src/agents/mcp/server.py
async def read_resource(self, uri: str) -> ReadResourceResult:
    """Read the contents of a specific resource by URI.

    Args:
        uri: The URI of the resource to read. See :class:`~pydantic.networks.AnyUrl`
            for the supported URI formats.

    Returns a :class:`~mcp.types.ReadResourceResult`.  Subclasses that do not
    support resources may leave this unimplemented; it will raise
    :exc:`NotImplementedError` at call time.
    """
    raise NotImplementedError(
        f"MCP server '{self._error_name}' does not support read_resource. "
        "Override this method in your server implementation."
    )

MCPServerStdioParams

Bases: TypedDict

Mirrors mcp.client.stdio.StdioServerParameters, but lets you pass params without another import.

ソースコード位置: src/agents/mcp/server.py
class MCPServerStdioParams(TypedDict):
    """Mirrors `mcp.client.stdio.StdioServerParameters`, but lets you pass params without another
    import.
    """

    command: str
    """The executable to run to start the server. For example, `python` or `node`."""

    args: NotRequired[list[str]]
    """Command line args to pass to the `command` executable. For example, `['foo.py']` or
    `['server.js', '--port', '8080']`."""

    env: NotRequired[dict[str, str]]
    """The environment variables to set for the server."""

    cwd: NotRequired[str | Path]
    """The working directory to use when spawning the process."""

    encoding: NotRequired[str]
    """The text encoding used when sending/receiving messages to the server. Defaults to `utf-8`."""

    encoding_error_handler: NotRequired[Literal["strict", "ignore", "replace"]]
    """The text encoding error handler. Defaults to `strict`.

    See https://docs.python.org/3/library/codecs.html#codec-base-classes for
    explanations of possible values.
    """

command instance-attribute

command: str

The executable to run to start the server. For example, python or node.

args instance-attribute

args: NotRequired[list[str]]

Command line args to pass to the command executable. For example, ['foo.py'] or ['server.js', '--port', '8080'].

env instance-attribute

env: NotRequired[dict[str, str]]

The environment variables to set for the server.

cwd instance-attribute

cwd: NotRequired[str | Path]

The working directory to use when spawning the process.

encoding instance-attribute

encoding: NotRequired[str]

The text encoding used when sending/receiving messages to the server. Defaults to utf-8.

encoding_error_handler instance-attribute

encoding_error_handler: NotRequired[
    Literal["strict", "ignore", "replace"]
]

The text encoding error handler. Defaults to strict.

See https://docs.python.org/3/library/codecs.html#codec-base-classes for explanations of possible values.

MCPServerStdio

Bases: _MCPServerWithClientSession

MCP server implementation that uses the stdio transport. See the [spec] (https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio) for details.

ソースコード位置: src/agents/mcp/server.py
class MCPServerStdio(_MCPServerWithClientSession):
    """MCP server implementation that uses the stdio transport. See the [spec]
    (https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio) for
    details.
    """

    def __init__(
        self,
        params: MCPServerStdioParams,
        cache_tools_list: bool = False,
        name: str | None = None,
        client_session_timeout_seconds: float | None = 5,
        tool_filter: ToolFilter = None,
        use_structured_content: bool = False,
        max_retry_attempts: int = 0,
        retry_backoff_seconds_base: float = 1.0,
        message_handler: MessageHandlerFnT | None = None,
        require_approval: RequireApprovalSetting = None,
        failure_error_function: ToolErrorFunction | None | _UnsetType = _UNSET,
        tool_meta_resolver: MCPToolMetaResolver | None = None,
        custom_data_extractor: MCPToolCustomDataExtractor | None = None,
    ):
        """Create a new MCP server based on the stdio transport.

        Args:
            params: The params that configure the server. This includes the command to run to
                start the server, the args to pass to the command, the environment variables to
                set for the server, the working directory to use when spawning the process, and
                the text encoding used when sending/receiving messages to the server.
            cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
                cached and only fetched from the server once. If `False`, the tools list will be
                fetched from the server on each call to `list_tools()`. The cache can be
                invalidated by calling `invalidate_tools_cache()`. You should set this to `True`
                if you know the server will not change its tools list, because it can drastically
                improve latency (by avoiding a round-trip to the server every time).
            name: A readable name for the server. If not provided, we'll create one from the
                command.
            client_session_timeout_seconds: The MCP ClientSession read timeout. Positive finite
                values representable by `datetime.timedelta` and at least one microsecond set a
                timeout; `None` and `0` disable it. Other values are rejected during server
                construction.
            tool_filter: The tool filter to use for filtering tools.
            use_structured_content: Whether to use `tool_result.structured_content` when calling an
                MCP tool. Defaults to False for backwards compatibility - most MCP servers still
                include the structured content in the `tool_result.content`, and using it by
                default will cause duplicate content. You can set this to True if you know the
                server will not duplicate the structured content in the `tool_result.content`.
            max_retry_attempts: Number of times to retry failed list_tools/call_tool calls.
                Defaults to no retries.
            retry_backoff_seconds_base: The base delay, in seconds, for exponential
                backoff between retries.
            message_handler: Optional handler invoked for session messages as delivered by the
                ClientSession.
            require_approval: Approval policy for tools on this server. Accepts "always"/"never",
                a dict of tool names to those values, or an object with always/never tool lists.
            failure_error_function: Optional function used to convert MCP tool failures into
                a model-visible error message. If explicitly set to None, tool errors will be
                raised instead of converted. If left unset, the agent-level configuration (or
                SDK default) will be used.
            tool_meta_resolver: Optional callable that produces MCP request metadata (`_meta`) for
                tool calls. It is invoked by the Agents SDK before calling `call_tool`.
            custom_data_extractor: Optional callable that produces SDK-only custom data for
                emitted MCP tool output items.
        """
        super().__init__(
            cache_tools_list=cache_tools_list,
            client_session_timeout_seconds=client_session_timeout_seconds,
            tool_filter=tool_filter,
            use_structured_content=use_structured_content,
            max_retry_attempts=max_retry_attempts,
            retry_backoff_seconds_base=retry_backoff_seconds_base,
            message_handler=message_handler,
            require_approval=require_approval,
            failure_error_function=failure_error_function,
            tool_meta_resolver=tool_meta_resolver,
            custom_data_extractor=custom_data_extractor,
        )

        self.params = StdioServerParameters(
            command=params["command"],
            args=params.get("args", []),
            env=params.get("env"),
            cwd=params.get("cwd"),
            encoding=params.get("encoding", "utf-8"),
            encoding_error_handler=params.get("encoding_error_handler", "strict"),
        )

        self._name = name or f"stdio: {self.params.command}"

    def create_streams(
        self,
    ) -> AbstractAsyncContextManager[MCPStreamTransport]:
        """Create the streams for the server."""
        return stdio_client(self.params)

    @property
    def name(self) -> str:
        """A readable name for the server."""
        return self._name

name property

name: str

A readable name for the server.

__init__

__init__(
    params: MCPServerStdioParams,
    cache_tools_list: bool = False,
    name: str | None = None,
    client_session_timeout_seconds: float | None = 5,
    tool_filter: ToolFilter = None,
    use_structured_content: bool = False,
    max_retry_attempts: int = 0,
    retry_backoff_seconds_base: float = 1.0,
    message_handler: MessageHandlerFnT | None = None,
    require_approval: RequireApprovalSetting = None,
    failure_error_function: ToolErrorFunction
    | None
    | _UnsetType = _UNSET,
    tool_meta_resolver: MCPToolMetaResolver | None = None,
    custom_data_extractor: MCPToolCustomDataExtractor
    | None = None,
)

Create a new MCP server based on the stdio transport.

引数:

名前 タイプ デスクリプション デフォルト
params MCPServerStdioParams

The params that configure the server. This includes the command to run to start the server, the args to pass to the command, the environment variables to set for the server, the working directory to use when spawning the process, and the text encoding used when sending/receiving messages to the server.

必須
cache_tools_list bool

Whether to cache the tools list. If True, the tools list will be cached and only fetched from the server once. If False, the tools list will be fetched from the server on each call to list_tools(). The cache can be invalidated by calling invalidate_tools_cache(). You should set this to True if you know the server will not change its tools list, because it can drastically improve latency (by avoiding a round-trip to the server every time).

False
name str | None

A readable name for the server. If not provided, we'll create one from the command.

None
client_session_timeout_seconds float | None

The MCP ClientSession read timeout. Positive finite values representable by datetime.timedelta and at least one microsecond set a timeout; None and 0 disable it. Other values are rejected during server construction.

5
tool_filter ToolFilter

The tool filter to use for filtering tools.

None
use_structured_content bool

Whether to use tool_result.structured_content when calling an MCP tool. Defaults to False for backwards compatibility - most MCP servers still include the structured content in the tool_result.content, and using it by default will cause duplicate content. You can set this to True if you know the server will not duplicate the structured content in the tool_result.content.

False
max_retry_attempts int

Number of times to retry failed list_tools/call_tool calls. Defaults to no retries.

0
retry_backoff_seconds_base float

The base delay, in seconds, for exponential backoff between retries.

1.0
message_handler MessageHandlerFnT | None

Optional handler invoked for session messages as delivered by the ClientSession.

None
require_approval RequireApprovalSetting

Approval policy for tools on this server. Accepts "always"/"never", a dict of tool names to those values, or an object with always/never tool lists.

None
failure_error_function ToolErrorFunction | None | _UnsetType

Optional function used to convert MCP tool failures into a model-visible error message. If explicitly set to None, tool errors will be raised instead of converted. If left unset, the agent-level configuration (or SDK default) will be used.

_UNSET
tool_meta_resolver MCPToolMetaResolver | None

Optional callable that produces MCP request metadata (_meta) for tool calls. It is invoked by the Agents SDK before calling call_tool.

None
custom_data_extractor MCPToolCustomDataExtractor | None

Optional callable that produces SDK-only custom data for emitted MCP tool output items.

None
ソースコード位置: src/agents/mcp/server.py
def __init__(
    self,
    params: MCPServerStdioParams,
    cache_tools_list: bool = False,
    name: str | None = None,
    client_session_timeout_seconds: float | None = 5,
    tool_filter: ToolFilter = None,
    use_structured_content: bool = False,
    max_retry_attempts: int = 0,
    retry_backoff_seconds_base: float = 1.0,
    message_handler: MessageHandlerFnT | None = None,
    require_approval: RequireApprovalSetting = None,
    failure_error_function: ToolErrorFunction | None | _UnsetType = _UNSET,
    tool_meta_resolver: MCPToolMetaResolver | None = None,
    custom_data_extractor: MCPToolCustomDataExtractor | None = None,
):
    """Create a new MCP server based on the stdio transport.

    Args:
        params: The params that configure the server. This includes the command to run to
            start the server, the args to pass to the command, the environment variables to
            set for the server, the working directory to use when spawning the process, and
            the text encoding used when sending/receiving messages to the server.
        cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
            cached and only fetched from the server once. If `False`, the tools list will be
            fetched from the server on each call to `list_tools()`. The cache can be
            invalidated by calling `invalidate_tools_cache()`. You should set this to `True`
            if you know the server will not change its tools list, because it can drastically
            improve latency (by avoiding a round-trip to the server every time).
        name: A readable name for the server. If not provided, we'll create one from the
            command.
        client_session_timeout_seconds: The MCP ClientSession read timeout. Positive finite
            values representable by `datetime.timedelta` and at least one microsecond set a
            timeout; `None` and `0` disable it. Other values are rejected during server
            construction.
        tool_filter: The tool filter to use for filtering tools.
        use_structured_content: Whether to use `tool_result.structured_content` when calling an
            MCP tool. Defaults to False for backwards compatibility - most MCP servers still
            include the structured content in the `tool_result.content`, and using it by
            default will cause duplicate content. You can set this to True if you know the
            server will not duplicate the structured content in the `tool_result.content`.
        max_retry_attempts: Number of times to retry failed list_tools/call_tool calls.
            Defaults to no retries.
        retry_backoff_seconds_base: The base delay, in seconds, for exponential
            backoff between retries.
        message_handler: Optional handler invoked for session messages as delivered by the
            ClientSession.
        require_approval: Approval policy for tools on this server. Accepts "always"/"never",
            a dict of tool names to those values, or an object with always/never tool lists.
        failure_error_function: Optional function used to convert MCP tool failures into
            a model-visible error message. If explicitly set to None, tool errors will be
            raised instead of converted. If left unset, the agent-level configuration (or
            SDK default) will be used.
        tool_meta_resolver: Optional callable that produces MCP request metadata (`_meta`) for
            tool calls. It is invoked by the Agents SDK before calling `call_tool`.
        custom_data_extractor: Optional callable that produces SDK-only custom data for
            emitted MCP tool output items.
    """
    super().__init__(
        cache_tools_list=cache_tools_list,
        client_session_timeout_seconds=client_session_timeout_seconds,
        tool_filter=tool_filter,
        use_structured_content=use_structured_content,
        max_retry_attempts=max_retry_attempts,
        retry_backoff_seconds_base=retry_backoff_seconds_base,
        message_handler=message_handler,
        require_approval=require_approval,
        failure_error_function=failure_error_function,
        tool_meta_resolver=tool_meta_resolver,
        custom_data_extractor=custom_data_extractor,
    )

    self.params = StdioServerParameters(
        command=params["command"],
        args=params.get("args", []),
        env=params.get("env"),
        cwd=params.get("cwd"),
        encoding=params.get("encoding", "utf-8"),
        encoding_error_handler=params.get("encoding_error_handler", "strict"),
    )

    self._name = name or f"stdio: {self.params.command}"

create_streams

create_streams() -> AbstractAsyncContextManager[
    MCPStreamTransport
]

Create the streams for the server.

ソースコード位置: src/agents/mcp/server.py
def create_streams(
    self,
) -> AbstractAsyncContextManager[MCPStreamTransport]:
    """Create the streams for the server."""
    return stdio_client(self.params)

connect async

connect()

Connect to the server.

ソースコード位置: src/agents/mcp/server.py
async def connect(self):
    """Connect to the server."""
    read_timeout = _client_session_read_timeout(self.client_session_timeout_seconds)
    connection_succeeded = False
    connection_error: UserError | None = None
    connection_cause: Exception | None = None
    connection_exception: BaseException | None = None
    cleanup_failure: BaseException | None = None
    try:
        transport = await self.exit_stack.enter_async_context(self.create_streams())
        # streamablehttp_client returns (read, write, get_session_id)
        # sse_client returns (read, write)

        read, write, *rest = transport
        # Capture the session-id callback when present (streamablehttp_client only).
        self._get_session_id = rest[0] if rest and callable(rest[0]) else None

        session = await self.exit_stack.enter_async_context(
            ClientSession(
                read,
                write,
                read_timeout,
                message_handler=self.message_handler,
            )
        )
        server_result = await session.initialize()
        self.server_initialize_result = server_result
        self.session = session
        connection_succeeded = True
    except BaseException as e:
        if not isinstance(e, Exception):
            connection_exception = e
        else:
            http_errors = self._extract_http_errors_from_exception(e)
            if not http_errors:
                connection_exception = e
            else:
                unsafe_http_error = _first_unretainable_transport_error(http_errors)
                http_error = unsafe_http_error or http_errors[0]
                connection_cause = _safe_transport_cause(http_error)
                maps_safe_error = isinstance(
                    http_error,
                    httpx.HTTPStatusError | httpx.ConnectError | httpx.TimeoutException,
                )
                if connection_cause is not None and not maps_safe_error:
                    connection_exception = e
                    connection_cause = None
                else:
                    connection_error = self._user_error_for_http_error(http_error)
                http_errors.clear()
                del http_error
                del unsafe_http_error

    # Run cleanup after leaving the connection exception handler so a cleanup UserError does
    # not retain the pending connection failure as its implicit context.
    if not connection_succeeded:
        try:
            await self.cleanup()
        except UserError as e:
            cleanup_failure = e
        except Exception as cleanup_error:
            # Suppress RuntimeError about cancel scopes during cleanup - this is a known
            # issue with the MCP library's async generator cleanup and shouldn't mask the
            # original error.
            if isinstance(cleanup_error, RuntimeError) and "cancel scope" in str(cleanup_error):
                logger.debug(
                    "%s",
                    get_mcp_server_log_message(
                        "Ignoring cancel scope error during cleanup of MCP server", self
                    ),
                    stacklevel=2,
                )
            else:
                # Log other cleanup errors but don't raise - original error is more important.
                logger.warning(
                    "%s",
                    get_mcp_server_log_message("Error during cleanup of MCP server", self),
                    stacklevel=2,
                )
        except BaseException as e:
            cleanup_failure = e

    if cleanup_failure is not None:
        connection_exception = None
        connection_error = None
        connection_cause = None
        if isinstance(cleanup_failure, UserError):
            self._raise_mapped_transport_error(cleanup_failure, None)
        raise cleanup_failure

    if connection_exception is not None:
        raise connection_exception

    if connection_error is not None:
        self._raise_mapped_transport_error(connection_error, connection_cause)

cleanup async

cleanup()

Cleanup the server.

ソースコード位置: src/agents/mcp/server.py
async def cleanup(self):
    """Cleanup the server."""
    async with self._cleanup_lock:
        # Only raise HTTP errors if we're cleaning up after a failed connection.
        # During normal teardown (via __aexit__), log but don't raise to avoid
        # masking the original exception.
        is_failed_connection_cleanup = self.session is None
        cleanup_error: UserError | None = None

        try:
            await self.exit_stack.aclose()
        except asyncio.CancelledError as e:
            log_tool_action_debug(
                logger,
                get_mcp_server_log_message("Cleanup cancelled for MCP server", self),
                e,
            )
            raise
        except (BaseExceptionGroup, httpx.HTTPStatusError, httpx.RequestError) as e:
            selected_http_error = self._select_cleanup_transport_error(e)
            if selected_http_error is not None:
                if is_failed_connection_cleanup:
                    cleanup_error = self._user_error_for_http_error(
                        selected_http_error,
                        include_http_reason_phrase=False,
                    )
                    del selected_http_error
                else:
                    _log_cleanup_transport_warning(
                        get_mcp_server_log_message(
                            _get_cleanup_transport_error_message(selected_http_error), self
                        )
                    )
            elif isinstance(e, httpx.RequestError):
                _log_cleanup_transport_warning(
                    get_mcp_server_log_message(_get_cleanup_transport_error_message(e), self)
                )
            elif isinstance(e, BaseExceptionGroup):
                http_errors = self._extract_http_errors_from_exception(e)
                if http_errors:
                    safe_error_group = _credential_safe_exception_group(e)
                    log_tool_action_error(
                        logger,
                        get_mcp_server_log_message("Error cleaning up MCP server", self),
                        safe_error_group,
                    )
                else:
                    # No HTTP error found, suppress RuntimeError about cancel scopes.
                    has_cancel_scope_error = any(
                        isinstance(exc, RuntimeError) and "cancel scope" in str(exc)
                        for exc in e.exceptions
                    )
                    if has_cancel_scope_error:
                        log_tool_action_debug(
                            logger,
                            get_mcp_server_log_message(
                                "Ignoring cancel scope error during cleanup of MCP server", self
                            ),
                            e,
                        )
                    else:
                        log_tool_action_error(
                            logger,
                            get_mcp_server_log_message("Error cleaning up MCP server", self),
                            e,
                        )
            else:
                log_tool_action_error(
                    logger,
                    get_mcp_server_log_message("Error cleaning up MCP server", self),
                    e,
                )
        except Exception as e:
            # Suppress RuntimeError about cancel scopes - this is a known issue with the MCP
            # library when background tasks fail during async generator cleanup
            if isinstance(e, RuntimeError) and "cancel scope" in str(e):
                log_tool_action_debug(
                    logger,
                    get_mcp_server_log_message(
                        "Ignoring cancel scope error during cleanup of MCP server", self
                    ),
                    e,
                )
            else:
                log_tool_action_error(
                    logger,
                    get_mcp_server_log_message("Error cleaning up MCP server", self),
                    e,
                )
        finally:
            self.session = None
            self._get_session_id = None

        if cleanup_error is not None:
            self._raise_mapped_transport_error(cleanup_error, None)

list_tools async

list_tools(
    run_context: RunContextWrapper[Any] | None = None,
    agent: AgentBase | None = None,
) -> list[Tool]

List the tools available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_tools(
    self,
    run_context: RunContextWrapper[Any] | None = None,
    agent: AgentBase | None = None,
) -> list[MCPTool]:
    """List the tools available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None

    transport_error: UserError | None = None
    transport_cause: Exception | None = None
    try:
        tools: list[MCPTool]
        # Return from cache if caching is enabled, we have tools, and the cache is not dirty
        if self.cache_tools_list and not self._cache_dirty and self._tools_list:
            tools = self._tools_list
        else:
            tools = []
            cursor: str | None = None
            seen_cursors: set[str | None] = set()

            async def fetch_pages() -> bool:
                nonlocal cursor
                while True:
                    result = await self._list_tools_page(session, cursor)
                    tools.extend(result.tools)
                    seen_cursors.add(cursor)
                    next_cursor = result.nextCursor
                    if next_cursor is None:
                        return True
                    if next_cursor in seen_cursors:
                        return False
                    cursor = next_cursor

            pagination_complete = False
            pagination_failure: BaseException | None = None
            try:
                pagination_complete = await self._run_with_retries(fetch_pages)
            except BaseException as error:
                if cursor is None:
                    raise
                if isinstance(error, BaseExceptionGroup):
                    pagination_failure = _credential_safe_exception_group(error)
                elif isinstance(error, Exception):
                    pagination_failure = self._user_error_for_request_operation(
                        "list tools", error
                    )
                else:
                    pagination_failure = _credential_safe_exception_leaf(error)

            if pagination_failure is not None or not pagination_complete:
                cursor = None
                seen_cursors.clear()
                tools.clear()
                del fetch_pages
                if pagination_failure is not None:
                    raise pagination_failure from None
                raise UserError(
                    f"MCP server '{self._error_name}' returned a repeated cursor while "
                    "listing tools."
                ) from None

            cursor = None
            seen_cursors.clear()
            del fetch_pages
            self._tools_list = tools
            self._cache_dirty = False

        # Filter tools based on tool_filter
        filtered_tools = tools
        if self.tool_filter is not None:
            filtered_tools = await self._apply_tool_filter(filtered_tools, run_context, agent)
        return filtered_tools
    except httpx.HTTPStatusError as e:
        status_code = e.response.status_code
        transport_error = UserError(
            f"Failed to list tools from MCP server '{self._error_name}': "
            f"HTTP error {status_code}"
        )
        transport_cause = _safe_transport_cause(e)
    except httpx.RequestError as e:
        transport_cause = _safe_transport_cause(e)
        if transport_cause is not None and not isinstance(e, httpx.ConnectError):
            raise
        if isinstance(e, httpx.ConnectError):
            transport_error = UserError(
                f"Failed to list tools from MCP server '{self._error_name}': Connection lost. "
                f"The server may have disconnected."
            )
        elif isinstance(e, httpx.TimeoutException):
            transport_error = UserError(
                f"Failed to list tools from MCP server '{self._error_name}': "
                "Connection timeout."
            )
        else:
            transport_error = UserError(
                f"Failed to list tools from MCP server '{self._error_name}': Request failed."
            )

    assert transport_error is not None
    self._raise_mapped_transport_error(transport_error, transport_cause)

call_tool async

call_tool(
    tool_name: str,
    arguments: dict[str, Any] | None,
    meta: dict[str, Any] | None = None,
) -> CallToolResult

Invoke a tool on the server.

ソースコード位置: src/agents/mcp/server.py
async def call_tool(
    self,
    tool_name: str,
    arguments: dict[str, Any] | None,
    meta: dict[str, Any] | None = None,
) -> CallToolResult:
    """Invoke a tool on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None

    transport_error: UserError | None = None
    transport_cause: Exception | None = None
    try:
        self._validate_required_parameters(tool_name=tool_name, arguments=arguments)
        if meta is None:
            return await self._run_with_retries(
                lambda: self._maybe_serialize_request(
                    lambda: session.call_tool(tool_name, arguments)
                )
            )
        return await self._run_with_retries(
            lambda: self._maybe_serialize_request(
                lambda: session.call_tool(tool_name, arguments, meta=meta)
            )
        )
    except httpx.HTTPStatusError as e:
        status_code = e.response.status_code
        transport_error = UserError(
            f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
            f"HTTP error {status_code}"
        )
        transport_cause = _safe_transport_cause(e)
    except httpx.RequestError as e:
        transport_cause = _safe_transport_cause(e)
        if transport_cause is not None and not isinstance(e, httpx.ConnectError):
            raise
        if isinstance(e, httpx.ConnectError):
            transport_error = UserError(
                f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                "Connection lost. The server may have disconnected."
            )
        elif isinstance(e, httpx.TimeoutException):
            transport_error = UserError(
                f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                "Connection timeout."
            )
        else:
            transport_error = UserError(
                f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                "Request failed."
            )

    assert transport_error is not None
    self._raise_mapped_transport_error(transport_error, transport_cause)

list_prompts async

list_prompts() -> ListPromptsResult

List the prompts available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_prompts(
    self,
) -> ListPromptsResult:
    """List the prompts available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    result = await self._list_prompts_page(session)
    if result.nextCursor is None:
        return result

    prompts = list(result.prompts)
    cursor: str | None = result.nextCursor
    seen_cursors: set[str | None] = {None}
    pagination_failure: BaseException | None = None
    repeated_cursor = False
    page: ListPromptsResult | None = None
    next_cursor: str | None = None
    while cursor is not None:
        try:
            page = await self._list_prompts_page(session, cursor)
        except BaseException as error:
            if isinstance(error, BaseExceptionGroup):
                pagination_failure = _credential_safe_exception_group(error)
            elif isinstance(error, Exception):
                pagination_failure = self._user_error_for_request_operation(
                    "list prompts", error
                )
            else:
                pagination_failure = _credential_safe_exception_leaf(error)
            break
        prompts.extend(page.prompts)
        seen_cursors.add(cursor)
        next_cursor = page.nextCursor
        if next_cursor is not None and next_cursor in seen_cursors:
            repeated_cursor = True
            break
        cursor = next_cursor

    if pagination_failure is not None or repeated_cursor:
        cursor = None
        seen_cursors.clear()
        prompts.clear()
        page = None
        next_cursor = None
        del result
        if pagination_failure is not None:
            raise pagination_failure from None
        raise UserError(
            f"MCP server '{self._error_name}' returned a repeated cursor while listing prompts."
        ) from None

    return result.model_copy(update={"prompts": prompts, "nextCursor": None})

get_prompt async

get_prompt(
    name: str, arguments: dict[str, Any] | None = None
) -> GetPromptResult

Get a specific prompt from the server.

ソースコード位置: src/agents/mcp/server.py
async def get_prompt(
    self, name: str, arguments: dict[str, Any] | None = None
) -> GetPromptResult:
    """Get a specific prompt from the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    return await self._run_request_with_transport_error_redaction(
        "get prompt",
        lambda: self._maybe_serialize_request(lambda: session.get_prompt(name, arguments)),
    )

list_resources async

list_resources(
    cursor: str | None = None,
) -> ListResourcesResult

List the resources available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_resources(self, cursor: str | None = None) -> ListResourcesResult:
    """List the resources available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    return await self._run_request_with_transport_error_redaction(
        "list resources",
        lambda: self._maybe_serialize_request(lambda: session.list_resources(cursor)),
    )

list_resource_templates async

list_resource_templates(
    cursor: str | None = None,
) -> ListResourceTemplatesResult

List the resource templates available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_resource_templates(
    self, cursor: str | None = None
) -> ListResourceTemplatesResult:
    """List the resource templates available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    return await self._run_request_with_transport_error_redaction(
        "list resource templates",
        lambda: self._maybe_serialize_request(lambda: session.list_resource_templates(cursor)),
    )

read_resource async

read_resource(uri: str) -> ReadResourceResult

Read the contents of a specific resource by URI.

引数:

名前 タイプ デスクリプション デフォルト
uri str

The URI of the resource to read. See :class:~pydantic.networks.AnyUrl for the supported URI formats.

必須
ソースコード位置: src/agents/mcp/server.py
async def read_resource(self, uri: str) -> ReadResourceResult:
    """Read the contents of a specific resource by URI.

    Args:
        uri: The URI of the resource to read. See :class:`~pydantic.networks.AnyUrl`
            for the supported URI formats.
    """
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    from pydantic import AnyUrl

    return await self._run_request_with_transport_error_redaction(
        "read resource",
        lambda: self._maybe_serialize_request(lambda: session.read_resource(AnyUrl(uri))),
    )

invalidate_tools_cache

invalidate_tools_cache()

Invalidate the tools cache.

ソースコード位置: src/agents/mcp/server.py
def invalidate_tools_cache(self):
    """Invalidate the tools cache."""
    self._cache_dirty = True

MCPServerSseParams

Bases: TypedDict

Mirrors the params in mcp.client.sse.sse_client.

ソースコード位置: src/agents/mcp/server.py
class MCPServerSseParams(TypedDict):
    """Mirrors the params in `mcp.client.sse.sse_client`."""

    url: str
    """The URL of the server."""

    headers: NotRequired[dict[str, str]]
    """The headers to send to the server."""

    timeout: NotRequired[float]
    """The timeout for the HTTP request. Defaults to 5 seconds."""

    sse_read_timeout: NotRequired[float]
    """The timeout for the SSE connection, in seconds. Defaults to 5 minutes."""

    auth: NotRequired[httpx.Auth | None]
    """Optional httpx authentication handler (e.g. ``httpx.BasicAuth``, a custom
    ``httpx.Auth`` subclass for OAuth token refresh, etc.).  When provided, it is
    passed directly to the underlying ``httpx.AsyncClient`` used by the SSE transport.
    """

    httpx_client_factory: NotRequired[HttpClientFactory]
    """Custom HTTP client factory for configuring httpx.AsyncClient behavior (e.g.
    to set custom SSL certificates, proxies, or other transport options).
    """

url instance-attribute

url: str

The URL of the server.

headers instance-attribute

headers: NotRequired[dict[str, str]]

The headers to send to the server.

timeout instance-attribute

timeout: NotRequired[float]

The timeout for the HTTP request. Defaults to 5 seconds.

sse_read_timeout instance-attribute

sse_read_timeout: NotRequired[float]

The timeout for the SSE connection, in seconds. Defaults to 5 minutes.

auth instance-attribute

auth: NotRequired[Auth | None]

Optional httpx authentication handler (e.g. httpx.BasicAuth, a custom httpx.Auth subclass for OAuth token refresh, etc.). When provided, it is passed directly to the underlying httpx.AsyncClient used by the SSE transport.

httpx_client_factory instance-attribute

httpx_client_factory: NotRequired[HttpClientFactory]

Custom HTTP client factory for configuring httpx.AsyncClient behavior (e.g. to set custom SSL certificates, proxies, or other transport options).

MCPServerSse

Bases: _MCPServerWithClientSession

MCP server implementation that uses the HTTP with SSE transport. See the [spec] (https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse) for details.

ソースコード位置: src/agents/mcp/server.py
class MCPServerSse(_MCPServerWithClientSession):
    """MCP server implementation that uses the HTTP with SSE transport. See the [spec]
    (https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse)
    for details.
    """

    def __init__(
        self,
        params: MCPServerSseParams,
        cache_tools_list: bool = False,
        name: str | None = None,
        client_session_timeout_seconds: float | None = 5,
        tool_filter: ToolFilter = None,
        use_structured_content: bool = False,
        max_retry_attempts: int = 0,
        retry_backoff_seconds_base: float = 1.0,
        message_handler: MessageHandlerFnT | None = None,
        require_approval: RequireApprovalSetting = None,
        failure_error_function: ToolErrorFunction | None | _UnsetType = _UNSET,
        tool_meta_resolver: MCPToolMetaResolver | None = None,
        custom_data_extractor: MCPToolCustomDataExtractor | None = None,
    ):
        """Create a new MCP server based on the HTTP with SSE transport.

        Args:
            params: The params that configure the server. This includes the URL of the server,
                the headers to send to the server, the timeout for the HTTP request, and the
                timeout for the SSE connection.

            cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
                cached and only fetched from the server once. If `False`, the tools list will be
                fetched from the server on each call to `list_tools()`. The cache can be
                invalidated by calling `invalidate_tools_cache()`. You should set this to `True`
                if you know the server will not change its tools list, because it can drastically
                improve latency (by avoiding a round-trip to the server every time).

            name: A readable name for the server. If not provided, we'll create one from the
                URL.

            client_session_timeout_seconds: The MCP ClientSession read timeout. Positive finite
                values representable by `datetime.timedelta` and at least one microsecond set a
                timeout; `None` and `0` disable it. Other values are rejected during server
                construction.
            tool_filter: The tool filter to use for filtering tools.
            use_structured_content: Whether to use `tool_result.structured_content` when calling an
                MCP tool. Defaults to False for backwards compatibility - most MCP servers still
                include the structured content in the `tool_result.content`, and using it by
                default will cause duplicate content. You can set this to True if you know the
                server will not duplicate the structured content in the `tool_result.content`.
            max_retry_attempts: Number of times to retry failed list_tools/call_tool calls.
                Defaults to no retries.
            retry_backoff_seconds_base: The base delay, in seconds, for exponential
                backoff between retries.
            message_handler: Optional handler invoked for session messages as delivered by the
                ClientSession.
            require_approval: Approval policy for tools on this server. Accepts "always"/"never",
                a dict of tool names to those values, or an object with always/never tool lists.
            failure_error_function: Optional function used to convert MCP tool failures into
                a model-visible error message. If explicitly set to None, tool errors will be
                raised instead of converted. If left unset, the agent-level configuration (or
                SDK default) will be used.
            tool_meta_resolver: Optional callable that produces MCP request metadata (`_meta`) for
                tool calls. It is invoked by the Agents SDK before calling `call_tool`.
            custom_data_extractor: Optional callable that produces SDK-only custom data for
                emitted MCP tool output items.
        """
        super().__init__(
            cache_tools_list=cache_tools_list,
            client_session_timeout_seconds=client_session_timeout_seconds,
            tool_filter=tool_filter,
            use_structured_content=use_structured_content,
            max_retry_attempts=max_retry_attempts,
            retry_backoff_seconds_base=retry_backoff_seconds_base,
            message_handler=message_handler,
            require_approval=require_approval,
            failure_error_function=failure_error_function,
            tool_meta_resolver=tool_meta_resolver,
            custom_data_extractor=custom_data_extractor,
        )

        self.params = params
        self._name = name or f"sse: {self.params['url']}"

    def create_streams(
        self,
    ) -> AbstractAsyncContextManager[MCPStreamTransport]:
        """Create the streams for the server."""
        kwargs: dict[str, Any] = {
            "url": self.params["url"],
            "headers": self.params.get("headers", None),
            "timeout": self.params.get("timeout", 5),
            "sse_read_timeout": self.params.get("sse_read_timeout", 60 * 5),
        }
        if "auth" in self.params:
            kwargs["auth"] = self.params["auth"]
        kwargs["httpx_client_factory"] = (
            self.params.get("httpx_client_factory") or _create_default_streamable_http_client
        )
        return sse_client(**kwargs)

    @property
    def name(self) -> str:
        """A readable name for the server."""
        return self._name

name property

name: str

A readable name for the server.

__init__

__init__(
    params: MCPServerSseParams,
    cache_tools_list: bool = False,
    name: str | None = None,
    client_session_timeout_seconds: float | None = 5,
    tool_filter: ToolFilter = None,
    use_structured_content: bool = False,
    max_retry_attempts: int = 0,
    retry_backoff_seconds_base: float = 1.0,
    message_handler: MessageHandlerFnT | None = None,
    require_approval: RequireApprovalSetting = None,
    failure_error_function: ToolErrorFunction
    | None
    | _UnsetType = _UNSET,
    tool_meta_resolver: MCPToolMetaResolver | None = None,
    custom_data_extractor: MCPToolCustomDataExtractor
    | None = None,
)

Create a new MCP server based on the HTTP with SSE transport.

引数:

名前 タイプ デスクリプション デフォルト
params MCPServerSseParams

The params that configure the server. This includes the URL of the server, the headers to send to the server, the timeout for the HTTP request, and the timeout for the SSE connection.

必須
cache_tools_list bool

Whether to cache the tools list. If True, the tools list will be cached and only fetched from the server once. If False, the tools list will be fetched from the server on each call to list_tools(). The cache can be invalidated by calling invalidate_tools_cache(). You should set this to True if you know the server will not change its tools list, because it can drastically improve latency (by avoiding a round-trip to the server every time).

False
name str | None

A readable name for the server. If not provided, we'll create one from the URL.

None
client_session_timeout_seconds float | None

The MCP ClientSession read timeout. Positive finite values representable by datetime.timedelta and at least one microsecond set a timeout; None and 0 disable it. Other values are rejected during server construction.

5
tool_filter ToolFilter

The tool filter to use for filtering tools.

None
use_structured_content bool

Whether to use tool_result.structured_content when calling an MCP tool. Defaults to False for backwards compatibility - most MCP servers still include the structured content in the tool_result.content, and using it by default will cause duplicate content. You can set this to True if you know the server will not duplicate the structured content in the tool_result.content.

False
max_retry_attempts int

Number of times to retry failed list_tools/call_tool calls. Defaults to no retries.

0
retry_backoff_seconds_base float

The base delay, in seconds, for exponential backoff between retries.

1.0
message_handler MessageHandlerFnT | None

Optional handler invoked for session messages as delivered by the ClientSession.

None
require_approval RequireApprovalSetting

Approval policy for tools on this server. Accepts "always"/"never", a dict of tool names to those values, or an object with always/never tool lists.

None
failure_error_function ToolErrorFunction | None | _UnsetType

Optional function used to convert MCP tool failures into a model-visible error message. If explicitly set to None, tool errors will be raised instead of converted. If left unset, the agent-level configuration (or SDK default) will be used.

_UNSET
tool_meta_resolver MCPToolMetaResolver | None

Optional callable that produces MCP request metadata (_meta) for tool calls. It is invoked by the Agents SDK before calling call_tool.

None
custom_data_extractor MCPToolCustomDataExtractor | None

Optional callable that produces SDK-only custom data for emitted MCP tool output items.

None
ソースコード位置: src/agents/mcp/server.py
def __init__(
    self,
    params: MCPServerSseParams,
    cache_tools_list: bool = False,
    name: str | None = None,
    client_session_timeout_seconds: float | None = 5,
    tool_filter: ToolFilter = None,
    use_structured_content: bool = False,
    max_retry_attempts: int = 0,
    retry_backoff_seconds_base: float = 1.0,
    message_handler: MessageHandlerFnT | None = None,
    require_approval: RequireApprovalSetting = None,
    failure_error_function: ToolErrorFunction | None | _UnsetType = _UNSET,
    tool_meta_resolver: MCPToolMetaResolver | None = None,
    custom_data_extractor: MCPToolCustomDataExtractor | None = None,
):
    """Create a new MCP server based on the HTTP with SSE transport.

    Args:
        params: The params that configure the server. This includes the URL of the server,
            the headers to send to the server, the timeout for the HTTP request, and the
            timeout for the SSE connection.

        cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
            cached and only fetched from the server once. If `False`, the tools list will be
            fetched from the server on each call to `list_tools()`. The cache can be
            invalidated by calling `invalidate_tools_cache()`. You should set this to `True`
            if you know the server will not change its tools list, because it can drastically
            improve latency (by avoiding a round-trip to the server every time).

        name: A readable name for the server. If not provided, we'll create one from the
            URL.

        client_session_timeout_seconds: The MCP ClientSession read timeout. Positive finite
            values representable by `datetime.timedelta` and at least one microsecond set a
            timeout; `None` and `0` disable it. Other values are rejected during server
            construction.
        tool_filter: The tool filter to use for filtering tools.
        use_structured_content: Whether to use `tool_result.structured_content` when calling an
            MCP tool. Defaults to False for backwards compatibility - most MCP servers still
            include the structured content in the `tool_result.content`, and using it by
            default will cause duplicate content. You can set this to True if you know the
            server will not duplicate the structured content in the `tool_result.content`.
        max_retry_attempts: Number of times to retry failed list_tools/call_tool calls.
            Defaults to no retries.
        retry_backoff_seconds_base: The base delay, in seconds, for exponential
            backoff between retries.
        message_handler: Optional handler invoked for session messages as delivered by the
            ClientSession.
        require_approval: Approval policy for tools on this server. Accepts "always"/"never",
            a dict of tool names to those values, or an object with always/never tool lists.
        failure_error_function: Optional function used to convert MCP tool failures into
            a model-visible error message. If explicitly set to None, tool errors will be
            raised instead of converted. If left unset, the agent-level configuration (or
            SDK default) will be used.
        tool_meta_resolver: Optional callable that produces MCP request metadata (`_meta`) for
            tool calls. It is invoked by the Agents SDK before calling `call_tool`.
        custom_data_extractor: Optional callable that produces SDK-only custom data for
            emitted MCP tool output items.
    """
    super().__init__(
        cache_tools_list=cache_tools_list,
        client_session_timeout_seconds=client_session_timeout_seconds,
        tool_filter=tool_filter,
        use_structured_content=use_structured_content,
        max_retry_attempts=max_retry_attempts,
        retry_backoff_seconds_base=retry_backoff_seconds_base,
        message_handler=message_handler,
        require_approval=require_approval,
        failure_error_function=failure_error_function,
        tool_meta_resolver=tool_meta_resolver,
        custom_data_extractor=custom_data_extractor,
    )

    self.params = params
    self._name = name or f"sse: {self.params['url']}"

create_streams

create_streams() -> AbstractAsyncContextManager[
    MCPStreamTransport
]

Create the streams for the server.

ソースコード位置: src/agents/mcp/server.py
def create_streams(
    self,
) -> AbstractAsyncContextManager[MCPStreamTransport]:
    """Create the streams for the server."""
    kwargs: dict[str, Any] = {
        "url": self.params["url"],
        "headers": self.params.get("headers", None),
        "timeout": self.params.get("timeout", 5),
        "sse_read_timeout": self.params.get("sse_read_timeout", 60 * 5),
    }
    if "auth" in self.params:
        kwargs["auth"] = self.params["auth"]
    kwargs["httpx_client_factory"] = (
        self.params.get("httpx_client_factory") or _create_default_streamable_http_client
    )
    return sse_client(**kwargs)

connect async

connect()

Connect to the server.

ソースコード位置: src/agents/mcp/server.py
async def connect(self):
    """Connect to the server."""
    read_timeout = _client_session_read_timeout(self.client_session_timeout_seconds)
    connection_succeeded = False
    connection_error: UserError | None = None
    connection_cause: Exception | None = None
    connection_exception: BaseException | None = None
    cleanup_failure: BaseException | None = None
    try:
        transport = await self.exit_stack.enter_async_context(self.create_streams())
        # streamablehttp_client returns (read, write, get_session_id)
        # sse_client returns (read, write)

        read, write, *rest = transport
        # Capture the session-id callback when present (streamablehttp_client only).
        self._get_session_id = rest[0] if rest and callable(rest[0]) else None

        session = await self.exit_stack.enter_async_context(
            ClientSession(
                read,
                write,
                read_timeout,
                message_handler=self.message_handler,
            )
        )
        server_result = await session.initialize()
        self.server_initialize_result = server_result
        self.session = session
        connection_succeeded = True
    except BaseException as e:
        if not isinstance(e, Exception):
            connection_exception = e
        else:
            http_errors = self._extract_http_errors_from_exception(e)
            if not http_errors:
                connection_exception = e
            else:
                unsafe_http_error = _first_unretainable_transport_error(http_errors)
                http_error = unsafe_http_error or http_errors[0]
                connection_cause = _safe_transport_cause(http_error)
                maps_safe_error = isinstance(
                    http_error,
                    httpx.HTTPStatusError | httpx.ConnectError | httpx.TimeoutException,
                )
                if connection_cause is not None and not maps_safe_error:
                    connection_exception = e
                    connection_cause = None
                else:
                    connection_error = self._user_error_for_http_error(http_error)
                http_errors.clear()
                del http_error
                del unsafe_http_error

    # Run cleanup after leaving the connection exception handler so a cleanup UserError does
    # not retain the pending connection failure as its implicit context.
    if not connection_succeeded:
        try:
            await self.cleanup()
        except UserError as e:
            cleanup_failure = e
        except Exception as cleanup_error:
            # Suppress RuntimeError about cancel scopes during cleanup - this is a known
            # issue with the MCP library's async generator cleanup and shouldn't mask the
            # original error.
            if isinstance(cleanup_error, RuntimeError) and "cancel scope" in str(cleanup_error):
                logger.debug(
                    "%s",
                    get_mcp_server_log_message(
                        "Ignoring cancel scope error during cleanup of MCP server", self
                    ),
                    stacklevel=2,
                )
            else:
                # Log other cleanup errors but don't raise - original error is more important.
                logger.warning(
                    "%s",
                    get_mcp_server_log_message("Error during cleanup of MCP server", self),
                    stacklevel=2,
                )
        except BaseException as e:
            cleanup_failure = e

    if cleanup_failure is not None:
        connection_exception = None
        connection_error = None
        connection_cause = None
        if isinstance(cleanup_failure, UserError):
            self._raise_mapped_transport_error(cleanup_failure, None)
        raise cleanup_failure

    if connection_exception is not None:
        raise connection_exception

    if connection_error is not None:
        self._raise_mapped_transport_error(connection_error, connection_cause)

cleanup async

cleanup()

Cleanup the server.

ソースコード位置: src/agents/mcp/server.py
async def cleanup(self):
    """Cleanup the server."""
    async with self._cleanup_lock:
        # Only raise HTTP errors if we're cleaning up after a failed connection.
        # During normal teardown (via __aexit__), log but don't raise to avoid
        # masking the original exception.
        is_failed_connection_cleanup = self.session is None
        cleanup_error: UserError | None = None

        try:
            await self.exit_stack.aclose()
        except asyncio.CancelledError as e:
            log_tool_action_debug(
                logger,
                get_mcp_server_log_message("Cleanup cancelled for MCP server", self),
                e,
            )
            raise
        except (BaseExceptionGroup, httpx.HTTPStatusError, httpx.RequestError) as e:
            selected_http_error = self._select_cleanup_transport_error(e)
            if selected_http_error is not None:
                if is_failed_connection_cleanup:
                    cleanup_error = self._user_error_for_http_error(
                        selected_http_error,
                        include_http_reason_phrase=False,
                    )
                    del selected_http_error
                else:
                    _log_cleanup_transport_warning(
                        get_mcp_server_log_message(
                            _get_cleanup_transport_error_message(selected_http_error), self
                        )
                    )
            elif isinstance(e, httpx.RequestError):
                _log_cleanup_transport_warning(
                    get_mcp_server_log_message(_get_cleanup_transport_error_message(e), self)
                )
            elif isinstance(e, BaseExceptionGroup):
                http_errors = self._extract_http_errors_from_exception(e)
                if http_errors:
                    safe_error_group = _credential_safe_exception_group(e)
                    log_tool_action_error(
                        logger,
                        get_mcp_server_log_message("Error cleaning up MCP server", self),
                        safe_error_group,
                    )
                else:
                    # No HTTP error found, suppress RuntimeError about cancel scopes.
                    has_cancel_scope_error = any(
                        isinstance(exc, RuntimeError) and "cancel scope" in str(exc)
                        for exc in e.exceptions
                    )
                    if has_cancel_scope_error:
                        log_tool_action_debug(
                            logger,
                            get_mcp_server_log_message(
                                "Ignoring cancel scope error during cleanup of MCP server", self
                            ),
                            e,
                        )
                    else:
                        log_tool_action_error(
                            logger,
                            get_mcp_server_log_message("Error cleaning up MCP server", self),
                            e,
                        )
            else:
                log_tool_action_error(
                    logger,
                    get_mcp_server_log_message("Error cleaning up MCP server", self),
                    e,
                )
        except Exception as e:
            # Suppress RuntimeError about cancel scopes - this is a known issue with the MCP
            # library when background tasks fail during async generator cleanup
            if isinstance(e, RuntimeError) and "cancel scope" in str(e):
                log_tool_action_debug(
                    logger,
                    get_mcp_server_log_message(
                        "Ignoring cancel scope error during cleanup of MCP server", self
                    ),
                    e,
                )
            else:
                log_tool_action_error(
                    logger,
                    get_mcp_server_log_message("Error cleaning up MCP server", self),
                    e,
                )
        finally:
            self.session = None
            self._get_session_id = None

        if cleanup_error is not None:
            self._raise_mapped_transport_error(cleanup_error, None)

list_tools async

list_tools(
    run_context: RunContextWrapper[Any] | None = None,
    agent: AgentBase | None = None,
) -> list[Tool]

List the tools available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_tools(
    self,
    run_context: RunContextWrapper[Any] | None = None,
    agent: AgentBase | None = None,
) -> list[MCPTool]:
    """List the tools available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None

    transport_error: UserError | None = None
    transport_cause: Exception | None = None
    try:
        tools: list[MCPTool]
        # Return from cache if caching is enabled, we have tools, and the cache is not dirty
        if self.cache_tools_list and not self._cache_dirty and self._tools_list:
            tools = self._tools_list
        else:
            tools = []
            cursor: str | None = None
            seen_cursors: set[str | None] = set()

            async def fetch_pages() -> bool:
                nonlocal cursor
                while True:
                    result = await self._list_tools_page(session, cursor)
                    tools.extend(result.tools)
                    seen_cursors.add(cursor)
                    next_cursor = result.nextCursor
                    if next_cursor is None:
                        return True
                    if next_cursor in seen_cursors:
                        return False
                    cursor = next_cursor

            pagination_complete = False
            pagination_failure: BaseException | None = None
            try:
                pagination_complete = await self._run_with_retries(fetch_pages)
            except BaseException as error:
                if cursor is None:
                    raise
                if isinstance(error, BaseExceptionGroup):
                    pagination_failure = _credential_safe_exception_group(error)
                elif isinstance(error, Exception):
                    pagination_failure = self._user_error_for_request_operation(
                        "list tools", error
                    )
                else:
                    pagination_failure = _credential_safe_exception_leaf(error)

            if pagination_failure is not None or not pagination_complete:
                cursor = None
                seen_cursors.clear()
                tools.clear()
                del fetch_pages
                if pagination_failure is not None:
                    raise pagination_failure from None
                raise UserError(
                    f"MCP server '{self._error_name}' returned a repeated cursor while "
                    "listing tools."
                ) from None

            cursor = None
            seen_cursors.clear()
            del fetch_pages
            self._tools_list = tools
            self._cache_dirty = False

        # Filter tools based on tool_filter
        filtered_tools = tools
        if self.tool_filter is not None:
            filtered_tools = await self._apply_tool_filter(filtered_tools, run_context, agent)
        return filtered_tools
    except httpx.HTTPStatusError as e:
        status_code = e.response.status_code
        transport_error = UserError(
            f"Failed to list tools from MCP server '{self._error_name}': "
            f"HTTP error {status_code}"
        )
        transport_cause = _safe_transport_cause(e)
    except httpx.RequestError as e:
        transport_cause = _safe_transport_cause(e)
        if transport_cause is not None and not isinstance(e, httpx.ConnectError):
            raise
        if isinstance(e, httpx.ConnectError):
            transport_error = UserError(
                f"Failed to list tools from MCP server '{self._error_name}': Connection lost. "
                f"The server may have disconnected."
            )
        elif isinstance(e, httpx.TimeoutException):
            transport_error = UserError(
                f"Failed to list tools from MCP server '{self._error_name}': "
                "Connection timeout."
            )
        else:
            transport_error = UserError(
                f"Failed to list tools from MCP server '{self._error_name}': Request failed."
            )

    assert transport_error is not None
    self._raise_mapped_transport_error(transport_error, transport_cause)

call_tool async

call_tool(
    tool_name: str,
    arguments: dict[str, Any] | None,
    meta: dict[str, Any] | None = None,
) -> CallToolResult

Invoke a tool on the server.

ソースコード位置: src/agents/mcp/server.py
async def call_tool(
    self,
    tool_name: str,
    arguments: dict[str, Any] | None,
    meta: dict[str, Any] | None = None,
) -> CallToolResult:
    """Invoke a tool on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None

    transport_error: UserError | None = None
    transport_cause: Exception | None = None
    try:
        self._validate_required_parameters(tool_name=tool_name, arguments=arguments)
        if meta is None:
            return await self._run_with_retries(
                lambda: self._maybe_serialize_request(
                    lambda: session.call_tool(tool_name, arguments)
                )
            )
        return await self._run_with_retries(
            lambda: self._maybe_serialize_request(
                lambda: session.call_tool(tool_name, arguments, meta=meta)
            )
        )
    except httpx.HTTPStatusError as e:
        status_code = e.response.status_code
        transport_error = UserError(
            f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
            f"HTTP error {status_code}"
        )
        transport_cause = _safe_transport_cause(e)
    except httpx.RequestError as e:
        transport_cause = _safe_transport_cause(e)
        if transport_cause is not None and not isinstance(e, httpx.ConnectError):
            raise
        if isinstance(e, httpx.ConnectError):
            transport_error = UserError(
                f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                "Connection lost. The server may have disconnected."
            )
        elif isinstance(e, httpx.TimeoutException):
            transport_error = UserError(
                f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                "Connection timeout."
            )
        else:
            transport_error = UserError(
                f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                "Request failed."
            )

    assert transport_error is not None
    self._raise_mapped_transport_error(transport_error, transport_cause)

list_prompts async

list_prompts() -> ListPromptsResult

List the prompts available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_prompts(
    self,
) -> ListPromptsResult:
    """List the prompts available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    result = await self._list_prompts_page(session)
    if result.nextCursor is None:
        return result

    prompts = list(result.prompts)
    cursor: str | None = result.nextCursor
    seen_cursors: set[str | None] = {None}
    pagination_failure: BaseException | None = None
    repeated_cursor = False
    page: ListPromptsResult | None = None
    next_cursor: str | None = None
    while cursor is not None:
        try:
            page = await self._list_prompts_page(session, cursor)
        except BaseException as error:
            if isinstance(error, BaseExceptionGroup):
                pagination_failure = _credential_safe_exception_group(error)
            elif isinstance(error, Exception):
                pagination_failure = self._user_error_for_request_operation(
                    "list prompts", error
                )
            else:
                pagination_failure = _credential_safe_exception_leaf(error)
            break
        prompts.extend(page.prompts)
        seen_cursors.add(cursor)
        next_cursor = page.nextCursor
        if next_cursor is not None and next_cursor in seen_cursors:
            repeated_cursor = True
            break
        cursor = next_cursor

    if pagination_failure is not None or repeated_cursor:
        cursor = None
        seen_cursors.clear()
        prompts.clear()
        page = None
        next_cursor = None
        del result
        if pagination_failure is not None:
            raise pagination_failure from None
        raise UserError(
            f"MCP server '{self._error_name}' returned a repeated cursor while listing prompts."
        ) from None

    return result.model_copy(update={"prompts": prompts, "nextCursor": None})

get_prompt async

get_prompt(
    name: str, arguments: dict[str, Any] | None = None
) -> GetPromptResult

Get a specific prompt from the server.

ソースコード位置: src/agents/mcp/server.py
async def get_prompt(
    self, name: str, arguments: dict[str, Any] | None = None
) -> GetPromptResult:
    """Get a specific prompt from the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    return await self._run_request_with_transport_error_redaction(
        "get prompt",
        lambda: self._maybe_serialize_request(lambda: session.get_prompt(name, arguments)),
    )

list_resources async

list_resources(
    cursor: str | None = None,
) -> ListResourcesResult

List the resources available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_resources(self, cursor: str | None = None) -> ListResourcesResult:
    """List the resources available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    return await self._run_request_with_transport_error_redaction(
        "list resources",
        lambda: self._maybe_serialize_request(lambda: session.list_resources(cursor)),
    )

list_resource_templates async

list_resource_templates(
    cursor: str | None = None,
) -> ListResourceTemplatesResult

List the resource templates available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_resource_templates(
    self, cursor: str | None = None
) -> ListResourceTemplatesResult:
    """List the resource templates available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    return await self._run_request_with_transport_error_redaction(
        "list resource templates",
        lambda: self._maybe_serialize_request(lambda: session.list_resource_templates(cursor)),
    )

read_resource async

read_resource(uri: str) -> ReadResourceResult

Read the contents of a specific resource by URI.

引数:

名前 タイプ デスクリプション デフォルト
uri str

The URI of the resource to read. See :class:~pydantic.networks.AnyUrl for the supported URI formats.

必須
ソースコード位置: src/agents/mcp/server.py
async def read_resource(self, uri: str) -> ReadResourceResult:
    """Read the contents of a specific resource by URI.

    Args:
        uri: The URI of the resource to read. See :class:`~pydantic.networks.AnyUrl`
            for the supported URI formats.
    """
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    from pydantic import AnyUrl

    return await self._run_request_with_transport_error_redaction(
        "read resource",
        lambda: self._maybe_serialize_request(lambda: session.read_resource(AnyUrl(uri))),
    )

invalidate_tools_cache

invalidate_tools_cache()

Invalidate the tools cache.

ソースコード位置: src/agents/mcp/server.py
def invalidate_tools_cache(self):
    """Invalidate the tools cache."""
    self._cache_dirty = True

MCPServerStreamableHttpParams

Bases: TypedDict

Mirrors the params in mcp.client.streamable_http.streamablehttp_client.

ソースコード位置: src/agents/mcp/server.py
class MCPServerStreamableHttpParams(TypedDict):
    """Mirrors the params in `mcp.client.streamable_http.streamablehttp_client`."""

    url: str
    """The URL of the server."""

    headers: NotRequired[dict[str, str]]
    """The headers to send to the server."""

    timeout: NotRequired[timedelta | float]
    """The timeout for the HTTP request. Defaults to 5 seconds."""

    sse_read_timeout: NotRequired[timedelta | float]
    """The timeout for the SSE connection, in seconds. Defaults to 5 minutes."""

    terminate_on_close: NotRequired[bool]
    """Terminate on close"""

    httpx_client_factory: NotRequired[HttpClientFactory]
    """Custom HTTP client factory for configuring httpx.AsyncClient behavior."""

    auth: NotRequired[httpx.Auth | None]
    """Optional httpx authentication handler (e.g. ``httpx.BasicAuth``, a custom
    ``httpx.Auth`` subclass for OAuth token refresh, etc.).  When provided, it is
    passed directly to the underlying ``httpx.AsyncClient`` used by the Streamable HTTP
    transport.
    """

    ignore_initialized_notification_failure: NotRequired[bool]
    """Whether to ignore failures when sending the best-effort
    ``notifications/initialized`` POST.

    Defaults to ``False``. When set to ``True``, initialized-notification failures are
    logged and ignored so subsequent requests on the same transport can continue.
    """

url instance-attribute

url: str

The URL of the server.

headers instance-attribute

headers: NotRequired[dict[str, str]]

The headers to send to the server.

timeout instance-attribute

timeout: NotRequired[timedelta | float]

The timeout for the HTTP request. Defaults to 5 seconds.

sse_read_timeout instance-attribute

sse_read_timeout: NotRequired[timedelta | float]

The timeout for the SSE connection, in seconds. Defaults to 5 minutes.

terminate_on_close instance-attribute

terminate_on_close: NotRequired[bool]

Terminate on close

httpx_client_factory instance-attribute

httpx_client_factory: NotRequired[HttpClientFactory]

Custom HTTP client factory for configuring httpx.AsyncClient behavior.

auth instance-attribute

auth: NotRequired[Auth | None]

Optional httpx authentication handler (e.g. httpx.BasicAuth, a custom httpx.Auth subclass for OAuth token refresh, etc.). When provided, it is passed directly to the underlying httpx.AsyncClient used by the Streamable HTTP transport.

ignore_initialized_notification_failure instance-attribute

ignore_initialized_notification_failure: NotRequired[bool]

Whether to ignore failures when sending the best-effort notifications/initialized POST.

Defaults to False. When set to True, initialized-notification failures are logged and ignored so subsequent requests on the same transport can continue.

MCPServerStreamableHttp

Bases: _MCPServerWithClientSession

MCP server implementation that uses the Streamable HTTP transport. See the [spec] (https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http) for details.

ソースコード位置: src/agents/mcp/server.py
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
class MCPServerStreamableHttp(_MCPServerWithClientSession):
    """MCP server implementation that uses the Streamable HTTP transport. See the [spec]
    (https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http)
    for details.
    """

    def __init__(
        self,
        params: MCPServerStreamableHttpParams,
        cache_tools_list: bool = False,
        name: str | None = None,
        client_session_timeout_seconds: float | None = 5,
        tool_filter: ToolFilter = None,
        use_structured_content: bool = False,
        max_retry_attempts: int = 0,
        retry_backoff_seconds_base: float = 1.0,
        message_handler: MessageHandlerFnT | None = None,
        require_approval: RequireApprovalSetting = None,
        failure_error_function: ToolErrorFunction | None | _UnsetType = _UNSET,
        tool_meta_resolver: MCPToolMetaResolver | None = None,
        custom_data_extractor: MCPToolCustomDataExtractor | None = None,
    ):
        """Create a new MCP server based on the Streamable HTTP transport.

        Args:
            params: The params that configure the server. This includes the URL of the server,
                the headers to send to the server, the timeout for the HTTP request, the
                timeout for the Streamable HTTP connection, whether we need to
                terminate on close, and an optional custom HTTP client factory.

            cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
                cached and only fetched from the server once. If `False`, the tools list will be
                fetched from the server on each call to `list_tools()`. The cache can be
                invalidated by calling `invalidate_tools_cache()`. You should set this to `True`
                if you know the server will not change its tools list, because it can drastically
                improve latency (by avoiding a round-trip to the server every time).

            name: A readable name for the server. If not provided, we'll create one from the
                URL.

            client_session_timeout_seconds: The MCP ClientSession read timeout. Positive finite
                values representable by `datetime.timedelta` and at least one microsecond set a
                timeout; `None` and `0` disable it. Other values are rejected during server
                construction.
            tool_filter: The tool filter to use for filtering tools.
            use_structured_content: Whether to use `tool_result.structured_content` when calling an
                MCP tool. Defaults to False for backwards compatibility - most MCP servers still
                include the structured content in the `tool_result.content`, and using it by
                default will cause duplicate content. You can set this to True if you know the
                server will not duplicate the structured content in the `tool_result.content`.
            max_retry_attempts: Number of times to retry failed list_tools/call_tool calls.
                Defaults to no retries.
            retry_backoff_seconds_base: The base delay, in seconds, for exponential
                backoff between retries.
            message_handler: Optional handler invoked for session messages as delivered by the
                ClientSession.
            require_approval: Approval policy for tools on this server. Accepts "always"/"never",
                a dict of tool names to those values, or an object with always/never tool lists.
            failure_error_function: Optional function used to convert MCP tool failures into
                a model-visible error message. If explicitly set to None, tool errors will be
                raised instead of converted. If left unset, the agent-level configuration (or
                SDK default) will be used.
            tool_meta_resolver: Optional callable that produces MCP request metadata (`_meta`) for
                tool calls. It is invoked by the Agents SDK before calling `call_tool`.
            custom_data_extractor: Optional callable that produces SDK-only custom data for
                emitted MCP tool output items.
        """
        super().__init__(
            cache_tools_list=cache_tools_list,
            client_session_timeout_seconds=client_session_timeout_seconds,
            tool_filter=tool_filter,
            use_structured_content=use_structured_content,
            max_retry_attempts=max_retry_attempts,
            retry_backoff_seconds_base=retry_backoff_seconds_base,
            message_handler=message_handler,
            require_approval=require_approval,
            failure_error_function=failure_error_function,
            tool_meta_resolver=tool_meta_resolver,
            custom_data_extractor=custom_data_extractor,
        )

        self.params = params
        self._name = name or f"streamable_http: {self.params['url']}"
        self._serialize_session_requests = True

    def create_streams(
        self,
    ) -> AbstractAsyncContextManager[MCPStreamTransport]:
        """Create the streams for the server."""
        kwargs: dict[str, Any] = {
            "url": self.params["url"],
            "headers": self.params.get("headers", None),
            "timeout": self.params.get("timeout", 5),
            "sse_read_timeout": self.params.get("sse_read_timeout", 60 * 5),
            "terminate_on_close": self.params.get("terminate_on_close", True),
        }
        httpx_client_factory = self.params.get("httpx_client_factory")
        if self.params.get("ignore_initialized_notification_failure", False):
            return _streamablehttp_client_with_transport(
                **kwargs,
                httpx_client_factory=httpx_client_factory or _create_default_streamable_http_client,
                auth=self.params.get("auth"),
                transport_factory=_InitializedNotificationTolerantStreamableHTTPTransport,
            )
        kwargs["httpx_client_factory"] = (
            httpx_client_factory or _create_default_streamable_http_client
        )
        if "auth" in self.params:
            kwargs["auth"] = self.params["auth"]
        return streamablehttp_client(**kwargs)

    @asynccontextmanager
    async def _isolated_client_session(self):
        read_timeout = _client_session_read_timeout(self.client_session_timeout_seconds)
        async with AsyncExitStack() as exit_stack:
            transport = await exit_stack.enter_async_context(self.create_streams())
            read, write, *_ = transport
            session = await exit_stack.enter_async_context(
                ClientSession(
                    read,
                    write,
                    read_timeout,
                    message_handler=self.message_handler,
                )
            )
            await session.initialize()
            yield session

    async def _call_tool_with_session(
        self,
        session: ClientSession,
        tool_name: str,
        arguments: dict[str, Any] | None,
        meta: dict[str, Any] | None = None,
    ) -> CallToolResult:
        if meta is None:
            return await session.call_tool(tool_name, arguments)
        return await session.call_tool(tool_name, arguments, meta=meta)

    def _should_retry_in_isolated_session(self, exc: BaseException) -> bool:
        if isinstance(
            exc,
            asyncio.CancelledError
            | ClosedResourceError
            | httpx.ConnectError
            | httpx.TimeoutException,
        ):
            return True
        if isinstance(exc, httpx.HTTPStatusError):
            return exc.response.status_code >= 500
        if isinstance(exc, McpError):
            return exc.error.code == httpx.codes.REQUEST_TIMEOUT
        if isinstance(exc, BaseExceptionGroup):
            return bool(exc.exceptions) and all(
                self._should_retry_in_isolated_session(inner) for inner in exc.exceptions
            )
        return False

    async def _call_tool_with_shared_session(
        self,
        tool_name: str,
        arguments: dict[str, Any] | None,
        meta: dict[str, Any] | None = None,
        *,
        allow_isolated_retry: bool,
    ) -> CallToolResult:
        session = self.session
        assert session is not None
        try:
            return await self._maybe_serialize_request(
                lambda: self._call_tool_with_session(session, tool_name, arguments, meta)
            )
        except BaseException as exc:
            if allow_isolated_retry and self._should_retry_in_isolated_session(exc):
                raise _SharedSessionRequestNeedsIsolation from exc
            raise

    async def _call_tool_with_isolated_retry(
        self,
        tool_name: str,
        arguments: dict[str, Any] | None,
        meta: dict[str, Any] | None = None,
        *,
        allow_isolated_retry: bool,
    ) -> tuple[CallToolResult, bool]:
        request_task = asyncio.create_task(
            self._call_tool_with_shared_session(
                tool_name,
                arguments,
                meta,
                allow_isolated_retry=allow_isolated_retry,
            )
        )
        try:
            return await asyncio.shield(request_task), False
        except _SharedSessionRequestNeedsIsolation:
            exit_stack = AsyncExitStack()
            try:
                session = await exit_stack.enter_async_context(self._isolated_client_session())
            except asyncio.CancelledError:
                await exit_stack.aclose()
                raise
            except BaseException as exc:
                await exit_stack.aclose()
                raise _IsolatedSessionRetryFailed() from exc
            try:
                try:
                    result = await self._call_tool_with_session(session, tool_name, arguments, meta)
                    return result, True
                except asyncio.CancelledError:
                    raise
                except BaseException as exc:
                    raise _IsolatedSessionRetryFailed() from exc
            finally:
                await exit_stack.aclose()
        except asyncio.CancelledError:
            if not request_task.done():
                request_task.cancel()
            try:
                await request_task
            except BaseException:
                pass
            raise

    async def call_tool(
        self,
        tool_name: str,
        arguments: dict[str, Any] | None,
        meta: dict[str, Any] | None = None,
    ) -> CallToolResult:
        if not self.session:
            raise UserError("Server not initialized. Make sure you call `connect()` first.")

        transport_error: UserError | None = None
        transport_cause: Exception | None = None
        try:
            self._validate_required_parameters(tool_name=tool_name, arguments=arguments)
            retries_used = 0
            first_attempt = True
            while True:
                if not first_attempt and self.max_retry_attempts != -1:
                    retries_used += 1
                allow_isolated_retry = (
                    self.max_retry_attempts == -1 or retries_used < self.max_retry_attempts
                )
                try:
                    result, used_isolated_retry = await self._call_tool_with_isolated_retry(
                        tool_name,
                        arguments,
                        meta,
                        allow_isolated_retry=allow_isolated_retry,
                    )
                    if used_isolated_retry and self.max_retry_attempts != -1:
                        retries_used += 1
                    return result
                except _IsolatedSessionRetryFailed as exc:
                    retries_used += 1
                    if self.max_retry_attempts != -1 and retries_used >= self.max_retry_attempts:
                        if exc.__cause__ is not None:
                            raise exc.__cause__ from exc
                        raise
                    backoff = self.retry_backoff_seconds_base * (2 ** (retries_used - 1))
                    await asyncio.sleep(backoff)
                except Exception:
                    if self.max_retry_attempts != -1 and retries_used >= self.max_retry_attempts:
                        raise
                    backoff = self.retry_backoff_seconds_base * (2**retries_used)
                    await asyncio.sleep(backoff)
                first_attempt = False
        except httpx.HTTPStatusError as e:
            status_code = e.response.status_code
            transport_error = UserError(
                f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                f"HTTP error {status_code}"
            )
            transport_cause = _safe_transport_cause(e)
        except httpx.RequestError as e:
            transport_cause = _safe_transport_cause(e)
            if transport_cause is not None and not isinstance(e, httpx.ConnectError):
                raise
            if isinstance(e, httpx.ConnectError):
                transport_error = UserError(
                    f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                    "Connection lost. The server may have disconnected."
                )
            elif isinstance(e, httpx.TimeoutException):
                transport_error = UserError(
                    f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                    "Connection timeout."
                )
            else:
                transport_error = UserError(
                    f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                    "Request failed."
                )
        except BaseExceptionGroup as e:
            http_errors = self._extract_http_errors_from_exception(e)
            if not http_errors:
                raise

            unsafe_http_error = _first_unretainable_transport_error(http_errors)
            http_error = unsafe_http_error or http_errors[0]
            transport_cause = _safe_transport_cause(http_error)
            if isinstance(http_error, httpx.HTTPStatusError):
                status_code = http_error.response.status_code
                transport_error = UserError(
                    f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                    f"HTTP error {status_code}"
                )
            elif isinstance(http_error, httpx.ConnectError):
                transport_error = UserError(
                    f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                    "Connection lost. The server may have disconnected."
                )
            elif isinstance(http_error, httpx.TimeoutException):
                transport_error = UserError(
                    f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                    "Connection timeout."
                )
            elif isinstance(http_error, httpx.RequestError):
                if transport_cause is not None:
                    raise
                transport_error = UserError(
                    f"Failed to call tool '{tool_name}' on MCP server '{self._error_name}': "
                    "Request failed."
                )
            else:
                raise
            if transport_cause is None:
                http_errors.clear()
                del http_error
                del unsafe_http_error

        assert transport_error is not None
        self._raise_mapped_transport_error(transport_error, transport_cause)

    @property
    def name(self) -> str:
        """A readable name for the server."""
        return self._name

    @property
    def session_id(self) -> str | None:
        """The MCP session ID assigned by the server, or None if not yet connected
        or if the server did not issue a session ID.

        The session ID is stable for the lifetime of this server instance's connection.
        You can persist it and pass it back via the Mcp-Session-Id request header
        (params["headers"]) on a new MCPServerStreamableHttp instance to resume
        the same server-side session across process restarts or stateless workers.

        Example::

            async with MCPServerStreamableHttp(params={"url": url}) as server:
                session_id = server.session_id

            # In a new worker / process:
            async with MCPServerStreamableHttp(
                params={"url": url, "headers": {"Mcp-Session-Id": session_id}}
            ) as server:
                # Resumes the same server-side session.
                ...
        """
        if self._get_session_id is None:
            return None
        return self._get_session_id()

name property

name: str

A readable name for the server.

session_id property

session_id: str | None

The MCP session ID assigned by the server, or None if not yet connected or if the server did not issue a session ID.

The session ID is stable for the lifetime of this server instance's connection. You can persist it and pass it back via the Mcp-Session-Id request header (params["headers"]) on a new MCPServerStreamableHttp instance to resume the same server-side session across process restarts or stateless workers.

Example::

async with MCPServerStreamableHttp(params={"url": url}) as server:
    session_id = server.session_id

# In a new worker / process:
async with MCPServerStreamableHttp(
    params={"url": url, "headers": {"Mcp-Session-Id": session_id}}
) as server:
    # Resumes the same server-side session.
    ...

__init__

__init__(
    params: MCPServerStreamableHttpParams,
    cache_tools_list: bool = False,
    name: str | None = None,
    client_session_timeout_seconds: float | None = 5,
    tool_filter: ToolFilter = None,
    use_structured_content: bool = False,
    max_retry_attempts: int = 0,
    retry_backoff_seconds_base: float = 1.0,
    message_handler: MessageHandlerFnT | None = None,
    require_approval: RequireApprovalSetting = None,
    failure_error_function: ToolErrorFunction
    | None
    | _UnsetType = _UNSET,
    tool_meta_resolver: MCPToolMetaResolver | None = None,
    custom_data_extractor: MCPToolCustomDataExtractor
    | None = None,
)

Create a new MCP server based on the Streamable HTTP transport.

引数:

名前 タイプ デスクリプション デフォルト
params MCPServerStreamableHttpParams

The params that configure the server. This includes the URL of the server, the headers to send to the server, the timeout for the HTTP request, the timeout for the Streamable HTTP connection, whether we need to terminate on close, and an optional custom HTTP client factory.

必須
cache_tools_list bool

Whether to cache the tools list. If True, the tools list will be cached and only fetched from the server once. If False, the tools list will be fetched from the server on each call to list_tools(). The cache can be invalidated by calling invalidate_tools_cache(). You should set this to True if you know the server will not change its tools list, because it can drastically improve latency (by avoiding a round-trip to the server every time).

False
name str | None

A readable name for the server. If not provided, we'll create one from the URL.

None
client_session_timeout_seconds float | None

The MCP ClientSession read timeout. Positive finite values representable by datetime.timedelta and at least one microsecond set a timeout; None and 0 disable it. Other values are rejected during server construction.

5
tool_filter ToolFilter

The tool filter to use for filtering tools.

None
use_structured_content bool

Whether to use tool_result.structured_content when calling an MCP tool. Defaults to False for backwards compatibility - most MCP servers still include the structured content in the tool_result.content, and using it by default will cause duplicate content. You can set this to True if you know the server will not duplicate the structured content in the tool_result.content.

False
max_retry_attempts int

Number of times to retry failed list_tools/call_tool calls. Defaults to no retries.

0
retry_backoff_seconds_base float

The base delay, in seconds, for exponential backoff between retries.

1.0
message_handler MessageHandlerFnT | None

Optional handler invoked for session messages as delivered by the ClientSession.

None
require_approval RequireApprovalSetting

Approval policy for tools on this server. Accepts "always"/"never", a dict of tool names to those values, or an object with always/never tool lists.

None
failure_error_function ToolErrorFunction | None | _UnsetType

Optional function used to convert MCP tool failures into a model-visible error message. If explicitly set to None, tool errors will be raised instead of converted. If left unset, the agent-level configuration (or SDK default) will be used.

_UNSET
tool_meta_resolver MCPToolMetaResolver | None

Optional callable that produces MCP request metadata (_meta) for tool calls. It is invoked by the Agents SDK before calling call_tool.

None
custom_data_extractor MCPToolCustomDataExtractor | None

Optional callable that produces SDK-only custom data for emitted MCP tool output items.

None
ソースコード位置: src/agents/mcp/server.py
def __init__(
    self,
    params: MCPServerStreamableHttpParams,
    cache_tools_list: bool = False,
    name: str | None = None,
    client_session_timeout_seconds: float | None = 5,
    tool_filter: ToolFilter = None,
    use_structured_content: bool = False,
    max_retry_attempts: int = 0,
    retry_backoff_seconds_base: float = 1.0,
    message_handler: MessageHandlerFnT | None = None,
    require_approval: RequireApprovalSetting = None,
    failure_error_function: ToolErrorFunction | None | _UnsetType = _UNSET,
    tool_meta_resolver: MCPToolMetaResolver | None = None,
    custom_data_extractor: MCPToolCustomDataExtractor | None = None,
):
    """Create a new MCP server based on the Streamable HTTP transport.

    Args:
        params: The params that configure the server. This includes the URL of the server,
            the headers to send to the server, the timeout for the HTTP request, the
            timeout for the Streamable HTTP connection, whether we need to
            terminate on close, and an optional custom HTTP client factory.

        cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
            cached and only fetched from the server once. If `False`, the tools list will be
            fetched from the server on each call to `list_tools()`. The cache can be
            invalidated by calling `invalidate_tools_cache()`. You should set this to `True`
            if you know the server will not change its tools list, because it can drastically
            improve latency (by avoiding a round-trip to the server every time).

        name: A readable name for the server. If not provided, we'll create one from the
            URL.

        client_session_timeout_seconds: The MCP ClientSession read timeout. Positive finite
            values representable by `datetime.timedelta` and at least one microsecond set a
            timeout; `None` and `0` disable it. Other values are rejected during server
            construction.
        tool_filter: The tool filter to use for filtering tools.
        use_structured_content: Whether to use `tool_result.structured_content` when calling an
            MCP tool. Defaults to False for backwards compatibility - most MCP servers still
            include the structured content in the `tool_result.content`, and using it by
            default will cause duplicate content. You can set this to True if you know the
            server will not duplicate the structured content in the `tool_result.content`.
        max_retry_attempts: Number of times to retry failed list_tools/call_tool calls.
            Defaults to no retries.
        retry_backoff_seconds_base: The base delay, in seconds, for exponential
            backoff between retries.
        message_handler: Optional handler invoked for session messages as delivered by the
            ClientSession.
        require_approval: Approval policy for tools on this server. Accepts "always"/"never",
            a dict of tool names to those values, or an object with always/never tool lists.
        failure_error_function: Optional function used to convert MCP tool failures into
            a model-visible error message. If explicitly set to None, tool errors will be
            raised instead of converted. If left unset, the agent-level configuration (or
            SDK default) will be used.
        tool_meta_resolver: Optional callable that produces MCP request metadata (`_meta`) for
            tool calls. It is invoked by the Agents SDK before calling `call_tool`.
        custom_data_extractor: Optional callable that produces SDK-only custom data for
            emitted MCP tool output items.
    """
    super().__init__(
        cache_tools_list=cache_tools_list,
        client_session_timeout_seconds=client_session_timeout_seconds,
        tool_filter=tool_filter,
        use_structured_content=use_structured_content,
        max_retry_attempts=max_retry_attempts,
        retry_backoff_seconds_base=retry_backoff_seconds_base,
        message_handler=message_handler,
        require_approval=require_approval,
        failure_error_function=failure_error_function,
        tool_meta_resolver=tool_meta_resolver,
        custom_data_extractor=custom_data_extractor,
    )

    self.params = params
    self._name = name or f"streamable_http: {self.params['url']}"
    self._serialize_session_requests = True

create_streams

create_streams() -> AbstractAsyncContextManager[
    MCPStreamTransport
]

Create the streams for the server.

ソースコード位置: src/agents/mcp/server.py
def create_streams(
    self,
) -> AbstractAsyncContextManager[MCPStreamTransport]:
    """Create the streams for the server."""
    kwargs: dict[str, Any] = {
        "url": self.params["url"],
        "headers": self.params.get("headers", None),
        "timeout": self.params.get("timeout", 5),
        "sse_read_timeout": self.params.get("sse_read_timeout", 60 * 5),
        "terminate_on_close": self.params.get("terminate_on_close", True),
    }
    httpx_client_factory = self.params.get("httpx_client_factory")
    if self.params.get("ignore_initialized_notification_failure", False):
        return _streamablehttp_client_with_transport(
            **kwargs,
            httpx_client_factory=httpx_client_factory or _create_default_streamable_http_client,
            auth=self.params.get("auth"),
            transport_factory=_InitializedNotificationTolerantStreamableHTTPTransport,
        )
    kwargs["httpx_client_factory"] = (
        httpx_client_factory or _create_default_streamable_http_client
    )
    if "auth" in self.params:
        kwargs["auth"] = self.params["auth"]
    return streamablehttp_client(**kwargs)

connect async

connect()

Connect to the server.

ソースコード位置: src/agents/mcp/server.py
async def connect(self):
    """Connect to the server."""
    read_timeout = _client_session_read_timeout(self.client_session_timeout_seconds)
    connection_succeeded = False
    connection_error: UserError | None = None
    connection_cause: Exception | None = None
    connection_exception: BaseException | None = None
    cleanup_failure: BaseException | None = None
    try:
        transport = await self.exit_stack.enter_async_context(self.create_streams())
        # streamablehttp_client returns (read, write, get_session_id)
        # sse_client returns (read, write)

        read, write, *rest = transport
        # Capture the session-id callback when present (streamablehttp_client only).
        self._get_session_id = rest[0] if rest and callable(rest[0]) else None

        session = await self.exit_stack.enter_async_context(
            ClientSession(
                read,
                write,
                read_timeout,
                message_handler=self.message_handler,
            )
        )
        server_result = await session.initialize()
        self.server_initialize_result = server_result
        self.session = session
        connection_succeeded = True
    except BaseException as e:
        if not isinstance(e, Exception):
            connection_exception = e
        else:
            http_errors = self._extract_http_errors_from_exception(e)
            if not http_errors:
                connection_exception = e
            else:
                unsafe_http_error = _first_unretainable_transport_error(http_errors)
                http_error = unsafe_http_error or http_errors[0]
                connection_cause = _safe_transport_cause(http_error)
                maps_safe_error = isinstance(
                    http_error,
                    httpx.HTTPStatusError | httpx.ConnectError | httpx.TimeoutException,
                )
                if connection_cause is not None and not maps_safe_error:
                    connection_exception = e
                    connection_cause = None
                else:
                    connection_error = self._user_error_for_http_error(http_error)
                http_errors.clear()
                del http_error
                del unsafe_http_error

    # Run cleanup after leaving the connection exception handler so a cleanup UserError does
    # not retain the pending connection failure as its implicit context.
    if not connection_succeeded:
        try:
            await self.cleanup()
        except UserError as e:
            cleanup_failure = e
        except Exception as cleanup_error:
            # Suppress RuntimeError about cancel scopes during cleanup - this is a known
            # issue with the MCP library's async generator cleanup and shouldn't mask the
            # original error.
            if isinstance(cleanup_error, RuntimeError) and "cancel scope" in str(cleanup_error):
                logger.debug(
                    "%s",
                    get_mcp_server_log_message(
                        "Ignoring cancel scope error during cleanup of MCP server", self
                    ),
                    stacklevel=2,
                )
            else:
                # Log other cleanup errors but don't raise - original error is more important.
                logger.warning(
                    "%s",
                    get_mcp_server_log_message("Error during cleanup of MCP server", self),
                    stacklevel=2,
                )
        except BaseException as e:
            cleanup_failure = e

    if cleanup_failure is not None:
        connection_exception = None
        connection_error = None
        connection_cause = None
        if isinstance(cleanup_failure, UserError):
            self._raise_mapped_transport_error(cleanup_failure, None)
        raise cleanup_failure

    if connection_exception is not None:
        raise connection_exception

    if connection_error is not None:
        self._raise_mapped_transport_error(connection_error, connection_cause)

cleanup async

cleanup()

Cleanup the server.

ソースコード位置: src/agents/mcp/server.py
async def cleanup(self):
    """Cleanup the server."""
    async with self._cleanup_lock:
        # Only raise HTTP errors if we're cleaning up after a failed connection.
        # During normal teardown (via __aexit__), log but don't raise to avoid
        # masking the original exception.
        is_failed_connection_cleanup = self.session is None
        cleanup_error: UserError | None = None

        try:
            await self.exit_stack.aclose()
        except asyncio.CancelledError as e:
            log_tool_action_debug(
                logger,
                get_mcp_server_log_message("Cleanup cancelled for MCP server", self),
                e,
            )
            raise
        except (BaseExceptionGroup, httpx.HTTPStatusError, httpx.RequestError) as e:
            selected_http_error = self._select_cleanup_transport_error(e)
            if selected_http_error is not None:
                if is_failed_connection_cleanup:
                    cleanup_error = self._user_error_for_http_error(
                        selected_http_error,
                        include_http_reason_phrase=False,
                    )
                    del selected_http_error
                else:
                    _log_cleanup_transport_warning(
                        get_mcp_server_log_message(
                            _get_cleanup_transport_error_message(selected_http_error), self
                        )
                    )
            elif isinstance(e, httpx.RequestError):
                _log_cleanup_transport_warning(
                    get_mcp_server_log_message(_get_cleanup_transport_error_message(e), self)
                )
            elif isinstance(e, BaseExceptionGroup):
                http_errors = self._extract_http_errors_from_exception(e)
                if http_errors:
                    safe_error_group = _credential_safe_exception_group(e)
                    log_tool_action_error(
                        logger,
                        get_mcp_server_log_message("Error cleaning up MCP server", self),
                        safe_error_group,
                    )
                else:
                    # No HTTP error found, suppress RuntimeError about cancel scopes.
                    has_cancel_scope_error = any(
                        isinstance(exc, RuntimeError) and "cancel scope" in str(exc)
                        for exc in e.exceptions
                    )
                    if has_cancel_scope_error:
                        log_tool_action_debug(
                            logger,
                            get_mcp_server_log_message(
                                "Ignoring cancel scope error during cleanup of MCP server", self
                            ),
                            e,
                        )
                    else:
                        log_tool_action_error(
                            logger,
                            get_mcp_server_log_message("Error cleaning up MCP server", self),
                            e,
                        )
            else:
                log_tool_action_error(
                    logger,
                    get_mcp_server_log_message("Error cleaning up MCP server", self),
                    e,
                )
        except Exception as e:
            # Suppress RuntimeError about cancel scopes - this is a known issue with the MCP
            # library when background tasks fail during async generator cleanup
            if isinstance(e, RuntimeError) and "cancel scope" in str(e):
                log_tool_action_debug(
                    logger,
                    get_mcp_server_log_message(
                        "Ignoring cancel scope error during cleanup of MCP server", self
                    ),
                    e,
                )
            else:
                log_tool_action_error(
                    logger,
                    get_mcp_server_log_message("Error cleaning up MCP server", self),
                    e,
                )
        finally:
            self.session = None
            self._get_session_id = None

        if cleanup_error is not None:
            self._raise_mapped_transport_error(cleanup_error, None)

list_tools async

list_tools(
    run_context: RunContextWrapper[Any] | None = None,
    agent: AgentBase | None = None,
) -> list[Tool]

List the tools available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_tools(
    self,
    run_context: RunContextWrapper[Any] | None = None,
    agent: AgentBase | None = None,
) -> list[MCPTool]:
    """List the tools available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None

    transport_error: UserError | None = None
    transport_cause: Exception | None = None
    try:
        tools: list[MCPTool]
        # Return from cache if caching is enabled, we have tools, and the cache is not dirty
        if self.cache_tools_list and not self._cache_dirty and self._tools_list:
            tools = self._tools_list
        else:
            tools = []
            cursor: str | None = None
            seen_cursors: set[str | None] = set()

            async def fetch_pages() -> bool:
                nonlocal cursor
                while True:
                    result = await self._list_tools_page(session, cursor)
                    tools.extend(result.tools)
                    seen_cursors.add(cursor)
                    next_cursor = result.nextCursor
                    if next_cursor is None:
                        return True
                    if next_cursor in seen_cursors:
                        return False
                    cursor = next_cursor

            pagination_complete = False
            pagination_failure: BaseException | None = None
            try:
                pagination_complete = await self._run_with_retries(fetch_pages)
            except BaseException as error:
                if cursor is None:
                    raise
                if isinstance(error, BaseExceptionGroup):
                    pagination_failure = _credential_safe_exception_group(error)
                elif isinstance(error, Exception):
                    pagination_failure = self._user_error_for_request_operation(
                        "list tools", error
                    )
                else:
                    pagination_failure = _credential_safe_exception_leaf(error)

            if pagination_failure is not None or not pagination_complete:
                cursor = None
                seen_cursors.clear()
                tools.clear()
                del fetch_pages
                if pagination_failure is not None:
                    raise pagination_failure from None
                raise UserError(
                    f"MCP server '{self._error_name}' returned a repeated cursor while "
                    "listing tools."
                ) from None

            cursor = None
            seen_cursors.clear()
            del fetch_pages
            self._tools_list = tools
            self._cache_dirty = False

        # Filter tools based on tool_filter
        filtered_tools = tools
        if self.tool_filter is not None:
            filtered_tools = await self._apply_tool_filter(filtered_tools, run_context, agent)
        return filtered_tools
    except httpx.HTTPStatusError as e:
        status_code = e.response.status_code
        transport_error = UserError(
            f"Failed to list tools from MCP server '{self._error_name}': "
            f"HTTP error {status_code}"
        )
        transport_cause = _safe_transport_cause(e)
    except httpx.RequestError as e:
        transport_cause = _safe_transport_cause(e)
        if transport_cause is not None and not isinstance(e, httpx.ConnectError):
            raise
        if isinstance(e, httpx.ConnectError):
            transport_error = UserError(
                f"Failed to list tools from MCP server '{self._error_name}': Connection lost. "
                f"The server may have disconnected."
            )
        elif isinstance(e, httpx.TimeoutException):
            transport_error = UserError(
                f"Failed to list tools from MCP server '{self._error_name}': "
                "Connection timeout."
            )
        else:
            transport_error = UserError(
                f"Failed to list tools from MCP server '{self._error_name}': Request failed."
            )

    assert transport_error is not None
    self._raise_mapped_transport_error(transport_error, transport_cause)

list_prompts async

list_prompts() -> ListPromptsResult

List the prompts available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_prompts(
    self,
) -> ListPromptsResult:
    """List the prompts available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    result = await self._list_prompts_page(session)
    if result.nextCursor is None:
        return result

    prompts = list(result.prompts)
    cursor: str | None = result.nextCursor
    seen_cursors: set[str | None] = {None}
    pagination_failure: BaseException | None = None
    repeated_cursor = False
    page: ListPromptsResult | None = None
    next_cursor: str | None = None
    while cursor is not None:
        try:
            page = await self._list_prompts_page(session, cursor)
        except BaseException as error:
            if isinstance(error, BaseExceptionGroup):
                pagination_failure = _credential_safe_exception_group(error)
            elif isinstance(error, Exception):
                pagination_failure = self._user_error_for_request_operation(
                    "list prompts", error
                )
            else:
                pagination_failure = _credential_safe_exception_leaf(error)
            break
        prompts.extend(page.prompts)
        seen_cursors.add(cursor)
        next_cursor = page.nextCursor
        if next_cursor is not None and next_cursor in seen_cursors:
            repeated_cursor = True
            break
        cursor = next_cursor

    if pagination_failure is not None or repeated_cursor:
        cursor = None
        seen_cursors.clear()
        prompts.clear()
        page = None
        next_cursor = None
        del result
        if pagination_failure is not None:
            raise pagination_failure from None
        raise UserError(
            f"MCP server '{self._error_name}' returned a repeated cursor while listing prompts."
        ) from None

    return result.model_copy(update={"prompts": prompts, "nextCursor": None})

get_prompt async

get_prompt(
    name: str, arguments: dict[str, Any] | None = None
) -> GetPromptResult

Get a specific prompt from the server.

ソースコード位置: src/agents/mcp/server.py
async def get_prompt(
    self, name: str, arguments: dict[str, Any] | None = None
) -> GetPromptResult:
    """Get a specific prompt from the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    return await self._run_request_with_transport_error_redaction(
        "get prompt",
        lambda: self._maybe_serialize_request(lambda: session.get_prompt(name, arguments)),
    )

list_resources async

list_resources(
    cursor: str | None = None,
) -> ListResourcesResult

List the resources available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_resources(self, cursor: str | None = None) -> ListResourcesResult:
    """List the resources available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    return await self._run_request_with_transport_error_redaction(
        "list resources",
        lambda: self._maybe_serialize_request(lambda: session.list_resources(cursor)),
    )

list_resource_templates async

list_resource_templates(
    cursor: str | None = None,
) -> ListResourceTemplatesResult

List the resource templates available on the server.

ソースコード位置: src/agents/mcp/server.py
async def list_resource_templates(
    self, cursor: str | None = None
) -> ListResourceTemplatesResult:
    """List the resource templates available on the server."""
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    return await self._run_request_with_transport_error_redaction(
        "list resource templates",
        lambda: self._maybe_serialize_request(lambda: session.list_resource_templates(cursor)),
    )

read_resource async

read_resource(uri: str) -> ReadResourceResult

Read the contents of a specific resource by URI.

引数:

名前 タイプ デスクリプション デフォルト
uri str

The URI of the resource to read. See :class:~pydantic.networks.AnyUrl for the supported URI formats.

必須
ソースコード位置: src/agents/mcp/server.py
async def read_resource(self, uri: str) -> ReadResourceResult:
    """Read the contents of a specific resource by URI.

    Args:
        uri: The URI of the resource to read. See :class:`~pydantic.networks.AnyUrl`
            for the supported URI formats.
    """
    if not self.session:
        raise UserError("Server not initialized. Make sure you call `connect()` first.")
    session = self.session
    assert session is not None
    from pydantic import AnyUrl

    return await self._run_request_with_transport_error_redaction(
        "read resource",
        lambda: self._maybe_serialize_request(lambda: session.read_resource(AnyUrl(uri))),
    )

invalidate_tools_cache

invalidate_tools_cache()

Invalidate the tools cache.

ソースコード位置: src/agents/mcp/server.py
def invalidate_tools_cache(self):
    """Invalidate the tools cache."""
    self._cache_dirty = True