mcp-openstack-ops 3.6.1__tar.gz → 3.6.2__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 (199) hide show
  1. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/AGENTS.md +6 -4
  2. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/PKG-INFO +11 -79
  3. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/README.md +10 -78
  4. mcp_openstack_ops-3.6.1/docs/multi-user-phase1.md → mcp_openstack_ops-3.6.2/docs/multi-user-guide.md +27 -133
  5. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/prompt_template.md +1 -1
  6. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_server_events.py +5 -1
  7. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/user_connection.py +49 -0
  8. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops.egg-info/PKG-INFO +11 -79
  9. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops.egg-info/SOURCES.txt +1 -8
  10. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops.egg-info/scm_file_list.json +1 -8
  11. mcp_openstack_ops-3.6.2/src/mcp_openstack_ops.egg-info/scm_version.json +8 -0
  12. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/tests/test_phase1_stabilization.py +12 -0
  13. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/tests/test_user_connection.py +111 -0
  14. mcp_openstack_ops-3.6.1/docs/expanded-validation-fixes-2026-11-02.json +0 -18906
  15. mcp_openstack_ops-3.6.1/docs/expanded-validation-fixes-2026-11-02.md +0 -205
  16. mcp_openstack_ops-3.6.1/docs/integration-validation.md +0 -64
  17. mcp_openstack_ops-3.6.1/docs/main-live-retest-2026-10-30.json +0 -2342
  18. mcp_openstack_ops-3.6.1/docs/main-live-retest-2026-10-30.md +0 -268
  19. mcp_openstack_ops-3.6.1/docs/main-live-validation-2026-10-30.json +0 -2745
  20. mcp_openstack_ops-3.6.1/docs/main-live-validation-2026-10-30.md +0 -315
  21. mcp_openstack_ops-3.6.1/src/mcp_openstack_ops.egg-info/scm_version.json +0 -8
  22. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/.env.example +0 -0
  23. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/.env.test +0 -0
  24. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/.github/FUNDING.yml +0 -0
  25. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/.github/copilot-instructions.md +0 -0
  26. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/.github/dependabot.yml +0 -0
  27. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/.github/workflows/pypi-publish.yml +0 -0
  28. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/.github/workflows/tests.yml +0 -0
  29. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/.gitignore +0 -0
  30. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/.gitleaks.toml +0 -0
  31. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/.pre-commit-config.yaml +0 -0
  32. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/.python-version +0 -0
  33. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/Dockerfile.MCP-Server +0 -0
  34. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/Dockerfile.MCPO-Proxy +0 -0
  35. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/LICENSE +0 -0
  36. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/MANIFEST.in +0 -0
  37. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/build-mcp-server-docker-image.sh +0 -0
  38. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/build-mcpo-server-docker-image.sh +0 -0
  39. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/diagnose_openstack.py +0 -0
  40. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/docker-compose.yml +0 -0
  41. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/img/MCP-Workflow-of-Quickstart-Tutorial.png +0 -0
  42. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/img/screenshot-claude-desktop.png +0 -0
  43. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/img/screenshot-example-cluster-status.png +0 -0
  44. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/img/screenshot-openstack-dashboard.png +0 -0
  45. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/main.py +0 -0
  46. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/mcp-config.json.http +0 -0
  47. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/mcp-config.json.multi-project +0 -0
  48. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/mcp-config.json.stdio +0 -0
  49. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/pyproject.toml +0 -0
  50. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/scripts/check_release.py +0 -0
  51. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/scripts/mcp-server-docker-cmd.sh +0 -0
  52. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/scripts/publish_release.py +0 -0
  53. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/scripts/run-mcp-inspector-local.sh +0 -0
  54. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/scripts/run-mcp-inspector-pypi.sh +0 -0
  55. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/setup.cfg +0 -0
  56. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/__init__.py +0 -0
  57. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/__main__.py +0 -0
  58. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/connection.py +0 -0
  59. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/functions.py +0 -0
  60. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/mcp_main.py +0 -0
  61. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/__init__.py +0 -0
  62. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/alarms.py +0 -0
  63. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/compute.py +0 -0
  64. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/core.py +0 -0
  65. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/identity.py +0 -0
  66. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/image.py +0 -0
  67. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/load_balancer/__init__.py +0 -0
  68. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/load_balancer/amphorae.py +0 -0
  69. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/load_balancer/core.py +0 -0
  70. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/load_balancer/health_monitors.py +0 -0
  71. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/load_balancer/l7_policies.py +0 -0
  72. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/load_balancer/listeners.py +0 -0
  73. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/load_balancer/management.py +0 -0
  74. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/load_balancer/pools.py +0 -0
  75. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/monitoring.py +0 -0
  76. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/network.py +0 -0
  77. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/orchestration.py +0 -0
  78. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/services/storage.py +0 -0
  79. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/__init__.py +0 -0
  80. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_availability_zones.py +0 -0
  81. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_domains.py +0 -0
  82. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_floating_ip_pools.py +0 -0
  83. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_floating_ips.py +0 -0
  84. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_heat_stack_details.py +0 -0
  85. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_heat_stacks.py +0 -0
  86. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_hypervisor_details.py +0 -0
  87. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_identity_groups.py +0 -0
  88. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_image_detail_list.py +0 -0
  89. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_image_members.py +0 -0
  90. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_instance.py +0 -0
  91. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_instance_by_name.py +0 -0
  92. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_instance_details.py +0 -0
  93. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_instances_by_status.py +0 -0
  94. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_keypair_list.py +0 -0
  95. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_amphorae.py +0 -0
  96. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_availability_zones.py +0 -0
  97. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_details.py +0 -0
  98. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_flavors.py +0 -0
  99. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_health_monitors.py +0 -0
  100. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_l7_policies.py +0 -0
  101. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_l7_rules.py +0 -0
  102. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_list.py +0 -0
  103. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_listeners.py +0 -0
  104. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_pool_members.py +0 -0
  105. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_pools.py +0 -0
  106. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_providers.py +0 -0
  107. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_load_balancer_quotas.py +0 -0
  108. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_network_details.py +0 -0
  109. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_network_qos_policies.py +0 -0
  110. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_project_details.py +0 -0
  111. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_quota.py +0 -0
  112. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_resource_monitoring.py +0 -0
  113. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_role_assignments.py +0 -0
  114. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_routers.py +0 -0
  115. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_security_groups.py +0 -0
  116. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_server_groups.py +0 -0
  117. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_server_volumes.py +0 -0
  118. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_service_status.py +0 -0
  119. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_usage_statistics.py +0 -0
  120. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_user_list.py +0 -0
  121. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_volume_backups.py +0 -0
  122. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_volume_groups.py +0 -0
  123. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_volume_list.py +0 -0
  124. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_volume_qos.py +0 -0
  125. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_volume_snapshots.py +0 -0
  126. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_volume_transfers.py +0 -0
  127. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/get_volume_types.py +0 -0
  128. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/search_instances.py +0 -0
  129. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_alarms.py +0 -0
  130. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_compute_agents.py +0 -0
  131. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_domains.py +0 -0
  132. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_flavor.py +0 -0
  133. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_floating_ip.py +0 -0
  134. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_floating_ip_port_forwarding.py +0 -0
  135. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_heat_stack.py +0 -0
  136. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_identity_groups.py +0 -0
  137. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_image.py +0 -0
  138. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_image_members.py +0 -0
  139. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_image_metadata.py +0 -0
  140. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_image_visibility.py +0 -0
  141. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_instance.py +0 -0
  142. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_keypair.py +0 -0
  143. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_load_balancer.py +0 -0
  144. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_load_balancer_amphora.py +0 -0
  145. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_load_balancer_availability_zone.py +0 -0
  146. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_load_balancer_flavor.py +0 -0
  147. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_load_balancer_health_monitor.py +0 -0
  148. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_load_balancer_l7_policy.py +0 -0
  149. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_load_balancer_l7_rule.py +0 -0
  150. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_load_balancer_listener.py +0 -0
  151. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_load_balancer_pool.py +0 -0
  152. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_load_balancer_pool_member.py +0 -0
  153. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_load_balancer_quota.py +0 -0
  154. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_metrics.py +0 -0
  155. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_network_agents.py +0 -0
  156. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_network_ports.py +0 -0
  157. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_network_qos_policies.py +0 -0
  158. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_networks.py +0 -0
  159. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_project.py +0 -0
  160. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_quota.py +0 -0
  161. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_roles.py +0 -0
  162. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_routers.py +0 -0
  163. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_security_groups.py +0 -0
  164. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_server_backup.py +0 -0
  165. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_server_dump.py +0 -0
  166. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_server_fixed_ip.py +0 -0
  167. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_server_floating_ip.py +0 -0
  168. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_server_group.py +0 -0
  169. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_server_migration.py +0 -0
  170. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_server_network.py +0 -0
  171. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_server_properties.py +0 -0
  172. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_server_security_group.py +0 -0
  173. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_server_volume.py +0 -0
  174. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_service_logs.py +0 -0
  175. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_services.py +0 -0
  176. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_snapshot.py +0 -0
  177. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_subnets.py +0 -0
  178. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_users.py +0 -0
  179. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_volume.py +0 -0
  180. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_volume_backups.py +0 -0
  181. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_volume_groups.py +0 -0
  182. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_volume_qos.py +0 -0
  183. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops/tools/set_volume_types.py +0 -0
  184. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops.egg-info/dependency_links.txt +0 -0
  185. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops.egg-info/entry_points.txt +0 -0
  186. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops.egg-info/requires.txt +0 -0
  187. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/src/mcp_openstack_ops.egg-info/top_level.txt +0 -0
  188. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/test_compatibility.sh +0 -0
  189. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/test_project_isolation.py +0 -0
  190. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/tests/test_connection.py +0 -0
  191. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/tests/test_expanded_validation_fixes.py +0 -0
  192. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/tests/test_floating_ip.py +0 -0
  193. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/tests/test_instance_image.py +0 -0
  194. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/tests/test_live_regressions.py +0 -0
  195. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/tests/test_operational_tools.py +0 -0
  196. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/tests/test_publish_release.py +0 -0
  197. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/tests/test_release.py +0 -0
  198. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/tests/test_tool_registration.py +0 -0
  199. {mcp_openstack_ops-3.6.1 → mcp_openstack_ops-3.6.2}/uv.lock +0 -0
