shareAI-lab/learn-claude-code · error · ValueError
Every MCP tool needs a non-empty name
Error message
Every MCP tool needs a non-empty name
What it means
MCPClient.register() requires every tool definition in tool_defs to carry a 'name' that is a non-empty string. A missing 'name' key (tool.get returns None), an empty string, or a non-string value (number, dict) fails fast at registration instead of producing a broken tools/list catalog.
Source
Thrown at s14_mcp_plugin/code.py:171
"edit_file": run_edit,
"glob": run_glob,
}
# -- New in s14: MCP discovery and dispatch --
class MCPClient:
"""Small in-process stand-in for MCP tools/list and tools/call."""
def __init__(self, name: str):
self.name = name
self.tools: list[dict] = []
self._handlers: dict[str, callable] = {}
def register(self, tool_defs: list[dict], handlers: dict[str, callable]):
names = [tool.get("name") for tool in tool_defs]
if any(not isinstance(name, str) or not name for name in names):
raise ValueError("Every MCP tool needs a non-empty name")
if len(set(names)) != len(names):
raise ValueError(f"Duplicate MCP tool name on server {self.name!r}")
missing = [name for name in names if name not in handlers]
if missing:
raise ValueError(f"Missing MCP handlers: {', '.join(missing)}")
self.tools = list(tool_defs)
self._handlers = dict(handlers)
def call_tool(self, tool_name: str, args: dict) -> str:
handler = self._handlers.get(tool_name)
if not handler:
return f"MCP error: unknown tool '{tool_name}'"
try:
return str(handler(**args))
except Exception as exc:
return f"MCP error: {type(exc).__name__}: {exc}"
View on GitHub (pinned to 985456f4ad)
Solutions
- Give every tool def a non-empty string 'name' key.
- Validate defs against a schema (e.g. jsonschema) before register() when loading from config.
- Log the offending tool_defs payload when registration fails to spot the malformed entry.
Example fix
// before
server.register([{'nam': 'search', ...}], handlers)
// after
server.register([{'name': 'search', 'description': '...', 'inputSchema': {...}}], handlers) Defensive patterns
Strategy: validation
Validate before calling
def tool_defs_wellformed(tool_defs: list[dict]) -> bool:
return all(
isinstance(t.get('name'), str) and t['name']
for t in tool_defs
)
assert tool_defs_wellformed(defs) before server.register(defs, handlers) Type guard
from typing import TypeGuard
def is_named_tool_def(value: dict) -> TypeGuard[dict]:
return isinstance(value.get('name'), str) and len(value['name']) > 0 Prevention
- Author tool defs next to their handlers in one registry so names are never omitted.
- Schema-validate defs loaded from JSON/YAML before register().
When it happens
Trigger: register([{'description': 'x'}], handlers={...}) (no name); register([{'name': ''}], ...); register([{'name': 42}], ...); tool defs loaded from JSON/YAML where the name key was misspelled ('Name', 'tool').
Common situations: Hand-written tool definition dicts; config files with typo'd keys; dynamic tool defs generated from a loop where a field is None.
Related errors
- Duplicate MCP tool name on server {self.name!r}
- Missing MCP handlers: {', '.join(missing)}
- MCP tool name is longer than 64 characters: {prefixed}
- Invalid input schema for {origin}
- Every MCP tool needs a non-empty name
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/ff7bc6727327a658.
Report an issue: GitHub.