mlspace-plugin 0.3.2__tar.gz → 0.3.4__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 (139) hide show
  1. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/.env.example +3 -0
  2. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/INSTALL.md +2 -2
  3. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/INSTALL_AGENT.md +1 -1
  4. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/PKG-INFO +28 -8
  5. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/README.md +27 -7
  6. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/RELEASE.md +5 -5
  7. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/.claude-plugin/plugin.json +1 -1
  8. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/.codex-plugin/plugin.json +1 -1
  9. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/.mcp.json +1 -1
  10. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/mcp.json +1 -1
  11. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/plugin.json +1 -1
  12. mlspace_plugin-0.3.4/plugin/skills/mlspace-diagnose-data-transfer/SKILL.md +71 -0
  13. mlspace_plugin-0.3.4/plugin/skills/mlspace-stage-s3-to-nfs/SKILL.md +68 -0
  14. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/pyproject.toml +1 -1
  15. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/__init__.py +1 -1
  16. mlspace_plugin-0.3.4/src/mlspace_mcp/__main__.py +125 -0
  17. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/client_setup.py +32 -32
  18. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/config.py +4 -1
  19. mlspace_plugin-0.3.4/src/mlspace_mcp/data_transfer_hooks.py +68 -0
  20. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/formatting.py +1 -1
  21. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/init_cli.py +89 -77
  22. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/native_plugins.py +15 -15
  23. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/registry.py +52 -3
  24. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/server.py +35 -1
  25. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/setup_conflicts.py +14 -14
  26. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/setup_ui.py +22 -4
  27. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/setup_verification.py +10 -10
  28. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tls.py +7 -6
  29. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/data_transfer.py +44 -16
  30. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/docker_registry.py +11 -3
  31. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/workspaces.py +6 -2
  32. mlspace_plugin-0.3.4/tests/test_acceptance_regressions.py +177 -0
  33. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_client_setup.py +7 -7
  34. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_formatting.py +11 -0
  35. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_init_cli.py +3 -3
  36. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_native_plugins.py +1 -1
  37. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_onboarding_init.py +9 -9
  38. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_opencode_journey.py +4 -4
  39. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_registry.py +2 -1
  40. mlspace_plugin-0.3.4/tests/test_secret_disclosure.py +91 -0
  41. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_setup_conflicts.py +4 -4
  42. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_setup_native_journey.py +4 -4
  43. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_setup_verification.py +3 -3
  44. mlspace_plugin-0.3.2/plugin/skills/mlspace-diagnose-data-transfer/SKILL.md +0 -41
  45. mlspace_plugin-0.3.2/plugin/skills/mlspace-stage-s3-to-nfs/SKILL.md +0 -45
  46. mlspace_plugin-0.3.2/src/mlspace_mcp/__main__.py +0 -125
  47. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/.agents/plugins/marketplace.json +0 -0
  48. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/.claude-plugin/marketplace.json +0 -0
  49. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/.gitignore +0 -0
  50. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/AGENTS.md +0 -0
  51. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/CONTRIBUTING.md +0 -0
  52. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/LICENSE +0 -0
  53. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/README.md +0 -0
  54. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/skills/mlspace-call-deployed-model-predict/SKILL.md +0 -0
  55. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/skills/mlspace-deploy-inference-service/SKILL.md +0 -0
  56. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/skills/mlspace-diagnose-failed-training-job/SKILL.md +0 -0
  57. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/skills/mlspace-diagnose-job-launch-rejection/SKILL.md +0 -0
  58. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/skills/mlspace-diagnose-unhealthy-inference/SKILL.md +0 -0
  59. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/skills/mlspace-discover-launchable-resources/SKILL.md +0 -0
  60. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/skills/mlspace-launch-training-job/SKILL.md +0 -0
  61. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/skills/mlspace-list-running-jobs/SKILL.md +0 -0
  62. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/skills/mlspace-resume-notebook-and-set-autoshutdown/SKILL.md +0 -0
  63. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/plugin/skills/mlspace-transfer-compute-node/SKILL.md +0 -0
  64. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/scripts/build_plugin.py +0 -0
  65. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/scripts/demo_multi_workspace.py +0 -0
  66. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/scripts/gen_body_schemas.py +0 -0
  67. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/scripts/gen_plugin.py +0 -0
  68. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/scripts/mcp_call.py +0 -0
  69. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/scripts/serve_stdio.sh +0 -0
  70. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/scripts/serve_stdio_dryrun.sh +0 -0
  71. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/_status.py +0 -0
  72. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/auth.py +0 -0
  73. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/bodyspec.py +0 -0
  74. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/client.py +0 -0
  75. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/errors.py +0 -0
  76. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/job_hooks.py +0 -0
  77. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/jsonc.py +0 -0
  78. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/overview.py +0 -0
  79. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/resource_refs.py +0 -0
  80. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/spec/body_schemas.json +0 -0
  81. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/spec/openapi.json +0 -0
  82. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/__init__.py +0 -0
  83. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/allocations.py +0 -0
  84. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/async_inference.py +0 -0
  85. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/build_image.py +0 -0
  86. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/dalle.py +0 -0
  87. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/inference.py +0 -0
  88. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/jobs.py +0 -0
  89. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/notebooks.py +0 -0
  90. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/queues.py +0 -0
  91. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/resources.py +0 -0
  92. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/tools/tensorboards.py +0 -0
  93. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/src/mlspace_mcp/workspace_context.py +0 -0
  94. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/conftest.py +0 -0
  95. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/specutil.py +0 -0
  96. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_allocations.py +0 -0
  97. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_artifact_sync.py +0 -0
  98. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_async_inference.py +0 -0
  99. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_auth.py +0 -0
  100. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_autofill.py +0 -0
  101. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_bodyspec.py +0 -0
  102. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_build_image.py +0 -0
  103. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_client.py +0 -0
  104. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_configs_shrink.py +0 -0
  105. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_credential_pointer.py +0 -0
  106. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_dalle.py +0 -0
  107. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_data_transfer.py +0 -0
  108. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_docker_registry.py +0 -0
  109. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_drift.py +0 -0
  110. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_dry_run.py +0 -0
  111. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_dry_run_fidelity.py +0 -0
  112. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_env_file.py +0 -0
  113. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_errors.py +0 -0
  114. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_false_success.py +0 -0
  115. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_integration.py +0 -0
  116. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_job_status.py +0 -0
  117. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_jobs.py +0 -0
  118. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_log_normalisation.py +0 -0
  119. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_mcp_error_contract.py +0 -0
  120. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_native_cli_integration.py +0 -0
  121. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_notebooks.py +0 -0
  122. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_onboarding_tls.py +0 -0
  123. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_overview.py +0 -0
  124. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_plugin_bundle.py +0 -0
  125. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_plugin_cli.py +0 -0
  126. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_plugin_release.py +0 -0
  127. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_preflight.py +0 -0
  128. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_queue_scope.py +0 -0
  129. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_queues.py +0 -0
  130. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_resource_refs.py +0 -0
  131. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_resources.py +0 -0
  132. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_route_confusion.py +0 -0
  133. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_setup_ui.py +0 -0
  134. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_skills.py +0 -0
  135. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_tensorboards.py +0 -0
  136. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_user_agent.py +0 -0
  137. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_workspace_context.py +0 -0
  138. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_workspaces.py +0 -0
  139. {mlspace_plugin-0.3.2 → mlspace_plugin-0.3.4}/tests/test_wrapper_hardening.py +0 -0
