# How handle_operation_result Handles Events in mcp_main.py: MCP OpenStack Ops Processing Guide

> Learn how handle_operation_result in mcp_main.py processes events: empty responses, failures, sync, and async ops. Get structured, readable results from OpenStack SDK.

- Repository: [JungJungIn/mcp-openstack-ops](https://github.com/call518/mcp-openstack-ops)
- Tags: how-to-guide
- Published: 2026-02-26

---

**The `handle_operation_result` function in [`src/mcp_openstack_ops/mcp_main.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/mcp_main.py) processes four distinct event types—empty responses, explicit failures, successful synchronous operations, and asynchronous operations—converting raw OpenStack SDK results into structured, human-readable responses with intelligent async detection and verification prompts.**

The `handle_operation_result` function serves as the central response formatter for the MCP-OpenStack-Ops project, ensuring every tool in the repository returns consistent, informative output regardless of the underlying OpenStack SDK behavior. Located in [`src/mcp_openstack_ops/mcp_main.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/mcp_main.py), this function acts as the final processing layer between low-level cloud operations and user-facing communication, implementing a robust event classification system that distinguishes between immediate failures, successful completions, and long-running asynchronous tasks.

## The Four Event Types Processed by handle_operation_result

The function implements a sequential branching logic that evaluates incoming results against four specific conditions, each triggered by distinct data patterns returned from OpenStack SDK calls.

### 1. Empty or Null Responses

When the OpenStack SDK returns a falsy value—including `None`, empty dictionaries `{}`, or any other false-equivalent result—the function detects this condition at lines 24–33 using a simple truthiness check.

```python
if not result:
    # Returns rich-text error with timeout/recommendation messaging

```

This event typically indicates network timeouts, connection failures, or unresponsive endpoints. The function generates a rich-text error message stating that the request timed out or received no response, optionally rendering additional context as bullet-style details while recommending verification steps.

### 2. Explicit Operation Failures

For results that explicitly report failure through structured data, the function checks for dictionary instances containing a `success` key set to `False` (lines 35–45).

```python
if isinstance(result, dict) and result.get('success') is False:
    message = result.get('message', 'Operation failed')
    # Builds markdown error block with details

```

This processing branch extracts the error message from `result['message']` or falls back to a generic failure notification. It constructs a formatted markdown error block, appending any supplementary details provided in the operation metadata to create comprehensive debugging information.

### 3. Successful Synchronous Operations

Successful operations are identified by `result.get('success') is True` (lines 47–113), where the function first determines whether the operation completed synchronously or requires asynchronous monitoring. For synchronous operations, the function sets `operation_type = "synchronous"` and returns the success message without additional verification prompts.

The function extracts the `Action` (e.g., `create`, `delete`) and resource name from the `details` parameter, consulting an internal `async_operations` configuration table (lines 55–92) to determine the operation's nature. If the action does not appear in the asynchronous registry, the result is immediately formatted as a completed synchronous operation.

### 4. Asynchronous Operation Detection and Augmentation

When a successful result corresponds to an action listed in the `async_operations` mapping, the function triggers specialized asynchronous processing logic. This event type represents long-running OpenStack operations such as instance creation or volume provisioning that complete in the background.

The function augments the original `result['message']` with contextual timing information and verification commands. For example, when processing a `create` action under *Instance Management*, the output receives an appended note specifying expected completion time (30–60 seconds) and a CLI verification command. The function additionally tags the response with `operation_type = "asynchronous"` and `verification_needed = True` to signal downstream components that polling is required.

## How the Async Operations Configuration Works

The `async_operations` dictionary defined at lines 55–92 in [`mcp_main.py`](https://github.com/call518/mcp-openstack-ops/blob/main/mcp_main.py) categorizes operations by resource type (*Instance Management*, *Volume Management*, *Network Management*, etc.), mapping specific actions to their temporal characteristics.

```python
async_operations = {
    "Instance Management": {
        "async_actions": ["create", "delete", "start", "stop"],
        "expected_time": "30-60 seconds",
        "verification_command": "Show instance status for {resource}"
    },
    # ... additional categories

}

```

When processing a result with `details={'Action': 'create', 'Instance': 'web01'}`, the function normalizes the action to lowercase, checks membership in `async_actions` for the specified operation category, and conditionally appends structured guidance:

```python
note = (f"This is an asynchronous operation. The {action} command has been "
        f"initiated successfully (expected completion: {timing}). You can verify "
        f"the status using '{verification_cmd}'.")
result["message"] += "\n\n📋 Note: " + note

```

## Fallback Formatting and Error Resilience

Regardless of the event type processed through the primary branches, the function implements defensive serialization at lines 115–129. It attempts `json.dumps(result, indent=2)` on the final output, catching serialization errors to return plain-text fallbacks. If the input result is not a dictionary, the function returns the raw string representation or a generic "operation failed" message, guaranteeing always-return-a-string behavior that prevents crashes in downstream MCP tools.

## Practical Implementation Examples

Individual tools throughout the repository invoke `handle_operation_result` after executing OpenStack SDK calls. The following excerpt from [`src/mcp_openstack_ops/tools/set_networks.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/tools/set_networks.py) demonstrates standard integration:

```python
from ..mcp_main import handle_operation_result

def set_networks(network_name, action, ...):
    result = openstack_sdk.create_network(...)  # Returns dict or None

    return handle_operation_result(
        result,
        "Network Management",
        {"Action": action, "Network": network_name}
    )

```

When `action` equals `"create"`, this automatically triggers the asynchronous operation detection for network resources, appending appropriate verification instructions to the response.

Simulating a quota failure demonstrates the error handling branch:

```python
from mcp_openstack_ops.mcp_main import handle_operation_result

failed_result = {"success": False, "message": "Quota exceeded"}
output = handle_operation_result(
    failed_result, 
    "Quota Management", 
    {"Project": "demo"}
)

# Returns formatted markdown with error details and project context

```

Handling missing responses:

```python
msg = handle_operation_result(None, "Instance Management", {"Instance": "web01"})

# Returns friendly timeout error with verification recommendation

```

Successful asynchronous instance creation:

```python
result = {
    "success": True, 
    "message": "Instance creation initiated"
}
output = handle_operation_result(
    result,
    "Instance Management", 
    {"Action": "create", "Instance": "web01"}
)

# Output includes async note with timing and verification command

```

## Summary

- **Four event categories**: Empty responses, explicit failures, synchronous successes, and asynchronous operations, each with specialized handling in [`src/mcp_openstack_ops/mcp_main.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/mcp_main.py).
- **Intelligent async detection**: The function consults a configurable mapping table (lines 55–92) to identify long-running operations and automatically appends verification instructions and timing estimates.
- **Consistent output formatting**: Every code path returns a string—either formatted JSON with augmented metadata or plain-text error messages—preventing downstream tool crashes.
- **Rich context preservation**: Error states preserve original messages and details, while successful operations receive contextual metadata like `operation_type` and `verification_needed` flags.
- **Tool integration**: All MCP tools in `src/mcp_openstack_ops/tools/*.py` rely on this central formatter to standardize communication between OpenStack SDK results and end-user interfaces.

## Frequently Asked Questions

### What happens when handle_operation_result receives None or an empty dictionary?

When the function receives `None`, `{}`, or any falsy value (detected at lines 24–33), it returns a rich-text error message indicating that the request timed out or received no response from the OpenStack backend. The function appends any provided details as bullet points and includes a recommendation to verify the operation status manually, ensuring users receive actionable feedback rather than raw Python exceptions.

### How does handle_operation_result distinguish between synchronous and asynchronous operations?

The function examines the `Action` field in the `details` parameter and compares it against the `async_operations` configuration dictionary defined at lines 55–92. If the normalized action name exists in the `async_actions` list for the specified operation category, the function marks the result with `"operation_type": "asynchronous"` and appends timing estimates and verification commands. Actions not listed in the async registry receive `"operation_type": "synchronous"` without additional polling instructions.

### Where is the async operations configuration defined in the codebase?

The asynchronous operation mappings reside directly in [`src/mcp_openstack_ops/mcp_main.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/mcp_main.py) between lines 55–92. This configuration table defines per-category settings for *Instance Management*, *Volume Management*, *Network Management*, and other OpenStack services, specifying which actions trigger asynchronous behavior, expected completion windows, and template strings for verification commands.

### Which files depend on handle_operation_result for event processing?

The `handle_operation_result` function is imported and invoked by multiple tool modules in `src/mcp_openstack_ops/tools/*.py`, including [`set_networks.py`](https://github.com/call518/mcp-openstack-ops/blob/main/set_networks.py), [`set_instance.py`](https://github.com/call518/mcp-openstack-ops/blob/main/set_instance.py), and related service-specific implementations. Additionally, the function serves as the final formatting layer for results generated by [`src/mcp_openstack_ops/functions.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/functions.py) and service helpers in `src/mcp_openstack_ops/services/*`, forming a complete response-handling pipeline from SDK calls to user-facing output.