{"record":{"id":"0f5b702202f7d0b0","repo":"Hmbown/CodeWhale","slug":"context-inputschema-must-be-a-valid-object-shaped-mcp-input","errorCode":null,"errorMessage":"{context}.inputSchema must be a valid object-shaped MCP input schema","messagePattern":"(.+?)\\.inputSchema must be a valid object-shaped MCP input schema","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/mcp/src/stdio_client.rs","lineNumber":148,"sourceCode":"fn parse_tool_entry(\n    server_name: &str,\n    tool: &Value,\n    index: usize,\n    allow_legacy_schema_omission: bool,\n) -> Result<(McpToolDescriptor, Value)> {\n    let context = format!(\"MCP server '{server_name}': tools/list tools[{index}]\");\n    let fields = tool\n        .as_object()\n        .with_context(|| format!(\"{context} must be an object\"))?;\n    let tool_name = fields\n        .get(\"name\")\n        .and_then(Value::as_str)\n        .with_context(|| format!(\"{context}.name must be a string\"))?\n        .to_string();\n    let description = optional_string_field(fields, \"description\", &context)?;\n    let input_schema = match fields.get(\"inputSchema\") {\n        Some(schema) if valid_tool_input_schema(schema) => schema.clone(),\n        Some(_) => bail!(\"{context}.inputSchema must be a valid object-shaped MCP input schema\"),\n        None if allow_legacy_schema_omission => {\n            // Servers that omit the entire initialize capabilities object are\n            // already identified as legacy by `validate_initialize_result`.\n            // Preserve omission compatibility only for that explicit mode;\n            // a standard advertised tools capability must send inputSchema.\n            json!({\"type\": \"object\", \"properties\": {}})\n        }\n        None => bail!(\"{context}.inputSchema is required for an advertised MCP tool\"),\n    };\n    Ok((\n        McpToolDescriptor {\n            server_name: server_name.to_string(),\n            // The manager owns qualification; report the raw name and let it\n            // build `mcp__server__tool`.\n            qualified_name: tool_name.clone(),\n            tool_name,\n            description,\n        },","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/mcp/src/stdio_client.rs#L130-L166","documentation":"parse_tool_entry requires an advertised tool's inputSchema to be a valid object-shaped MCP input schema. If the field is present but fails valid_tool_input_schema (not an object, or wrong shape), parsing bails. A missing inputSchema is only tolerated in the explicit legacy mode where the server also omitted the whole initialize capabilities object; a server advertising tools must send schemas.","triggerScenarios":"list_tools_with_input_schemas parses a tool entry where \"inputSchema\" exists but is not a valid object schema — e.g. inputSchema is a string, array, null, or an object missing type/properties shape requirements.","commonSituations":"Server advertises the tools capability but sends partial/broken schemas; hand-written server emits JSON-Schema drafts the validator rejects; proxy/中间 layer truncates or re-serializes schemas incorrectly; legacy server partially upgraded (advertises tools but omits well-formed schemas).","solutions":["Fix the server to emit a well-formed object schema: {\"type\":\"object\",\"properties\":{...}} for every advertised tool.","Update the server library/version so inputSchema serializes correctly.","If the server is genuinely legacy (omits initialize capabilities), confirm the legacy mode path is actually enabled — a standard capabilities advertisement must include valid schemas.","Validate the server's raw tools/list JSON out-of-band (curl/pipe) to see the exact malformed inputSchema value."],"exampleFix":"// before (server output)\n{\"name\":\"search\",\"inputSchema\":\"object\"}\n// after\n{\"name\":\"search\",\"inputSchema\":{\"type\":\"object\",\"properties\":{}}}","handlingStrategy":"validation","validationCode":"fn has_valid_input_schema(tool: &serde_json::Value) -> bool {\n    tool.get(\"inputSchema\").map(valid_tool_input_schema).unwrap_or(false)\n}\n// pre-screen each tools/list entry before passing to the manager","typeGuard":"fn well_formed_object_schema(v: &serde_json::Value) -> bool {\n    v.is_object() && v.get(\"type\").and_then(|t| t.as_str()) == Some(\"object\")\n}","tryCatchPattern":"match manager.list_tools_with_input_schemas(server) {\n    Err(e) if e.to_string().contains(\"inputSchema must be a valid\") => {\n        tracing::error!(\"server {server} advertises tools with malformed inputSchema: {e}\");\n        // disable tools for this server or switch to legacy mode if truly legacy\n    }\n    other => other,\n}","preventionTips":["Run a conformance smoke test against new MCP server versions before deploying them.","Server-side: validate your tools/list JSON against the MCP schema in CI.","Keep initialize capabilities and per-tool schemas in sync — advertise tools only when schemas are available."],"tags":["mcp","json-schema","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}