{"record":{"id":"48e283ce844d7d45","repo":"shareAI-lab/learn-claude-code","slug":"invalid-input-schema-for-origin-48e283","errorCode":null,"errorMessage":"Invalid input schema for {origin}","messagePattern":"Invalid input schema for (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"s15_integrated_harness/code.py","lineNumber":2563,"sourceCode":"    for server_name, mcp_client in mcp_clients.items():\n        safe_server = normalize_mcp_name(server_name)\n        for tool_def in mcp_client.tools:\n            raw_name = tool_def[\"name\"]\n            safe_tool = normalize_mcp_name(raw_name)\n            prefixed = f\"mcp__{safe_server}__{safe_tool}\"\n            if len(prefixed) > 64:\n                raise ValueError(\n                    f\"MCP tool name is longer than 64 characters: {prefixed}\"\n                )\n            origin = f\"MCP tool {server_name!r}/{raw_name!r}\"\n            if prefixed in origins:\n                raise ValueError(\n                    \"MCP tool name collision after normalization: \"\n                    f\"{prefixed!r} maps both {origins[prefixed]} and {origin}\"\n                )\n            schema = tool_def.get(\"inputSchema\", {})\n            if not isinstance(schema, dict) or schema.get(\"type\", \"object\") != \"object\":\n                raise ValueError(f\"Invalid input schema for {origin}\")\n            origins[prefixed] = origin\n            tools.append({\n                \"name\": prefixed,\n                \"description\": tool_def.get(\"description\", \"\"),\n                \"input_schema\": schema,\n            })\n            handlers[prefixed] = (\n                lambda *, client=mcp_client, tool=raw_name, **kwargs:\n                client.call_tool(tool, kwargs)\n            )\n            policies[prefixed] = MCP_HOST_POLICY.get(\n                (server_name, raw_name), \"confirm\"\n            )\n    mcp_tool_policies = policies\n    return tools, handlers\n\n\n# -- Lead Worktree Tools --","sourceCodeStart":2545,"sourceCodeEnd":2581,"githubUrl":"https://github.com/shareAI-lab/learn-claude-code/blob/985456f4adea6f4df8fbad4112245dbd97444eae/s15_integrated_harness/code.py#L2545-L2581","documentation":"Each MCP tool definition must carry an inputSchema that is a dict whose 'type' is 'object' (absent 'type' defaults to 'object'). A schema that is not a dict, or typed as 'array'/'string'/etc., is rejected with ValueError because the host republishes it as the tool's input_schema for the model and only object schemas are valid for tool arguments.","triggerScenarios":"Registering a tool_def with \"inputSchema\": {\"type\": \"array\", ...}, with \"inputSchema\": [] or a string, or omitting a malformed schema key ('inputSchema': None). Tools registered without register() and appended directly to client.tools bypass the earlier name checks but still hit this one at wiring time.","commonSituations":"Hand-writing tool definitions instead of using a schema helper. Copying an output schema into the inputSchema field. MCP servers from other ecosystems that describe args as a JSON array of parameters instead of a JSON-schema object.","solutions":["Make inputSchema an object schema: {\"type\": \"object\", \"properties\": {...}, \"required\": [...]}","If a tool takes no arguments, use {\"type\": \"object\", \"properties\": {}} or omit inputSchema entirely (it defaults)","Add a fixture/test that registers every production tool_def so schema errors surface in CI"],"exampleFix":"# before\n{\"name\": \"deploy\", \"inputSchema\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}}\n\n# after\n{\"name\": \"deploy\", \"inputSchema\": {\"type\": \"object\", \"properties\": {\"target\": {\"type\": \"string\"}}, \"required\": [\"target\"]}}","handlingStrategy":"validation","validationCode":"def is_object_schema(schema) -> bool:\n    return isinstance(schema, dict) and schema.get(\"type\", \"object\") == \"object\"\n\nfor tool in client.tools:\n    assert is_object_schema(tool.get(\"inputSchema\", {})), f\"bad schema on {tool.get('name')}\"","typeGuard":"def has_valid_input_schema(tool_def: dict) -> bool:\n    schema = tool_def.get(\"inputSchema\", {})\n    return isinstance(schema, dict) and schema.get(\"type\", \"object\") == \"object\"","tryCatchPattern":"try:\n    harness = build_harness(mcp_clients)\nexcept ValueError as exc:\n    if \"Invalid input schema\" in str(exc):\n        # origin in message identifies server/tool; fix its inputSchema to an object schema\n        raise SystemExit(str(exc)) from exc\n    raise","preventionTips":["Default every inputSchema to {\"type\": \"object\", \"properties\": {}}","Generate schemas with a helper that always emits object schemas","Never copy an array-style parameter list into inputSchema"],"tags":["mcp","validation","json-schema","tool-registration"],"backgroundTag":null,"analyzedSha":"985456f4adea6f4df8fbad4112245dbd97444eae","analyzedAt":"2026-08-14T22:02:26.028Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}