msty-admin-mcp 6.2.1__tar.gz → 6.2.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 (53) hide show
  1. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/CHANGELOG.md +22 -0
  2. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/PKG-INFO +9 -6
  3. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/README.md +8 -5
  4. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/pyproject.toml +1 -1
  5. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/db.py +30 -2
  6. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/paths.py +122 -11
  7. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/server.py +51 -36
  8. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/writes.py +38 -3
  9. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/test_glama_quality.py +2 -1
  10. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/test_hybrid.py +11 -1
  11. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/test_server.py +3 -3
  12. msty_admin_mcp-6.2.2/tests/test_studio3_guard.py +376 -0
  13. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/.dockerignore +0 -0
  14. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/.github/workflows/ci.yml +0 -0
  15. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/.gitignore +0 -0
  16. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/Dockerfile +0 -0
  17. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/LICENSE +0 -0
  18. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/assets/demo.gif +0 -0
  19. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/assets/logo.svg +0 -0
  20. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/docs/BLOOM_GUIDE.md +0 -0
  21. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/glama.json +0 -0
  22. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/requirements.txt +0 -0
  23. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/__init__.py +0 -0
  24. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/analytics.py +0 -0
  25. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/automation/__init__.py +0 -0
  26. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/__init__.py +0 -0
  27. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/cv_behaviors.py +0 -0
  28. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/evaluator.py +0 -0
  29. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/example_behaviors.py +0 -0
  30. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/mcp_tools.py +0 -0
  31. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/ollama_adapter.py +0 -0
  32. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/calibration/__init__.py +0 -0
  33. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/config/__init__.py +0 -0
  34. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/database/__init__.py +0 -0
  35. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/escalation.py +0 -0
  36. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/frontier.py +0 -0
  37. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/frontier_main.py +0 -0
  38. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/hardware/__init__.py +0 -0
  39. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/hardware/catalog.py +0 -0
  40. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/install.py +0 -0
  41. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/intelligence/__init__.py +0 -0
  42. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/inventory.py +0 -0
  43. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/nexus.py +0 -0
  44. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/phase4_5_tools.py +0 -0
  45. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/safe_io.py +0 -0
  46. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/services.py +0 -0
  47. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/tooling.py +0 -0
  48. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/utils/__init__.py +0 -0
  49. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/version.py +0 -0
  50. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/__init__.py +0 -0
  51. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/test_clean_install.py +0 -0
  52. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/test_frontier.py +0 -0
  53. {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/test_packaging.py +0 -0
@@ -2,6 +2,28 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v6.2.2 - 2026-11-10
6
+
7
+ Safety release for Msty Studio 3.0.
8
+
9
+ ### Added
10
+
11
+ - Studio version gate. The app version is parsed as numbers, so 10.0.0 sorts above 2.9.12. Studio 2.4 to 2.9.x is supported. Versions below 2.4 and from 3.0 on are unsupported. A missing, unreadable or over-long version is unknown.
12
+ - `get_msty_installation` reports `layout` and `layout_status`.
13
+ - Studio read results carry a warning when the version is unknown, because the data may be a stale copy.
14
+ - macOS detection also looks for `~/Applications/MstyStudio.app`.
15
+
16
+ ### Changed
17
+
18
+ - On Studio 3.x and below 2.4 every Studio storage read and write is refused with one clear message. Detection no longer falls back to the legacy `msty.db` files or a search of the `File System` folder, because after a 3.0 migration those may be stale copies.
19
+ - Persona and prompt writes need a detected Studio 2.4 to 2.9.x. They are refused on other versions and when the version is unknown, and an explicit database path cannot bypass this. The JSON pack is still saved for import in Persona Studio.
20
+ - On Windows and Linux the Studio version cannot be read yet, so Studio writes are refused there. Reads work as before and carry the stale-copy warning.
21
+ - `recommend_model` still works on Studio 3.x. It recommends from hardware alone and notes that Studio usage was not used.
22
+ - `get_status(scope=server)` reports `studio_target` as 2.4 to 2.9.x, with Studio 3.x detected and refused.
23
+ - README warning about Studio 3.x, and the write conditions in the README name the Studio version check and Windows and Linux.
24
+
25
+ Model, service, Nexus, calibration and Bloom tools are unchanged.
26
+
5
27
  ## v6.2.1 - 2026-11-02
6
28
 
7
29
  Glama tool-quality pass. 61 tools become 54.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: msty-admin-mcp
3
- Version: 6.2.1
3
+ Version: 6.2.2
4
4
  Summary: Comprehensive MCP server for administering Msty Studio Desktop 2.9+ with 54 tools, hardware-aware model install, Studio writes with confirm, insights analytics, Nexus bridge, Bloom evaluation, and a Cursor/Grok/Claude handoff for local models
5
5
  Author-email: M-Pineapple 🍍 <128090761+M-Pineapple@users.noreply.github.com>
6
6
  License: MIT
@@ -22,7 +22,7 @@ Description-Content-Type: text/markdown
22
22
 
23
23
  <img src="assets/logo.svg" alt="Msty Admin MCP logo" width="240"/>
24
24
 
25
- # Msty Admin MCP v6.2.1
25
+ # Msty Admin MCP v6.2.2
26
26
 
27
27
  [![Licence: MIT](https://img.shields.io/github/license/M-Pineapple/msty-admin-mcp)](LICENSE)
28
28
  [![Python](https://img.shields.io/badge/Python-3.10+-3776AB?logo=python&logoColor=white)](https://www.python.org)
@@ -33,6 +33,9 @@ Description-Content-Type: text/markdown
33
33
 
34
34
  > Unofficial community project. Not affiliated with, or endorsed by, Msty. Msty is a trademark of its owner.
35
35
 
36
+ > [!WARNING]
37
+ > **Msty Studio 3.x is not supported yet.** Studio 3.0 can move workspaces to file-based storage, which this release cannot read safely. From v6.2.2 the server detects Studio 3.x and turns off every Studio read and write, so it never reports a stale copy as current or writes a row Studio 3.0 may reject. Model, service, Nexus, calibration and Bloom tools still work. Supported Studio versions are 2.4 to 2.9.x. Persona and prompt writes need a detected Studio 2.4 to 2.9.x, so they are refused when the version cannot be read. On Windows and Linux the Studio version cannot be read yet, so persona and prompt writes are refused there. Import the saved JSON pack in Persona Studio instead. If you rely on the Studio data tools, stay on the Studio 2.x update line for now. Studio 2.x installs stay on that line until you choose the 3.x track.
38
+
36
39
  <img src="assets/demo.gif" alt="msty-admin-mcp answering initialize and listing its tools" width="720"/>
37
40
 
38
41
  **Let the AI you already use plan, check and look after your local AI in Msty Studio, and let your local model ask for stronger help only when it needs it.**
@@ -204,7 +207,7 @@ Msty Studio users who want their usual AI app to help choose, test and organise
204
207
 
205
208
  - Inventory, analytics and free-form SQL stay **read only**. Credential columns always read as NULL. Secrets typed into free text, such as a chat message or a note, are out of scope.
206
209
  - Write tools always save a JSON pack under `~/.msty-admin/imports/` (mode `0600`, directory `0700`). `import_tool_config` and the tools, toolsets and skills keys of `import_studio_pack` never write the Studio database. Import that pack in Toolbox. Configs with `command`, `args` or `env` are flagged as running a program on your machine.
207
- - Personas and prompts insert into Studio SQLite only when both `confirm=true` and the operator env `MSTY_ALLOW_STUDIO_WRITES=1` are set. The LLM cannot set that env through a tool argument. Writes take a SQLite backup (including WAL) under `~/.msty-admin/backups/` and refuse while Msty Studio is running against the live database. Tests use fixture copies, never the live DB.
210
+ - Personas and prompts insert into Studio SQLite only when `confirm=true`, the operator env `MSTY_ALLOW_STUDIO_WRITES=1` and a detected Studio 2.4 to 2.9.x are all present. On Windows and Linux the Studio version cannot be read yet, so these writes are refused there. The LLM cannot set that env through a tool argument. Writes take a SQLite backup (including WAL) under `~/.msty-admin/backups/` and refuse while Msty Studio is running against the live database. Tests use fixture copies, never the live DB.
208
211
  - `query_local_ai_service` is allow-listed (tags, version, show, chat). Pull and create go through `install_model` and `set_model_settings`, which also need `confirm=true`.
209
212
  - Calibration and Bloom history live under `~/.msty-admin/`, not in Studio.
210
213
  - Frontier needs `CURSOR_API_KEY` for Cursor, `XAI_API_KEY` for Grok, or `ANTHROPIC_API_KEY` for Claude. Keys stay in Msty's toolbox environment and never belong in this repository. In ask mode the Cursor agent does not send mail, move or delete files, or use trading tools.
@@ -235,7 +238,7 @@ If you already have Python 3.10+ as `python3`, `python3 -m venv .venv` is enough
235
238
 
236
239
  If `pip install msty-admin-mcp` cannot find the package, install the release straight from GitHub:
237
240
  ```bash
238
- pip install "msty-admin-mcp @ git+https://github.com/M-Pineapple/msty-admin-mcp@v6.2.1"
241
+ pip install "msty-admin-mcp @ git+https://github.com/M-Pineapple/msty-admin-mcp@v6.2.2"
239
242
  ```
240
243
 
241
244
  ### With HTTP Transport
@@ -424,7 +427,7 @@ The admin server still has the Studio inventory tools. Add the Frontier server a
424
427
  ### Phase 2: Configuration (5)
425
428
  - `export_tool_config`: export a tool by name/id
426
429
  - `sync_claude_preferences`: Claude to Msty delta report
427
- - `generate_persona`: persona JSON pack. SQLite insert needs `confirm=true` and `MSTY_ALLOW_STUDIO_WRITES=1`
430
+ - `generate_persona`: persona JSON pack. SQLite insert needs `confirm=true`, `MSTY_ALLOW_STUDIO_WRITES=1` and a detected Studio 2.4 to 2.9.x, so it is refused on Windows and Linux
428
431
  - `import_tool_config`: JSON pack for Toolbox. Never writes the Studio database
429
432
  - `import_studio_pack`: tools, toolsets and skills stay in the JSON pack. Personas and prompts need the env gate
430
433
 
@@ -497,7 +500,7 @@ v6 ships unit tests for path resolution, read-only SQL guards, redaction, invent
497
500
  **A**: No. v6 targets Studio 2.9+ (works on 2.4+ layouts when the File System DB is present). Use v4.x for older process-based detection.
498
501
 
499
502
  ### Q: Does this write to the Studio database?
500
- **A**: Inventory and analytics stay read-only. Write tools always save a JSON pack under `~/.msty-admin/imports/`. Tools, toolsets and skills are import-file only. Personas and prompts insert into Studio SQLite only with `confirm=true` and `MSTY_ALLOW_STUDIO_WRITES=1` in the MCP server environment, after a timestamped SQLite backup that includes WAL, and they refuse while Msty Studio is running against the live database. Quit Studio first, or import the JSON pack in Persona Studio or Toolbox.
503
+ **A**: Inventory and analytics stay read-only. Write tools always save a JSON pack under `~/.msty-admin/imports/`. Tools, toolsets and skills are import-file only. Personas and prompts insert into Studio SQLite only with `confirm=true`, `MSTY_ALLOW_STUDIO_WRITES=1` in the MCP server environment and a detected Studio 2.4 to 2.9.x, after a timestamped SQLite backup that includes WAL, and they refuse while Msty Studio is running against the live database. Quit Studio first, or import the JSON pack in Persona Studio or Toolbox. On Windows and Linux the Studio version cannot be read yet, so these writes are refused there.
501
504
 
502
505
  ### Q: What is the Nexus integration?
503
506
  **A**: [Msty Nexus](https://msty.ai/nexus/) is the local runtime/gateway. `get_nexus` detects it. `list_models` with `backend=nexus` lists models on its OpenAI-compatible endpoint (`MSTY_NEXUS_PORT`).
@@ -2,7 +2,7 @@
2
2
 
3
3
  <img src="assets/logo.svg" alt="Msty Admin MCP logo" width="240"/>
4
4
 
5
- # Msty Admin MCP v6.2.1
5
+ # Msty Admin MCP v6.2.2
6
6
 
7
7
  [![Licence: MIT](https://img.shields.io/github/license/M-Pineapple/msty-admin-mcp)](LICENSE)
8
8
  [![Python](https://img.shields.io/badge/Python-3.10+-3776AB?logo=python&logoColor=white)](https://www.python.org)
@@ -13,6 +13,9 @@
13
13
 
14
14
  > Unofficial community project. Not affiliated with, or endorsed by, Msty. Msty is a trademark of its owner.
15
15
 
16
+ > [!WARNING]
17
+ > **Msty Studio 3.x is not supported yet.** Studio 3.0 can move workspaces to file-based storage, which this release cannot read safely. From v6.2.2 the server detects Studio 3.x and turns off every Studio read and write, so it never reports a stale copy as current or writes a row Studio 3.0 may reject. Model, service, Nexus, calibration and Bloom tools still work. Supported Studio versions are 2.4 to 2.9.x. Persona and prompt writes need a detected Studio 2.4 to 2.9.x, so they are refused when the version cannot be read. On Windows and Linux the Studio version cannot be read yet, so persona and prompt writes are refused there. Import the saved JSON pack in Persona Studio instead. If you rely on the Studio data tools, stay on the Studio 2.x update line for now. Studio 2.x installs stay on that line until you choose the 3.x track.
18
+
16
19
  <img src="assets/demo.gif" alt="msty-admin-mcp answering initialize and listing its tools" width="720"/>
17
20
 
18
21
  **Let the AI you already use plan, check and look after your local AI in Msty Studio, and let your local model ask for stronger help only when it needs it.**
@@ -184,7 +187,7 @@ Msty Studio users who want their usual AI app to help choose, test and organise
184
187
 
185
188
  - Inventory, analytics and free-form SQL stay **read only**. Credential columns always read as NULL. Secrets typed into free text, such as a chat message or a note, are out of scope.
186
189
  - Write tools always save a JSON pack under `~/.msty-admin/imports/` (mode `0600`, directory `0700`). `import_tool_config` and the tools, toolsets and skills keys of `import_studio_pack` never write the Studio database. Import that pack in Toolbox. Configs with `command`, `args` or `env` are flagged as running a program on your machine.
187
- - Personas and prompts insert into Studio SQLite only when both `confirm=true` and the operator env `MSTY_ALLOW_STUDIO_WRITES=1` are set. The LLM cannot set that env through a tool argument. Writes take a SQLite backup (including WAL) under `~/.msty-admin/backups/` and refuse while Msty Studio is running against the live database. Tests use fixture copies, never the live DB.
190
+ - Personas and prompts insert into Studio SQLite only when `confirm=true`, the operator env `MSTY_ALLOW_STUDIO_WRITES=1` and a detected Studio 2.4 to 2.9.x are all present. On Windows and Linux the Studio version cannot be read yet, so these writes are refused there. The LLM cannot set that env through a tool argument. Writes take a SQLite backup (including WAL) under `~/.msty-admin/backups/` and refuse while Msty Studio is running against the live database. Tests use fixture copies, never the live DB.
188
191
  - `query_local_ai_service` is allow-listed (tags, version, show, chat). Pull and create go through `install_model` and `set_model_settings`, which also need `confirm=true`.
189
192
  - Calibration and Bloom history live under `~/.msty-admin/`, not in Studio.
190
193
  - Frontier needs `CURSOR_API_KEY` for Cursor, `XAI_API_KEY` for Grok, or `ANTHROPIC_API_KEY` for Claude. Keys stay in Msty's toolbox environment and never belong in this repository. In ask mode the Cursor agent does not send mail, move or delete files, or use trading tools.
@@ -215,7 +218,7 @@ If you already have Python 3.10+ as `python3`, `python3 -m venv .venv` is enough
215
218
 
216
219
  If `pip install msty-admin-mcp` cannot find the package, install the release straight from GitHub:
217
220
  ```bash
218
- pip install "msty-admin-mcp @ git+https://github.com/M-Pineapple/msty-admin-mcp@v6.2.1"
221
+ pip install "msty-admin-mcp @ git+https://github.com/M-Pineapple/msty-admin-mcp@v6.2.2"
219
222
  ```
220
223
 
221
224
  ### With HTTP Transport
@@ -404,7 +407,7 @@ The admin server still has the Studio inventory tools. Add the Frontier server a
404
407
  ### Phase 2: Configuration (5)
405
408
  - `export_tool_config`: export a tool by name/id
406
409
  - `sync_claude_preferences`: Claude to Msty delta report
407
- - `generate_persona`: persona JSON pack. SQLite insert needs `confirm=true` and `MSTY_ALLOW_STUDIO_WRITES=1`
410
+ - `generate_persona`: persona JSON pack. SQLite insert needs `confirm=true`, `MSTY_ALLOW_STUDIO_WRITES=1` and a detected Studio 2.4 to 2.9.x, so it is refused on Windows and Linux
408
411
  - `import_tool_config`: JSON pack for Toolbox. Never writes the Studio database
409
412
  - `import_studio_pack`: tools, toolsets and skills stay in the JSON pack. Personas and prompts need the env gate
410
413
 
@@ -477,7 +480,7 @@ v6 ships unit tests for path resolution, read-only SQL guards, redaction, invent
477
480
  **A**: No. v6 targets Studio 2.9+ (works on 2.4+ layouts when the File System DB is present). Use v4.x for older process-based detection.
478
481
 
479
482
  ### Q: Does this write to the Studio database?
480
- **A**: Inventory and analytics stay read-only. Write tools always save a JSON pack under `~/.msty-admin/imports/`. Tools, toolsets and skills are import-file only. Personas and prompts insert into Studio SQLite only with `confirm=true` and `MSTY_ALLOW_STUDIO_WRITES=1` in the MCP server environment, after a timestamped SQLite backup that includes WAL, and they refuse while Msty Studio is running against the live database. Quit Studio first, or import the JSON pack in Persona Studio or Toolbox.
483
+ **A**: Inventory and analytics stay read-only. Write tools always save a JSON pack under `~/.msty-admin/imports/`. Tools, toolsets and skills are import-file only. Personas and prompts insert into Studio SQLite only with `confirm=true`, `MSTY_ALLOW_STUDIO_WRITES=1` in the MCP server environment and a detected Studio 2.4 to 2.9.x, after a timestamped SQLite backup that includes WAL, and they refuse while Msty Studio is running against the live database. Quit Studio first, or import the JSON pack in Persona Studio or Toolbox. On Windows and Linux the Studio version cannot be read yet, so these writes are refused there.
481
484
 
482
485
  ### Q: What is the Nexus integration?
483
486
  **A**: [Msty Nexus](https://msty.ai/nexus/) is the local runtime/gateway. `get_nexus` detects it. `list_models` with `backend=nexus` lists models on its OpenAI-compatible endpoint (`MSTY_NEXUS_PORT`).
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "msty-admin-mcp"
7
- version = "6.2.1"
7
+ version = "6.2.2"
8
8
  description = "Comprehensive MCP server for administering Msty Studio Desktop 2.9+ with 54 tools, hardware-aware model install, Studio writes with confirm, insights analytics, Nexus bridge, Bloom evaluation, and a Cursor/Grok/Claude handoff for local models"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -13,7 +13,14 @@ import time
13
13
  from pathlib import Path
14
14
  from typing import Any, Dict, List, Optional, Sequence, Tuple
15
15
 
16
- from src.paths import detect_msty_installation
16
+ from src.paths import (
17
+ LAYOUT_UNKNOWN,
18
+ LAYOUT_UNSUPPORTED,
19
+ UnsupportedStudioLayout,
20
+ detect_msty_installation,
21
+ unknown_version_read_warning,
22
+ unsupported_layout_message,
23
+ )
17
24
 
18
25
  # Only allow SELECT / WITH / PRAGMA for arbitrary query tool
19
26
  _SAFE_SQL = re.compile(r"^\s*(SELECT|WITH|PRAGMA)\b", re.IGNORECASE | re.DOTALL)
@@ -393,11 +400,32 @@ def names_credential_column(query: str) -> bool:
393
400
  return False
394
401
 
395
402
 
403
+ def with_read_warning(payload: Any) -> Any:
404
+ """Add a stale-copy warning to a read result when the Studio version is unknown."""
405
+ if not isinstance(payload, dict):
406
+ return payload
407
+ try:
408
+ status = detect_msty_installation().layout_status
409
+ except Exception:
410
+ status = LAYOUT_UNKNOWN
411
+ if status == LAYOUT_UNKNOWN:
412
+ payload = dict(payload)
413
+ payload["warning"] = unknown_version_read_warning()
414
+ return payload
415
+
416
+
396
417
  def get_database_path(explicit: Optional[str] = None) -> Optional[Path]:
418
+ """Resolve the Studio SQLite path for reads.
419
+
420
+ Raises UnsupportedStudioLayout on Studio 3.x, even for an explicit path,
421
+ so no Studio-storage read runs against a layout this release cannot read.
422
+ """
423
+ install = detect_msty_installation()
424
+ if install.layout_status == LAYOUT_UNSUPPORTED:
425
+ raise UnsupportedStudioLayout(unsupported_layout_message(install.version))
397
426
  if explicit:
398
427
  path = Path(explicit)
399
428
  return path if path.exists() else None
400
- install = detect_msty_installation()
401
429
  if install.database_path:
402
430
  return Path(install.database_path)
403
431
  return None
@@ -10,10 +10,11 @@ from __future__ import annotations
10
10
  import json
11
11
  import platform
12
12
  import plistlib
13
+ import re
13
14
  import socket
14
15
  from dataclasses import asdict, dataclass, field
15
16
  from pathlib import Path
16
- from typing import Any, Dict, List, Optional
17
+ from typing import Any, Dict, List, Optional, Tuple
17
18
 
18
19
  try:
19
20
  import psutil
@@ -30,6 +31,98 @@ DEFAULT_PORTS = {
30
31
  }
31
32
 
32
33
 
34
+ # Studio storage layouts this release can read and write. Studio 3.x moved to
35
+ # file-based workspace storage, which this MCP does not understand yet.
36
+ UNSUPPORTED_MAJOR = 3
37
+ SUPPORTED_MIN = (2, 4)
38
+ SUPPORTED_BELOW = (UNSUPPORTED_MAJOR,)
39
+ VERSION_MAX_LEN = 64
40
+ VERSION_PART_MAX_DIGITS = 6
41
+
42
+ LAYOUT_SUPPORTED = "supported"
43
+ LAYOUT_UNSUPPORTED = "unsupported"
44
+ LAYOUT_UNKNOWN = "unknown"
45
+
46
+ _VERSION_RE = re.compile(r"^\s*v?(\d+(?:\.\d+)*)")
47
+
48
+
49
+ class UnsupportedStudioLayout(RuntimeError):
50
+ """Raised when Studio storage access is refused for the detected version."""
51
+
52
+
53
+ def parse_version(value: Optional[str]) -> Optional[Tuple[int, ...]]:
54
+ """Parse a dotted version into a numeric tuple, or None when unparseable.
55
+
56
+ Numeric tuples order 10.0.0 above 2.9.12, which a string compare does not.
57
+ """
58
+ if not isinstance(value, str) or len(value) > VERSION_MAX_LEN:
59
+ return None
60
+ match = _VERSION_RE.match(value)
61
+ if not match:
62
+ return None
63
+ parts = match.group(1).split(".")
64
+ if any(len(part) > VERSION_PART_MAX_DIGITS for part in parts):
65
+ return None
66
+ try:
67
+ return tuple(int(part) for part in parts)
68
+ except ValueError:
69
+ return None
70
+
71
+
72
+ def layout_status(version: Optional[str]) -> str:
73
+ """Classify a Studio version.
74
+
75
+ Supported only for 2.4 <= version < 3. Anything below 2.4 or at 3.0 and
76
+ above is unsupported. A missing or unparseable version is unknown.
77
+ """
78
+ parsed = parse_version(version)
79
+ if parsed is None:
80
+ return LAYOUT_UNKNOWN
81
+ if SUPPORTED_MIN <= parsed < SUPPORTED_BELOW:
82
+ return LAYOUT_SUPPORTED
83
+ return LAYOUT_UNSUPPORTED
84
+
85
+
86
+ def _is_pre_2_4(version: Optional[str]) -> bool:
87
+ parsed = parse_version(version)
88
+ return parsed is not None and parsed < SUPPORTED_MIN
89
+
90
+
91
+ def unsupported_layout_message(version: Optional[str]) -> str:
92
+ """User-facing refusal text for unsupported Studio versions."""
93
+ if _is_pre_2_4(version):
94
+ return (
95
+ f"Msty Studio version {version} is older than 2.4. This MCP supports the Studio "
96
+ "2.4 to 2.9.x storage layout only, so Studio reads and writes are disabled. "
97
+ "Service, model and Nexus tools still work."
98
+ )
99
+ return (
100
+ f"Msty Studio 3.x detected (version {version}). This MCP supports the Studio 2.9 "
101
+ "storage layout only. Studio 3.0 file-based workspace storage is not supported yet, "
102
+ "so Studio reads and writes are disabled to avoid reading stale data or damaging your "
103
+ "workspace. Service, model and Nexus tools still work. Track support in the "
104
+ "msty-admin-mcp README."
105
+ )
106
+
107
+
108
+ def unknown_version_read_warning() -> str:
109
+ """Warning added to Studio read results when the version cannot be read."""
110
+ return (
111
+ "Msty Studio version could not be read. These results come from the Studio 2.x "
112
+ "database and may be a stale copy if this machine runs Studio 3.x."
113
+ )
114
+
115
+
116
+ def unknown_version_write_message() -> str:
117
+ """User-facing refusal text for Studio writes when the version cannot be read."""
118
+ return (
119
+ "Msty Studio version could not be read, so Studio writes are refused. Writes run only "
120
+ "on a detected Studio 2.4 to 2.9.x install, because Studio 3.x changed workspace "
121
+ "storage. On Windows and Linux the version cannot be read yet. "
122
+ "Import the saved JSON pack in Persona Studio instead."
123
+ )
124
+
125
+
33
126
  @dataclass
34
127
  class MstyInstallation:
35
128
  """Detected Msty Studio installation."""
@@ -48,6 +141,8 @@ class MstyInstallation:
48
141
  platform_info: Dict[str, Any] = field(default_factory=dict)
49
142
  service_ports: Dict[str, int] = field(default_factory=dict)
50
143
  schema_note: Optional[str] = None
144
+ layout: Optional[str] = None
145
+ layout_status: str = LAYOUT_UNKNOWN
51
146
 
52
147
  def to_dict(self) -> Dict[str, Any]:
53
148
  return asdict(self)
@@ -61,6 +156,7 @@ def get_msty_paths() -> Dict[str, Path]:
61
156
  if system == "Darwin":
62
157
  return {
63
158
  "app": Path("/Applications/MstyStudio.app"),
159
+ "app_user": home / "Applications" / "MstyStudio.app",
64
160
  "app_alt": Path("/Applications/Msty.app"),
65
161
  "data": home / "Library" / "Application Support" / "MstyStudio",
66
162
  "data_legacy": home / "Library" / "Application Support" / "Msty",
@@ -247,10 +343,14 @@ def detect_msty_installation() -> MstyInstallation:
247
343
  )
248
344
 
249
345
  app = paths.get("app")
346
+ app_user = paths.get("app_user")
250
347
  app_alt = paths.get("app_alt")
251
348
  if app and app.exists():
252
349
  install.app_path = str(app)
253
350
  install.version = read_app_version(app)
351
+ elif app_user and app_user.exists():
352
+ install.app_path = str(app_user)
353
+ install.version = read_app_version(app_user)
254
354
  elif app_alt and app_alt.exists():
255
355
  install.app_path = str(app_alt)
256
356
  install.version = read_app_version(app_alt)
@@ -285,16 +385,27 @@ def detect_msty_installation() -> MstyInstallation:
285
385
  if sidecar and sidecar.exists():
286
386
  install.sidecar_path = str(sidecar)
287
387
 
288
- db = resolve_database_path(paths)
289
- if db:
290
- install.database_path = str(db)
291
- if "File System" in str(db):
292
- install.schema_note = (
293
- "Studio stores the workspace SQLite under Chromium File System "
294
- "(not legacy msty.db)."
295
- )
296
- else:
297
- install.schema_note = "Using legacy msty.db path."
388
+ install.layout_status = layout_status(install.version)
389
+ if install.layout_status == LAYOUT_UNSUPPORTED:
390
+ # Studio 3.x (or below 2.4): never fall back to the 2.9 blob, legacy
391
+ # msty.db or an rglob search. Those files may be a stale copy.
392
+ install.layout = "unsupported_pre_2_4" if _is_pre_2_4(install.version) else "unsupported_3x"
393
+ install.schema_note = unsupported_layout_message(install.version)
394
+ else:
395
+ db = resolve_database_path(paths)
396
+ if db:
397
+ install.database_path = str(db)
398
+ if "File System" in str(db):
399
+ install.layout = "studio_2x_file_system"
400
+ install.schema_note = (
401
+ "Studio stores the workspace SQLite under Chromium File System "
402
+ "(not legacy msty.db)."
403
+ )
404
+ else:
405
+ install.layout = "legacy_msty_db"
406
+ install.schema_note = "Using legacy msty.db path."
407
+ if install.layout_status == LAYOUT_UNKNOWN:
408
+ install.schema_note = f"{unknown_version_read_warning()} {install.schema_note}"
298
409
 
299
410
  install.is_running = is_process_running("MstyStudio")
300
411
  install.installed = bool(install.app_path or install.data_path or install.database_path)