nextmv 1.2.2.dev0__tar.gz → 1.2.3.dev0__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 (313) hide show
  1. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/.gitignore +3 -0
  2. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/PKG-INFO +7 -1
  3. nextmv-1.2.3.dev0/nextmv/__about__.py +1 -0
  4. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/main.py +3 -1
  5. nextmv-1.2.3.dev0/nextmv/cli/mcp/__init__.py +26 -0
  6. nextmv-1.2.3.dev0/nextmv/cli/mcp/serve.py +76 -0
  7. nextmv-1.2.3.dev0/nextmv/cli/mcp/server.py +100 -0
  8. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/__init__.py +1 -0
  9. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/_helpers.py +87 -0
  10. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/acceptance.py +107 -0
  11. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/account.py +47 -0
  12. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/app.py +141 -0
  13. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/batch.py +107 -0
  14. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/community.py +45 -0
  15. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/ensemble.py +207 -0
  16. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/input_set.py +130 -0
  17. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/instance.py +128 -0
  18. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/local.py +423 -0
  19. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/managed_input.py +103 -0
  20. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/profile.py +81 -0
  21. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/run.py +235 -0
  22. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/scenario.py +370 -0
  23. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/secrets.py +96 -0
  24. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/shadow.py +145 -0
  25. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/sso.py +29 -0
  26. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/switchback.py +158 -0
  27. nextmv-1.2.3.dev0/nextmv/cli/mcp/tools/version.py +106 -0
  28. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_run.py +3 -3
  29. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/batch_experiment.py +2 -0
  30. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/pyproject.toml +9 -0
  31. nextmv-1.2.3.dev0/tests/cli/test_mcp.py +933 -0
  32. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/uv.lock +597 -303
  33. nextmv-1.2.2.dev0/nextmv/__about__.py +0 -1
  34. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/.python-version +0 -0
  35. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/CONTRIBUTING.md +0 -0
  36. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/LICENSE +0 -0
  37. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/README.md +0 -0
  38. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/__entrypoint__.py +0 -0
  39. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/__init__.py +0 -0
  40. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/_serialization.py +0 -0
  41. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/base_model.py +0 -0
  42. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/__init__.py +0 -0
  43. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/__init__.py +0 -0
  44. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/acceptance/__init__.py +0 -0
  45. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/acceptance/create.py +0 -0
  46. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/acceptance/delete.py +0 -0
  47. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/acceptance/get.py +0 -0
  48. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/acceptance/list.py +0 -0
  49. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/acceptance/update.py +0 -0
  50. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/account/__init__.py +0 -0
  51. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/account/create.py +0 -0
  52. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/account/delete.py +0 -0
  53. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/account/get.py +0 -0
  54. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/account/update.py +0 -0
  55. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/app/__init__.py +0 -0
  56. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/app/create.py +0 -0
  57. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/app/delete.py +0 -0
  58. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/app/exists.py +0 -0
  59. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/app/get.py +0 -0
  60. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/app/list.py +0 -0
  61. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/app/push.py +0 -0
  62. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/app/update.py +0 -0
  63. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/batch/__init__.py +0 -0
  64. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/batch/create.py +0 -0
  65. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/batch/delete.py +0 -0
  66. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/batch/get.py +0 -0
  67. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/batch/list.py +0 -0
  68. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/batch/metadata.py +0 -0
  69. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/batch/update.py +0 -0
  70. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/data/__init__.py +0 -0
  71. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/data/upload.py +0 -0
  72. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/ensemble/__init__.py +0 -0
  73. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/ensemble/create.py +0 -0
  74. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/ensemble/delete.py +0 -0
  75. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/ensemble/get.py +0 -0
  76. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/ensemble/list.py +0 -0
  77. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/ensemble/update.py +0 -0
  78. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/input_set/__init__.py +0 -0
  79. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/input_set/create.py +0 -0
  80. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/input_set/delete.py +0 -0
  81. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/input_set/get.py +0 -0
  82. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/input_set/list.py +0 -0
  83. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/input_set/update.py +0 -0
  84. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/instance/__init__.py +0 -0
  85. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/instance/create.py +0 -0
  86. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/instance/delete.py +0 -0
  87. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/instance/exists.py +0 -0
  88. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/instance/get.py +0 -0
  89. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/instance/list.py +0 -0
  90. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/instance/update.py +0 -0
  91. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/managed_input/__init__.py +0 -0
  92. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/managed_input/create.py +0 -0
  93. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/managed_input/delete.py +0 -0
  94. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/managed_input/get.py +0 -0
  95. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/managed_input/list.py +0 -0
  96. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/managed_input/update.py +0 -0
  97. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/__init__.py +0 -0
  98. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/app/__init__.py +0 -0
  99. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/app/create.py +0 -0
  100. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/app/get.py +0 -0
  101. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/app/list.py +0 -0
  102. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/app/update.py +0 -0
  103. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/subscription/__init__.py +0 -0
  104. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/subscription/create.py +0 -0
  105. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/subscription/delete.py +0 -0
  106. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/subscription/get.py +0 -0
  107. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/subscription/list.py +0 -0
  108. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/version/__init__.py +0 -0
  109. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/version/create.py +0 -0
  110. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/version/get.py +0 -0
  111. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/version/list.py +0 -0
  112. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/marketplace/version/update.py +0 -0
  113. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/run/__init__.py +0 -0
  114. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/run/cancel.py +0 -0
  115. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/run/create.py +0 -0
  116. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/run/get.py +0 -0
  117. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/run/input.py +0 -0
  118. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/run/list.py +0 -0
  119. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/run/logs.py +0 -0
  120. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/run/metadata.py +0 -0
  121. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/run/track.py +0 -0
  122. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/scenario/__init__.py +0 -0
  123. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/scenario/create.py +0 -0
  124. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/scenario/delete.py +0 -0
  125. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/scenario/get.py +0 -0
  126. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/scenario/list.py +0 -0
  127. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/scenario/metadata.py +0 -0
  128. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/scenario/update.py +0 -0
  129. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/secrets/__init__.py +0 -0
  130. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/secrets/create.py +0 -0
  131. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/secrets/delete.py +0 -0
  132. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/secrets/get.py +0 -0
  133. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/secrets/list.py +0 -0
  134. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/secrets/update.py +0 -0
  135. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/shadow/__init__.py +0 -0
  136. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/shadow/create.py +0 -0
  137. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/shadow/delete.py +0 -0
  138. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/shadow/get.py +0 -0
  139. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/shadow/list.py +0 -0
  140. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/shadow/metadata.py +0 -0
  141. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/shadow/start.py +0 -0
  142. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/shadow/stop.py +0 -0
  143. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/shadow/update.py +0 -0
  144. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/sso/__init__.py +0 -0
  145. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/sso/create.py +0 -0
  146. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/sso/delete.py +0 -0
  147. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/sso/disable.py +0 -0
  148. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/sso/domain/__init__.py +0 -0
  149. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/sso/domain/delete.py +0 -0
  150. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/sso/enable.py +0 -0
  151. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/sso/get.py +0 -0
  152. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/sso/update.py +0 -0
  153. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/switchback/__init__.py +0 -0
  154. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/switchback/create.py +0 -0
  155. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/switchback/delete.py +0 -0
  156. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/switchback/get.py +0 -0
  157. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/switchback/list.py +0 -0
  158. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/switchback/metadata.py +0 -0
  159. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/switchback/start.py +0 -0
  160. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/switchback/stop.py +0 -0
  161. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/switchback/update.py +0 -0
  162. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/upload/__init__.py +0 -0
  163. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/upload/create.py +0 -0
  164. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/version/__init__.py +0 -0
  165. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/version/create.py +0 -0
  166. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/version/delete.py +0 -0
  167. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/version/exists.py +0 -0
  168. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/version/get.py +0 -0
  169. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/version/list.py +0 -0
  170. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/cloud/version/update.py +0 -0
  171. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/community/__init__.py +0 -0
  172. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/community/clone.py +0 -0
  173. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/community/list.py +0 -0
  174. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/configuration/__init__.py +0 -0
  175. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/configuration/config.py +0 -0
  176. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/configuration/create.py +0 -0
  177. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/configuration/delete.py +0 -0
  178. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/configuration/list.py +0 -0
  179. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/__init__.py +0 -0
  180. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/app/__init__.py +0 -0
  181. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/app/delete.py +0 -0
  182. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/app/get.py +0 -0
  183. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/app/list.py +0 -0
  184. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/app/register.py +0 -0
  185. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/app/registered.py +0 -0
  186. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/app/sync.py +0 -0
  187. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/app/update.py +0 -0
  188. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/run/__init__.py +0 -0
  189. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/run/create.py +0 -0
  190. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/run/get.py +0 -0
  191. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/run/input.py +0 -0
  192. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/run/list.py +0 -0
  193. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/run/logs.py +0 -0
  194. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/run/metadata.py +0 -0
  195. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/local/run/visuals.py +0 -0
  196. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/manifest/__init__.py +0 -0
  197. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/manifest/init.py +0 -0
  198. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/manifest/validate.py +0 -0
  199. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/message.py +0 -0
  200. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/options.py +0 -0
  201. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cli/version.py +0 -0
  202. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/__init__.py +0 -0
  203. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/acceptance_test.py +0 -0
  204. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/account.py +0 -0
  205. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/__init__.py +0 -0
  206. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_acceptance.py +0 -0
  207. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_batch_scenario.py +0 -0
  208. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_ensemble.py +0 -0
  209. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_input_set.py +0 -0
  210. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_instance.py +0 -0
  211. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_managed_input.py +0 -0
  212. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_secrets.py +0 -0
  213. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_shadow.py +0 -0
  214. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_switchback.py +0 -0
  215. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_utils.py +0 -0
  216. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/application/_version.py +0 -0
  217. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/assets.py +0 -0
  218. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/client.py +0 -0
  219. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/community.py +0 -0
  220. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/ensemble.py +0 -0
  221. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/input_set.py +0 -0
  222. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/instance.py +0 -0
  223. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/integration.py +0 -0
  224. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/marketplace.py +0 -0
  225. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/package.py +0 -0
  226. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/scenario.py +0 -0
  227. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/secrets.py +0 -0
  228. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/shadow.py +0 -0
  229. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/sso.py +0 -0
  230. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/switchback.py +0 -0
  231. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/url.py +0 -0
  232. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/cloud/version.py +0 -0
  233. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/content_format.py +0 -0
  234. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/default_app/.gitignore +0 -0
  235. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/default_app/README.md +0 -0
  236. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/default_app/app.yaml +0 -0
  237. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/default_app/input.json +0 -0
  238. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/default_app/main.py +0 -0
  239. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/default_app/requirements.txt +0 -0
  240. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/default_app/src/__init__.py +0 -0
  241. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/default_app/src/visuals.py +0 -0
  242. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/deprecated.py +0 -0
  243. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/input.py +0 -0
  244. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/local/__init__.py +0 -0
  245. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/local/application.py +0 -0
  246. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/local/executor.py +0 -0
  247. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/local/geojson_handler.py +0 -0
  248. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/local/local.py +0 -0
  249. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/local/plotly_handler.py +0 -0
  250. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/local/registry.py +0 -0
  251. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/local/runner.py +0 -0
  252. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/logger.py +0 -0
  253. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/manifest.py +0 -0
  254. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/model.py +0 -0
  255. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/options.py +0 -0
  256. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/output.py +0 -0
  257. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/polling.py +0 -0
  258. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/run.py +0 -0
  259. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/safe.py +0 -0
  260. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/status.py +0 -0
  261. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/templates/binary_json_app.yaml +0 -0
  262. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/templates/binary_multi-file_app.yaml +0 -0
  263. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/templates/go_json_app.yaml +0 -0
  264. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/templates/go_multi-file_app.yaml +0 -0
  265. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/templates/java_json_app.yaml +0 -0
  266. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/templates/java_multi-file_app.yaml +0 -0
  267. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/templates/python_json_app.yaml +0 -0
  268. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/nextmv/templates/python_multi-file_app.yaml +0 -0
  269. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/__init__.py +0 -0
  270. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/cli/__init__.py +0 -0
  271. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/cli/test_configuration.py +0 -0
  272. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/cli/test_main.py +0 -0
  273. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/cli/test_version.py +0 -0
  274. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/cloud/__init__.py +0 -0
  275. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/cloud/app.yaml +0 -0
  276. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/cloud/test_client.py +0 -0
  277. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/cloud/test_instance.py +0 -0
  278. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/cloud/test_package.py +0 -0
  279. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/cloud/test_scenario.py +0 -0
  280. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/integration/__init__.py +0 -0
  281. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/integration/cloud/__init__.py +0 -0
  282. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/integration/cloud/test_integration_cloud.py +0 -0
  283. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/integration/cloud/test_integration_marketplace.py +0 -0
  284. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/local/__init__.py +0 -0
  285. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/local/test_application.py +0 -0
  286. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/local/test_executor.py +0 -0
  287. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/local/test_registry.py +0 -0
  288. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/local/test_runner.py +0 -0
  289. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/scripts/__init__.py +0 -0
  290. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/scripts/options1.py +0 -0
  291. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/scripts/options2.py +0 -0
  292. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/scripts/options3.py +0 -0
  293. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/scripts/options4.py +0 -0
  294. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/scripts/options5.py +0 -0
  295. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/scripts/options6.py +0 -0
  296. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/scripts/options7.py +0 -0
  297. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_base_model.py +0 -0
  298. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_entrypoint/__init__.py +0 -0
  299. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_entrypoint/test_entrypoint.py +0 -0
  300. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_input.py +0 -0
  301. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_inputs/test_data.csv +0 -0
  302. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_inputs/test_data.json +0 -0
  303. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_inputs/test_data.txt +0 -0
  304. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_logger.py +0 -0
  305. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_manifest.py +0 -0
  306. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_model.py +0 -0
  307. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_options.py +0 -0
  308. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_output.py +0 -0
  309. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_polling.py +0 -0
  310. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_run.py +0 -0
  311. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_safe.py +0 -0
  312. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_serialization.py +0 -0
  313. {nextmv-1.2.2.dev0 → nextmv-1.2.3.dev0}/tests/test_version.py +0 -0
