agentscope-ai/agentscope · error · ValueError

STDIO MCP must be stateful (is_stateful=True).

Error message

STDIO MCP must be stateful (is_stateful=True).

What it means

STDIO-based MCP servers run as a local subprocess whose process state persists across tool calls, so they cannot operate statelessly. MCPClient's post-init validation enforces that a stdio_mcp configuration requires is_stateful=True.

Source

Thrown at src/agentscope/mcp/_mcp_client.py:131

        Returns:
            True if connected, False otherwise.
        """
        return self._is_connected

    def model_post_init(self, __context: Any) -> None:
        """Validate configuration and initialize client."""
        # MCP name is used to compose model-facing tool names
        # (mcp__{name}__{tool}), which must match ^[a-zA-Z0-9_-]+$.
        if not re.fullmatch(r"[a-zA-Z0-9_-]+", self.name):
            raise ValueError(
                f"MCPClient name '{self.name}' contains characters not "
                f"allowed by LLM providers (only [a-zA-Z0-9_-] are "
                f"permitted). Please rename it.",
            )

        # STDIO MCP must be stateful
        if self.mcp_config.type == "stdio_mcp" and not self.is_stateful:
            raise ValueError(
                "STDIO MCP must be stateful (is_stateful=True).",
            )

        # Check arguments for self.enable_tools and disable_tools
        if self.enable_tools is not None:
            if not isinstance(self.enable_tools, list) or any(
                not isinstance(_, str) for _ in self.enable_tools
            ):
                raise ValueError(
                    "Enable tools should be a list of strings, but got "
                    f"{self.enable_tools}.",
                )

        if self.disable_tools is not None:
            if not isinstance(self.disable_tools, list) or any(
                not isinstance(_, str) for _ in self.disable_tools
            ):
                raise ValueError(

View on GitHub (pinned to e90f1c7592)

Solutions

  1. Set is_stateful=True (or omit it if the default is True for stdio) for stdio_mcp configs
  2. If you intended stateless operation, use an HTTP/SSE/streamable transport type instead of stdio_mcp

Example fix

// before
client = MCPClient(
    name="fs",
    mcp_config=MCPConfig(type="stdio_mcp", command="npx", args=["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]),
    is_stateful=False,
)

// after
client = MCPClient(
    name="fs",
    mcp_config=MCPConfig(type="stdio_mcp", command="npx", args=["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]),
    is_stateful=True,
)
Defensive patterns

Strategy: validation

Validate before calling

if cfg.type == "stdio_mcp":
    is_stateful = True  # forced
client = MCPClient(name=n, mcp_config=cfg, is_stateful=is_stateful)

Try / catch

try:
    MCPClient(name=n, mcp_config=cfg, is_stateful=False)
except ValueError as e:
    if "must be stateful" in str(e):
        client = MCPClient(name=n, mcp_config=cfg, is_stateful=True)

Prevention

When it happens

Trigger: MCPClient(mcp_config=MCPConfig(type="stdio_mcp", ...), is_stateful=False) — explicitly setting is_stateful=False or using a stateless preset/template with a stdio transport.

Common situations: Copying a stateless HTTP/SSE MCPClient configuration and swapping in a stdio command without flipping is_stateful; library examples defaulting to stateless for simplicity.

Understand the failure class

Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.

Related errors


AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28). Data as JSON: /api/errors/073463f6b3af133d. Report an issue: GitHub.