Format a raw MCP tool result for the LLM conversation. Borrowed pattern from agent/tools/formatting.py but: - Handles list results with proper JSON (not repr) - No YAML-workflow-specific prompt injections
(tool_name: str, raw: Any)
| 68 | |
| 69 | |
| 70 | def _format_mcp_result(tool_name: str, raw: Any) -> str: |
| 71 | """Format a raw MCP tool result for the LLM conversation. |
| 72 | |
| 73 | Borrowed pattern from agent/tools/formatting.py but: |
| 74 | - Handles list results with proper JSON (not repr) |
| 75 | - No YAML-workflow-specific prompt injections |
| 76 | """ |
| 77 | # Unwrap nested {"result": {...}} structures produced by some MCP tools |
| 78 | if isinstance(raw, dict) and "result" in raw and isinstance(raw["result"], dict): |
| 79 | raw = raw["result"] |
| 80 | |
| 81 | # Special formatting for shell_run: extract structured fields |
| 82 | if tool_name == "shell_run": |
| 83 | if not isinstance(raw, dict): |
| 84 | return f"Return code: None\nOutput: {raw}" |
| 85 | parts = [ |
| 86 | f"Return code: {raw.get('returncode')}", |
| 87 | f"Output: {raw.get('output')}", |
| 88 | ] |
| 89 | if raw.get("error"): |
| 90 | parts.append(f"Error: {raw['error']}") |
| 91 | if raw.get("warning"): |
| 92 | parts.append(f"Warning: {raw['warning']}") |
| 93 | return "\n".join(parts) |
| 94 | |
| 95 | # Dicts and lists: pretty-printed JSON |
| 96 | if isinstance(raw, (dict, list)): |
| 97 | try: |
| 98 | return json.dumps(raw, indent=2, default=str) |
| 99 | except Exception: |
| 100 | return str(raw) |
| 101 | |
| 102 | if raw is None: |
| 103 | return "Result: None" |
| 104 | return str(raw) |
| 105 | |
| 106 | |
| 107 | def _truncate_tool_result(result_str: str, max_chars: int) -> str: |