@@ -33,10 +33,12 @@ consistent with the resulting implementation and actual verification.
33
33
  Label targeted retests as partial; do not extrapolate them to the full toolset.
34
34
  Document polling limits and distinguish accepted requests from confirmed final
35
35
  resource states. Explain changes in test conditions that affect comparisons.
36
- - Keep dated reports as historical evidence and link the latest applicable
37
- report from README.md. Reports must state verification limits, observed
38
- failures, and cleanup results without exposing credentials, private endpoints,
39
- or sensitive resource data.
36
+ - Keep `docs/` for reusable user guidance only. Do not create or retain
37
+ issue-specific reports, dated test results, or evidence JSON in `docs/`, or
38
+ embed those records in usage guides. Report case-specific verification results,
39
+ limits, failures, and cleanup in chat unless the user explicitly requests a
40
+ separate artifact. Never expose credentials, private endpoints, or sensitive
41
+ resource data. Do not add report links to README.md.
40
42
  - Before completion, check summary arithmetic, percentages, tool/action names,
41
43
  Status/Notes, source identity, and evidence links for agreement. If README.ko.md
42
44
  exists, maintain equivalent information in both README files.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-openstack-ops
3
- Version: 3.6.1
3
+ Version: 3.6.2
4
4
  Summary: OpenStack operations automation MCP server
5
5
  Author-email: JungJungIn <call518@gmail.com>
6
6
  Requires-Python: >=3.12
@@ -42,7 +42,7 @@ Dynamic: license-file
42
42
  ## Features
43
43
 
44
44
  Experimental per-user remote connections are available for testing with the
