How handle_operation_result Handles Events in mcp_main.py: MCP OpenStack Ops Processing Guide
The handle_operation_result function in 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, 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.
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).
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 categorizes operations by resource type (Instance Management, Volume Management, Network Management, etc.), mapping specific actions to their temporal characteristics.
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:
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 demonstrates standard integration:
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:
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:
msg = handle_operation_result(None, "Instance Management", {"Instance": "web01"})
# Returns friendly timeout error with verification recommendation
Successful asynchronous instance creation:
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. - 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_typeandverification_neededflags. - Tool integration: All MCP tools in
src/mcp_openstack_ops/tools/*.pyrely 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 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, 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 and service helpers in src/mcp_openstack_ops/services/*, forming a complete response-handling pipeline from SDK calls to user-facing output.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →