ellmos-servercommander-mcp 0.1.0-alpha.1 → 0.1.0-alpha.3
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.
- package/README.md +44 -32
- package/README_de.md +84 -0
- package/assets/servercommander-logo.jpg +0 -0
- package/config/servercommander.example.toml +8 -6
- package/package.json +4 -1
- package/pyproject.toml +2 -2
- package/src/servercommander/__init__.py +2 -2
- package/src/servercommander/config.py +8 -1
- package/src/servercommander/i18n.py +98 -0
- package/src/servercommander/server.py +10 -1
package/README.md
CHANGED
|
@@ -1,72 +1,84 @@
|
|
|
1
1
|
# ellmos-servercommander-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="assets/servercommander-logo.jpg" alt="ellmos ServerCommander MCP logo" width="360">
|
|
5
|
+
</p>
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- Transport: stdio über das Python-MCP-SDK
|
|
8
|
-
- Paketstatus: Alpha-Paket, GitHub-Repo unter `ellmos-ai` vorgesehen
|
|
9
|
-
- Aktiver Kern: MCP-Tool-Liste, MCP-Tool-Dispatch, Config-Lader, `sc_logs_analyze`, `sc_health_check`
|
|
10
|
-
- Sichere Alpha-Handler: `sc_deploy` erstellt lokale SHA256-Manifeste im Dry-run, `sc_mail_*` führt noch keine IMAP/SMTP-Aktionen aus
|
|
7
|
+
Alpha MCP server for server operations: deployment dry-runs, mail status, access-log analysis, and HTTP health checks.
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
German README: [README_de.md](README_de.md)
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
cd "C:\Users\User\OneDrive\.TOPICS\.AI\.MCP\ellmos-servercommander-mcp"
|
|
16
|
-
$env:PYTHONIOENCODING = "utf-8"
|
|
17
|
-
python -m pip install -e ".[dev]"
|
|
18
|
-
python -m pytest -q
|
|
19
|
-
```
|
|
11
|
+
## Status
|
|
20
12
|
|
|
21
|
-
|
|
13
|
+
- Transport: stdio via the Python MCP SDK
|
|
14
|
+
- Package status: public alpha package under `ellmos-ai`
|
|
15
|
+
- Current core: MCP tool listing, MCP tool dispatch, config loading, `sc_logs_analyze`, `sc_health_check`
|
|
16
|
+
- Safe alpha handlers: `sc_deploy` builds local SHA256 manifests in dry-run mode; `sc_mail_*` does not perform IMAP/SMTP operations yet
|
|
17
|
+
- i18n: localized MCP tool descriptions for `en`, `de`, `es`, `zh`, `ja`, `ru` with English fallback
|
|
22
18
|
|
|
23
|
-
##
|
|
19
|
+
## Install
|
|
24
20
|
|
|
25
|
-
|
|
21
|
+
The npm package contains a Node wrapper that starts the Python server. You still need Python 3.10+ and the Python package `mcp>=1.0.0`.
|
|
26
22
|
|
|
27
23
|
```powershell
|
|
28
24
|
npm install -g ellmos-servercommander-mcp@alpha
|
|
29
25
|
ellmos-servercommander
|
|
30
26
|
```
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
For local development:
|
|
33
29
|
|
|
34
30
|
```powershell
|
|
35
|
-
ellmos-servercommander
|
|
31
|
+
cd "C:\Users\User\OneDrive\.TOPICS\.AI\.MCP\ellmos-servercommander-mcp"
|
|
32
|
+
$env:PYTHONIOENCODING = "utf-8"
|
|
33
|
+
python -m pip install -e ".[dev]"
|
|
34
|
+
python -m pytest -q
|
|
36
35
|
```
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
Do not create a `.venv` inside a OneDrive-synced folder. If you need an isolated environment, create it outside OneDrive.
|
|
38
|
+
|
|
39
|
+
## Start From Source
|
|
39
40
|
|
|
40
41
|
```powershell
|
|
41
42
|
$env:PYTHONPATH = "src"
|
|
42
43
|
python -m servercommander.server
|
|
43
44
|
```
|
|
44
45
|
|
|
45
|
-
##
|
|
46
|
+
## Configuration
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
Example: [config/servercommander.example.toml](config/servercommander.example.toml)
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
Default paths:
|
|
50
51
|
|
|
51
52
|
- `%USERPROFILE%\.servercommander\config.toml`
|
|
52
53
|
- `%USERPROFILE%\.config\servercommander\config.toml`
|
|
53
|
-
-
|
|
54
|
+
- override with `SERVERCOMMANDER_CONFIG`
|
|
55
|
+
|
|
56
|
+
Language can be configured with `[server].language`, `SERVERCOMMANDER_LANG`, or `SERVERCOMMANDER_LOCALE`.
|
|
57
|
+
|
|
58
|
+
```toml
|
|
59
|
+
[server]
|
|
60
|
+
name = "ellmos-servercommander"
|
|
61
|
+
language = "en" # en, de, es, zh, ja, ru
|
|
62
|
+
```
|
|
54
63
|
|
|
55
|
-
Secrets
|
|
64
|
+
Secrets should be referenced through environment variables, for example `$MAIL_PASSWORD` or `$SFTP_PASSWORD`.
|
|
56
65
|
|
|
57
66
|
## Tools
|
|
58
67
|
|
|
59
|
-
- `sc_health_check`:
|
|
60
|
-
- `sc_logs_analyze`:
|
|
61
|
-
- `sc_deploy`:
|
|
62
|
-
- `sc_deploy_status`:
|
|
63
|
-
- `sc_mail_list`, `sc_mail_read`, `sc_mail_send`, `sc_mail_search`:
|
|
68
|
+
- `sc_health_check`: checks HTTP endpoints and reports status code plus latency
|
|
69
|
+
- `sc_logs_analyze`: analyzes Apache/Nginx access logs from inline text or a local file
|
|
70
|
+
- `sc_deploy`: creates a deployment plan with a local SHA256 manifest, but does not upload yet
|
|
71
|
+
- `sc_deploy_status`: shows configured deploy profiles and the current alpha history status
|
|
72
|
+
- `sc_mail_list`, `sc_mail_read`, `sc_mail_send`, `sc_mail_search`: safe alpha status responses without IMAP/SMTP connections
|
|
64
73
|
|
|
65
|
-
##
|
|
74
|
+
## Development
|
|
66
75
|
|
|
67
76
|
```powershell
|
|
68
77
|
$env:PYTHONIOENCODING = "utf-8"
|
|
78
|
+
$env:PYTHONDONTWRITEBYTECODE = "1"
|
|
69
79
|
python -m pytest -q
|
|
80
|
+
npm run smoke
|
|
81
|
+
npm pack --dry-run
|
|
70
82
|
```
|
|
71
83
|
|
|
72
|
-
|
|
84
|
+
Next useful step: extract real SFTP, IMAP/SMTP, and extended traffic-analysis modules from `.UMBRUCH` into credential-free adapters with local tests.
|
package/README_de.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# ellmos-servercommander-mcp
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="assets/servercommander-logo.jpg" alt="ellmos ServerCommander MCP Logo" width="360">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
Alpha-MCP-Server für Server-Operationen: Deployment-Dry-runs, Mail-Status, Access-Log-Analyse und HTTP-Health-Checks.
|
|
8
|
+
|
|
9
|
+
Englische Standard-README: [README.md](README.md)
|
|
10
|
+
|
|
11
|
+
## Status
|
|
12
|
+
|
|
13
|
+
- Transport: stdio über das Python-MCP-SDK
|
|
14
|
+
- Paketstatus: öffentliches Alpha-Paket unter `ellmos-ai`
|
|
15
|
+
- Aktiver Kern: MCP-Tool-Liste, MCP-Tool-Dispatch, Config-Lader, `sc_logs_analyze`, `sc_health_check`
|
|
16
|
+
- Sichere Alpha-Handler: `sc_deploy` erstellt lokale SHA256-Manifeste im Dry-run, `sc_mail_*` führt noch keine IMAP/SMTP-Aktionen aus
|
|
17
|
+
- i18n: lokalisierte MCP-Tool-Beschreibungen für `en`, `de`, `es`, `zh`, `ja`, `ru` mit Englisch-Fallback
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
Das npm-Paket enthält einen Node-Wrapper, der den Python-Server startet. Voraussetzung bleibt Python 3.10+ mit installiertem Python-Paket `mcp>=1.0.0`.
|
|
22
|
+
|
|
23
|
+
```powershell
|
|
24
|
+
npm install -g ellmos-servercommander-mcp@alpha
|
|
25
|
+
ellmos-servercommander
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Für lokale Entwicklung:
|
|
29
|
+
|
|
30
|
+
```powershell
|
|
31
|
+
cd "C:\Users\User\OneDrive\.TOPICS\.AI\.MCP\ellmos-servercommander-mcp"
|
|
32
|
+
$env:PYTHONIOENCODING = "utf-8"
|
|
33
|
+
python -m pip install -e ".[dev]"
|
|
34
|
+
python -m pytest -q
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Keine `.venv` im OneDrive-Ordner anlegen. Falls eine isolierte Umgebung gebraucht wird, außerhalb von OneDrive erstellen.
|
|
38
|
+
|
|
39
|
+
## Start Aus Dem Quellbaum
|
|
40
|
+
|
|
41
|
+
```powershell
|
|
42
|
+
$env:PYTHONPATH = "src"
|
|
43
|
+
python -m servercommander.server
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Konfiguration
|
|
47
|
+
|
|
48
|
+
Beispiel: [config/servercommander.example.toml](config/servercommander.example.toml)
|
|
49
|
+
|
|
50
|
+
Standardpfade:
|
|
51
|
+
|
|
52
|
+
- `%USERPROFILE%\.servercommander\config.toml`
|
|
53
|
+
- `%USERPROFILE%\.config\servercommander\config.toml`
|
|
54
|
+
- Override per `SERVERCOMMANDER_CONFIG`
|
|
55
|
+
|
|
56
|
+
Die Sprache kann über `[server].language`, `SERVERCOMMANDER_LANG` oder `SERVERCOMMANDER_LOCALE` gesetzt werden.
|
|
57
|
+
|
|
58
|
+
```toml
|
|
59
|
+
[server]
|
|
60
|
+
name = "ellmos-servercommander"
|
|
61
|
+
language = "de" # en, de, es, zh, ja, ru
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Secrets sollen als Umgebungsvariablen referenziert werden, zum Beispiel `$MAIL_PASSWORD` oder `$SFTP_PASSWORD`.
|
|
65
|
+
|
|
66
|
+
## Tools
|
|
67
|
+
|
|
68
|
+
- `sc_health_check`: prüft HTTP-Endpunkte und meldet Status-Code plus Latenz
|
|
69
|
+
- `sc_logs_analyze`: analysiert Apache-/Nginx-Access-Logs aus Text oder Datei
|
|
70
|
+
- `sc_deploy`: erstellt einen Deployment-Plan mit lokalem SHA256-Manifest, führt aber noch keinen Upload aus
|
|
71
|
+
- `sc_deploy_status`: zeigt konfigurierte Deploy-Profile und den aktuellen Alpha-History-Status
|
|
72
|
+
- `sc_mail_list`, `sc_mail_read`, `sc_mail_send`, `sc_mail_search`: sichere Alpha-Statusantworten ohne IMAP/SMTP-Verbindung
|
|
73
|
+
|
|
74
|
+
## Entwicklung
|
|
75
|
+
|
|
76
|
+
```powershell
|
|
77
|
+
$env:PYTHONIOENCODING = "utf-8"
|
|
78
|
+
$env:PYTHONDONTWRITEBYTECODE = "1"
|
|
79
|
+
python -m pytest -q
|
|
80
|
+
npm run smoke
|
|
81
|
+
npm pack --dry-run
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Der nächste sinnvolle Schritt ist die Extraktion der echten SFTP-, IMAP/SMTP- und erweiterten Traffic-Module aus `.UMBRUCH` in credential-freie Adapter mit lokalen Tests.
|
|
Binary file
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
# ellmos-servercommander-mcp
|
|
2
|
-
#
|
|
1
|
+
# ellmos-servercommander-mcp configuration
|
|
2
|
+
# Copy to ~/.servercommander/config.toml and adjust.
|
|
3
3
|
|
|
4
4
|
[server]
|
|
5
5
|
name = "ellmos-servercommander"
|
|
6
|
+
# Tool metadata language: en, de, es, zh, ja, ru
|
|
7
|
+
language = "en"
|
|
6
8
|
|
|
7
|
-
# --- Deploy
|
|
9
|
+
# --- Deploy profiles ---
|
|
8
10
|
[deploy.profiles.example_site]
|
|
9
11
|
host = "sftp.example.com"
|
|
10
12
|
user = "deploy-user"
|
|
11
13
|
remote_path = "/var/www/example"
|
|
12
14
|
local_path = "./dist"
|
|
13
15
|
protocol = "sftp"
|
|
14
|
-
# password = "$SFTP_PASSWORD" #
|
|
16
|
+
# password = "$SFTP_PASSWORD" # Use environment variables for secrets.
|
|
15
17
|
|
|
16
18
|
# [deploy.profiles.other]
|
|
17
19
|
# host = "..."
|
|
@@ -26,11 +28,11 @@ username = "$MAIL_USER"
|
|
|
26
28
|
password = "$MAIL_PASSWORD"
|
|
27
29
|
cache_db = "~/.servercommander/mail_cache.db"
|
|
28
30
|
|
|
29
|
-
# --- Log
|
|
31
|
+
# --- Log analysis ---
|
|
30
32
|
[logs]
|
|
31
33
|
default_format = "apache" # apache | nginx
|
|
32
34
|
|
|
33
|
-
# --- Health
|
|
35
|
+
# --- Health checks ---
|
|
34
36
|
[health]
|
|
35
37
|
timeout = 5
|
|
36
38
|
endpoints = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ellmos-servercommander-mcp",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
4
|
"description": "Alpha MCP server for server operations: deploy dry-runs, mail status, log analysis, and health checks.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,10 +17,12 @@
|
|
|
17
17
|
"ellmos-servercommander": "bin/ellmos-servercommander.js"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
|
+
"assets/",
|
|
20
21
|
"bin/",
|
|
21
22
|
"config/",
|
|
22
23
|
"src/",
|
|
23
24
|
"README.md",
|
|
25
|
+
"README_de.md",
|
|
24
26
|
"KONZEPT.md",
|
|
25
27
|
"pyproject.toml"
|
|
26
28
|
],
|
|
@@ -29,6 +31,7 @@
|
|
|
29
31
|
"server",
|
|
30
32
|
"deploy",
|
|
31
33
|
"logs",
|
|
34
|
+
"i18n",
|
|
32
35
|
"health-checks",
|
|
33
36
|
"ellmos"
|
|
34
37
|
],
|
package/pyproject.toml
CHANGED
|
@@ -4,13 +4,13 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ellmos-servercommander-mcp"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.0a3"
|
|
8
8
|
description = "MCP server for server operations: deploy, mail, log analysis, health checks."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
11
11
|
requires-python = ">=3.10"
|
|
12
12
|
authors = [{ name = "Lukas Geiger" }]
|
|
13
|
-
keywords = ["mcp", "deploy", "server-management", "ellmos"]
|
|
13
|
+
keywords = ["mcp", "deploy", "server-management", "i18n", "ellmos"]
|
|
14
14
|
dependencies = [
|
|
15
15
|
"mcp>=1.0.0",
|
|
16
16
|
]
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"""ellmos-servercommander-mcp
|
|
1
|
+
"""ellmos-servercommander-mcp - server operations via MCP."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.1.
|
|
3
|
+
__version__ = "0.1.0a3"
|
|
@@ -22,6 +22,7 @@ DEFAULT_CONFIG_PATHS = [
|
|
|
22
22
|
@dataclass
|
|
23
23
|
class ServerCommanderConfig:
|
|
24
24
|
server_name: str = "ellmos-servercommander"
|
|
25
|
+
language: str = "en"
|
|
25
26
|
deploy_profiles: dict[str, dict[str, Any]] = field(default_factory=dict)
|
|
26
27
|
mail: dict[str, Any] = field(default_factory=dict)
|
|
27
28
|
logs: dict[str, Any] = field(default_factory=dict)
|
|
@@ -45,7 +46,7 @@ def load_config(path: str | Path | None = None) -> ServerCommanderConfig:
|
|
|
45
46
|
break
|
|
46
47
|
|
|
47
48
|
if path is None or not Path(path).exists():
|
|
48
|
-
return ServerCommanderConfig()
|
|
49
|
+
return ServerCommanderConfig(language=_env_language("en"))
|
|
49
50
|
|
|
50
51
|
with open(path, "rb") as f:
|
|
51
52
|
raw = tomllib.load(f)
|
|
@@ -53,9 +54,11 @@ def load_config(path: str | Path | None = None) -> ServerCommanderConfig:
|
|
|
53
54
|
deploy = raw.get("deploy", {})
|
|
54
55
|
profiles = deploy.get("profiles", {}) if isinstance(deploy, dict) else {}
|
|
55
56
|
server = raw.get("server", {})
|
|
57
|
+
language = _env_language(server.get("language") or server.get("locale") or "en")
|
|
56
58
|
|
|
57
59
|
return ServerCommanderConfig(
|
|
58
60
|
server_name=server.get("name", "ellmos-servercommander"),
|
|
61
|
+
language=language,
|
|
59
62
|
deploy_profiles=profiles if isinstance(profiles, dict) else {},
|
|
60
63
|
mail=raw.get("mail", {}),
|
|
61
64
|
logs=raw.get("logs", {}),
|
|
@@ -69,3 +72,7 @@ def resolve_env_value(value: Any) -> Any:
|
|
|
69
72
|
if isinstance(value, str) and value.startswith("$") and len(value) > 1:
|
|
70
73
|
return os.environ.get(value[1:], "")
|
|
71
74
|
return value
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _env_language(default: str) -> str:
|
|
78
|
+
return os.environ.get("SERVERCOMMANDER_LANG") or os.environ.get("SERVERCOMMANDER_LOCALE") or default
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Locale helpers for ServerCommander MCP tool metadata."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
DEFAULT_LOCALE = "en"
|
|
8
|
+
SUPPORTED_LOCALES = ("en", "de", "es", "zh", "ja", "ru")
|
|
9
|
+
|
|
10
|
+
ALIASES = {
|
|
11
|
+
"en-us": "en",
|
|
12
|
+
"en-gb": "en",
|
|
13
|
+
"de-de": "de",
|
|
14
|
+
"de-at": "de",
|
|
15
|
+
"de-ch": "de",
|
|
16
|
+
"es-es": "es",
|
|
17
|
+
"es-mx": "es",
|
|
18
|
+
"zh-cn": "zh",
|
|
19
|
+
"zh-hans": "zh",
|
|
20
|
+
"ja-jp": "ja",
|
|
21
|
+
"ru-ru": "ru",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
TRANSLATIONS: dict[str, dict[str, str]] = {
|
|
25
|
+
"de": {
|
|
26
|
+
"tool.sc_deploy": "Erstellt einen sicheren Deployment-Plan. Alpha: Ausführung nur als Dry-run.",
|
|
27
|
+
"tool.sc_deploy_status": "Zeigt konfigurierte Deployment-Profile und Alpha-History-Status.",
|
|
28
|
+
"tool.sc_mail_list": "Alpha-Mail-Status für das Auflisten eines IMAP-Ordners.",
|
|
29
|
+
"tool.sc_mail_read": "Alpha-Mail-Status für das Lesen einer Nachricht.",
|
|
30
|
+
"tool.sc_mail_send": "Alpha-Mail-Status für das Senden einer E-Mail; sendet noch nicht.",
|
|
31
|
+
"tool.sc_mail_search": "Alpha-Mail-Status für die Mail-Suche.",
|
|
32
|
+
"tool.sc_logs_analyze": "Analysiert Apache-/Nginx-Access-Logs aus Text oder Datei.",
|
|
33
|
+
"tool.sc_health_check": "Prüft HTTP-Endpunkte und meldet Status-Codes plus Latenz.",
|
|
34
|
+
},
|
|
35
|
+
"es": {
|
|
36
|
+
"tool.sc_deploy": "Crea un plan de despliegue seguro. Alpha: solo dry-run.",
|
|
37
|
+
"tool.sc_deploy_status": "Muestra perfiles de despliegue y estado de historial alpha.",
|
|
38
|
+
"tool.sc_mail_list": "Estado alpha para listar una carpeta IMAP.",
|
|
39
|
+
"tool.sc_mail_read": "Estado alpha para leer un mensaje.",
|
|
40
|
+
"tool.sc_mail_send": "Estado alpha para enviar correo; aún no envía.",
|
|
41
|
+
"tool.sc_mail_search": "Estado alpha para buscar correo.",
|
|
42
|
+
"tool.sc_logs_analyze": "Analiza logs de acceso Apache/Nginx desde texto o archivo.",
|
|
43
|
+
"tool.sc_health_check": "Comprueba endpoints HTTP y devuelve código de estado y latencia.",
|
|
44
|
+
},
|
|
45
|
+
"zh": {
|
|
46
|
+
"tool.sc_deploy": "创建安全部署计划。Alpha 版仅支持 dry-run。",
|
|
47
|
+
"tool.sc_deploy_status": "显示部署配置和 Alpha 历史状态。",
|
|
48
|
+
"tool.sc_mail_list": "用于列出 IMAP 文件夹的 Alpha 邮件状态。",
|
|
49
|
+
"tool.sc_mail_read": "用于读取邮件的 Alpha 状态。",
|
|
50
|
+
"tool.sc_mail_send": "用于发送邮件的 Alpha 状态;当前不会真正发送。",
|
|
51
|
+
"tool.sc_mail_search": "用于搜索邮件的 Alpha 状态。",
|
|
52
|
+
"tool.sc_logs_analyze": "从文本或文件分析 Apache/Nginx 访问日志。",
|
|
53
|
+
"tool.sc_health_check": "检查 HTTP 端点并返回状态码和延迟。",
|
|
54
|
+
},
|
|
55
|
+
"ja": {
|
|
56
|
+
"tool.sc_deploy": "安全なデプロイ計画を作成します。Alpha では dry-run のみです。",
|
|
57
|
+
"tool.sc_deploy_status": "設定済みデプロイプロファイルと Alpha 履歴状態を表示します。",
|
|
58
|
+
"tool.sc_mail_list": "IMAP フォルダ一覧用の Alpha メール状態を返します。",
|
|
59
|
+
"tool.sc_mail_read": "メッセージ読み取り用の Alpha メール状態を返します。",
|
|
60
|
+
"tool.sc_mail_send": "メール送信用の Alpha 状態を返します。まだ送信しません。",
|
|
61
|
+
"tool.sc_mail_search": "メール検索用の Alpha 状態を返します。",
|
|
62
|
+
"tool.sc_logs_analyze": "テキストまたはファイルから Apache/Nginx アクセスログを分析します。",
|
|
63
|
+
"tool.sc_health_check": "HTTP エンドポイントを確認し、ステータスコードとレイテンシを返します。",
|
|
64
|
+
},
|
|
65
|
+
"ru": {
|
|
66
|
+
"tool.sc_deploy": "Создает безопасный план деплоя. Alpha: только dry-run.",
|
|
67
|
+
"tool.sc_deploy_status": "Показывает профили деплоя и alpha-статус истории.",
|
|
68
|
+
"tool.sc_mail_list": "Alpha-статус для просмотра папки IMAP.",
|
|
69
|
+
"tool.sc_mail_read": "Alpha-статус для чтения сообщения.",
|
|
70
|
+
"tool.sc_mail_send": "Alpha-статус отправки почты; пока не отправляет.",
|
|
71
|
+
"tool.sc_mail_search": "Alpha-статус поиска почты.",
|
|
72
|
+
"tool.sc_logs_analyze": "Анализирует access-логи Apache/Nginx из текста или файла.",
|
|
73
|
+
"tool.sc_health_check": "Проверяет HTTP endpoints и возвращает коды статуса и задержку.",
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def normalize_locale(locale: str | None) -> str:
|
|
79
|
+
if not locale:
|
|
80
|
+
return DEFAULT_LOCALE
|
|
81
|
+
normalized = locale.strip().lower().replace("_", "-")
|
|
82
|
+
normalized = ALIASES.get(normalized, normalized.split("-", 1)[0])
|
|
83
|
+
if normalized in SUPPORTED_LOCALES:
|
|
84
|
+
return normalized
|
|
85
|
+
return DEFAULT_LOCALE
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@dataclass(frozen=True)
|
|
89
|
+
class I18n:
|
|
90
|
+
locale: str = DEFAULT_LOCALE
|
|
91
|
+
|
|
92
|
+
def __post_init__(self) -> None:
|
|
93
|
+
object.__setattr__(self, "locale", normalize_locale(self.locale))
|
|
94
|
+
|
|
95
|
+
def t(self, key: str, default: str | None = None) -> str:
|
|
96
|
+
if self.locale == DEFAULT_LOCALE:
|
|
97
|
+
return default or key
|
|
98
|
+
return TRANSLATIONS.get(self.locale, {}).get(key) or default or key
|
|
@@ -15,6 +15,7 @@ from mcp.server.stdio import stdio_server
|
|
|
15
15
|
from servercommander.config import ServerCommanderConfig, load_config
|
|
16
16
|
from servercommander.deploy import sc_deploy, sc_deploy_status
|
|
17
17
|
from servercommander.health import sc_health_check
|
|
18
|
+
from servercommander.i18n import I18n
|
|
18
19
|
from servercommander.logs import sc_logs_analyze
|
|
19
20
|
from servercommander.mail import sc_mail_list, sc_mail_read, sc_mail_search, sc_mail_send
|
|
20
21
|
from servercommander.tooling import ToolDefinition
|
|
@@ -31,9 +32,17 @@ class ServerCommanderRegistry:
|
|
|
31
32
|
self.config = config
|
|
32
33
|
self._tools = build_tools(config)
|
|
33
34
|
self._handlers = {tool.name: tool.handler for tool in self._tools}
|
|
35
|
+
self.i18n = I18n(config.language)
|
|
34
36
|
|
|
35
37
|
def list_tools(self) -> list[types.Tool]:
|
|
36
|
-
return [
|
|
38
|
+
return [
|
|
39
|
+
types.Tool(
|
|
40
|
+
name=tool.name,
|
|
41
|
+
description=self.i18n.t(f"tool.{tool.name}", tool.description),
|
|
42
|
+
inputSchema=tool.input_schema,
|
|
43
|
+
)
|
|
44
|
+
for tool in self._tools
|
|
45
|
+
]
|
|
37
46
|
|
|
38
47
|
async def call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
39
48
|
handler = self._handlers.get(name)
|