@@ -163,3 +163,6 @@ cython_debug/
163
163
 
164
164
  # Documentation stuff
165
165
  site/
166
+
167
+ scratch
168
+ .claude
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextmv
3
- Version: 1.2.2.dev0
3
+ Version: 1.2.3.dev0
4
4
  Summary: The all-purpose Python SDK for Nextmv
5
5
  Project-URL: Homepage, https://www.nextmv.io
6
6
  Project-URL: Documentation, https://nextmv-py.docs.nextmv.io/en/latest/nextmv/
@@ -227,6 +227,12 @@ Requires-Dist: questionary>=2.1.1
227
227
  Requires-Dist: requests>=2.31.0
228
228
  Requires-Dist: typer>=0.20.1
229
229
  Requires-Dist: urllib3>=2.1.0
230
+ Provides-Extra: all
231
+ Requires-Dist: folium>=0.20.0; extra == 'all'
232
+ Requires-Dist: mcp[cli]>=1.0; extra == 'all'
233
+ Requires-Dist: plotly>=6.0.1; extra == 'all'
234
+ Provides-Extra: mcp
235
+ Requires-Dist: mcp[cli]>=1.0; extra == 'mcp'
230
236
  Provides-Extra: notebook
231
237
  Requires-Dist: mlflow>=3.9.0; extra == 'notebook'
