Hmbown/CodeWhale · error

.inputSchema is required for an advertised MCP tool

Error message

{context}.inputSchema is required for an advertised MCP tool

What it means

parse_tool_entry fails closed when an advertised tool has no inputSchema at all and the legacy schema-omission mode is not enabled. Servers that declare the standard tools capability must include inputSchema for every tool; the manager refuses to invent one, unlike the explicit legacy compatibility path.

Solutions

  1. Add a valid inputSchema ({"type":"object","properties":{}} minimally) for each tool in the server's tools/list response.
  2. Update the MCP server to a spec-conformant version that always sends inputSchema with advertised tools.
  3. If the server legitimately cannot send schemas (legacy), run it in/enable the explicit legacy omission mode recognized by validate_initialize_result rather than weakening the standard path.

Example fix

// before (server output)
{"name":"search","description":"Search"}
// after
{"name":"search","description":"Search","inputSchema":{"type":"object","properties":{"query":{"type":"string"}}}}
Defensive patterns

Strategy: validation

Validate before calling

fn all_tools_have_input_schema(tools: &[serde_json::Value]) -> bool {
    tools.iter().all(|t| t.get("inputSchema").is_some())
}
// assert on the raw tools/list payload before wiring the server into the manager

Try / catch

match manager.list_tools_with_input_schemas(server) {
    Err(e) if e.to_string().contains("inputSchema is required") => {
        tracing::error!("server {server} omits inputSchema: {e}");
        // reconnect in legacy mode if the server cannot emit schemas, or fix the server
    }
    other => other,
}

Prevention

When it happens

Trigger: list_tools_with_input_schemas parses a tools/list entry lacking the "inputSchema" key while allow_legacy_schema_omission is false (i.e., the server sent a standard initialize capabilities object advertising tools).

Common situations: Server claims tools capability in initialize but omits schemas per tool (common with minimal hand-rolled servers); older server versions predating required inputSchema; frameworks that auto-advertise tools without collecting parameter schemas.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/a83c9ad84a338d49. Report an issue: GitHub.

Appendix: source

Thrown at crates/mcp/src/stdio_client.rs:156

        .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,
        },
        input_schema,
    ))
}

fn parse_resource_entry(
    server_name: &str,
    resource: &Value,
    index: usize,

View on GitHub (pinned to 73e0f67d83)