From c37fdec2d9170cf159011f5477e8cd0fb5c3718a Mon Sep 17 00:00:00 2001
From: Teknium <127238744+teknium1@users.noreply.github.com>
Date: Thu, 18 Jun 2026 09:40:56 -0700
Subject: [PATCH] feat(dashboard): surface full per-MCP catalog detail; fix
pip-install doc (#48520)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The dashboard MCP catalog only showed name/description/transport and a
non-clickable source. Users couldn't see what an entry connects to or runs
before installing — the exact detail the docs trust model tells them to vet.
- /api/mcp/catalog now returns transport target (url, or command+args),
auth_type, git install source/ref + bootstrap commands, default-enabled
tool hint, and post-install guidance per entry.
- McpPage renders the endpoint URL (http) or command+args (stdio), the git
install source/ref, a collapsible bootstrap-commands list, setup notes,
and the source as a clickable link when it's a URL.
- Docs: drop the 'uv pip install -e .[mcp]' quick-start step (Hermes does
not support pip installs; MCP ships with the standard install) and note
the dashboard now surfaces this detail.
- Strengthen the catalog endpoint test to assert the new inspection fields.
---
hermes_cli/web_server.py | 20 ++++-
.../test_dashboard_admin_endpoints.py | 26 +++++-
web/src/lib/api.ts | 11 +++
web/src/pages/McpPage.tsx | 83 ++++++++++++++++++-
website/docs/user-guide/features/mcp.md | 14 ++--
5 files changed, 141 insertions(+), 13 deletions(-)
diff --git a/hermes_cli/web_server.py b/hermes_cli/web_server.py
index ed619979bfb..fcda37d6dfe 100644
--- a/hermes_cli/web_server.py
+++ b/hermes_cli/web_server.py
@@ -7593,17 +7593,35 @@ async def list_mcp_catalog(profile: Optional[str] = None):
}
for entry in catalog_entries:
auth = entry.auth
+ transport = entry.transport
+ install = entry.install
entries.append({
"name": entry.name,
"description": entry.description,
"source": entry.source,
- "transport": entry.transport.type,
+ "transport": transport.type,
"auth_type": getattr(auth, "type", "none"),
# Env vars the user must supply (names + prompts only, never values).
"required_env": [
{"name": e.name, "prompt": e.prompt, "required": e.required}
for e in getattr(auth, "env", []) or []
],
+ # Transport details so the UI can show exactly what connects/runs.
+ # The trust model (docs: user-guide/features/mcp) tells users to
+ # inspect command/args/url and the install bootstrap before
+ # installing — surface them rather than hiding them in the repo.
+ "command": transport.command,
+ "args": list(transport.args or []),
+ "url": transport.url,
+ # Git bootstrap (present only for entries that clone + build).
+ "install_url": install.url if install else None,
+ "install_ref": install.ref if install else None,
+ "bootstrap": list(install.bootstrap) if install else [],
+ # Default tool pre-selection hint and post-install guidance.
+ "default_enabled": list(entry.tools.default_enabled)
+ if entry.tools.default_enabled is not None
+ else None,
+ "post_install": entry.post_install or "",
"needs_install": entry.install is not None,
"installed": installed_state.get(entry.name, (False, False))[0],
"enabled": installed_state.get(entry.name, (False, False))[1],
diff --git a/tests/hermes_cli/test_dashboard_admin_endpoints.py b/tests/hermes_cli/test_dashboard_admin_endpoints.py
index 3eb2ca37d2d..6650d055a42 100644
--- a/tests/hermes_cli/test_dashboard_admin_endpoints.py
+++ b/tests/hermes_cli/test_dashboard_admin_endpoints.py
@@ -94,9 +94,31 @@ class TestMcpEndpoints:
body = r.json()
assert "entries" in body and "diagnostics" in body
# The shipped optional-mcps/ catalog has at least one entry; each must
- # carry the install/enabled status fields the UI relies on.
+ # carry the install/enabled status fields plus the inspection detail
+ # the dashboard renders (transport target, install source, guidance) so
+ # users can vet an entry before installing.
for e in body["entries"]:
- assert {"name", "transport", "installed", "enabled", "needs_install"} <= set(e)
+ assert {
+ "name",
+ "transport",
+ "auth_type",
+ "installed",
+ "enabled",
+ "needs_install",
+ "command",
+ "args",
+ "url",
+ "install_url",
+ "install_ref",
+ "bootstrap",
+ "default_enabled",
+ "post_install",
+ } <= set(e)
+ # http entries expose a url; stdio entries expose a command.
+ if e["transport"] == "http":
+ assert e["url"]
+ elif e["transport"] == "stdio":
+ assert e["command"]
def test_catalog_install_unknown_404(self):
r = self.client.post("/api/mcp/catalog/install", json={"name": "no-such-mcp-xyz"})
diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts
index 9b5b7afc835..ec03997b6c6 100644
--- a/web/src/lib/api.ts
+++ b/web/src/lib/api.ts
@@ -1301,6 +1301,17 @@ export interface McpCatalogEntry {
transport: "http" | "stdio";
auth_type: "api_key" | "oauth" | "none";
required_env: Array<{ name: string; prompt: string; required: boolean }>;
+ // Transport details — what actually connects (http) or runs (stdio).
+ command: string | null;
+ args: string[];
+ url: string | null;
+ // Git bootstrap (only set for entries that clone + build locally).
+ install_url: string | null;
+ install_ref: string | null;
+ bootstrap: string[];
+ // Default tool pre-selection (null = all tools pre-checked) + guidance text.
+ default_enabled: string[] | null;
+ post_install: string;
needs_install: boolean;
installed: boolean;
enabled: boolean;
diff --git a/web/src/pages/McpPage.tsx b/web/src/pages/McpPage.tsx
index 29088a6fc6a..cc933645b71 100644
--- a/web/src/pages/McpPage.tsx
+++ b/web/src/pages/McpPage.tsx
@@ -26,6 +26,10 @@ import { cn, themedBody } from "@/lib/utils";
type Transport = "http" | "stdio";
+function isHttpUrl(value: string): boolean {
+ return /^https?:\/\//i.test(value.trim());
+}
+
function truncateText(value: string, maxLength: number): string {
return value.length > maxLength ? value.slice(0, maxLength) + "..." : value;
}
@@ -707,9 +711,21 @@ export default function McpPage() {
>
{entry.transport}
-
+ Endpoint:{" "}
+ {entry.url}
+
+ Runs:{" "}
+
+ {[entry.command, ...entry.args].join(" ")}
+
+
+ Installs from:{" "}
+ {isHttpUrl(entry.install_url) ? (
+
+ {entry.install_url}
+
+ ) : (
+ {entry.install_url}
+ )}
+ {entry.install_ref && (
+ @ {entry.install_ref}
+ )}
+
{cmd}
+ + {entry.post_install.trim()} +
+/manifest.yaml`](https://github.com/NousResearch/hermes-agent/tree/main/optional-mcps) on GitHub. The picker also prints the manifest's `source:` URL at install -time so you can quickly verify the upstream repo. +time so you can quickly verify the upstream repo. The web dashboard's MCP +page surfaces the same detail per catalog entry — transport, auth type, the +endpoint URL (HTTP) or command + args (stdio), the git install source/ref and +bootstrap commands, and setup notes — with the `source:` rendered as a +clickable link, so you can inspect exactly what an entry connects to or runs +before clicking Install. ### Manifest version compatibility