45
- opt-in `--multi-user` mode. See the [phase 1 setup and validation guide](docs/multi-user-phase1.md)
45
+ opt-in `--multi-user` mode. See the [multi-user setup and usage guide](docs/multi-user-guide.md)
46
46
  for authentication, client limitations, and the test checklist. Administrator
47
47
  cross-project queries are outside this phase.
48
48
 
@@ -183,80 +183,12 @@ New consolidated `get_instance` tool replaces multiple separate tools:
183
183
 
184
184
  ## 📊 OpenStack CLI vs MCP Tools Mapping
185
185
 
186
- **Latest targeted validation — 2026-11-02:** working tree based on `6a36b6e`.
187
- See the [fixes and final retest report](docs/expanded-validation-fixes-2026-11-02.md)
188
- and [sanitized evidence](docs/expanded-validation-fixes-2026-11-02.json).
189
- The final executable paths were tested with FastMCP **3.4.10** from `uv.lock`,
190
- two ordinary-user projects, **20 VMs and 20 one-GiB volumes**. Post-test tool
191
- wording/prompt corrections are identified separately in the report's source
192
- fingerprints; Claude replay remains unverified.
193
-
194
- | Verification group | Item | Result |
195
- | --- | --- | --- |
196
- | Live tool checks | Unique tools retested in limited scenarios | **14/14 (100%)**, 0 failed/unverified within this scope |
197
- | Live tool checks | Registered inventory not repeated in this final run | **91 of 105** tools; historical evidence below is not a current full sweep |
198
- | Named live harness cases | Fixture, isolation, lifecycle and grouped load checks | **101/102**, one Cinder storage-permission fixture failure, 0 skipped |
199
- | Local unit tests | Locked environment, `python -m pytest -q tests` | **199/199 (100%)**, 0 failed/skipped; 21 added regressions |
200
- | Bounded load requests | Shared-server, two-project bursts | **14/14**, actual overlap up to 8 |
201
- | Bounded load requests | Same shared server, 120 seconds, four workers | **209/209**, median 2.03 s, p95 2.70 s, max 3.24 s |
202
- | Backup recovery | After operator corrected one NFS directory permission | **6/6 fresh backups available**, both reader MCP state checks passed |
203
- | Claude client | Minimal actual model API preflight | Blocked before tools: credit/balance error; no final-source Claude replay |
204
-
205
- Network creation now uses the backend's default MTU when omitted; automatic
206
- 1450 and explicit 1400 were verified. Both `set_volume` and `set_server_volume`
207
- attach/detach reached final states, with cross-project requests rejected. Both
208
- search wrappers now honor offset/case sensitivity and correct `has_more`.
209
- Default write restrictions remain in place. These successes do not certify all
210
- actions of those tools or all 105 registered tools.
211
-
212
- The Cinder fixture failure occurred through its API, independently of MCP. The
213
- operator corrected the failing directory's group-write permission; the original
214
- failure remains recorded alongside the successful targeted recovery. Actual
215
- Claude same-URL duplicate registration was not established as a product defect;
216
- single-entry/distinct-URL attempts also failed before tools. Restoring model API
217
- access is required for that controlled comparison.
218
-
219
- Earlier same-day results are consolidated in the final report's
220
- [sanitized evidence](docs/expanded-validation-fixes-2026-11-02.json), under
221
- `historical_evidence.earlier_runs`. The previous 33-tool classification and
222
- 41 actual Claude template attempts belong to the pre-fix source, not this
223
- final source. The complete 105-tool snapshot below is also historical.
224
-
225
- **Validation snapshot — 2026-10-30** (main working tree based on `dd98993`,
226
- with the uncommitted fixes described in the report):
227
-
228
- <table border="1" rules="cols">
229
- <thead>
230
- <tr><th>Verification type</th><th>Item</th><th>Result</th></tr>
231
- </thead>
232
- <tbody>
233
- <tr><td rowspan="5">Live tool checks</td><td>Registered tools invoked and classified</td><td><strong>105</strong></td></tr>
234
- <tr><td>Passed within the exercised live scenarios</td><td><strong>74</strong></td></tr>
235
- <tr><td>Implemented, live unverified: service/API unavailable</td><td><strong>28</strong></td></tr>
236
- <tr><td>Intentional capability limitations</td><td><strong>3</strong></td></tr>
237
- <tr><td>Reproduced code defects / state-check timeouts in the retest</td><td><strong>0 / 0</strong></td></tr>
238
- <tr><td>Local unit tests</td><td>Test cases in <code>tests/test_*.py</code></td><td><strong>160/160 (100%)</strong></td></tr>
239
- </tbody>
240
- </table>
241
-
242
- State polling allowed 180 seconds; soft reboot completed in 131.66 seconds
243
- (previously it exceeded the 90-second check). No reboot implementation change
244
- was needed.
245
-
246
- The 10 previously reproduced tool defects were corrected. The 28 unavailable
247
- paths are **not live-validated successes**: 24 Octavia tools, two Neutron QoS
248
- tools, one Aodh tool, and one Neutron port-forwarding tool. Each affected table
249
- row is marked **⚠️ Live unverified**. An absent tool/action is marked **❌ Not
250
- implemented** rather than presented as an available feature.
251
-
252
- ✅ means an implemented API path; it does not certify every action or backend.
253
- The live-pass count covers only the scenarios in the
254
- [latest retest report](docs/main-live-retest-2026-10-30.md), with
255
- [sanitized evidence](docs/main-live-retest-2026-10-30.json). API policy, asynchronous
256
- completion, production HTTPS/client compatibility, load, and guest I/O limits
257
- are stated there. All test resources were cleaned up; the final audit found zero
258
- remaining test resources across 24 categories. See also
259
- [API prerequisites and result semantics](#api-prerequisites-and-result-semantics).
186
+ ✅ denotes an implemented API path, not certification of every action or
187
+ OpenStack deployment. **⚠️ Live unverified** identifies paths without successful
188
+ live validation; **❌ Not implemented** identifies unavailable capabilities.
189
+ Service availability, permissions, and asynchronous completion affect results.
190
+ See [API prerequisites and result semantics](#api-prerequisites-and-result-semantics)
191
+ and the [multi-user setup guide](docs/multi-user-guide.md).
260
192
 
261
193
  **Detailed Mapping by Category**
262
194
 
@@ -302,7 +234,7 @@ remaining test resources across 24 categories. See also
302
234
  | `openstack server set` | `set_server_properties` (action="set") | ✅ | Server property setting |
303
235
  | `openstack server unset` | `set_server_properties` (action="unset") | ✅ | Server property unsetting |
304
236
  | `openstack server dump create` | `set_server_dump` | ❌ Unsupported | Returns an explicit unsupported result; no dump is created |
305
- | `openstack server event list` | `get_server_events` | ✅ | Server event tracking |
237
+ | `openstack server event list` | `get_server_events` | ✅ | Pass the server name or UUID via `instance_name`, not `server_id`; event visibility follows Nova policy |
306
238
  | `openstack server group list` | `get_server_groups` | ✅ | Server group listing |
307
239
  | `openstack server group create/delete` | `set_server_group` | ✅ | Server group management |
308
240
  | `openstack flavor list` | `set_flavor` (action="list") | ✅ | Requires modification tools to be enabled for registration |
@@ -542,7 +474,7 @@ remaining test resources across 24 categories. See also
542
474
 
543
475
  ### API prerequisites and result semantics
544
476
 
545
- The feature table marks implemented API paths, not verification against every OpenStack deployment. The management and query paths have local mocked API tests. Selected paths also passed live tests on a single-node Kolla Ansible deployment; see [integration validation](docs/integration-validation.md) for coverage and skipped operations. A missing service, extension, required microversion, or permission is an operation failure, not an empty successful result.
477
+ The feature table marks implemented API paths, not verification against every OpenStack deployment. Service and policy requirements must be checked in the target deployment. A missing service, extension, required microversion, or permission is an operation failure, not an empty successful result.
546
478
 
547
479
  - **Modification tools:** the MCP server registers `set_*` management tools only when `ALLOW_MODIFY_OPERATIONS=true`. Existing action guards also reject writes when disabled. Dedicated read-only `get_*` tools remain available. API authorization is enforced by the target cloud; agent, user, domain, type and QoS administration may require elevated OpenStack roles.
548
480
  - **Alarms:** `set_alarms` calls the Keystone catalog's `alarming` endpoint for the configured interface/region. It supports list/create/show/delete of project alarms and creates `gnocchi_resources_threshold` alarms. Aodh, Gnocchi, the specified resource and a collected metric are required. The default metric is `cpu_util`, which is not collected by every deployment. `metric`, `resource_type`, `aggregation_method`, `granularity`, `evaluation_periods`, and `alarm_actions` can be supplied. An empty action list creates an alarm without notifications. There is no simulation fallback.
@@ -744,7 +676,7 @@ unset OPENSTACK_MCP_TOKEN
744
676
  ```
745
677
 
746
678
  This Bearer configuration uses the server's configured OpenStack account. For
747
- experimental per-user authentication, see the [phase 1 guide](docs/multi-user-phase1.md).
679
+ experimental per-user authentication, see the [multi-user guide](docs/multi-user-guide.md).
748
680
  See also the [Claude Code MCP documentation](https://code.claude.com/docs/en/mcp).
749
681
 
750
682
  ## Server Configuration
@@ -24,7 +24,7 @@
24
24
  ## Features
25
25
 
26
26
  Experimental per-user remote connections are available for testing with the
27
- opt-in `--multi-user` mode. See the [phase 1 setup and validation guide](docs/multi-user-phase1.md)
27
+ opt-in `--multi-user` mode. See the [multi-user setup and usage guide](docs/multi-user-guide.md)
28
28
  for authentication, client limitations, and the test checklist. Administrator
29
29
  cross-project queries are outside this phase.
30
30
 
@@ -165,80 +165,12 @@ New consolidated `get_instance` tool replaces multiple separate tools:
165
165
 
166
166
  ## 📊 OpenStack CLI vs MCP Tools Mapping
167
167
 
168
- **Latest targeted validation — 2026-11-02:** working tree based on `6a36b6e`.
169
- See the [fixes and final retest report](docs/expanded-validation-fixes-2026-11-02.md)
170
- and [sanitized evidence](docs/expanded-validation-fixes-2026-11-02.json).
171
- The final executable paths were tested with FastMCP **3.4.10** from `uv.lock`,
172
- two ordinary-user projects, **20 VMs and 20 one-GiB volumes**. Post-test tool
173
- wording/prompt corrections are identified separately in the report's source
174
- fingerprints; Claude replay remains unverified.
175
-
176
- | Verification group | Item | Result |
177
- | --- | --- | --- |
178
- | Live tool checks | Unique tools retested in limited scenarios | **14/14 (100%)**, 0 failed/unverified within this scope |
179
- | Live tool checks | Registered inventory not repeated in this final run | **91 of 105** tools; historical evidence below is not a current full sweep |
180
- | Named live harness cases | Fixture, isolation, lifecycle and grouped load checks | **101/102**, one Cinder storage-permission fixture failure, 0 skipped |
181
- | Local unit tests | Locked environment, `python -m pytest -q tests` | **199/199 (100%)**, 0 failed/skipped; 21 added regressions |
182
- | Bounded load requests | Shared-server, two-project bursts | **14/14**, actual overlap up to 8 |
183
- | Bounded load requests | Same shared server, 120 seconds, four workers | **209/209**, median 2.03 s, p95 2.70 s, max 3.24 s |
184
- | Backup recovery | After operator corrected one NFS directory permission | **6/6 fresh backups available**, both reader MCP state checks passed |
185
- | Claude client | Minimal actual model API preflight | Blocked before tools: credit/balance error; no final-source Claude replay |
186
-
187
- Network creation now uses the backend's default MTU when omitted; automatic
188
- 1450 and explicit 1400 were verified. Both `set_volume` and `set_server_volume`
189
- attach/detach reached final states, with cross-project requests rejected. Both
190
- search wrappers now honor offset/case sensitivity and correct `has_more`.
191
- Default write restrictions remain in place. These successes do not certify all
192
- actions of those tools or all 105 registered tools.
193
-
194
- The Cinder fixture failure occurred through its API, independently of MCP. The
195
- operator corrected the failing directory's group-write permission; the original
196
- failure remains recorded alongside the successful targeted recovery. Actual
197
- Claude same-URL duplicate registration was not established as a product defect;
198
- single-entry/distinct-URL attempts also failed before tools. Restoring model API
199
- access is required for that controlled comparison.
200
-
201
- Earlier same-day results are consolidated in the final report's
202
- [sanitized evidence](docs/expanded-validation-fixes-2026-11-02.json), under
203
- `historical_evidence.earlier_runs`. The previous 33-tool classification and
204
- 41 actual Claude template attempts belong to the pre-fix source, not this
205
- final source. The complete 105-tool snapshot below is also historical.
206
-
207
- **Validation snapshot — 2026-10-30** (main working tree based on `dd98993`,
208
- with the uncommitted fixes described in the report):
209
-
210
- <table border="1" rules="cols">
211
- <thead>
212
- <tr><th>Verification type</th><th>Item</th><th>Result</th></tr>
213
- </thead>
214
- <tbody>
215
- <tr><td rowspan="5">Live tool checks</td><td>Registered tools invoked and classified</td><td><strong>105</strong></td></tr>
216
- <tr><td>Passed within the exercised live scenarios</td><td><strong>74</strong></td></tr>
217
- <tr><td>Implemented, live unverified: service/API unavailable</td><td><strong>28</strong></td></tr>
218
- <tr><td>Intentional capability limitations</td><td><strong>3</strong></td></tr>
219
- <tr><td>Reproduced code defects / state-check timeouts in the retest</td><td><strong>0 / 0</strong></td></tr>
220
- <tr><td>Local unit tests</td><td>Test cases in <code>tests/test_*.py</code></td><td><strong>160/160 (100%)</strong></td></tr>
221
- </tbody>
222
- </table>
223
-
224
- State polling allowed 180 seconds; soft reboot completed in 131.66 seconds
225
- (previously it exceeded the 90-second check). No reboot implementation change
226
- was needed.
227
-
228
- The 10 previously reproduced tool defects were corrected. The 28 unavailable
229
- paths are **not live-validated successes**: 24 Octavia tools, two Neutron QoS
230
- tools, one Aodh tool, and one Neutron port-forwarding tool. Each affected table
231
- row is marked **⚠️ Live unverified**. An absent tool/action is marked **❌ Not
232
- implemented** rather than presented as an available feature.
233
-
234
- ✅ means an implemented API path; it does not certify every action or backend.
235
- The live-pass count covers only the scenarios in the
236
- [latest retest report](docs/main-live-retest-2026-10-30.md), with
237
- [sanitized evidence](docs/main-live-retest-2026-10-30.json). API policy, asynchronous
238
- completion, production HTTPS/client compatibility, load, and guest I/O limits
239
- are stated there. All test resources were cleaned up; the final audit found zero
240
- remaining test resources across 24 categories. See also
241
- [API prerequisites and result semantics](#api-prerequisites-and-result-semantics).
168
+ ✅ denotes an implemented API path, not certification of every action or
169
+ OpenStack deployment. **⚠️ Live unverified** identifies paths without successful
170
+ live validation; **❌ Not implemented** identifies unavailable capabilities.
171
+ Service availability, permissions, and asynchronous completion affect results.
172
+ See [API prerequisites and result semantics](#api-prerequisites-and-result-semantics)
173
+ and the [multi-user setup guide](docs/multi-user-guide.md).
242
174
 
243
175
  **Detailed Mapping by Category**
244
176
 
@@ -284,7 +216,7 @@ remaining test resources across 24 categories. See also
284
216
  | `openstack server set` | `set_server_properties` (action="set") | ✅ | Server property setting |
285
217
  | `openstack server unset` | `set_server_properties` (action="unset") | ✅ | Server property unsetting |
286
218
  | `openstack server dump create` | `set_server_dump` | ❌ Unsupported | Returns an explicit unsupported result; no dump is created |
287
- | `openstack server event list` | `get_server_events` | ✅ | Server event tracking |
219
+ | `openstack server event list` | `get_server_events` | ✅ | Pass the server name or UUID via `instance_name`, not `server_id`; event visibility follows Nova policy |
288
220
  | `openstack server group list` | `get_server_groups` | ✅ | Server group listing |
289
221
  | `openstack server group create/delete` | `set_server_group` | ✅ | Server group management |
290
222
  | `openstack flavor list` | `set_flavor` (action="list") | ✅ | Requires modification tools to be enabled for registration |
@@ -524,7 +456,7 @@ remaining test resources across 24 categories. See also
524
456
 
525
457
  ### API prerequisites and result semantics
526
458
 
527
- The feature table marks implemented API paths, not verification against every OpenStack deployment. The management and query paths have local mocked API tests. Selected paths also passed live tests on a single-node Kolla Ansible deployment; see [integration validation](docs/integration-validation.md) for coverage and skipped operations. A missing service, extension, required microversion, or permission is an operation failure, not an empty successful result.
459
+ The feature table marks implemented API paths, not verification against every OpenStack deployment. Service and policy requirements must be checked in the target deployment. A missing service, extension, required microversion, or permission is an operation failure, not an empty successful result.
528
460
 
529
461
  - **Modification tools:** the MCP server registers `set_*` management tools only when `ALLOW_MODIFY_OPERATIONS=true`. Existing action guards also reject writes when disabled. Dedicated read-only `get_*` tools remain available. API authorization is enforced by the target cloud; agent, user, domain, type and QoS administration may require elevated OpenStack roles.
530
462
  - **Alarms:** `set_alarms` calls the Keystone catalog's `alarming` endpoint for the configured interface/region. It supports list/create/show/delete of project alarms and creates `gnocchi_resources_threshold` alarms. Aodh, Gnocchi, the specified resource and a collected metric are required. The default metric is `cpu_util`, which is not collected by every deployment. `metric`, `resource_type`, `aggregation_method`, `granularity`, `evaluation_periods`, and `alarm_actions` can be supplied. An empty action list creates an alarm without notifications. There is no simulation fallback.
@@ -726,7 +658,7 @@ unset OPENSTACK_MCP_TOKEN
726
658
  ```
727
659
 
728
660
  This Bearer configuration uses the server's configured OpenStack account. For
729
- experimental per-user authentication, see the [phase 1 guide](docs/multi-user-phase1.md).
661
+ experimental per-user authentication, see the [multi-user guide](docs/multi-user-guide.md).
730
662
  See also the [Claude Code MCP documentation](https://code.claude.com/docs/en/mcp).
731
663
 
732
664
  ## Server Configuration
@@ -1,10 +1,10 @@
1
- # Multi-user HTTP: phase 1 testing
1
+ # Multi-user HTTP setup and usage guide
2
2
 
3
- The server provides an opt-in, experimental remote mode for issue #73. It keeps
3
+ The server provides an opt-in, experimental multi-user HTTP mode. It keeps
4
4
  existing project ownership checks and the default write restriction. The normal
5
5
  single-account HTTP and stdio modes remain available without this option.
6
6
 
7
- ## Initial authentication approach
7
+ ## Authentication
8
8
 
9
9
  Clients send their own Keystone Application Credential ID and secret in two
10
10
  dedicated HTTP headers on **every request**. The server authenticates against
@@ -13,10 +13,9 @@ project-scoped connection. Authentication failure never falls back to the server
13
13
  environment account. `Authorization` is not forwarded to OpenStack; this is custom
14
14
  header authentication, not an OAuth server or Keystone token passthrough.
15
15
 
16
- Application Credentials are the initial method because they avoid LDAP passwords
16
+ Application Credentials avoid LDAP passwords
17
17
  and already specify a project and delegated roles. Raw Keystone tokens, browser
18
- login, project switching, and administrator cross-project access are not provided
19
- in phase 1. Use another Application Credential/client entry for another project.
18
+ login, project switching, and administrator cross-project access are not supported. Use another Application Credential/client entry for another project.
20
19
 
21
20
  The HTTP transport is stateless with JSON responses. Every HTTP request creates a
22
21
  fresh Keystone authentication and SDK connection; there is no authentication or
@@ -70,6 +69,26 @@ credential `.env` or `clouds.yaml`. `OS_USERNAME`, `OS_PASSWORD`, and
70
69
  and `REMOTE_SECRET_KEY`: the shared Bearer mode cannot be combined with this mode.
71
70
  DEBUG logging is rejected to avoid authentication wire dumps.
72
71
 
72
+ Unsupported OAuth metadata routes (`/.well-known/oauth-protected-resource`,
73
+ `/.well-known/oauth-authorization-server`, `/.well-known/openid-configuration`,
74
+ including their path suffixes) and `/register` return 404 without Keystone
75
+ authentication. This mode does not provide OAuth discovery or registration;
76
+ `/mcp` still requires both application-credential headers.
77
+
78
+ HTTP 400 responses from the MCP transport produce an INFO diagnostic with a
79
+ server-generated `request_id` and a fixed `reason` classification:
80
+ `invalid_json`, `invalid_jsonrpc`, `unsupported_protocol`, `missing_session_id`,
81
+ or `unclassified`. Request bodies, header values, and raw error messages are not
82
+ included in this diagnostic. Unknown, oversized, or non-JSON error responses
83
+ may remain unclassified. A 400 alone does not establish an authentication failure
84
+ or explain the reported first-connection behavior; correlate its request ID
85
+ with the client response before drawing a conclusion. A client may probe with a
86
+ newer protocol version, receive `unsupported_protocol`, and then negotiate a
87
+ supported version successfully. Check whether initialization and subsequent
88
+ requests succeed before treating that rejection as a connection failure. Do not
89
+ bypass protocol validation merely to suppress the initial 400 response.
90
+
91
+
73
92
  Expose `/mcp` through an HTTPS reverse proxy. Do not expose the plaintext backend
74
93
  port to clients. Configure the proxy to redact both credential headers and
75
94
  `Authorization`, avoid request/header dumps, and enforce rate and concurrency
@@ -134,7 +153,7 @@ Sources checked while designing this branch:
134
153
  - [Claude connector request-header limitations](https://claude.com/docs/connectors/custom/add-unlisted#authenticate-with-request-headers)
135
154
  - [Keystone Application Credentials](https://docs.openstack.org/keystone/latest/user/application_credentials.html)
136
155
 
137
- ## Validation checklist for the issue author
156
+ ## Deployment validation checklist
138
157
 
139
158
  Use disposable test projects and independently created credentials. Record client
140
159
  versions, service versions, and results without posting secrets or resource data.
@@ -146,7 +165,7 @@ versions, service versions, and results without posting secrets or resource data
146
165
  project's private resources. Public/shared resources remain governed by the
147
166
  existing checks and service policy. Project isolation is not ownership per user.
148
167
  3. Look up a known private resource ID from the other project: access must fail.
149
- Even an admin credential remains under the existing project checks in phase 1.
168
+ Even an admin credential remains subject to the same project ownership checks.
150
169
  4. Connect the same user with two separate project credentials/client entries;
151
170
  verify each entry sees only its intended project.
152
171
  5. Omit, invalidate, or duplicate either credential header. No tool must execute,
@@ -173,128 +192,3 @@ Automated tests cover authentication rejection/revalidation, concurrent contexts
173
192
  including synchronous tools, cleanup, default write gating, project checks, and
174
193
  legacy cache behavior. They do not establish actual Keystone revocation timing,
175
194
  service policy enforcement, or Claude client compatibility.
176
-
177
- ## Local cloud validation (2026-10-29)
178
-
179
- Real-cloud testing used two disposable projects, two non-admin users, and one
180
- private network per project. An additional reader-only Application Credential
181
- verified delegated role enforcement. Initial empty-list validation passed 36
182
- checks. Follow-up validation added one Cirros VM (`m1.tiny`: 1 vCPU, 512 MB RAM,
183
- 1 GB disk) and one empty 1 GB volume per project. All 66 recorded follow-up checks
184
- passed; the latest unit-test run passed 46 tests.
185
-
186
- The test used real Keystone, Nova, Neutron, and Cinder APIs through temporary
187
- loopback TLS proxies with certificate verification. The proxy-to-cluster leg was
188
- HTTP because the test cluster has no TLS on its API ports. MCP calls went through
189
- the actual FastMCP ASGI HTTP application using an HTTP test client; this was not a
190
- Claude Code or Desktop session and does not validate a production TLS deployment.
191
-
192
- Validated behavior:
193
-
194
- - Concurrent users retained their own project identity and private network view.
195
- - Lookup of the other project's private network ID returned 403/404.
196
- - Registered instance, network, and volume read tools returned only the expected
197
- project resources. Own-instance detail queries succeeded; SDK detail queries
198
- for the other project's VM and volume IDs returned 403/404.
199
- - Write tools were absent by default; a test-only SDK write probe with reader
200
- credentials was rejected with HTTP 403 by Neutron.
201
- - Missing, invalid, and deleted credentials were rejected with HTTP 401.
202
- - After credential deletion, the very next request was rejected. This observation
203
- is not a deployment-independent revocation SLA.
204
- - Captured application logs identified users and tools without any known test
205
- passwords, Application Credential IDs/secrets, or issued tokens appearing.
206
- - All test Application Credentials were deleted and both test users disabled.
207
- The two isolated projects and private networks were retained for follow-up.
208
- - Both VMs reached `ACTIVE`, and both volumes reached `available`. All four were
209
- deleted after testing; Nova instance/core/RAM and Cinder volume/GB quota usage
210
- and reservations returned to zero in both projects.
211
-
212
- Testing exposed and fixed Cinder's SDK service-name/version/project-URL setup and
213
- classification of Keystone's deleted-credential `NotFound` response as 401 rather
214
- than 503. The populated-resource follow-up required no additional application
215
- changes. Claude Desktop/IDE, sustained load, guest networking/SSH, volume
216
- attachment/I/O, and a complete production HTTPS path remain unverified.
217
-
218
- ## Actual Claude Code validation (2026-10-29)
219
-
220
- Claude Code 2.1.312 was used as the real MCP client, not an ASGI test client.
221
- Two isolated Claude configuration directories registered the server with
222
- `claude mcp add-json --scope user`. The server ran on a real HTTPS TCP listener
223
- with certificate verification; the temporary cloud-side TLS proxies described
224
- above remained necessary. No tools or OpenStack responses were mocked.
225
-
226
- Both clients executed the request "Show me the overall cluster status" through
227
- the actual configured Claude API. Initialization reported the user-scoped MCP
228
- server as `connected`; CLI stream events and server audit logs confirmed actual
229
- calls to registered service-status, monitoring, instance, network, and volume
230
- tools. A second request for each user's named private network confirmed that
231
- the actual client returned its own network ID rather than the other project's.
232
- All 28 connection/isolation/cleanup checks passed. Temporary registrations were
233
- removed, credentials deleted, and test users disabled afterward. Original Claude
234
- configuration was left unchanged; test credentials were not found in client
235
- configuration files or captured server logs.
236
-
237
- **Connection validation is not a complete status-report accuracy pass.** The
238
- real prompt exposed existing reporting defects outside the connection layer:
239
-
240
- - `functions.get_service_status` omits some services after permission failures
241
- and uses a fixed "skipped" Heat entry without actually checking Heat.
242
- - Compute/volume availability zones read a nonexistent `available` attribute
243
- rather than the SDK's `state['available']`, incorrectly defaulting to false.
244
- - Resource-monitoring capacity zeros cannot establish physical capacity when
245
- hypervisor access is denied. A project-scoped user cannot assess global health.
246
-
247
- These findings were identified during validation and have not been repaired in
248
- this test step. Do not treat the model's successful completion or its availability
249
- summary as proof that the whole cluster is healthy or unavailable.
250
-
251
- ## Ordinary-user Claude Code queries (2026-10-29)
252
-
253
- Administrator-only API denials are expected for ordinary users and are not a
254
- phase-1 authentication/connection failure. Each of the two real, registered
255
- Claude Code clients therefore executed these ordinary project requests:
256
-
257
- | Request | Actual tool | Observed result for both users |
258
- | --- | --- | --- |
259
- | List all instances in the project | `get_instance` | Empty after VM cleanup |
260
- | Show all networks and their subnets | `get_network_details` | Own private network and shared external network; no other test project's private network |
261
- | List all volumes and their status | `get_volume_list` | Empty after volume cleanup |
262
-
263
- All six actual Claude requests completed, and all 52 recorded connection,
264
- tool-execution, isolation, credential/logging, and cleanup checks passed. Own
265
- fixture networks have no subnets because none were created. Missing subnet
266
- details for a shared network do not establish that the network has no subnets.
267
- The earlier populated VM/volume test remains the evidence for nonempty resource
268
- isolation. Test registrations and credentials were removed and users disabled.
269
-
270
- These results validate the phase-1 project-user workflow separately from global
271
- administrator reporting. They do not certify every legacy reporting field: an
272
- optional `get_floating_ip_pools` call exposed an existing placeholder calculation
273
- of 100 IPs per allocation pool. That is not a measured pool capacity and was not
274
- counted as a verified result. The status/AZ reporting findings above also remain.
275
-
276
- ## Default WSL Claude configuration validation (2026-10-29)
277
-
278
- A further test used the actual default WSL Claude user configuration at
279
- `/root/.claude.json`, without a `CLAUDE_CONFIG_DIR` override or `--mcp-config`.
280
- `claude mcp add-json --scope user` registered `openstack73-a` and `openstack73-b`
281
- sequentially. Plain `claude mcp list` confirmed `Connected`; an independent plain
282
- CLI invocation also confirmed the active registration. Each registration was
283
- kept visible briefly for inspection before executing the three project queries.
284
-
285
- All six actual Claude queries and all 57 recorded checks passed, including
286
- correct server selection, real tool results, private-network isolation, and
287
- cleanup. These registrations used the real server on WSL-only HTTP loopback;
288
- the cloud-side TLS proxies remained as above. A same-user, permission-restricted
289
- Unix-socket helper supplied credential headers from memory, so no credential
290
- values were stored in the normal user registration or command arguments.
291
-
292
- The initial attempt with both entries simultaneously present did not validate
293
- both clients: one remained `pending`. The successful default-configuration test
294
- therefore establishes sequential registrations, not simultaneous same-profile
295
- multi-entry support. Earlier simultaneous-client tests used separate profiles.
296
-
297
- Only the test registrations were removed afterward. Existing MCP registrations
298
- were preserved, test credentials deleted, and test users disabled. The temporary
299
- helper/server stopped after the test, so saved commands are an execution record,
300
- not sufficient to reconnect without restarting the test infrastructure.
@@ -913,4 +913,4 @@ This approach provides **comprehensive 360-degree cluster visibility** with infr
913
913
  - `get_heat_stack_details`: `section` is resources/events/template/outputs.
914
914
  - `set_service_logs(action="show")` and `set_metrics(action="show")` are unavailable without additional backend implementation. Never claim to have retrieved logs or telemetry samples from metadata-only results.
915
915
 
916
- API paths have local mocked tests, and selected paths passed single-node Kolla Ansible integration checks. See docs/integration-validation.md for coverage: successful Aodh/Neutron QoS lifecycles and live network-agent state changes remain unverified. Check returned errors and partial flags; never describe an accepted asynchronous request as a completed operation. Usage date bounds are UTC midnight, start inclusive/end exclusive. Missing physical capacity is null, not zero. Physical capacity and project allocations have different scopes and must not be divided into a utilization rate.
916
+ Confirm service availability and permissions in the target deployment before attempting Aodh/Neutron QoS operations or network-agent state changes. Check returned errors and partial flags; never describe an accepted asynchronous request as a completed operation. Usage date bounds are UTC midnight, start inclusive/end exclusive. Missing physical capacity is null, not zero. Physical capacity and project allocations have different scopes and must not be divided into a utilization rate.
@@ -14,7 +14,11 @@ async def get_server_events(
14
14
  limit: int = 50
15
15
  ) -> str:
16
16
  """
17
- Get recent events for a specific server
17
+ Get recent events for a server by name or UUID.
18
+
19
+ Pass either value using instance_name, for example
20
+ get_server_events(instance_name="<server UUID>"). There is no server_id
21
+ parameter; do not use server_id or instance_id as argument names.
18
22
 
19
23
  Args:
20
24
  instance_name: Name or ID of the server instance
@@ -1,6 +1,7 @@
1
1
  """Request-local Application Credential authentication for remote clients."""
2
2
 
3
3
  import asyncio
4
+ import json
4
5
  import logging
5
6
  import os
6
7
  from contextvars import ContextVar
@@ -214,6 +215,26 @@ def authenticate(credential_id: str, secret: str) -> RequestIdentity:
214
215
  raise
215
216
 
216
217
 
218
+ def _bad_request_reason(body: bytes) -> str:
219
+ """Classify SDK rejections without exposing response text or request values."""
220
+ try:
221
+ payload = json.loads(body)
222
+ except (ValueError, RecursionError):
223
+ return "unclassified"
224
+ error = payload.get("error") if isinstance(payload, dict) else None
225
+ message = error.get("message") if isinstance(error, dict) else None
226
+ if isinstance(message, str):
227
+ for prefix, reason in (
228
+ ("Parse error:", "invalid_json"),
229
+ ("Validation error:", "invalid_jsonrpc"),
230
+ ("Bad Request: Unsupported protocol version:", "unsupported_protocol"),
231
+ ("Bad Request: Missing session ID", "missing_session_id"),
232
+ ):
233
+ if message.startswith(prefix):
234
+ return reason
235
+ return "unclassified"
236
+
237
+
217
238
  class UserConnectionMiddleware:
218
239
  """Authenticate every HTTP request and close its connection after delivery.
219
240
 
@@ -228,6 +249,22 @@ class UserConnectionMiddleware:
228
249
  if scope["type"] != "http":
229
250
  await self.app(scope, receive, send)
230
251
  return
252
+ # This mode uses application credentials, not OAuth. Never forward these
253
+ # unsupported discovery/registration routes to an authenticated handler.
254
+ path = scope.get("path", "")
255
+ discovery_paths = (
256
+ "/.well-known/oauth-protected-resource",
257
+ "/.well-known/oauth-authorization-server",
258
+ "/.well-known/openid-configuration",
259
+ )
260
+ if path in ("/register", "/register/") or any(
261
+ path == base or path.startswith(base + "/")
262
+ for base in discovery_paths
263
+ ):
264
+ await JSONResponse({"error": "Not found"}, status_code=404)(
265
+ scope, receive, send
266
+ )
267
+ return
231
268
  headers = Headers(scope=scope)
232
269
  ids = headers.getlist("x-openstack-application-credential-id")
233
270
  secrets = headers.getlist("x-openstack-application-credential-secret")
@@ -283,11 +320,23 @@ class UserConnectionMiddleware:
283
320
  (perf_counter() - started) * 1000,
284
321
  )
285
322
  status = 500
323
+ rejection_body = bytearray()
286
324
 
287
325
  async def audit_send(message: Message) -> None:
288
326
  nonlocal status
289
327
  if message["type"] == "http.response.start":
290
328
  status = message["status"]
329
+ elif status == 400 and message["type"] == "http.response.body":
330
+ # Bound diagnostic memory and never consume or log request bodies.
331
+ rejection_body.extend(
332
+ message.get("body", b"")[:8192 - len(rejection_body)]
333
+ )
334
+ if not message.get("more_body", False):
335
+ logger.info(
336
+ "OpenStack transport rejected request_id=%s "
337
+ "http_status=400 reason=%s",
338
+ request_id, _bad_request_reason(bytes(rejection_body)),
339
+ )
291
340
  await send(message)
292
341
 
293
342
  try: