fix MCPHub group publishing and recovery

This commit is contained in:
Mikei386 committed 2026-08-26 11:42:39 +02:00
1 parent 167448d778
commit 9ae7d22618
5 files changed
+67 -4

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<Container version="2">
<Name>MCPHub</Name>
<Repository>casaderoll/mcphub:1.2.3</Repository>
<Repository>casaderoll/mcphub:1.2.4</Repository>
<Registry>https://hub.docker.com/r/samanhappy/mcphub</Registry>
<Network>bridge</Network>
<MyIP/>
+13
View File
@@ -76,6 +76,19 @@ class MCPHubSettingsTests(unittest.TestCase):
with self.assertRaises(SystemExit):
self.module.registry_servers(self.registry, self.secrets, {})
def test_hermes_group_is_recoverable_and_bounded(self):
settings = {"groups": [{"id": "keep", "name": "other", "servers": []}]}
self.module.ensure_hermes_group(settings)
self.module.ensure_hermes_group(settings)
groups = settings["groups"]
self.assertEqual(len([group for group in groups if group["name"] == "hermes"]), 1)
hermes = next(group for group in groups if group["name"] == "hermes")
fritzbox = next(item for item in hermes["servers"] if item["name"] == "fritzbox")
self.assertEqual(
fritzbox["tools"],
["list_services", "list_actions", "describe_action", "call_action"],
)
if __name__ == "__main__":
unittest.main()
+1 -1
View File
@@ -95,7 +95,7 @@ docker run --rm --entrypoint python \
-v "$HERMES_DATA_DIR:/hermes:rw" \
-v "$mcphub_registry:/run/input/mcp-registry.json:ro" \
"${token_mount[@]}" \
casaderoll/mcphub:1.2.3 \
casaderoll/mcphub:1.2.4 \
/stack/platform/mcp/sync-clients.py "${sync_args[@]}"
"$STACK_DIR/platform/hermes/install-skills.sh"
+37
View File
@@ -82,6 +82,42 @@ def registry_servers(registry: pathlib.Path, secrets_dir: pathlib.Path,
return result
def ensure_hermes_group(settings: dict[str, object]) -> None:
"""Seed the bounded Hermes aggregate route on fresh installs/recovery."""
server_names = [
"mcphub-admin", "athena-operator", "github", "arr", "navidrome",
"deemix", "unraid",
]
members: list[dict[str, object]] = [
{"name": name, "tools": "all", "prompts": "all", "resources": "all"}
for name in server_names
]
members.append({
"name": "fritzbox",
"tools": ["list_services", "list_actions", "describe_action", "call_action"],
"prompts": [],
"resources": [],
})
groups = settings.setdefault("groups", [])
if not isinstance(groups, list):
groups = []
settings["groups"] = groups
current = next(
(group for group in groups
if isinstance(group, dict) and group.get("name") == "hermes"),
None,
)
if current is None:
current = {
"id": str(uuid.uuid4()),
"owner": "system",
"name": "hermes",
}
groups.append(current)
current["description"] = "Gefilterte zentrale MCP-Auswahl für alle Hermes-Clients"
current["servers"] = members
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("settings", type=pathlib.Path)
@@ -114,6 +150,7 @@ def main() -> None:
}
settings["mcpServers"] = servers
ensure_hermes_group(settings)
settings.setdefault("users", [])
token_path = args.settings.parent / "client-token"
keys = settings.setdefault("bearerKeys", [])
+15 -2
View File
@@ -149,10 +149,23 @@ def _install(name: str, config: dict[str, Any]) -> str:
}, ensure_ascii=False)
def _group_id(name: str) -> str:
result = _request("GET", "/groups")
rows = result.get("data", []) if isinstance(result, dict) else []
match = next(
(row for row in rows
if isinstance(row, dict) and (row.get("name") == name or row.get("id") == name)),
None,
)
if not isinstance(match, dict) or not match.get("id"):
raise HubError(f"MCPHub group does not exist: {name}")
return str(match["id"])
def _add_to_group(name: str, tools: list[str] | None = None) -> Any:
if not CLIENT_GROUP:
return {"skipped": "no-client-group"}
group = urllib.parse.quote(CLIENT_GROUP, safe="")
group = urllib.parse.quote(_group_id(CLIENT_GROUP), safe="")
configs = _request("GET", f"/groups/{group}/server-configs")
rows = configs.get("data", []) if isinstance(configs, dict) else []
present = any(isinstance(row, dict) and row.get("name") == name for row in rows)
@@ -238,7 +251,7 @@ def mcphub_admin_publish_to_hermes(name: str, tools: list[str] | None = None) ->
def mcphub_admin_unpublish_from_hermes(name: str) -> str:
"""Remove one server from the central Hermes group without uninstalling or disabling the server itself."""
name = _name(name)
group = urllib.parse.quote(CLIENT_GROUP, safe="")
group = urllib.parse.quote(_group_id(CLIENT_GROUP), safe="")
result = _request("DELETE", f"/groups/{group}/servers/{urllib.parse.quote(name, safe='')}")
return json.dumps({"unpublished": name, "group": CLIENT_GROUP, "result": _redact(result)}, ensure_ascii=False)