Hmbown/CodeWhale · error

.annotations is not a valid MCP annotations object

Error message

{context}.annotations is not a valid MCP annotations object

What it means

parse_resource_entry validates the optional 'annotations' field of an MCP resource entry against valid_annotations (audience, priority range, lastModifiedDateTime shape). If the object does not conform to the MCP annotations schema, the entry is rejected with this error instead of passing invalid metadata into the catalog.

Solutions

  1. Fix the server to emit annotations conforming to the MCP spec (audience array of Role, priority in 0.0..1.0)
  2. Drop the 'annotations' field if it cannot be made valid — it is optional
  3. Compare the emitted object against the validator (valid_annotations) to pinpoint the non-conforming key

Example fix

// before
"annotations":{"priority":5}
// after
"annotations":{"audience":["user"],"priority":0.5}
Defensive patterns

Strategy: validation

Validate before calling

fn has_valid_annotations(v: &Value) -> bool {
    v.get("annotations").map_or(true, |a| {
        a.is_object()
            && a.get("priority").map_or(true, |p| p.as_f64().map_or(false, |f| (0.0..=1.0).contains(&f)))
            && a.get("audience").map_or(true, |x| x.is_array())
    })
}

Type guard

fn annotations_are_valid(a: &serde_json::Value) -> bool {
    a.is_object()
        && a.get("audience").map_or(true, |x| x.as_array().map_or(false, |arr| arr.iter().all(|r| r == "user" || r == "assistant")))
        && a.get("priority").map_or(true, |p| p.as_f64().map_or(false, |f| (0.0..=1.0).contains(&f)))
}

Try / catch

match client.list_resources_with_metadata().await {
    Ok(entries) => use(entries),
    Err(e) if e.to_string().contains("annotations is not a valid MCP annotations object") => {
        log::warn("malformed annotations; treating entry as unannotated");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: list_resources_with_metadata parses a resources/list entry whose 'annotations' is present but fails valid_annotations — wrong types, missing/invalid audience, priority outside 0.0..=1.0, or not an object at all.

Common situations: MCP server bug emitting malformed annotations; manually crafted server responses; newer annotations fields not covered by the validator after a server upgrade.

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


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

Appendix: source

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

        .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 mime_type = optional_string_field(fields, "mimeType", &context)?;

    let mut metadata = json!({"name": name});
    if let Some(mime_type) = mime_type {
        metadata["mimeType"] = Value::String(mime_type);
    }
    if let Some(size) = fields.get("size") {
        if size.as_i64().is_none() && size.as_u64().is_none() {
            bail!("{context}.size must be an integer");
        }
        metadata["size"] = size.clone();
    }
    if let Some(annotations) = fields.get("annotations") {
        if !valid_annotations(annotations) {
            bail!("{context}.annotations is not a valid MCP annotations object");
        }
        metadata["annotations"] = annotations.clone();
    }

    Ok((
        McpResourceDescriptor {
            server_name: server_name.to_string(),
            uri,
            description,
        },
        metadata,
    ))
}

/// Read one newline-delimited child message without ever retaining more than
/// `max_bytes`. On an oversized line the reader is intentionally abandoned;
/// continuing after losing JSON-RPC framing would be unsafe.
pub(crate) fn read_bounded_line<R: BufRead>(

View on GitHub (pinned to 73e0f67d83)