232
238
  Description-Content-Type: text/markdown
@@ -0,0 +1 @@
1
+ __version__ = "v1.2.3.dev0"
@@ -26,6 +26,7 @@ from nextmv.cli.configuration import app as configuration_app
26
26
  from nextmv.cli.configuration.config import CONFIG_DIR, GO_CLI_PATH, load_config
27
27
  from nextmv.cli.local import app as local_app
28
28
  from nextmv.cli.manifest import app as manifest_app
29
+ from nextmv.cli.mcp import app as mcp_app
29
30
  from nextmv.cli.message import confirmation, error, info, success, warning
30
31
  from nextmv.cli.version import app as version_app
31
32
  from nextmv.cli.version import version_callback
@@ -51,6 +52,7 @@ app.add_typer(community_app, name="community")
51
52
  app.add_typer(configuration_app, name="configuration")
52
53
  app.add_typer(local_app, name="local")
53
54
  app.add_typer(manifest_app, name="manifest")
55
+ app.add_typer(mcp_app, name="mcp")
54
56
  app.add_typer(version_app)
55
57
 
56
58
 
@@ -77,7 +79,7 @@ def callback(
77
79
  return
78
80
 
79
81
  # Skip checks for certain commands.
80
- ignored_commands = {"configuration", "version"}
82
+ ignored_commands = {"configuration", "mcp", "version"}
81
83
  if ctx.invoked_subcommand in ignored_commands:
82
84
  return
83
85
 
@@ -0,0 +1,26 @@
1
+ """MCP (Model Context Protocol) server for the Nextmv CLI."""
2
+
3
+ import typer
4
+
5
+ from nextmv.cli.mcp.serve import app as serve_app
6
+
7
+ # Set up subcommand application.
8
+ app = typer.Typer()
9
+ app.add_typer(serve_app)
10
+
11
+
12
+ @app.callback()
13
+ def callback() -> None:
14
+ """
15
+ Model Context Protocol (MCP) server for LLM integrations.
16
+
17
+ Start an MCP server so that any MCP-compatible client (Claude Code,
18
+ Cursor, VS Code, etc.) can interact with Nextmv Cloud through natural
19
+ language.
20
+
21
+ [bold][underline]Quick start[/underline][/bold]
22
+
23
+ - Register with Claude Code.
24
+ $ [dim]claude mcp add nextmv -- nextmv mcp serve[/dim]
25
+ """
26
+ pass
@@ -0,0 +1,76 @@
1
+ """MCP server command for the Nextmv CLI."""
2
+
3
+ from typing import Annotated
4
+
5
+ import typer
6
+
7
+ from nextmv.cli.message import error
8
+
9
+ # Set up subcommand application.
10
+ app = typer.Typer()
11
+
12
+
13
+ @app.command()
14
+ def serve(
15
+ port: Annotated[
16
+ int,
17
+ typer.Option(
18
+ "--port",
19
+ help="Port for the HTTP transport.",
20
+ metavar="PORT",
21
+ ),
22
+ ] = 8080,
23
+ transport: Annotated[
24
+ str,
25
+ typer.Option(
26
+ "--transport",
27
+ "-t",
28
+ help="Transport protocol. "
29
+ "Allowed values: [magenta]stdio[/magenta], [magenta]streamable-http[/magenta].",
30
+ metavar="TRANSPORT",
31
+ ),
32
+ ] = "stdio",
33
+ ) -> None:
34
+ """
35
+ Start the Nextmv MCP server.
36
+
37
+ The MCP server exposes Nextmv Cloud functionality as tools that any
38
+ MCP-compatible client can use. The default transport is
39
+ [magenta]stdio[/magenta], which is what Claude Code, Cursor, and most
40
+ local clients expect.
41
+
42
+ Requires the [magenta]mcp[/magenta] optional dependency. Install with:
43
+ [code]pip install 'nextmv[mcp]'[/code]
44
+
45
+ [bold][underline]Examples[/underline][/bold]
46
+
47
+ - Start the MCP server with stdio transport (default).
48
+ $ [dim]nextmv mcp serve[/dim]
49
+
50
+ - Start the MCP server with HTTP transport on port 9090.
51
+ $ [dim]nextmv mcp serve --transport streamable-http --port 9090[/dim]
52
+
53
+ - Register with Claude Code.
54
+ $ [dim]claude mcp add nextmv -- nextmv mcp serve[/dim]
55
+ """
56
+
57
+ try:
58
+ from nextmv.cli.mcp.server import create_server
59
+ except ImportError:
60
+ error(
61
+ "MCP support requires the [magenta]mcp[/magenta] package. "
62
+ "Install with: [code]pip install 'nextmv[mcp]'[/code]"
63
+ )
64
+ return # unreachable, error() raises
65
+
66
+ server = create_server()
67
+
68
+ if transport == "stdio":
69
+ server.run(transport="stdio")
70
+ elif transport in ("http", "streamable-http"):
71
+ server.run(transport="streamable-http", port=port)
72
+ else:
73
+ error(
74
+ f"Unknown transport [magenta]{transport}[/magenta]. "
75
+ "Allowed values are: [magenta]stdio[/magenta], [magenta]streamable-http[/magenta]."
76
+ )
@@ -0,0 +1,100 @@
1
+ """Nextmv MCP server definition.
2
+
3
+ This module is the public entry point for the MCP server. It delegates
4
+ tool registration to domain-specific submodules under ``tools/`` and
5
+ re-exports shared helpers so that existing imports continue to work.
6
+ """
7
+
8
+ from mcp.server.fastmcp import FastMCP
9
+
10
+ # Import tool registration submodules.
11
+ from nextmv.cli.mcp.tools import (
12
+ acceptance,
13
+ account,
14
+ app,
15
+ batch,
16
+ community,
17
+ ensemble,
18
+ input_set,
19
+ instance,
20
+ local,
21
+ managed_input,
22
+ profile,
23
+ run,
24
+ scenario,
25
+ secrets,
26
+ shadow,
27
+ sso,
28
+ switchback,
29
+ version,
30
+ )
31
+
32
+ # Re-export helpers for backward compatibility — tests and external code
33
+ # may import these directly from ``nextmv.cli.mcp.server``.
34
+ from nextmv.cli.mcp.tools._helpers import ( # noqa: F401
35
+ _current_profile,
36
+ _get_app,
37
+ _get_client,
38
+ _get_local_app,
39
+ _mask_key,
40
+ _save_to_file,
41
+ )
42
+
43
+ # Re-export SDK names that tests patch on this module.
44
+ from nextmv.cloud import list_applications # noqa: F401
45
+
46
+
47
+ def create_server() -> FastMCP:
48
+ """Create and return the Nextmv MCP server."""
49
+
50
+ mcp = FastMCP(
51
+ "nextmv",
52
+ json_response=True,
53
+ instructions=(
54
+ "Nextmv is a platform for deploying and managing decision "
55
+ "models (optimization, routing, scheduling, etc.). Use these "
56
+ "tools to interact with Nextmv Cloud apps: list apps, submit "
57
+ "runs, check results, manage versions/instances, run experiments, "
58
+ "and work with local applications.\n\n"
59
+ "IMPORTANT: Always use these MCP tools instead of shelling out "
60
+ "to the `nextmv` CLI binary. Large responses (run results, "
61
+ "inputs, logs) are automatically saved to local temp files to "
62
+ "keep the context window small — the tool will return the file "
63
+ "path so you can selectively read what you need. Large inputs "
64
+ "can be passed directly as tool parameters without concern.\n\n"
65
+ "PROFILES: The server supports multiple profiles from "
66
+ "~/.nextmv/config.yaml. Use cloud_list_profiles to see "
67
+ "available profiles and cloud_set_profile to switch. The "
68
+ "default profile is used unless changed. When the user asks "
69
+ "to use a specific profile (e.g. \"list apps in my dev "
70
+ "profile\"), call cloud_set_profile first. Always state which "
71
+ "profile you are using when calling cloud tools, e.g. "
72
+ "(profile: \"default\")."
73
+ ),
74
+ )
75
+
76
+ # Cloud tools
77
+ profile.register(mcp)
78
+ app.register(mcp)
79
+ run.register(mcp)
80
+ version.register(mcp)
81
+ instance.register(mcp)
82
+ batch.register(mcp)
83
+ input_set.register(mcp)
84
+ acceptance.register(mcp)
85
+ scenario.register(mcp)
86
+ ensemble.register(mcp)
87
+ shadow.register(mcp)
88
+ switchback.register(mcp)
89
+ secrets.register(mcp)
90
+ sso.register(mcp)
91
+ account.register(mcp)
92
+ managed_input.register(mcp)
93
+
94
+ # Community tools
95
+ community.register(mcp)
96
+
97
+ # Local tools
98
+ local.register(mcp)
99
+
100
+ return mcp
@@ -0,0 +1 @@
1
+ """MCP tool registration submodules, organized by domain."""
@@ -0,0 +1,87 @@
1
+ """Shared helpers for MCP tool modules."""
2
+
3
+ import json
4
+ import os
5
+ import tempfile
6
+ from typing import Any
7
+
8
+ from nextmv import local
9
+ from nextmv.cloud import Application, Client
10
+
11
+ # Session-level profile. None means "default" (top-level config keys).
12
+ _current_profile: str | None = None
13
+
14
+
15
+ def _mask_key(key: str | None) -> str | None:
16
+ """Mask an API key, keeping only the last 4 characters visible."""
17
+
18
+ if not key:
19
+ return None
20
+ if len(key) <= 4:
21
+ return key
22
+ return "X" * (len(key) - 4) + key[-4:]
23
+
24
+
25
+ def _get_client(profile: str | None = None) -> Client:
26
+ """Build a Nextmv Cloud client from env var or CLI config.
27
+
28
+ Checks for credentials in the following order:
29
+
30
+ 1. ``NEXTMV_API_KEY`` environment variable (unless a profile is active).
31
+ 2. CLI configuration file at ``~/.nextmv/config.yaml``.
32
+
33
+ Args:
34
+ profile: Optional profile name override. If not provided, uses
35
+ the session-level ``_current_profile``.
36
+ """
37
+
38
+ resolved = profile or _current_profile
39
+
40
+ api_key = os.getenv("NEXTMV_API_KEY")
41
+ if api_key and not resolved:
42
+ endpoint = os.getenv("NEXTMV_ENDPOINT", "https://api.cloud.nextmv.io")
43
+ if not endpoint.startswith("http"):
44
+ endpoint = f"https://{endpoint}"
45
+ return Client(api_key=api_key, url=endpoint)
46
+
47
+ # Fall back to the CLI configuration file (~/.nextmv/config.yaml).
48
+ try:
49
+ from nextmv.cli.configuration.config import build_client
50
+
51
+ # "default" means use top-level keys (profile=None in build_client).
52
+ p = None if resolved is None or resolved == "default" else resolved
53
+ return build_client(profile=p)
54
+ except Exception as e:
55
+ raise ValueError(
56
+ "No Nextmv API key found. Either set the NEXTMV_API_KEY "
57
+ "environment variable or configure the CLI with: "
58
+ "nextmv configuration create"
59
+ ) from e
60
+
61
+
62
+ def _get_app(app_id: str, profile: str | None = None) -> Application:
63
+ """Build a cloud Application handle for the given ID."""
64
+
65
+ client = _get_client(profile=profile)
66
+ return Application(client=client, id=app_id)
67
+
68
+
69
+ def _get_local_app(app_dir: str, app_id: str | None = None) -> local.Application:
70
+ """Build a local Application, registering it if needed."""
71
+
72
+ app, _ = local.Application.get_or_register(app_src=app_dir, app_id=app_id)
73
+ return app
74
+
75
+
76
+ def _save_to_file(data: Any, prefix: str) -> str:
77
+ """Serialize data to a temp JSON file and return a message with the path.
78
+
79
+ This keeps large payloads out of the MCP response (and thus out of
80
+ the LLM context window). The caller can selectively read the file
81
+ using standard file-reading tools.
82
+ """
83
+
84
+ fd, path = tempfile.mkstemp(suffix=".json", prefix=f"{prefix}_")
85
+ with os.fdopen(fd, "w") as fh:
86
+ json.dump(data, fh, indent=2)
87
+ return f"Data saved to {path} — use file-reading tools to inspect the contents."
@@ -0,0 +1,107 @@
1
+ """MCP tools for cloud acceptance tests."""
2
+
3
+ from typing import Any
4
+
5
+ from mcp.server.fastmcp import FastMCP
6
+
7
+ from nextmv.cli.mcp.tools import _helpers
8
+
9
+
10
+ def register(mcp: FastMCP) -> None:
11
+ """Register cloud acceptance test tools."""
12
+
13
+ @mcp.tool()
14
+ def cloud_list_acceptance_tests(app_id: str) -> list[dict[str, Any]]:
15
+ """List acceptance tests for a Nextmv Cloud application.
16
+
17
+ Acceptance tests compare a candidate instance against a
18
+ baseline using defined metrics. Returns a list of test
19
+ summaries.
20
+
21
+ Args:
22
+ app_id: The application ID.
23
+ """
24
+
25
+ app = _helpers._get_app(app_id)
26
+ tests = app.list_acceptance_tests()
27
+ return [t.to_dict() for t in tests]
28
+
29
+ @mcp.tool()
30
+ def cloud_get_acceptance_test(
31
+ app_id: str,
32
+ acceptance_test_id: str,
33
+ ) -> str:
34
+ """Get details and results of an acceptance test.
35
+
36
+ Saves the full test data (including metric comparisons and
37
+ pass/fail results) to a local temp file. Use file-reading
38
+ tools to inspect the contents.
39
+
40
+ Args:
41
+ app_id: The application ID.
42
+ acceptance_test_id: The acceptance test ID.
43
+ """
44
+
45
+ app = _helpers._get_app(app_id)
46
+ test = app.acceptance_test(acceptance_test_id=acceptance_test_id)
47
+ return _helpers._save_to_file(test.to_dict(), prefix=f"acceptance_test_{acceptance_test_id}")
48
+
49
+ @mcp.tool()
50
+ def cloud_create_acceptance_test(
51
+ app_id: str,
52
+ candidate_instance_id: str,
53
+ baseline_instance_id: str,
54
+ metrics: list[dict[str, Any]],
55
+ acceptance_test_id: str | None = None,
56
+ name: str | None = None,
57
+ input_set_id: str | None = None,
58
+ description: str | None = None,
59
+ ) -> dict[str, Any]:
60
+ """Create an acceptance test comparing two instances.
61
+
62
+ An acceptance test runs both instances against the same input
63
+ set and compares results using the specified metrics to
64
+ determine whether the candidate meets acceptance criteria.
65
+
66
+ Args:
67
+ app_id: The application ID.
68
+ candidate_instance_id: The candidate instance to evaluate.
69
+ baseline_instance_id: The baseline instance to compare
70
+ the candidate against.
71
+ metrics: List of metric definitions. Each metric is a dict
72
+ with keys: ``field``, ``metric_type``, ``params``,
73
+ ``statistic``.
74
+ acceptance_test_id: Optional test ID. Auto-generated if
75
+ omitted.
76
+ name: Optional human-readable name.
77
+ input_set_id: Optional input set ID to run the test against.
78
+ description: Optional description.
79
+ """
80
+
81
+ app = _helpers._get_app(app_id)
82
+ test = app.new_acceptance_test(
83
+ candidate_instance_id=candidate_instance_id,
84
+ baseline_instance_id=baseline_instance_id,
85
+ metrics=metrics,
86
+ id=acceptance_test_id,
87
+ name=name,
88
+ input_set_id=input_set_id,
89
+ description=description,
90
+ )
91
+ return test.to_dict()
92
+
93
+ @mcp.tool()
94
+ def cloud_delete_acceptance_test(
95
+ app_id: str,
96
+ acceptance_test_id: str,
97
+ ) -> str:
98
+ """Delete an acceptance test permanently.
99
+
100
+ Args:
101
+ app_id: The application ID.
102
+ acceptance_test_id: The acceptance test ID to delete.
103
+ """
104
+
105
+ app = _helpers._get_app(app_id)
106
+ app.delete_acceptance_test(acceptance_test_id=acceptance_test_id)
107
+ return f"Deleted acceptance test {acceptance_test_id}"
@@ -0,0 +1,47 @@
1
+ """MCP tools for cloud account management."""
2
+
3
+ from typing import Any
4
+
5
+ from mcp.server.fastmcp import FastMCP
6
+
7
+ from nextmv.cli.mcp.tools import _helpers
8
+
9
+
10
+ def register(mcp: FastMCP) -> None:
11
+ """Register cloud account tools."""
12
+
13
+ @mcp.tool()
14
+ def cloud_get_account(account_id: str) -> dict[str, Any]:
15
+ """Get details of a Nextmv Cloud account.
16
+
17
+ Returns account information including organization name,
18
+ plan details, and usage limits.
19
+
20
+ Args:
21
+ account_id: The account ID to retrieve.
22
+ """
23
+
24
+ from nextmv.cloud.account import Account
25
+
26
+ client = _helpers._get_client()
27
+ account = Account.get(client=client, account_id=account_id)
28
+ return account.to_dict()
29
+
30
+ @mcp.tool()
31
+ def cloud_get_queue(account_id: str) -> dict[str, Any]:
32
+ """Get the run queue for a Nextmv Cloud account.
33
+
34
+ Returns information about currently queued and running runs
35
+ across all applications in the account, including queue
36
+ depth and concurrency usage.
37
+
38
+ Args:
39
+ account_id: The account ID.
40
+ """
41
+
42
+ from nextmv.cloud.account import Account
43
+
44
+ client = _helpers._get_client()
45
+ account = Account.get(client=client, account_id=account_id)
46
+ queue = account.queue()
47
+ return queue.to_dict()
@@ -0,0 +1,141 @@
1
+ """MCP tools for cloud application management."""
2
+
3
+ from typing import Any
4
+
5
+ from mcp.server.fastmcp import FastMCP
6
+
7
+ from nextmv.cli.mcp.tools import _helpers
8
+ from nextmv.cloud import Application, list_applications
9
+
10
+
11
+ def register(mcp: FastMCP) -> None:
12
+ """Register cloud application management tools."""
13
+
14
+ @mcp.tool()
15
+ def cloud_list_apps() -> list[dict[str, Any]]:
16
+ """List all Nextmv Cloud applications in the current account.
17
+
18
+ Returns a list of application dictionaries containing each
19
+ application's ID, name, description, and default instance.
20
+ """
21
+
22
+ client = _helpers._get_client()
23
+ apps = list_applications(client)
24
+ return [a.to_dict() for a in apps]
25
+
26
+ @mcp.tool()
27
+ def cloud_get_app(app_id: str) -> dict[str, Any]:
28
+ """Get details of a specific Nextmv Cloud application.
29
+
30
+ Returns the full application object including its name,
31
+ description, default instance, and creation timestamp.
32
+
33
+ Args:
34
+ app_id: The application ID (e.g., ``"my-routing-app"``).
35
+ """
36
+
37
+ client = _helpers._get_client()
38
+ app = Application.get(client=client, id=app_id)
39
+ return app.to_dict()
40
+
41
+ @mcp.tool()
42
+ def cloud_create_app(
43
+ name: str,
44
+ app_id: str | None = None,
45
+ description: str | None = None,
46
+ ) -> dict[str, Any]:
47
+ """Create a new Nextmv Cloud application.
48
+
49
+ Returns the created application object. A version and default
50
+ instance are automatically provisioned.
51
+
52
+ Args:
53
+ name: A human-readable name for the application.
54
+ app_id: Optional URL-friendly ID. Auto-generated from
55
+ the name if omitted.
56
+ description: Optional description of what the application does.
57
+ """
58
+
59
+ client = _helpers._get_client()
60
+ app = Application.new(
61
+ client=client,
62
+ name=name,
63
+ id=app_id,
64
+ description=description,
65
+ )
66
+ return app.to_dict()
67
+
68
+ @mcp.tool()
69
+ def cloud_delete_app(app_id: str) -> str:
70
+ """Delete a Nextmv Cloud application permanently.
71
+
72
+ This action cannot be undone. All versions, instances, and
73
+ run history associated with the application will be removed.
74
+
75
+ Args:
76
+ app_id: The application ID to delete.
77
+ """
78
+
79
+ app = _helpers._get_app(app_id)
80
+ app.delete()
81
+ return f"Deleted application {app_id}"
82
+
83
+ @mcp.tool()
84
+ def cloud_app_exists(app_id: str) -> bool:
85
+ """Check whether a Nextmv Cloud application exists.
86
+
87
+ Returns True if an application with the given ID exists in
88
+ the current account, False otherwise.
89
+
90
+ Args:
91
+ app_id: The application ID to check.
92
+ """
93
+
94
+ client = _helpers._get_client()
95
+ return Application.exists(client=client, id=app_id)
96
+
97
+ @mcp.tool()
98
+ def cloud_update_app(
99
+ app_id: str,
100
+ name: str | None = None,
101
+ description: str | None = None,
102
+ default_instance_id: str | None = None,
103
+ ) -> dict[str, Any]:
104
+ """Update attributes of a Nextmv Cloud application.
105
+
106
+ Only the provided fields are updated; omitted fields remain
107
+ unchanged. Returns the updated application object.
108
+
109
+ Args:
110
+ app_id: The application ID to update.
111
+ name: New human-readable name for the application.
112
+ description: New description.
113
+ default_instance_id: New default instance ID used when no
114
+ instance is specified at run time.
115
+ """
116
+
117
+ app = _helpers._get_app(app_id)
118
+ updated = app.update(
119
+ name=name,
120
+ description=description,
121
+ default_instance_id=default_instance_id,
122
+ )
123
+ return updated.to_dict()
124
+
125
+ @mcp.tool()
126
+ def cloud_push_app(app_id: str, app_dir: str) -> str:
127
+ """Push local application code to a Nextmv Cloud application.
128
+
129
+ Uploads the contents of a local directory as a new version of
130
+ the application. The directory must contain an ``app.yaml``
131
+ manifest.
132
+
133
+ Args:
134
+ app_id: The application ID to push to.
135
+ app_dir: Absolute path to the local directory containing the
136
+ application code and ``app.yaml`` manifest.
137
+ """
138
+
139
+ app = _helpers._get_app(app_id)
140
+ app.push(app_dir=app_dir)
141
+ return f"Pushed {app_dir} to application {app_id}"