@@ -30,6 +30,9 @@ MLSPACE_BASE_URL=https://api.ai.cloud.ru
30
30
  MLSPACE_READONLY=false # true hides and blocks all 58 write actions
31
31
  # when writes are enabled, destructive actions
32
32
  # additionally require confirm=true
33
+ # Account-wide password rotation is blocked unless the operator explicitly opts in.
34
+ # Enable only for an approved rotation, then disable and restart the MCP server.
35
+ # MLSPACE_ALLOW_REGISTRY_PASSWORD_ROTATION=false
33
36
  MLSPACE_TRANSPORT=streamable-http # streamable-http | stdio
34
37
  MLSPACE_HOST=127.0.0.1 # loopback only (no server-side auth in v1)
35
38
  MLSPACE_PORT=8000
@@ -21,7 +21,7 @@ mlspace-plugin setup
21
21
  ```
22
22
 
23
23
  Если пакет уже установлен: `uv tool install --force .`.
24
- При установке из wheel: `uv tool install /путь/к/mlspace_plugin-0.3.2-py3-none-any.whl`.
24
+ При установке из wheel: `uv tool install /путь/к/mlspace_plugin-0.3.4-py3-none-any.whl`.
25
25
  Не используйте editable-установку из `/tmp` для постоянной работы.
26
26
  Далее команды показаны для PyPI. После установки исходников или wheel через
27
27
  `uv tool install` заменяйте `uvx mlspace-plugin@latest` на `mlspace-plugin`,
@@ -43,7 +43,7 @@ mlspace-plugin setup
43
43
 
44
44
  Если настройка клиента не завершилась, проверенные ключи остаются сохранёнными.
45
45
  Мастер перечислит установленные клиенты; устраните причину и выполните напечатанную
46
- команду `Retry`. Она сохраняет выбор клиентов, включая незавершённые подключения.
46
+ команду после «Повторите команду». Она сохраняет выбор клиентов, включая незавершённые подключения.
47
47
 
48
48
  Откройте новую сессию выбранного клиента; если MCP не появился, перезапустите клиент.
49
49
  Сервер запускается клиентом автоматически. Первый запрос:
@@ -41,7 +41,7 @@
41
41
  запустить ту же команду без `--non-interactive`, сохранив endpoint, путь и выбор клиентов.
42
42
  Для конфликта нативного плагина Claude/Codex разберите указанный несекретный путь;
43
43
  не удаляйте чужую интеграцию автоматически.
44
- При частичном успехе сообщите, какие этапы завершены, и используйте команду `Retry`
44
+ При частичном успехе сообщите, какие этапы завершены, и используйте команду после «Повторите команду»
45
45
  из ошибки: она сохраняет выбор незавершённых подключений. Для автоматизации
46
46
  добавьте прежние `--non-interactive` и `--workspace`.
47
47
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: mlspace-plugin
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Cloud.ru MLSpace plugin: MCP server, agent skills and setup
5
5
  Project-URL: Repository, https://github.com/noesskeetit/mlspace-plugin
6
6
  Project-URL: Issues, https://github.com/noesskeetit/mlspace-plugin/issues
@@ -290,15 +290,21 @@ write-запросов подаются параметром `body: dict`; об
290
290
  Для других агентов предусмотрены Agent Plugins 1.0, Agent Skills и обычное
291
291
  MCP-подключение; поддержку конкретного загрузчика нужно проверять отдельно.
292
292
  Пошаговые сценарии поставляются только скиллами плагина; сервер отдаёт общие правила
293
- в instructions. `tests/test_skills.py` сверяет скиллы с реальными инструментами.
293
+ в instructions. Ключевые правила подачи ответа также включены в описания инструментов
294
+ для клиентов, которые не передают модели instructions сервера.
295
+ `tests/test_skills.py` сверяет скиллы с реальными инструментами.
294
296
 
295
297
  ---
296
298
 
297
299
  ## Безопасность
298
300
 
299
301
  - **Гейт подтверждения**: 16 необратимых действий (удаления, отзыв доступа,
300
- отмена переноса, ротация пароля реестра) требуют `confirm=true`. Это основной
301
- рубеж в конфигурации по умолчанию.
302
+ отмена переноса, ротация пароля реестра) требуют `confirm=true`.
303
+ - **Смена пароля Registry выключена по умолчанию**, поскольку затрагивает личный
304
+ аккаунт и уже работающие подключения. После согласования ротации оператор может
305
+ задать `MLSPACE_ALLOW_REGISTRY_PASSWORD_ROTATION=true` в конфигурации сервера и
306
+ перезапустить MCP. `setup` не включает этот параметр. После операции выключите его
307
+ и снова перезапустите MCP. Флаг инструмента `confirm=true` не обходит этот запрет.
302
308
  - **Режим read-only** (`MLSPACE_READONLY=true`): все 58 write-действий исчезают
303
309
  из `action`-перечня — модель их не видит — и блокируются в рантайме как
304
310
  страховка. По умолчанию **выключен**: сервер задуман как рабочий инструмент, а
@@ -313,13 +319,27 @@ MCP-подключение; поддержку конкретного загру
313
319
  общего сервера. Жизненный цикл воркспейса — только через консоль.
314
320
  - **Сеть**: HTTP-транспорт отказывается слушать не-loopback адрес (в v1 нет
315
321
  серверной аутентификации).
316
- - **Секреты в ответах** (пароль registry, api-key воркспейса) редактируются.
322
+ - **Секреты в ответах** (пароль Registry, API key воркспейса) по умолчанию
323
+ маскируются. Для задачи, которой нужно реальное значение, действия
324
+ `mlspace_docker_registry(action="generate_password")` и
325
+ `mlspace_workspaces(action="get_api_key")` принимают `reveal_secret=true`
326
+ вместе с `confirm=true`. Это раскрывает секрет в результате инструмента:
327
+ он становится доступен модели и может сохраниться в истории MCP-клиента.
328
+ Флаг действует только на эти операции, а не отключает маскирование глобально.
329
+ `generate_password` меняет пароль; агент должен получить разрешение на ротацию
330
+ и передать `reveal_secret=true` сразу, если новый пароль нужен для `docker login`.
331
+ Для входа используйте `--password-stdin`; не помещайте пароль в обычный ответ,
332
+ документацию или репозиторий. Обычным MCP-запросам ручное получение ключа не нужно.
317
333
 
318
334
  > Важно про `confirm`: этот флаг ставит **сам агент** в том же вызове. Это защита от
319
335
  > случайного действия, а **не** human-in-the-loop. Подтверждение человеком обеспечивает
320
- > окно вашего MCP-клиента, которому мы помогаем аннотацией `destructiveHint`.
321
- > Единственный рубеж, который агент обойти не может, — `MLSPACE_READONLY=true`;
322
- > в конфигурации по умолчанию его нет, и решение остаётся за клиентом.
336
+ > клиент, если в нём настроено согласование операций; `destructiveHint` — лишь подсказка.
337
+ > `reveal_secret` также является явным запросом агента, а не отдельным окном согласия.
338
+ > `MLSPACE_READONLY=true` блокирует изменения, включая ротацию пароля, но не чтение
339
+ > workspace API key с явным раскрытием. Это не режим запрета экспорта секретов.
340
+ > Агент с доступом к изменению конфигурации сервера способен изменить и его ограничения;
341
+ > настройки MCP не заменяют права доступа в API и клиенте. После явного раскрытия секрета
342
+ > сервер не может гарантировать, что модель не повторит его в своём ответе.
323
343
 
324
344
  ---
325
345
 
@@ -239,15 +239,21 @@ write-запросов подаются параметром `body: dict`; об
239
239
  Для других агентов предусмотрены Agent Plugins 1.0, Agent Skills и обычное
240
240
  MCP-подключение; поддержку конкретного загрузчика нужно проверять отдельно.
241
241
  Пошаговые сценарии поставляются только скиллами плагина; сервер отдаёт общие правила
242
- в instructions. `tests/test_skills.py` сверяет скиллы с реальными инструментами.
242
+ в instructions. Ключевые правила подачи ответа также включены в описания инструментов
243
+ для клиентов, которые не передают модели instructions сервера.
244
+ `tests/test_skills.py` сверяет скиллы с реальными инструментами.
243
245
 
244
246
  ---
245
247
 
246
248
  ## Безопасность
247
249
 
248
250
  - **Гейт подтверждения**: 16 необратимых действий (удаления, отзыв доступа,
249
- отмена переноса, ротация пароля реестра) требуют `confirm=true`. Это основной
250
- рубеж в конфигурации по умолчанию.
251
+ отмена переноса, ротация пароля реестра) требуют `confirm=true`.
252
+ - **Смена пароля Registry выключена по умолчанию**, поскольку затрагивает личный
253
+ аккаунт и уже работающие подключения. После согласования ротации оператор может
254
+ задать `MLSPACE_ALLOW_REGISTRY_PASSWORD_ROTATION=true` в конфигурации сервера и
255
+ перезапустить MCP. `setup` не включает этот параметр. После операции выключите его
256
+ и снова перезапустите MCP. Флаг инструмента `confirm=true` не обходит этот запрет.
251
257
  - **Режим read-only** (`MLSPACE_READONLY=true`): все 58 write-действий исчезают
252
258
  из `action`-перечня — модель их не видит — и блокируются в рантайме как
253
259
  страховка. По умолчанию **выключен**: сервер задуман как рабочий инструмент, а
@@ -262,13 +268,27 @@ MCP-подключение; поддержку конкретного загру
262
268
  общего сервера. Жизненный цикл воркспейса — только через консоль.
263
269
  - **Сеть**: HTTP-транспорт отказывается слушать не-loopback адрес (в v1 нет
264
270
  серверной аутентификации).
265
- - **Секреты в ответах** (пароль registry, api-key воркспейса) редактируются.
271
+ - **Секреты в ответах** (пароль Registry, API key воркспейса) по умолчанию
272
+ маскируются. Для задачи, которой нужно реальное значение, действия
273
+ `mlspace_docker_registry(action="generate_password")` и
274
+ `mlspace_workspaces(action="get_api_key")` принимают `reveal_secret=true`
275
+ вместе с `confirm=true`. Это раскрывает секрет в результате инструмента:
276
+ он становится доступен модели и может сохраниться в истории MCP-клиента.
277
+ Флаг действует только на эти операции, а не отключает маскирование глобально.
278
+ `generate_password` меняет пароль; агент должен получить разрешение на ротацию
279
+ и передать `reveal_secret=true` сразу, если новый пароль нужен для `docker login`.
280
+ Для входа используйте `--password-stdin`; не помещайте пароль в обычный ответ,
281
+ документацию или репозиторий. Обычным MCP-запросам ручное получение ключа не нужно.
266
282
 
267
283
  > Важно про `confirm`: этот флаг ставит **сам агент** в том же вызове. Это защита от
268
284
  > случайного действия, а **не** human-in-the-loop. Подтверждение человеком обеспечивает
269
- > окно вашего MCP-клиента, которому мы помогаем аннотацией `destructiveHint`.
270
- > Единственный рубеж, который агент обойти не может, — `MLSPACE_READONLY=true`;
271
- > в конфигурации по умолчанию его нет, и решение остаётся за клиентом.
285
+ > клиент, если в нём настроено согласование операций; `destructiveHint` — лишь подсказка.
286
+ > `reveal_secret` также является явным запросом агента, а не отдельным окном согласия.
287
+ > `MLSPACE_READONLY=true` блокирует изменения, включая ротацию пароля, но не чтение
288
+ > workspace API key с явным раскрытием. Это не режим запрета экспорта секретов.
289
+ > Агент с доступом к изменению конфигурации сервера способен изменить и его ограничения;
290
+ > настройки MCP не заменяют права доступа в API и клиенте. После явного раскрытия секрета
291
+ > сервер не может гарантировать, что модель не повторит его в своём ответе.
272
292
 
273
293
  ---
274
294
 
@@ -7,11 +7,11 @@
7
7
  `uv lock` и `uv run python scripts/gen_plugin.py`. Обновите примеры имён wheel/ZIP
8
8
  в инструкциях, если версия присутствует в имени файла.
9
9
  2. Выполните проверки из `CONTRIBUTING.md` на Linux и macOS.
10
- 3. Соберите пакет (в командах ниже замените 0.3.2 на выпускаемую версию):
10
+ 3. Соберите пакет (в командах ниже замените 0.3.4 на выпускаемую версию):
11
11
 
12
12
  ```sh
