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.
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/CHANGELOG.md +22 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/PKG-INFO +9 -6
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/README.md +8 -5
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/pyproject.toml +1 -1
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/db.py +30 -2
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/paths.py +122 -11
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/server.py +51 -36
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/writes.py +38 -3
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/test_glama_quality.py +2 -1
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/test_hybrid.py +11 -1
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/test_server.py +3 -3
- msty_admin_mcp-6.2.2/tests/test_studio3_guard.py +376 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/.dockerignore +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/.github/workflows/ci.yml +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/.gitignore +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/Dockerfile +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/LICENSE +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/assets/demo.gif +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/assets/logo.svg +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/docs/BLOOM_GUIDE.md +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/glama.json +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/requirements.txt +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/__init__.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/analytics.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/automation/__init__.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/__init__.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/cv_behaviors.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/evaluator.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/example_behaviors.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/mcp_tools.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/bloom/ollama_adapter.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/calibration/__init__.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/config/__init__.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/database/__init__.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/escalation.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/frontier.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/frontier_main.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/hardware/__init__.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/hardware/catalog.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/install.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/intelligence/__init__.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/inventory.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/nexus.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/phase4_5_tools.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/safe_io.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/services.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/tooling.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/utils/__init__.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/src/version.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/__init__.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/test_clean_install.py +0 -0
- {msty_admin_mcp-6.2.1 → msty_admin_mcp-6.2.2}/tests/test_frontier.py +0 -0
- {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.
|
|
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.
|
|
25
|
+
# Msty Admin MCP v6.2.2
|
|
26
26
|
|
|
27
27
|
[](LICENSE)
|
|
28
28
|
[](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
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
5
|
+
# Msty Admin MCP v6.2.2
|
|
6
6
|
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](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
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
|
|
289
|
-
if
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
install.
|
|
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)
|