Invoke tools on MCP mcp_servers (single or batch).
CHOOSE THIS when: you want to execute tool(s) on mcp_server(s). This is the main entry point. CHOOSE hangar_tools when: you need to discover available tools before calling. CHOOSE hangar_start when: you only want to pre-warm without invoking.
Side effects: May start cold mcp_servers. Executes calls in parallel.
Concurrency model: Two levels of concurrency control apply simultaneously:
- Per-batch: max_concurrency limits threads for THIS invocation.
- System-wide: global and per-mcp_server semaphores (configured via config.yaml `
execution.max_concurrency and per-mcp_server max_concurrency`) provide cross-batch backpressure.
All calls are submitted to the thread pool at once. Semaphores gate execution -- a call starts as soon as a slot frees up, without waiting for the entire batch wave to complete.
Args: calls: list[{mcp_server, tool, arguments, timeout?}] - Invocations to execute max_concurrency: int - Parallel workers for this batch (default: 10, range: 1-50) timeout: float - Batch timeout in seconds (default: 60, range: 1-300) fail_fast: bool - Stop batch on first error (default: false) max_attempts: int - Total attempts per call including retries (default: 1, range: 1-10)
Returns: Success: { batch_id: str, success: true, total: int, succeeded: int, failed: int, elapsed_ms: float, results: [{ index: int, call_id: str, success: true, result: any, error: null, error_type: null, elapsed_ms: float }] } Partial failure: { batch_id: str, success: false, total: int, succeeded: int, failed: int, elapsed_ms: float, results: [{ index: int, call_id: str, success: bool, result: any | null, error: str | null, error_type: str | null, elapsed_ms: float, retry_metadata?: {attempts: int, retries: list} }] } Validation error: { batch_id: str, success: false, error: "Validation failed", validation_errors: [{index: int, field: str, message: str}] } Truncated result: Individual result contains additional fields: {truncated: true, truncated_reason: str, original_size_bytes: int, continuation_id: str} Retrieve full data with hangar_fetch_continuation(continuation_id).
Example: # Single call - success hangar_call(calls=[{"mcp_server": "math", "tool": "add", "arguments": {"a": 1, "b": 2}}]) # {"batch_id": "abc-123", "success": true, "total": 1, "succeeded": 1, "failed": 0, # "elapsed_ms": 45.2, "results": [{"index": 0, "call_id": "def-456", # "success": true, "result": 3, "error": null, "elapsed_ms": 42.1}]}
# Validation error - unknown mcp_server hangar_call(calls=[{"mcp_server": "unknown", "tool": "x", "arguments": {}}]) # {"batch_id": "abc-123", "success": false, "error": "Validation failed", # "validation_errors": [{"index": 0, "field": "mcp_server", "message": "..."}]}
# Partial failure - some succeed, some fail hangar_call(calls=[ {"mcp_server": "math", "tool": "add", "arguments": {"a": 1, "b": 2}}, {"mcp_server": "math", "tool": "divide", "arguments": {"a": 1, "b": 0}} ]) # {"batch_id": "...", "success": false, "total": 2, "succeeded": 1, "failed": 1, # "results": [ # {"index": 0, "success": true, "result": 3, ...}, # {"index": 1, "success": false, "error": "division by zero", "error_type": "ValueError"} # ]}
# With retry - shows retry_metadata on failure hangar_call(calls=[...], max_attempts=3) # On failure: {"results": [{"retry_metadata": {"attempts": 3, "retries": [...]}, ...}]}