shareAI-lab/learn-claude-code · error · ValueError
Invalid input schema for {origin}
Error message
Invalid input schema for {origin} What it means
Raised while registering tools from an MCP server: each tool's advertised inputSchema must be a JSON object schema (a dict whose 'type' is 'object', explicitly or by default). The harness enforces this because it forwards the schema verbatim to the model as the tool's input contract, and a non-object or non-dict schema would produce an invalid tool definition. The offending server/tool is named in {origin} as 'MCP tool <server>/<rawname>'.
Source
Thrown at s14_mcp_plugin/code.py:340
}
for server_name, server in mcp_clients.items():
safe_server = normalize_mcp_name(server_name)
for tool_def in server.tools:
raw_name = tool_def["name"]
safe_tool = normalize_mcp_name(raw_name)
prefixed = f"mcp__{safe_server}__{safe_tool}"
if len(prefixed) > 64:
raise ValueError(f"MCP tool name is longer than 64 characters: {prefixed}")
origin = f"MCP tool {server_name!r}/{raw_name!r}"
if prefixed in origins:
raise ValueError(
"MCP tool name collision after normalization: "
f"{prefixed!r} maps both {origins[prefixed]} and {origin}"
)
schema = tool_def.get("inputSchema", {})
if not isinstance(schema, dict) or schema.get("type", "object") != "object":
raise ValueError(f"Invalid input schema for {origin}")
origins[prefixed] = origin
tools.append({
"name": prefixed,
"description": tool_def.get("description", ""),
"input_schema": schema,
})
handlers[prefixed] = (
lambda *, client=server, tool=raw_name, **kwargs:
client.call_tool(tool, kwargs)
)
policies[prefixed] = MCP_HOST_POLICY.get(
(server_name, raw_name), "confirm"
)
mcp_tool_policies = policies
return tools, handlers
View on GitHub (pinned to 985456f4ad)
Solutions
- Fix the offending MCP server so each tool definition includes inputSchema as a dict with "type": "object" (or omit 'type' so the default 'object' applies).
- If you cannot change the server, wrap its tool_defs and inject {"type": "object"} as a default inputSchema before registration.
- Inspect the server's tools/list response (e.g. via MCPClient.call_tool or a raw client) to identify exactly which tool advertises the bad schema named in {origin}.
Example fix
// before
tool_defs = [{"name": "echo", "description": "echo text"}]
server.register(tool_defs, handlers) // raises: Invalid input schema for MCP tool ...
// after
tool_defs = [{
"name": "echo",
"description": "echo text",
"inputSchema": {"type": "object", "properties": {"text": {"type": "string"}}},
}]
server.register(tool_defs, handlers) Defensive patterns
Strategy: validation
Validate before calling
def valid_tool_defs(tool_defs):
for t in tool_defs:
s = t.get("inputSchema")
if not isinstance(s, dict) or s.get("type", "object") != "object":
return False
return True
if not valid_tool_defs(tool_defs):
tool_defs = [{**t, "inputSchema": t.get("inputSchema") if isinstance(t.get("inputSchema"), dict) and t["inputSchema"].get("type", "object") == "object" else {"type": "object"}} for t in tool_defs] Type guard
def is_object_schema(schema) -> bool:
return isinstance(schema, dict) and schema.get("type", "object") == "object" Try / catch
try:
register_mcp_tools(server, tool_defs)
except ValueError as e:
if "Invalid input schema" in str(e):
log.warning("skipping %s: bad inputSchema", e)
else:
raise Prevention
- Always emit inputSchema: {"type": "object", ...} from custom MCP servers.
- Validate server tool lists with a small schema check before registration in tests.
- Prefer forwarding real tools/list payloads rather than hand-writing tool dicts.
When it happens
Trigger: Calling the MCP plugin's registration loop (build of mcp__<server>__<tool> handlers) where a tool_def's 'inputSchema' key is missing, is a list/string/None, or has "type": "array" / "string" / non-'object'. Typical of hand-rolled MCP servers or test doubles that omit inputSchema or emit JSON-Schema draft-style arrays.
Common situations: A custom in-process MCP server registered with tool dicts lacking 'inputSchema'; a server copied from docs that uses 'parameters' instead of 'inputSchema'; a proxy that stringifies the schema; upstream server version change renaming the field.
Related errors
- Every MCP tool needs a non-empty name
- Duplicate MCP tool name on server {self.name!r}
- Missing MCP handlers: {', '.join(missing)}
- MCP tool name is longer than 64 characters: {prefixed}
- 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/bb81f45a26fbafc5.
Report an issue: GitHub.