publish MCPs through a filtered Hermes group

This commit is contained in:
Mikei386 committed 2026-08-26 11:34:15 +02:00
1 parent 2595bab17b
commit 167448d778
6 files changed
+54 -7

No files matched your search

+47 -1
View File
@@ -13,6 +13,7 @@ import os
import pathlib
import re
import urllib.error
import urllib.parse
import urllib.request
from typing import Any
@@ -21,6 +22,7 @@ from mcp.server.fastmcp import FastMCP
API_BASE = os.environ.get("MCPHUB_API_URL", "http://127.0.0.1:3000/api").rstrip("/")
TOKEN_FILE = pathlib.Path(os.environ.get("MCPHUB_API_TOKEN_FILE", "/app/data/client-token"))
CLIENT_GROUP = os.environ.get("MCPHUB_CLIENT_GROUP", "hermes").strip()
NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,62}$")
NPM_PACKAGE_RE = re.compile(r"^(?:@[A-Za-z0-9._-]+/)?[A-Za-z0-9._-]+(?:@[A-Za-z0-9._+~-]+)?$")
PYTHON_PACKAGE_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*(?:==[A-Za-z0-9._+~-]+)?$")
@@ -135,9 +137,35 @@ def _install(name: str, config: dict[str, Any]) -> str:
if any(isinstance(row, dict) and row.get("name") == name for row in rows):
raise HubError(f"Server already exists: {name}; inspect or update it instead")
result = _request("POST", "/servers", {"name": name, "config": config})
group_result = _add_to_group(name)
verified = _request("GET", f"/servers/{name}")
data = verified.get("data", verified) if isinstance(verified, dict) else verified
return json.dumps({"installed": True, "server": _redact(data), "api_result": _redact(result)}, ensure_ascii=False)
return json.dumps({
"installed": True,
"published_to": CLIENT_GROUP,
"server": _redact(data),
"api_result": _redact(result),
"group_result": _redact(group_result),
}, ensure_ascii=False)
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="")
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)
result: Any = {"already_present": True}
if not present:
result = _request("POST", f"/groups/{group}/servers", {"serverName": name})
if tools is not None:
result = _request(
"PUT",
f"/groups/{group}/server-configs/{urllib.parse.quote(name, safe='')}/tools",
{"tools": tools},
)
return result
@mcp.tool()
@@ -197,6 +225,24 @@ def mcphub_admin_reload(name: str) -> str:
return json.dumps(_redact(result), ensure_ascii=False)
@mcp.tool()
def mcphub_admin_publish_to_hermes(name: str, tools: list[str] | None = None) -> str:
"""Publish one installed server to the central Hermes group. Optionally expose only the named tools; omit tools to expose all."""
name = _name(name)
selected = None if tools is None else _args(tools)
result = _add_to_group(name, selected)
return json.dumps({"published": name, "group": CLIENT_GROUP, "result": _redact(result)}, ensure_ascii=False)
@mcp.tool()
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="")
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)
@mcp.tool()
def mcphub_admin_remove(name: str, confirmation: str) -> str:
"""Permanently remove a server only after the user explicitly requested it. confirmation must exactly equal REMOVE:<name>."""