13
- uv build --out-dir dist/release-0.3.2
14
- uv run python scripts/build_plugin.py --output dist/plugin-release-0.3.2
13
+ uv build --out-dir dist/release-0.3.4
14
+ uv run python scripts/build_plugin.py --output dist/plugin-release-0.3.4
15
15
  ```
16
16
 
17
17
  4. Просмотрите содержимое wheel, sdist и ZIP. В них не должно быть credentials,
@@ -23,11 +23,11 @@ uv run python scripts/build_plugin.py --output dist/plugin-release-0.3.2
23
23
  `UV_PUBLISH_TOKEN` средствами вашего хранилища секретов, не аргументом команды:
24
24
 
25
25
  ```sh
26
- uv publish --trusted-publishing never dist/release-0.3.2/mlspace_plugin-0.3.2-py3-none-any.whl dist/release-0.3.2/mlspace_plugin-0.3.2.tar.gz
26
+ uv publish --trusted-publishing never dist/release-0.3.4/mlspace_plugin-0.3.4-py3-none-any.whl dist/release-0.3.4/mlspace_plugin-0.3.4.tar.gz
27
27
  ```
28
28
 
29
29
  6. Проверьте версию и SHA256 обоих файлов через PyPI JSON API; проверьте установку
30
- `uvx --from mlspace-plugin==0.3.2 mlspace-plugin --version` из нового кеша.
30
+ `uvx --from mlspace-plugin==0.3.4 mlspace-plugin --version` из нового кеша.
31
31
  7. Только после проверки точной версии в PyPI обновите рабочую ветку GitHub
32
32
  marketplace и создайте тег релиза. До этого проверяйте изменения на отдельной
33
33
  release-ветке или локальном Git marketplace: main не должен ссылаться на
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mlspace",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Cloud.ru MLSpace: training jobs, inference, notebooks, data transfer, registry and compute catalog — an MCP server plus skills.",
5
5
  "author": {
6
6
  "name": "Cloud.ru"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mlspace",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Cloud.ru MLSpace: training jobs, inference, notebooks, data transfer, registry and compute catalog — an MCP server plus skills.",
5
5
  "author": {
6
6
  "name": "Cloud.ru"
@@ -5,7 +5,7 @@
5
5
  "command": "uvx",
6
6
  "args": [
7
7
  "--from",
8
- "mlspace-plugin==0.3.2",
8
+ "mlspace-plugin==0.3.4",
9
9
  "mlspace-plugin",
10
10
  "--transport",
11
11
  "stdio"
@@ -6,7 +6,7 @@
6
6
  "command": "uvx",
7
7
  "args": [
8
8
  "--from",
9
- "mlspace-plugin==0.3.2",
9
+ "mlspace-plugin==0.3.4",
10
10
  "mlspace-plugin",
11
11
  "--transport",
12
12
  "stdio"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "mlspace",
4
- "version": "0.3.2",
4
+ "version": "0.3.4",
5
5
  "description": "Cloud.ru MLSpace: training jobs, inference, notebooks, data transfer, registry and compute catalog — an MCP server plus skills.",
6
6
  "author": {
7
7
  "name": "Cloud.ru"
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: mlspace-diagnose-data-transfer
3
+ description: "Diagnose a failed / partial data transfer on Cloud.ru MLSpace. Did my data transfer actually fail / land incompletely, and why. Uses the mlspace_data_transfer tools."
4
+ license: MIT
5
+ compatibility: Requires the `mlspace` MCP server from this plugin (Cloud.ru MLSpace credentials needed).
6
+ ---
7
+
8
+ # Diagnose a failed / partial data transfer
9
+
10
+ Did my data transfer actually fail / land incompletely, and why.
11
+
12
+ This skill drives the `mlspace` MCP server shipped in the same plugin. If its
13
+ tools are not connected, say so instead of guessing — none of these steps can be
14
+ carried out any other way.
15
+
16
+ ## Arguments
17
+
18
+ - `transfer_id` — Transfer id (or give a name).
19
+ - `transfer_name` — Transfer name to look up.
20
+ - `expected_rows` — Rows you expected, to judge completeness.
21
+ - `act` — If true, may rerun a failed run (after confirm).
22
+ - `target` — Connected workspace ID or unambiguous name, if scoped.
23
+
24
+ ## Procedure
25
+
26
+ Final-answer contract:
27
+ - **Status and reported counters**: observations returned by the API.
28
+ - **Failure cause and phase**: use explicit matching log evidence; otherwise unknown.
29
+ - **Data impact**: unknown until an independent source/destination contents check
30
+ establishes it. Even a known cause such as AccessDenied at PutObject does not
31
+ establish whether other writes in the run already happened. A known cause and
32
+ unknown data impact can both be true. Zero counters are not that contents check.
33
+
34
+ The tool's `_mcp_evidence` describes the limits of those observations, not an API
35
+ defect or a separate user-facing warning. Never translate zero counters into
36
+ "the run failed before transfer started" or "nothing was read/written".
37
+
38
+ Goal: determine whether a data transfer truly failed / was partial, and why.
39
+ 1. Resolve the transfer: if transfer_id given use it, else data_transfer list_transfers
40
+ and match transfer_name.
41
+ 2. data_transfer list_history (transfer_id, page=1, page_size=20 — this endpoint uses
42
+ page/page_size). Take the latest run's history_id + metrics (size_bytes, rows_count,
43
+ progress, status).
44
+ 3. data_transfer get_history_status (ids=[history_id]) for the authoritative status
45
+ (in_progress|success|failed|cancelled).
46
+ 4. If failed/cancelled, data_transfer get_event_logs (history_id, offset=0, limit=50,
47
+ as_enum_resolved=true) for the decoded reason.
48
+ If events are empty, retain the failed/cancelled status and inspect the matching
49
+ history entry and existing connector logs. Do not call try_connector merely to
50
+ read logs: it can activate the connector. Treat a value such as not_found as an
51
+ observation, not proof of a missing SQL table; that cause needs supporting logs
52
+ or a separate authorized check. Never invent the reason for failure.
53
+ 5. Compare rows_count/size_bytes vs the user's expectation to judge "partial".
54
+ These are reported counters, not an audit of source/destination contents.
55
+ Even zero bytes/rows/progress does not prove the run never started, identify
56
+ its failure phase, or prove data was unchanged. Do not claim any of those
57
+ without independent evidence. Distinguish "this diagnostic made no changes"
58
+ from "the earlier transfer made no changes". A connector's saved success
59
+ status is not a fresh connection test and does not establish current health.
60
+ Output: status + hard numbers (rows/bytes/progress) + completeness verdict + decoded
61
+ event reasons; separate "genuinely failed" from "clean exit / fewer rows than expected".
62
+ When failure logs are empty, conclude that the cause and data impact are unknown.
63
+ Report the counters as observations; do not turn them into a narrative about which
64
+ execution phase failed. Suggest the next read-only check instead of inventing a cause.
65
+ If no evidence identifies a failure phase, do not list speculative phases as the
66
+ diagnosis. Rerunning is a write that may change destination data: never include it
67
+ in a list of read-only checks or propose it when the user asked for read-only diagnosis.
68
+ Only if act=true: rerun_history (body={history_id}) for a failed run, after confirming.
69
+ For reasoning: status is only a 4-value enum; "finished but data looks wrong" is
70
+ inferred from the numbers, not a dedicated field. In the answer, explain only the
71
+ evidence and remaining uncertainty relevant to this run, not a general API audit.
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: mlspace-stage-s3-to-nfs
3
+ description: "Stage S3 data to NFS (one-off or nightly) on Cloud.ru MLSpace. Copy/sync S3 -> NFS for a GPU job, optionally on a schedule. Write action. Uses the mlspace_data_transfer tools."
4
+ license: MIT
5
+ compatibility: Requires the `mlspace` MCP server from this plugin (Cloud.ru MLSpace credentials needed).
6
+ ---
7
+
8
+ # Stage S3 data to NFS (one-off or nightly)
9
+
10
+ Copy/sync S3 -> NFS for a GPU job, optionally on a schedule. Write action.
11
+
12
+ This skill drives the `mlspace` MCP server shipped in the same plugin. If its
13
+ tools are not connected, say so instead of guessing — none of these steps can be
14
+ carried out any other way.
15
+
16
+ ## Arguments
17
+
18
+ - `source_hint` — Which S3 connector/bucket.
19
+ - `destination_hint` — Which NFS/cluster connector.
20
+ - `source_path` — Path within the source.
21
+ - `destination_path` — Path within the NFS share.
22
+ - `schedule` — Desired recurrence, start time and timezone, or a verified CronViewModel object.
23
+ - `transfer_name` — Name for the transfer.
24
+ - `cluster_name` — Target cluster name (required, not auto-derivable).
25
+ - `target` — Connected workspace ID or unambiguous name, if scoped.
26
+
27
+ ## Procedure
28
+
29
+ Goal: copy/sync S3 -> NFS, optionally on a nightly schedule (write actions;
30
+ refused under MLSPACE_READONLY=true).
31
+ 1. data_transfer list_connectors with page=1, page_size=20; continue as needed to
32
+ locate the requested connectors. SOURCE: an object-storage connector (s3amazon/
33
+ s3custom/s3google). DEST: an NFS/cluster connector. Capture both connector ids.
34
+ Reuse existing system connectors rather than attempting to create them. A system
35
+ NFS connector may be absent from list output. For the selected destination
36
+ workspace, its workspace ID can be tested as a candidate via get_connector
37
+ (connector_type="nfs", id_=workspace ID); use it only after verifying the returned
38
+ connector belongs to the intended destination. Do not probe unrelated workspaces.
39
+ 2. cluster_name is required. Use a verified value from task context or consult the
40
+ configured endpoint's /public/v2/openapi.json, components.schemas.TransferClusterEnum
41
+ and TransferMultiClusterEnum. These describe accepted names, not current reachability
42
+ or access rights. Do not infer API names from UI labels or construct routes by
43
+ concatenating cluster names. If the requested route is absent, explain that the
44
+ direct route is not established; do not launch a multi-hop transfer without an
45
+ agreed intermediate destination and confirmation of both supported legs.
46
+ If names or destination remain ambiguous, ask the user.
47
+ 3. (optional, S3 only) try_connector to pre-check connectivity (+ its /try/logs).
48
+ 4. Ensure source_path + destination_path are known (ask if absent). Choose the
49
+ strategy from the user's overwrite/append/sync intent; recurrence alone does
50
+ not determine it. For a schedule, confirm the time and timezone and build
51
+ crontab as a CronViewModel JSON object (start_at, time, weekdays, monthdays,
52
+ period as applicable), never a cron-expression string. Verify the service's
53
+ field semantics before converting the requested recurrence; the schema alone
54
+ does not establish period units or timezone behavior. Do not guess fractional
55
+ periods or silently substitute a different interval. Read back the saved
56
+ schedule and compare it with the requested one before claiming success.
57
+ For a one-off run omit crontab; creation starts the transfer immediately.
58
+ 5. list_transfers; if one matches this source->dest and the user means "edit", capture
59
+ its id for update instead of create.
60
+ 6. create_transfer (body=TransferInputViewModelV5: name, connector ids, paths,
61
+ cluster_name, strategy, optional crontab) OR update_transfer(id_, full body).
62
+ To just enable/disable: switch_transfer(id_, body={"active": true|false}).
63
+ 7. Verify: list_history(transfer_id) -> latest run id + status; get_history_status.
64
+ Output: source and destination, the created/updated transfer id, schedule with
65
+ timezone, and verified run status. A future scheduled run has not succeeded yet.
66
+ Before writing, summarize the destination, strategy and schedule for the user;
67
+ do not dump the request body or connector credentials. Report any unverified
68
+ schedule or incomplete result plainly; include API details only for diagnosis.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mlspace-plugin"
3
- version = "0.3.2"
3
+ version = "0.3.4"
4
4
  description = "Cloud.ru MLSpace plugin: MCP server, agent skills and setup"
5
5
  keywords = ["mlspace", "mcp", "agent-skills", "cloudru"]
6
6
  classifiers = [
@@ -1,4 +1,4 @@
1
1
  """mlspace_mcp — MCP server for the Cloud.ru MLSpace public API v2."""
2
2
 
3
- __version__ = "0.3.2"
3
+ __version__ = "0.3.4"
4
4
  USER_AGENT = f"mlspace-plugin/{__version__}"
@@ -0,0 +1,125 @@
1
+ """CLI entry point for mlspace-plugin."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import logging
7
+ import os
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ from . import __version__
12
+ from .config import load_settings, user_config_file
13
+ from .server import build_server
14
+
15
+
16
+ def _configure_logging() -> None:
17
+ """Basic stderr logging so the server's logger.warning/exception emit in prod.
18
+ Level via MLSPACE_LOG_LEVEL (default INFO). stderr keeps stdout clean for stdio MCP.
19
+ """
20
+ level = os.environ.get("MLSPACE_LOG_LEVEL", "INFO").upper()
21
+ logging.basicConfig(
22
+ level=getattr(logging, level, logging.INFO),
23
+ format="%(asctime)s %(levelname)s %(name)s: %(message)s",
24
+ stream=sys.stderr,
25
+ )
26
+
27
+
28
+ def main(argv: list[str] | None = None) -> int:
29
+ parser = argparse.ArgumentParser(
30
+ prog="mlspace-plugin",
31
+ description="MCP-сервер для публичного API v2 Cloud.ru MLSpace.",
32
+ )
33
+ parser.add_argument("--version", action="version", version=f"mlspace-plugin {__version__}")
34
+ parser.add_argument(
35
+ "--transport",
36
+ choices=["streamable-http", "stdio"],
37
+ help="Использовать этот транспорт вместо MLSPACE_TRANSPORT.",
38
+ )
39
+ parser.add_argument(
40
+ "--list-tools",
41
+ action="store_true",
42
+ help="Показать доступные инструменты и завершить работу (ключи не нужны).",
43
+ )
44
+ # Optional subcommand: with none given the CLI serves, as it always has.
45
+ sub = parser.add_subparsers(dest="command")
46
+ setup = sub.add_parser(
47
+ "setup",
48
+ help="Настроить ключи доступа, воркспейсы, MCP-клиенты и skills.",
49
+ description=(
50
+ "Введите Cloud.ru Key ID и Cloud.ru Key Secret, выберите доступные воркспейсы MLSpace. Настройки сохраняются в "
51
+ f"{user_config_file()} с правами 0600 (доступ только вашему пользователю). Ввод выполняется в вашем терминале: ключи "
52
+ "не передаются модели. Оба поля скрыты звёздочками. Затем подключаются MCP и skills выбранных клиентов."
53
+ ),
54
+ )
55
+ setup.add_argument("--path", type=Path, help="Сохранить ключи и воркспейсы в указанный файл вместо стандартного файла настроек.")
56
+ setup.add_argument("--force", action="store_true", help="Повторить настройку существующего файла с сохранёнными ключами. Конфликты пользовательских skills требуют отдельного выбора.")
57
+ setup.add_argument(
58
+ "--base-url",
59
+ help="Сохранить этот HTTPS-адрес API MLSpace; по умолчанию используется адрес из файла или production.",
60
+ )
61
+ setup.add_argument(
62
+ "--no-verify", action="store_true", help="Сохранить настройки без проверки API; нужны --config-only и --workspace. Клиенты не подключаются."
63
+ )
64
+ setup.add_argument("--client", dest="clients", action="append", choices=["claude-code", "codex", "opencode"], help="Подключить этот клиент; повторите флаг для нескольких. По умолчанию клиенты определяются автоматически.")
65
+ setup.add_argument("--client-path", dest="client_paths", action="append", metavar="CLIENT=PATH", help="Путь к исполняемому файлу клиента, если он отсутствует в PATH: например codex=/usr/local/bin/codex.")
66
+ setup.add_argument("--config-only", action="store_true", help="Сохранить только ключи и воркспейсы. Для подключения клиентов позже повторите setup --force --client CLIENT.")
67
+ setup.add_argument("--non-interactive", action="store_true", help="Без вопросов в терминале: укажите ID через --workspace и источник ключей либо используйте сохранённые ключи.")
68
+ setup.add_argument("--from-env", action="store_true", help="Прочитать ключи из переменных MLSPACE_CLIENT_ID / MLSPACE_CLIENT_SECRET.")
69
+ setup.add_argument("--credentials-file", type=Path, help="Прочитать ключи из существующего dotenv-файла без вывода их значений.")
70
+ setup.add_argument("--replace-credentials", action="store_true", help="Запросить новые ключи вместо сохранённых; для существующего файла также нужен --force.")
71
+ setup.add_argument("--workspace", dest="workspace_ids", action="append", help="Выбрать воркспейс по точному ID; повторите флаг для нескольких.")
72
+ setup.add_argument("--ca-file", type=Path, help="Файл доверенного CA в формате PEM от администратора. Копия сохраняется для следующих запусков MCP; проверка TLS включена.")
73
+ setup.add_argument("--list-workspaces", action="store_true", help="Вывести страницу доступных воркспейсов в JSON без сохранения и установки.")
74
+ setup.add_argument("--search", default="", help="Фильтровать JSON воркспейсов по названию, проекту или ID (с --list-workspaces).")
75
+ setup.add_argument("--offset", type=int, default=0, help="Пропустить это число результатов JSON; не меньше 0, по умолчанию 0.")
76
+ setup.add_argument("--limit", type=int, default=20, help="Число воркспейсов на странице JSON: 1–100, по умолчанию 20.")
77
+ args = parser.parse_args(argv)
78
+
79
+ if args.command == "setup":
80
+ from .init_cli import run_init
81
+
82
+ return run_init(
83
+ args.path,
84
+ force=args.force,
85
+ verify=not args.no_verify,
86
+ base_url=args.base_url,
87
+ config_only=args.config_only, non_interactive=args.non_interactive,
88
+ from_env=args.from_env, credentials_file=args.credentials_file,
89
+ workspace_ids=args.workspace_ids, clients=args.clients, client_paths=args.client_paths,
90
+ ca_file=args.ca_file, replace_credentials=args.replace_credentials,
91
+ list_workspaces=args.list_workspaces, search=args.search, offset=args.offset, limit=args.limit,
92
+ )
93
+
94
+ _configure_logging()
95
+ settings = load_settings()
96
+ if args.transport:
97
+ settings.transport = args.transport
98
+
99
+ if args.list_tools:
100
+ mcp = build_server(settings)
101
+ tools = mcp._tool_manager.list_tools()
102
+ mode = "read-only" if settings.readonly else "read-write"
103
+ print(f"mlspace-plugin {__version__} — {len(tools)} инструментов ({mode}):")
104
+ for tool in sorted(tools, key=lambda t: t.name):
105
+ print(f" {tool.name}")
106
+ return 0
107
+
108
+ settings.validate_bind()
109
+ settings.require_credentials()
110
+ mcp = build_server(settings)
111
+
112
+ if settings.transport == "stdio":
113
+ mcp.run(transport="stdio")
114
+ else:
115
+ print(
116
+ f"mlspace-plugin: сервер streamable-HTTP запущен на "
117
+ f"http://{settings.host}:{settings.port}/mcp",
118
+ file=sys.stderr,
119
+ )
120
+ mcp.run(transport="streamable-http")
121
+ return 0
122
+
123
+
124
+ if __name__ == "__main__":
125
+ raise SystemExit(main())