Hmbown/CodeWhale · error
.inputSchema must be a valid object-shaped MCP input schema
Error message
{context}.inputSchema must be a valid object-shaped MCP input schema What it means
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.
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.
Example fix
// before (server output)
{"name":"search","inputSchema":"object"}
// after
{"name":"search","inputSchema":{"type":"object","properties":{}}} Defensive patterns
Strategy: validation
Validate before calling
fn has_valid_input_schema(tool: &serde_json::Value) -> bool {
tool.get("inputSchema").map(valid_tool_input_schema).unwrap_or(false)
}
// pre-screen each tools/list entry before passing to the manager Type guard
fn well_formed_object_schema(v: &serde_json::Value) -> bool {
v.is_object() && v.get("type").and_then(|t| t.as_str()) == Some("object")
} Try / catch
match manager.list_tools_with_input_schemas(server) {
Err(e) if e.to_string().contains("inputSchema must be a valid") => {
tracing::error!("server {server} advertises tools with malformed inputSchema: {e}");
// disable tools for this server or switch to legacy mode if truly legacy
}
other => other,
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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).
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- bad_target
- .annotations is not a valid MCP annotations object
- .inputSchema is required for an advertised MCP tool
- .size must be an integer
- invalid JSON payload at key
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/0f5b702202f7d0b0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/mcp/src/stdio_client.rs:148
fn parse_tool_entry(
server_name: &str,
tool: &Value,
index: usize,
allow_legacy_schema_omission: bool,
) -> Result<(McpToolDescriptor, Value)> {
let context = format!("MCP server '{server_name}': tools/list tools[{index}]");
let fields = tool
.as_object()
.with_context(|| format!("{context} must be an object"))?;
let tool_name = fields
.get("name")
.and_then(Value::as_str)
.with_context(|| format!("{context}.name must be a string"))?
.to_string();
let description = optional_string_field(fields, "description", &context)?;
let input_schema = match fields.get("inputSchema") {
Some(schema) if valid_tool_input_schema(schema) => schema.clone(),
Some(_) => bail!("{context}.inputSchema must be a valid object-shaped MCP input schema"),
None if allow_legacy_schema_omission => {
// Servers that omit the entire initialize capabilities object are
// already identified as legacy by `validate_initialize_result`.
// Preserve omission compatibility only for that explicit mode;
// a standard advertised tools capability must send inputSchema.
json!({"type": "object", "properties": {}})
}
None => bail!("{context}.inputSchema is required for an advertised MCP tool"),
};
Ok((
McpToolDescriptor {
server_name: server_name.to_string(),
// The manager owns qualification; report the raw name and let it
// build `mcp__server__tool`.
qualified_name: tool_name.clone(),
tool_name,
description,
},View on GitHub (pinned to 73e0f67d83)