agentscope-ai/agentscope · error · ValueError
Enable tools should be a list of strings, but got {self.enab
Error message
Enable tools should be a list of strings, but got {self.enable_tools}. What it means
MCPClient validates that enable_tools, when provided, is a list of strings (tool names). Passing a single string, a set, a tuple, None-like values, or a list containing non-strings raises this ValueError at construction time.
Source
Thrown at src/agentscope/mcp/_mcp_client.py:140
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(
"Disable tools should be a list of strings, but got "
f"{self.disable_tools}.",
)
if self.enable_tools is not None and self.disable_tools is not None:
intersection = set(self.enable_tools).intersection(
set(self.disable_tools),
)
if len(intersection) != 0:View on GitHub (pinned to e90f1c7592)
Solutions
- Wrap the value in a list: enable_tools=["search"]
- Ensure every element is a str; convert non-strings explicitly before passing
- Validate config-derived values before constructing MCPClient
Example fix
// before client = MCPClient(name="db", mcp_config=cfg, enable_tools="query") // after client = MCPClient(name="db", mcp_config=cfg, enable_tools=["query"])
Defensive patterns
Strategy: validation
Validate before calling
enable_tools = None if enable_tools is None else [str(t) for t in enable_tools] assert isinstance(enable_tools, list) client = MCPClient(name=n, mcp_config=cfg, enable_tools=enable_tools)
Type guard
def is_tool_name_list(v) -> bool:
return v is None or (isinstance(v, list) and all(isinstance(x, str) for x in v)) Try / catch
try:
MCPClient(name=n, mcp_config=cfg, enable_tools=enable_tools)
except ValueError:
enable_tools = list(map(str, enable_tools or [])) or None
client = MCPClient(name=n, mcp_config=cfg, enable_tools=enable_tools) Prevention
- Always pass tool filters as list[str]
- Normalize external config values before constructing MCPClient
- Add type hints (list[str] | None) at call sites to catch mistakes statically
When it happens
Trigger: MCPClient(..., enable_tools="search") (bare string instead of list), enable_tools={"search"} (set), or enable_tools=["search", 3] (mixed types).
Common situations: Passing a single tool name as a convenience string; deserializing tool filters from JSON/YAML where a scalar or non-list sneaks in; refactoring from a tuple to a list API.
Related errors
- Disable tools should be a list of strings, but got {self.dis
- The tools in enable_tools and disable_tools should not overl
- STDIO MCP does not support ephemeral mode. Use 'shared' or '
- Invalid values for MCP {card.name!r}: {e.message}
- MCP {card.name!r} needs a value for: {', '.join(sorted(missi
AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28).
Data as JSON: /api/errors/0cff0836c1c303d2.
Report an issue: GitHub.