mcp-openstack-ops 3.2.2__tar.gz → 3.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. {mcp_openstack_ops-3.2.2/src/mcp_openstack_ops.egg-info → mcp_openstack_ops-3.2.3}/PKG-INFO +201 -2
  2. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/README.md +200 -1
  3. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/pyproject.toml +1 -1
  4. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3/src/mcp_openstack_ops.egg-info}/PKG-INFO +201 -2
  5. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/LICENSE +0 -0
  6. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/MANIFEST.in +0 -0
  7. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/setup.cfg +0 -0
  8. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/__init__.py +0 -0
  9. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/__main__.py +0 -0
  10. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/connection.py +0 -0
  11. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/functions.py +0 -0
  12. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/mcp_main.py +0 -0
  13. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/__init__.py +0 -0
  14. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/compute.py +0 -0
  15. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/core.py +0 -0
  16. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/identity.py +0 -0
  17. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/image.py +0 -0
  18. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/load_balancer/__init__.py +0 -0
  19. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/load_balancer/amphorae.py +0 -0
  20. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/load_balancer/core.py +0 -0
  21. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/load_balancer/health_monitors.py +0 -0
  22. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/load_balancer/l7_policies.py +0 -0
  23. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/load_balancer/listeners.py +0 -0
  24. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/load_balancer/management.py +0 -0
  25. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/load_balancer/pools.py +0 -0
  26. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/monitoring.py +0 -0
  27. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/network.py +0 -0
  28. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/orchestration.py +0 -0
  29. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/services/storage.py +0 -0
  30. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/__init__.py +0 -0
  31. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_availability_zones.py +0 -0
  32. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_floating_ip_pools.py +0 -0
  33. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_floating_ips.py +0 -0
  34. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_heat_stacks.py +0 -0
  35. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_hypervisor_details.py +0 -0
  36. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_image_detail_list.py +0 -0
  37. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_instance.py +0 -0
  38. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_instance_by_name.py +0 -0
  39. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_instance_details.py +0 -0
  40. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_instances_by_status.py +0 -0
  41. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_keypair_list.py +0 -0
  42. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_amphorae.py +0 -0
  43. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_availability_zones.py +0 -0
  44. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_details.py +0 -0
  45. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_flavors.py +0 -0
  46. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_health_monitors.py +0 -0
  47. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_l7_policies.py +0 -0
  48. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_l7_rules.py +0 -0
  49. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_list.py +0 -0
  50. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_listeners.py +0 -0
  51. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_pool_members.py +0 -0
  52. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_pools.py +0 -0
  53. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_providers.py +0 -0
  54. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_load_balancer_quotas.py +0 -0
  55. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_network_details.py +0 -0
  56. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_project_details.py +0 -0
  57. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_quota.py +0 -0
  58. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_resource_monitoring.py +0 -0
  59. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_role_assignments.py +0 -0
  60. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_routers.py +0 -0
  61. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_security_groups.py +0 -0
  62. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_server_events.py +0 -0
  63. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_server_groups.py +0 -0
  64. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_server_volumes.py +0 -0
  65. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_service_status.py +0 -0
  66. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_usage_statistics.py +0 -0
  67. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_user_list.py +0 -0
  68. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_volume_list.py +0 -0
  69. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_volume_snapshots.py +0 -0
  70. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/get_volume_types.py +0 -0
  71. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/search_instances.py +0 -0
  72. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_alarms.py +0 -0
  73. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_compute_agents.py +0 -0
  74. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_domains.py +0 -0
  75. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_flavor.py +0 -0
  76. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_floating_ip.py +0 -0
  77. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_floating_ip_port_forwarding.py +0 -0
  78. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_heat_stack.py +0 -0
  79. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_identity_groups.py +0 -0
  80. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_image.py +0 -0
  81. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_image_members.py +0 -0
  82. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_image_metadata.py +0 -0
  83. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_image_visibility.py +0 -0
  84. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_instance.py +0 -0
  85. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_keypair.py +0 -0
  86. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_load_balancer.py +0 -0
  87. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_load_balancer_amphora.py +0 -0
  88. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_load_balancer_availability_zone.py +0 -0
  89. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_load_balancer_flavor.py +0 -0
  90. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_load_balancer_health_monitor.py +0 -0
  91. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_load_balancer_l7_policy.py +0 -0
  92. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_load_balancer_l7_rule.py +0 -0
  93. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_load_balancer_listener.py +0 -0
  94. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_load_balancer_pool.py +0 -0
  95. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_load_balancer_pool_member.py +0 -0
  96. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_load_balancer_quota.py +0 -0
  97. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_metrics.py +0 -0
  98. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_network_agents.py +0 -0
  99. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_network_ports.py +0 -0
  100. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_network_qos_policies.py +0 -0
  101. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_networks.py +0 -0
  102. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_project.py +0 -0
  103. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_quota.py +0 -0
  104. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_roles.py +0 -0
  105. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_server_backup.py +0 -0
  106. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_server_dump.py +0 -0
  107. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_server_fixed_ip.py +0 -0
  108. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_server_floating_ip.py +0 -0
  109. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_server_group.py +0 -0
  110. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_server_migration.py +0 -0
  111. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_server_network.py +0 -0
  112. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_server_properties.py +0 -0
  113. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_server_security_group.py +0 -0
  114. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_server_volume.py +0 -0
  115. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_service_logs.py +0 -0
  116. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_services.py +0 -0
  117. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_snapshot.py +0 -0
  118. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_subnets.py +0 -0
  119. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_volume.py +0 -0
  120. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_volume_backups.py +0 -0
  121. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_volume_groups.py +0 -0
  122. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops/tools/set_volume_qos.py +0 -0
  123. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops.egg-info/SOURCES.txt +0 -0
  124. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops.egg-info/dependency_links.txt +0 -0
  125. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops.egg-info/entry_points.txt +0 -0
  126. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops.egg-info/requires.txt +0 -0
  127. {mcp_openstack_ops-3.2.2 → mcp_openstack_ops-3.2.3}/src/mcp_openstack_ops.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-openstack-ops
