Add ug mcp list, help on bare ug mcp, and MCP counts in ug status - #679
sunishsheth2009 wants to merge 4 commits into
Conversation
`ug mcp` with no subcommand now reports the Databricks MCP servers ug has configured, each annotated per coding agent with live status read from that agent's own `mcp list` (connected/failed; Codex reports enabled/disabled since its listing does not health-check). Workspace-managed servers and the skills connection are shown separately, and servers an agent lists that ug did not configure are summarized. Read-only; needs no Databricks login. The add/remove/web-search subcommands are unchanged. Co-authored-by: Isaac <no-reply@databricks.com>
…ion + status UX Now based on databricks#679 (`ug mcp` list). Reuses databricks#679's machinery instead of duplicating: - Extracts databricks#679's dev+workspace-managed server merge into a shared `configured_mcp_servers_by_name(state, agents)` in mcp.py; `list_mcp_command` and `ug mcp login` both use it (behavior-preserving for list). - `ug mcp login` now also covers WORKSPACE-MANAGED connection mcp-services (not just developer-configured), matching what `ug mcp` lists. - Adopts databricks#679's display style: `print_section`/`print_kv`/`print_heading` + a `_login_status_markup` mirroring `_live_status_markup` (✔ signed in / • needs sign-in / no sign-in needed / ? unknown), and shows the agents each service is configured for. Note: sign-in status is intentionally NOT added to the bare `ug mcp` list — that command stays Databricks-login-free, whereas the credential-status API needs a token. Co-authored-by: Isaac <no-reply@databricks.com>
…atus` Per e2e review feedback: `ug mcp` with no subcommand now shows the group help (its command list) following the Claude CLI convention, and the connection listing moved to the `ug mcp list` subcommand. `ug status` is kept a high-level overview — it now shows a per-agent MCP server count and points to `ug mcp list` for the per-server detail and live connection status, instead of printing each agent's raw `mcp list` command and server names. Co-authored-by: Isaac <no-reply@databricks.com>
ug mcp to list configured MCP servers and their connection statusug mcp list, help on bare ug mcp, and MCP counts in ug status
Replaces the multi-line per-agent output with a single NAME/LOCATION/AGENTS/ STATUS table (one row per server), addressing review feedback that the listing was too long. STATUS aggregates the agents a server is on — treating a Codex `enabled` and a Claude `connected` as one healthy state so the common case collapses to a single token, and splitting into `agent:state` only when agents diverge (e.g. a failure on one). The skills connection is a `skills` row in the same table, and servers ug didn't configure are summarized as a per-agent count instead of a name dump. Co-authored-by: Isaac <no-reply@databricks.com>
The skills registry connection is surfaced by the skill commands (`ug skill` / `ug configure skills`), so it no longer appears as a row in `ug mcp list`. It is still treated as ug-managed, so it's never miscounted in the "other servers not configured by ug" summary. Co-authored-by: Isaac <no-reply@databricks.com>
| if ( | ||
| any(marker in rest for marker in _HEALTH_FAIL_MARKERS) | ||
| or "fail" in low | ||
| or "error" in low | ||
| or "disconnect" in low | ||
| ): |
There was a problem hiding this comment.
Not a blocker, and likely rare in practice: the failure keywords ('fail'/'error'/'disconnect') are matched across the whole line (command/URL included) and before the health glyph, so a healthy server whose name or URL happens to contain one of those words would render as failed. If cheap, consider checking the ✔/✘ glyph first and only falling back to keyword text when no glyph is present.
| mcp_count = sum( | ||
| 1 | ||
| for server in mcp_servers | ||
| if tool in (server.get("clients") or []) | ||
| and server.get("name") | ||
| and server.get("kind") != SKILLS_MCP_KIND | ||
| ] | ||
| print_kv("MCP list command", str(MCP_CLIENTS[tool]["list_command"])) | ||
| print_kv( | ||
| "MCP servers", | ||
| ", ".join(tool_mcp_servers) if tool_mcp_servers else "none saved by ug", | ||
| ) |
There was a problem hiding this comment.
This count reads only mcp_servers, but ug mcp list also counts managed_mcp_servers (workspace-pushed). So a workspace with a managed server shows MCP servers: 0 here yet lists it under ug mcp list, which the note just below points to for the detail. Worth folding managed servers into the count so the two views agree.
| if other_summary: | ||
| print_note(f"Other MCP servers not configured by ug — {other_summary}.") | ||
|
|
||
| print_note("Live status is from each agent's `mcp list`; Codex reports enabled/disabled.") |
There was a problem hiding this comment.
Nit (non-blocking): this note mentions Codex even when --agents scopes Codex out (e.g. ug mcp list --agents claude), so it reads a bit oddly. Could show the Codex clause only when codex is in the reported set.
| if AIGW_MCP_SERVICES_PATH in url: | ||
| return url.split(AIGW_MCP_SERVICES_PATH, 1)[1] or "mcp-service" | ||
| if "/api/2.0/mcp/external/" in url: | ||
| return f"connection:{stripped.rsplit('/', 1)[-1]}" | ||
| if "/api/2.0/mcp/genie/" in url: | ||
| return f"genie:{stripped.rsplit('/', 1)[-1]}" | ||
| if "/api/2.0/mcp/vector-search/" in url: | ||
| return f"vector-search:{'.'.join(stripped.split('/')[-2:])}" | ||
| if "/api/2.0/mcp/functions/" in url: | ||
| return f"uc-functions:{'.'.join(stripped.split('/')[-2:])}" | ||
| if stripped.endswith("/api/2.0/mcp/sql"): | ||
| return "databricks-sql" |
There was a problem hiding this comment.
Non-blocking (DRY): these /api/2.0/mcp/... fragments are the same set already spelled out in _is_app_mcp_server and the URL builders, so this is a fourth copy that could drift over time. Could pull them into shared constants when convenient.
What & why
Adds a way to see the Databricks MCP servers ug has configured and whether each coding agent is currently connected to them, plus related UX fixes from end-to-end review feedback.
ug mcp list— one compact row per configured MCP server:NAME,LOCATION,AGENTS, and aSTATUSaggregated from each agent's ownmcp list(connected/failed; Codex reportsenabled/disabled, since its listing does not health-check). Connected and enabled are treated as one healthy state so the common case collapses to a single token;STATUSsplits intoagent:stateonly when agents disagree (e.g. a failure on one). Workspace-managed servers are tagged, and servers an agent lists that ug didn't configure are summarized as a per-agent count. Skills connections are managed separately (ug skill/ug configure skills) and aren't listed here.--agents claude,codexscopes the report. Read-only — needs no Databricks login.ug mcp(no subcommand) shows the group help / command list, following the Claude CLI convention.add/remove/web-searchsubcommands are unchanged.ug statusstays a high-level overview: it now shows a per-agent MCP server count and points toug mcp listfor the detail, instead of printing each agent's rawmcp listcommand and server names.Output examples
ug mcp— shows the command list:ug mcp list— one row per server (sample data):ug status— the MCP view is now a per-agent count plus a pointer (excerpt, sample data):How it was tested
claude/codexoutput parsers, the empty and colon-less/glyph shapes, ANSI-escape stripping (cursor-agent progress output leaked into names before this), andlist_mcp_command(the table with the healthy-state collapse, missing/not-installed states, the skills connection excluded, the other-servers count,--agentsscoping, unknown-agent error, and the no-servers/no-clients path).ug mcpshows the group help,ug mcp listruns the lister and forwards--agents, and thatug statusshows MCP counts + theug mcp listpointer (existing status tests updated to the count-based view).ruff check/ruff formatclean; full unit suite green. Smoke-testedug mcp,ug mcp list,ug mcp list --agents cursor,ug mcp --help, andug status.Follow-up (not in this PR): the review also discussed pointing
ug statusatug skills list; that command doesn't exist yet and skills are a separate workstream, so the skills section is unchanged here.This pull request and its description were written by Isaac.