Skip to main content

zagens_runtime_adapters/mcp/
format.rs

1use serde_json;
2
3/// Whether an MCP `tools/call` result signals a **tool-level** failure via
4/// the spec's `isError` flag. This is distinct from a JSON-RPC protocol
5/// error (handled in `connection.rs`): a tool can return a successful RPC
6/// response whose payload still represents a failed tool invocation.
7pub fn is_tool_error(result: &serde_json::Value) -> bool {
8    result
9        .get("isError")
10        .and_then(serde_json::Value::as_bool)
11        .unwrap_or(false)
12}
13
14/// Extract the model-facing content from an MCP `tools/call` result.
15///
16/// Concatenates the text of every `text` content block; non-text blocks
17/// (image, resource, …) are rendered as `[<type> content]` placeholders so
18/// the model knows something was returned without flooding the context with
19/// base64. Falls back to pretty-printed JSON when there's no `content` array.
20pub fn extract_tool_content(result: &serde_json::Value) -> String {
21    result
22        .get("content")
23        .and_then(|v| v.as_array())
24        .map_or_else(
25            || serde_json::to_string_pretty(result).unwrap_or_default(),
26            |arr| {
27                arr.iter()
28                    .filter_map(|item| match item.get("type")?.as_str()? {
29                        "text" => item.get("text")?.as_str().map(String::from),
30                        other => Some(format!("[{other} content]")),
31                    })
32                    .collect::<Vec<_>>()
33                    .join("\n")
34            },
35        )
36}
37
38/// Human-readable rendering of a tool result, prefixing `Error:` on failure.
39/// Prefer [`is_tool_error`] + [`extract_tool_content`] on execution paths that
40/// need to map failures onto a structured error type.
41pub fn format_tool_result(result: &serde_json::Value) -> String {
42    let content = extract_tool_content(result);
43    if is_tool_error(result) {
44        format!("Error: {content}")
45    } else {
46        content
47    }
48}