3
- Version: 3.2.2
3
+ Version: 3.2.3
4
4
  Summary: OpenStack operations automation MCP server
5
5
  Author-email: JungJungIn <call518@gmail.com>
6
6
  Requires-Python: >=3.12
@@ -19,10 +19,15 @@ Dynamic: license-file
19
19
  > **MCP OpenStack Operations Server**: A comprehensive MCP (Model Context Protocol) server providing OpenStack project management and monitoring capabilities with built-in safety controls and single-project scope.
20
20
 
21
21
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
22
- [![Deploy to PyPI with tag](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml/badge.svg)](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml)
22
+ ![Python](https://img.shields.io/badge/Python-3776AB?style=flat&logo=python&logoColor=white)
23
+ ![Docker Pulls](https://img.shields.io/docker/pulls/call518/mcp-server-openstack-ops)
23
24
  [![smithery badge](https://smithery.ai/badge/@call518/mcp-openstack-ops)](https://smithery.ai/server/@call518/mcp-openstack-ops)
24
25
  [![BuyMeACoffee](https://raw.githubusercontent.com/pachadotdev/buymeacoffee-badges/main/bmc-donate-yellow.svg)](https://www.buymeacoffee.com/call518)
25
26
 
27
+ [![Deploy to PyPI with tag](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml/badge.svg)](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml)
28
+ ![PyPI](https://img.shields.io/pypi/v/MCP-OpenStack-Ops?label=pypi%20package)
29
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/MCP-OpenStack-Ops)
30
+
26
31
  ---
27
32
 
28
33
  ## Architecture & Internal (DeepWiki)
@@ -1029,6 +1034,200 @@ When authentication fails, the server returns:
1029
1034
 
1030
1035
  ---
1031
1036
 
1037
+ ## 🚀 Adding Custom Tools
1038
+
1039
+ This MCP server is designed for easy extensibility. Follow these steps to add your own custom tools:
1040
+
1041
+ ### Step-by-Step Guide
1042
+
1043
+ #### 1. **Add Helper Functions (Optional)**
1044
+
1045
+ Add reusable data functions to `src/mcp_openstack_ops/functions.py`:
1046
+
1047
+ ```python
1048
+ async def get_your_custom_data(target_resource: str = None) -> List[Dict[str, Any]]:
1049
+ """Your custom data retrieval function."""
1050
+ # Example implementation - adapt to your OpenStack service
1051
+ conn = get_openstack_connection()
1052
+ results = []
1053
+
1054
+ try:
1055
+ # Example: Custom query using OpenStack SDK
1056
+ resources = conn.your_service.list_resources(
1057
+ filters={'name': target_resource} if target_resource else {}
1058
+ )
1059
+
1060
+ for resource in resources:
1061
+ results.append({
1062
+ 'name': resource.name,
1063
+ 'id': resource.id,
1064
+ 'status': resource.status,
1065
+ 'created_at': resource.created_at,
1066
+ # Add your custom fields
1067
+ })
1068
+
1069
+ except Exception as e:
1070
+ logger.error(f"Failed to get custom data: {e}")
1071
+ return []
1072
+
1073
+ return results
1074
+ ```
1075
+
1076
+ #### 2. **Create Your MCP Tool File**
1077
+
1078
+ Create a new file `src/mcp_openstack_ops/tools/get_your_custom_analysis.py`:
1079
+
1080
+ ```python
1081
+ """Tool implementation for get_your_custom_analysis."""
1082
+
1083
+ import json
1084
+ from datetime import datetime
1085
+ from typing import Optional
1086
+ from ..functions import get_your_custom_data # Import your helper function
1087
+ from ..mcp_main import (
1088
+ logger,
1089
+ mcp,
1090
+ )
1091
+
1092
+ @mcp.tool()
1093
+ async def get_your_custom_analysis(limit: int = 50, target_name: Optional[str] = None) -> str:
1094
+ """
1095
+ [Tool Purpose]: Brief description of what your tool does
1096
+
1097
+ [Exact Functionality]:
1098
+ - Feature 1: Data aggregation and analysis
1099
+ - Feature 2: Resource monitoring and insights
1100
+ - Feature 3: Performance metrics and reporting
1101
+
1102
+ [Required Use Cases]:
1103
+ - When user asks "your specific analysis request"
1104
+ - Your business-specific monitoring needs
1105
+
1106
+ Args:
1107
+ limit: Maximum results (1-100)
1108
+ target_name: Target resource/service name
1109
+
1110
+ Returns:
1111
+ Formatted analysis results
1112
+ """
1113
+ try:
1114
+ limit = max(1, min(limit, 100)) # Always validate input
1115
+
1116
+ logger.info(f"Getting custom analysis, limit: {limit}, target: {target_name}")
1117
+
1118
+ results = await get_your_custom_data(target_resource=target_name)
1119
+
1120
+ if not results:
1121
+ return f"No custom analysis data found" + (f" for '{target_name}'" if target_name else "")
1122
+
1123
+ # Apply limit
1124
+ results = results[:limit]
1125
+
1126
+ # Format results as table
1127
+ table_data = []
1128
+ for item in results:
1129
+ table_data.append({
1130
+ 'Name': item.get('name', 'N/A'),
1131
+ 'ID': item.get('id', 'N/A'),
1132
+ 'Status': item.get('status', 'N/A'),
1133
+ 'Created': item.get('created_at', 'N/A'),
1134
+ })
1135
+
1136
+ # Return formatted JSON
1137
+ return json.dumps({
1138
+ 'title': f'Custom Analysis (Top {len(results)})',
1139
+ 'data': table_data,
1140
+ 'total_count': len(results),
1141
+ 'timestamp': datetime.now().isoformat()
1142
+ }, indent=2)
1143
+
1144
+ except Exception as e:
1145
+ logger.error(f"Failed to get custom analysis: {e}")
1146
+ return f"Error: {str(e)}"
1147
+ ```
1148
+
1149
+ #### 3. **For Modify Operations (Optional)**
1150
+
1151
+ If your tool performs modify operations, use the `@conditional_tool` decorator instead:
1152
+
1153
+ ```python
1154
+ """Tool implementation for set_your_custom_resource."""
1155
+
1156
+ from ..mcp_main import (
1157
+ conditional_tool, # Use this instead of @mcp.tool()
1158
+ handle_operation_result,
1159
+ logger,
1160
+ )
1161
+ from ..functions import set_your_custom_resource
1162
+
1163
+ @conditional_tool # Only registers when ALLOW_MODIFY_OPERATIONS=true
1164
+ async def set_your_custom_resource(resource_name: str, action: str) -> str:
1165
+ """
1166
+ Manage your custom OpenStack resources.
1167
+
1168
+ Use when user requests custom resource management.
1169
+ """
1170
+ try:
1171
+ result = set_your_custom_resource(resource_name, action)
1172
+
1173
+ return handle_operation_result(
1174
+ result=result,
1175
+ operation_name="Custom Resource Management",
1176
+ details={
1177
+ 'Resource': resource_name,
1178
+ 'Action': action
1179
+ }
1180
+ )
1181
+
1182
+ except Exception as e:
1183
+ logger.error(f"Custom resource operation failed: {e}")
1184
+ return f"Error: {str(e)}"
1185
+ ```
1186
+
1187
+ #### 4. **Update Prompt Template (Recommended)**
1188
+
1189
+ Add your tool description to `src/mcp_openstack_ops/prompt_template.md` for better natural language recognition:
1190
+
1191
+ ```markdown
1192
+ ### **Your Custom Analysis Tool**
1193
+
1194
+ ### X. **get_your_custom_analysis**
1195
+ **Purpose**: Brief description of what your tool does
1196
+ **Usage**: "Show me your custom analysis" or "Get custom analysis for resource_name"
1197
+ **Features**: Data aggregation, resource monitoring, performance metrics
1198
+ **Optional**: `target_name` parameter for specific resource analysis
1199
+ ```
1200
+
1201
+ #### 5. **Test Your Tool**
1202
+
1203
+ ```bash
1204
+ # Local testing
1205
+ ./scripts/run-mcp-inspector-local.sh
1206
+
1207
+ # Or with Docker
1208
+ docker-compose up -d
1209
+ docker-compose logs -f mcp-server
1210
+
1211
+ # Test with natural language:
1212
+ # "Show me your custom analysis"
1213
+ # "Get custom analysis for target_name"
1214
+ ```
1215
+
1216
+ ### Tool Registration System
1217
+
1218
+ The MCP server uses automatic tool discovery. When you create a new file in `src/mcp_openstack_ops/tools/`, it's automatically registered through the `register_all_tools()` function in `tools/__init__.py`. No manual import registration needed!
1219
+
1220
+ ### Safety System
1221
+
1222
+ - **Read-only tools**: Use `@mcp.tool()` - always available
1223
+ - **Modify tools**: Use `@conditional_tool` - only available when `ALLOW_MODIFY_OPERATIONS=true`
1224
+ - **Connection**: Always use `get_openstack_connection()` for OpenStack API access
1225
+ - **Project isolation**: All operations are automatically scoped to `OS_PROJECT_NAME`
1226
+
1227
+ That's it! Your custom tool is ready to use with natural language queries.
1228
+
1229
+ ---
1230
+
1032
1231
  ## License
1033
1232
 
1034
1233
  This project is licensed under the MIT License - see the LICENSE file for details.
@@ -3,10 +3,15 @@
3
3
  > **MCP OpenStack Operations Server**: A comprehensive MCP (Model Context Protocol) server providing OpenStack project management and monitoring capabilities with built-in safety controls and single-project scope.
4
4
 
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
- [![Deploy to PyPI with tag](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml/badge.svg)](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml)
6
+ ![Python](https://img.shields.io/badge/Python-3776AB?style=flat&logo=python&logoColor=white)
7
+ ![Docker Pulls](https://img.shields.io/docker/pulls/call518/mcp-server-openstack-ops)
7
8
  [![smithery badge](https://smithery.ai/badge/@call518/mcp-openstack-ops)](https://smithery.ai/server/@call518/mcp-openstack-ops)
8
9
  [![BuyMeACoffee](https://raw.githubusercontent.com/pachadotdev/buymeacoffee-badges/main/bmc-donate-yellow.svg)](https://www.buymeacoffee.com/call518)
9
10
 
11
+ [![Deploy to PyPI with tag](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml/badge.svg)](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml)
12
+ ![PyPI](https://img.shields.io/pypi/v/MCP-OpenStack-Ops?label=pypi%20package)
13
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/MCP-OpenStack-Ops)
14
+
10
15
  ---
11
16
 
12
17
  ## Architecture & Internal (DeepWiki)
@@ -1013,6 +1018,200 @@ When authentication fails, the server returns:
1013
1018
 
1014
1019
  ---
1015
1020
 
1021
+ ## 🚀 Adding Custom Tools
1022
+
1023
+ This MCP server is designed for easy extensibility. Follow these steps to add your own custom tools:
1024
+
1025
+ ### Step-by-Step Guide
1026
+
1027
+ #### 1. **Add Helper Functions (Optional)**
1028
+
1029
+ Add reusable data functions to `src/mcp_openstack_ops/functions.py`:
1030
+
1031
+ ```python
1032
+ async def get_your_custom_data(target_resource: str = None) -> List[Dict[str, Any]]:
1033
+ """Your custom data retrieval function."""
1034
+ # Example implementation - adapt to your OpenStack service
1035
+ conn = get_openstack_connection()
1036
+ results = []
1037
+
1038
+ try:
1039
+ # Example: Custom query using OpenStack SDK
1040
+ resources = conn.your_service.list_resources(
1041
+ filters={'name': target_resource} if target_resource else {}
1042
+ )
1043
+
1044
+ for resource in resources:
1045
+ results.append({
1046
+ 'name': resource.name,
1047
+ 'id': resource.id,
1048
+ 'status': resource.status,
1049
+ 'created_at': resource.created_at,
1050
+ # Add your custom fields
1051
+ })
1052
+
1053
+ except Exception as e:
1054
+ logger.error(f"Failed to get custom data: {e}")
1055
+ return []
1056
+
1057
+ return results
1058
+ ```
1059
+
1060
+ #### 2. **Create Your MCP Tool File**
1061
+
1062
+ Create a new file `src/mcp_openstack_ops/tools/get_your_custom_analysis.py`:
1063
+
1064
+ ```python
1065
+ """Tool implementation for get_your_custom_analysis."""
1066
+
1067
+ import json
1068
+ from datetime import datetime
1069
+ from typing import Optional
1070
+ from ..functions import get_your_custom_data # Import your helper function
1071
+ from ..mcp_main import (
1072
+ logger,
1073
+ mcp,
1074
+ )
1075
+
1076
+ @mcp.tool()
1077
+ async def get_your_custom_analysis(limit: int = 50, target_name: Optional[str] = None) -> str:
1078
+ """
1079
+ [Tool Purpose]: Brief description of what your tool does
1080
+
1081
+ [Exact Functionality]:
1082
+ - Feature 1: Data aggregation and analysis
1083
+ - Feature 2: Resource monitoring and insights
1084
+ - Feature 3: Performance metrics and reporting
1085
+
1086
+ [Required Use Cases]:
1087
+ - When user asks "your specific analysis request"
1088
+ - Your business-specific monitoring needs
1089
+
1090
+ Args:
1091
+ limit: Maximum results (1-100)
1092
+ target_name: Target resource/service name
1093
+
1094
+ Returns:
1095
+ Formatted analysis results
1096
+ """
1097
+ try:
1098
+ limit = max(1, min(limit, 100)) # Always validate input
1099
+
1100
+ logger.info(f"Getting custom analysis, limit: {limit}, target: {target_name}")
1101
+
1102
+ results = await get_your_custom_data(target_resource=target_name)
1103
+
1104
+ if not results:
1105
+ return f"No custom analysis data found" + (f" for '{target_name}'" if target_name else "")
1106
+
1107
+ # Apply limit
1108
+ results = results[:limit]
1109
+
1110
+ # Format results as table
1111
+ table_data = []
1112
+ for item in results:
1113
+ table_data.append({
1114
+ 'Name': item.get('name', 'N/A'),
1115
+ 'ID': item.get('id', 'N/A'),
1116
+ 'Status': item.get('status', 'N/A'),
1117
+ 'Created': item.get('created_at', 'N/A'),
1118
+ })
1119
+
1120
+ # Return formatted JSON
1121
+ return json.dumps({
1122
+ 'title': f'Custom Analysis (Top {len(results)})',
1123
+ 'data': table_data,
1124
+ 'total_count': len(results),
1125
+ 'timestamp': datetime.now().isoformat()
1126
+ }, indent=2)
1127
+
1128
+ except Exception as e:
1129
+ logger.error(f"Failed to get custom analysis: {e}")
1130
+ return f"Error: {str(e)}"
1131
+ ```
1132
+
1133
+ #### 3. **For Modify Operations (Optional)**
1134
+
1135
+ If your tool performs modify operations, use the `@conditional_tool` decorator instead:
1136
+
1137
+ ```python
1138
+ """Tool implementation for set_your_custom_resource."""
1139
+
1140
+ from ..mcp_main import (
1141
+ conditional_tool, # Use this instead of @mcp.tool()
1142
+ handle_operation_result,
1143
+ logger,
1144
+ )
1145
+ from ..functions import set_your_custom_resource
1146
+
1147
+ @conditional_tool # Only registers when ALLOW_MODIFY_OPERATIONS=true
1148
+ async def set_your_custom_resource(resource_name: str, action: str) -> str:
1149
+ """
1150
+ Manage your custom OpenStack resources.
1151
+
1152
+ Use when user requests custom resource management.
1153
+ """
1154
+ try:
1155
+ result = set_your_custom_resource(resource_name, action)
1156
+
1157
+ return handle_operation_result(
1158
+ result=result,
1159
+ operation_name="Custom Resource Management",
1160
+ details={
1161
+ 'Resource': resource_name,
1162
+ 'Action': action
1163
+ }
1164
+ )
1165
+
1166
+ except Exception as e:
1167
+ logger.error(f"Custom resource operation failed: {e}")
1168
+ return f"Error: {str(e)}"
1169
+ ```
1170
+
1171
+ #### 4. **Update Prompt Template (Recommended)**
1172
+
1173
+ Add your tool description to `src/mcp_openstack_ops/prompt_template.md` for better natural language recognition:
1174
+
1175
+ ```markdown
1176
+ ### **Your Custom Analysis Tool**
1177
+
1178
+ ### X. **get_your_custom_analysis**
1179
+ **Purpose**: Brief description of what your tool does
1180
+ **Usage**: "Show me your custom analysis" or "Get custom analysis for resource_name"
1181
+ **Features**: Data aggregation, resource monitoring, performance metrics
1182
+ **Optional**: `target_name` parameter for specific resource analysis
1183
+ ```
1184
+
1185
+ #### 5. **Test Your Tool**
1186
+
1187
+ ```bash
1188
+ # Local testing
1189
+ ./scripts/run-mcp-inspector-local.sh
1190
+
1191
+ # Or with Docker
1192
+ docker-compose up -d
1193
+ docker-compose logs -f mcp-server
1194
+
1195
+ # Test with natural language:
1196
+ # "Show me your custom analysis"
1197
+ # "Get custom analysis for target_name"
1198
+ ```
1199
+
1200
+ ### Tool Registration System
1201
+
1202
+ The MCP server uses automatic tool discovery. When you create a new file in `src/mcp_openstack_ops/tools/`, it's automatically registered through the `register_all_tools()` function in `tools/__init__.py`. No manual import registration needed!
1203
+
1204
+ ### Safety System
1205
+
1206
+ - **Read-only tools**: Use `@mcp.tool()` - always available
1207
+ - **Modify tools**: Use `@conditional_tool` - only available when `ALLOW_MODIFY_OPERATIONS=true`
1208
+ - **Connection**: Always use `get_openstack_connection()` for OpenStack API access
1209
+ - **Project isolation**: All operations are automatically scoped to `OS_PROJECT_NAME`
1210
+
1211
+ That's it! Your custom tool is ready to use with natural language queries.
1212
+
1213
+ ---
1214
+
1016
1215
  ## License
1017
1216
 
1018
1217
  This project is licensed under the MIT License - see the LICENSE file for details.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mcp-openstack-ops"
3
- version = "3.2.2"
3
+ version = "3.2.3"
4
4
  description = "OpenStack operations automation MCP server"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-openstack-ops
3
- Version: 3.2.2
3
+ Version: 3.2.3
4
4
  Summary: OpenStack operations automation MCP server
5
5
  Author-email: JungJungIn <call518@gmail.com>
6
6
  Requires-Python: >=3.12
@@ -19,10 +19,15 @@ Dynamic: license-file
19
19
  > **MCP OpenStack Operations Server**: A comprehensive MCP (Model Context Protocol) server providing OpenStack project management and monitoring capabilities with built-in safety controls and single-project scope.
20
20
 
21
21
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
22
- [![Deploy to PyPI with tag](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml/badge.svg)](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml)
22
+ ![Python](https://img.shields.io/badge/Python-3776AB?style=flat&logo=python&logoColor=white)
23
+ ![Docker Pulls](https://img.shields.io/docker/pulls/call518/mcp-server-openstack-ops)
23
24
  [![smithery badge](https://smithery.ai/badge/@call518/mcp-openstack-ops)](https://smithery.ai/server/@call518/mcp-openstack-ops)
24
25
  [![BuyMeACoffee](https://raw.githubusercontent.com/pachadotdev/buymeacoffee-badges/main/bmc-donate-yellow.svg)](https://www.buymeacoffee.com/call518)
25
26
 
27
+ [![Deploy to PyPI with tag](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml/badge.svg)](https://github.com/call518/MCP-OpenStack-Ops/actions/workflows/pypi-publish.yml)
28
+ ![PyPI](https://img.shields.io/pypi/v/MCP-OpenStack-Ops?label=pypi%20package)
29
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/MCP-OpenStack-Ops)
30
+
26
31
  ---
27
32
 
28
33
  ## Architecture & Internal (DeepWiki)
@@ -1029,6 +1034,200 @@ When authentication fails, the server returns:
1029
1034
 
1030
1035
  ---
1031
1036
 
1037
+ ## 🚀 Adding Custom Tools
1038
+
1039
+ This MCP server is designed for easy extensibility. Follow these steps to add your own custom tools:
1040
+
1041
+ ### Step-by-Step Guide
1042
+
1043
+ #### 1. **Add Helper Functions (Optional)**
1044
+
1045
+ Add reusable data functions to `src/mcp_openstack_ops/functions.py`:
1046
+
1047
+ ```python
1048
+ async def get_your_custom_data(target_resource: str = None) -> List[Dict[str, Any]]:
1049
+ """Your custom data retrieval function."""
1050
+ # Example implementation - adapt to your OpenStack service
1051
+ conn = get_openstack_connection()
1052
+ results = []
1053
+
1054
+ try:
1055
+ # Example: Custom query using OpenStack SDK
1056
+ resources = conn.your_service.list_resources(
1057
+ filters={'name': target_resource} if target_resource else {}
1058
+ )
1059
+
1060
+ for resource in resources:
1061
+ results.append({
1062
+ 'name': resource.name,
1063
+ 'id': resource.id,
1064
+ 'status': resource.status,
1065
+ 'created_at': resource.created_at,
1066
+ # Add your custom fields
1067
+ })
1068
+
1069
+ except Exception as e:
1070
+ logger.error(f"Failed to get custom data: {e}")
1071
+ return []
1072
+
1073
+ return results
1074
+ ```
1075
+
1076
+ #### 2. **Create Your MCP Tool File**
1077
+
1078
+ Create a new file `src/mcp_openstack_ops/tools/get_your_custom_analysis.py`:
1079
+
1080
+ ```python
1081
+ """Tool implementation for get_your_custom_analysis."""
1082
+
1083
+ import json
1084
+ from datetime import datetime
1085
+ from typing import Optional
1086
+ from ..functions import get_your_custom_data # Import your helper function
1087
+ from ..mcp_main import (
1088
+ logger,
1089
+ mcp,
1090
+ )
1091
+
1092
+ @mcp.tool()
1093
+ async def get_your_custom_analysis(limit: int = 50, target_name: Optional[str] = None) -> str:
1094
+ """
1095
+ [Tool Purpose]: Brief description of what your tool does
1096
+
1097
+ [Exact Functionality]:
1098
+ - Feature 1: Data aggregation and analysis
1099
+ - Feature 2: Resource monitoring and insights
1100
+ - Feature 3: Performance metrics and reporting
1101
+
1102
+ [Required Use Cases]:
1103
+ - When user asks "your specific analysis request"
1104
+ - Your business-specific monitoring needs
1105
+
1106
+ Args:
1107
+ limit: Maximum results (1-100)
1108
+ target_name: Target resource/service name
1109
+
1110
+ Returns:
1111
+ Formatted analysis results
1112
+ """
1113
+ try:
1114
+ limit = max(1, min(limit, 100)) # Always validate input
1115
+
1116
+ logger.info(f"Getting custom analysis, limit: {limit}, target: {target_name}")
1117
+
1118
+ results = await get_your_custom_data(target_resource=target_name)
1119
+
1120
+ if not results:
1121
+ return f"No custom analysis data found" + (f" for '{target_name}'" if target_name else "")
1122
+
1123
+ # Apply limit
1124
+ results = results[:limit]
1125
+
1126
+ # Format results as table
1127
+ table_data = []
1128
+ for item in results:
1129
+ table_data.append({
1130
+ 'Name': item.get('name', 'N/A'),
1131
+ 'ID': item.get('id', 'N/A'),
1132
+ 'Status': item.get('status', 'N/A'),
1133
+ 'Created': item.get('created_at', 'N/A'),
1134
+ })
1135
+
1136
+ # Return formatted JSON
1137
+ return json.dumps({
1138
+ 'title': f'Custom Analysis (Top {len(results)})',
1139
+ 'data': table_data,
1140
+ 'total_count': len(results),
1141
+ 'timestamp': datetime.now().isoformat()
1142
+ }, indent=2)
1143
+
1144
+ except Exception as e:
1145
+ logger.error(f"Failed to get custom analysis: {e}")
1146
+ return f"Error: {str(e)}"
1147
+ ```
1148
+
1149
+ #### 3. **For Modify Operations (Optional)**
1150
+
1151
+ If your tool performs modify operations, use the `@conditional_tool` decorator instead:
1152
+
1153
+ ```python
1154
+ """Tool implementation for set_your_custom_resource."""
1155
+
1156
+ from ..mcp_main import (
1157
+ conditional_tool, # Use this instead of @mcp.tool()
1158
+ handle_operation_result,
1159
+ logger,
1160
+ )
1161
+ from ..functions import set_your_custom_resource
1162
+
1163
+ @conditional_tool # Only registers when ALLOW_MODIFY_OPERATIONS=true
1164
+ async def set_your_custom_resource(resource_name: str, action: str) -> str:
1165
+ """
1166
+ Manage your custom OpenStack resources.
1167
+
1168
+ Use when user requests custom resource management.
1169
+ """
1170
+ try:
1171
+ result = set_your_custom_resource(resource_name, action)
1172
+
1173
+ return handle_operation_result(
1174
+ result=result,
1175
+ operation_name="Custom Resource Management",
1176
+ details={
1177
+ 'Resource': resource_name,
1178
+ 'Action': action
1179
+ }
1180
+ )
1181
+
1182
+ except Exception as e:
1183
+ logger.error(f"Custom resource operation failed: {e}")
1184
+ return f"Error: {str(e)}"
1185
+ ```
1186
+
1187
+ #### 4. **Update Prompt Template (Recommended)**
1188
+
1189
+ Add your tool description to `src/mcp_openstack_ops/prompt_template.md` for better natural language recognition:
1190
+
1191
+ ```markdown
1192
+ ### **Your Custom Analysis Tool**
1193
+
1194
+ ### X. **get_your_custom_analysis**
1195
+ **Purpose**: Brief description of what your tool does
1196
+ **Usage**: "Show me your custom analysis" or "Get custom analysis for resource_name"
1197
+ **Features**: Data aggregation, resource monitoring, performance metrics
1198
+ **Optional**: `target_name` parameter for specific resource analysis
1199
+ ```
1200
+
1201
+ #### 5. **Test Your Tool**
1202
+
1203
+ ```bash
1204
+ # Local testing
1205
+ ./scripts/run-mcp-inspector-local.sh
1206
+
1207
+ # Or with Docker
1208
+ docker-compose up -d
1209
+ docker-compose logs -f mcp-server
1210
+
1211
+ # Test with natural language:
1212
+ # "Show me your custom analysis"
1213
+ # "Get custom analysis for target_name"
1214
+ ```
1215
+
1216
+ ### Tool Registration System
1217
+
1218
+ The MCP server uses automatic tool discovery. When you create a new file in `src/mcp_openstack_ops/tools/`, it's automatically registered through the `register_all_tools()` function in `tools/__init__.py`. No manual import registration needed!
1219
+
1220
+ ### Safety System
1221
+
1222
+ - **Read-only tools**: Use `@mcp.tool()` - always available
1223
+ - **Modify tools**: Use `@conditional_tool` - only available when `ALLOW_MODIFY_OPERATIONS=true`
1224
+ - **Connection**: Always use `get_openstack_connection()` for OpenStack API access
1225
+ - **Project isolation**: All operations are automatically scoped to `OS_PROJECT_NAME`
1226
+
1227
+ That's it! Your custom tool is ready to use with natural language queries.
1228
+
1229
+ ---
1230
+
1032
1231
  ## License
1033
1232
 
1034
1233
  This project is licensed under the MIT License - see the LICENSE file for details.