feat(ui): add Team (Owner) column to MCP servers table

Shows the owning team alias resolved from team_id. Global servers
(team_id=null) display "Global". Header includes info icon explaining
that only servers from teams with mcp:read permission are visible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
yuneng-jiang 2026-03-21 13:03:25 -07:00
parent 79ca00bbec
commit baa1fa4151
2 changed files with 39 additions and 2 deletions

View file

@ -5,7 +5,7 @@ import { Icon } from "@tremor/react";
import { PencilAltIcon, TrashIcon } from "@heroicons/react/outline";
import { getMaskedAndFullUrl } from "./utils";
import { Tooltip } from "antd";
import { CheckOutlined } from "@ant-design/icons";
import { CheckOutlined, InfoCircleOutlined } from "@ant-design/icons";
const HealthStatusBadge: React.FC<{
server: MCPServer;
@ -92,6 +92,7 @@ export const mcpServerColumns = (
onByokConnect?: (server: MCPServer) => void,
onRecheckHealth?: (serverId: string) => void,
recheckingServerIds?: Set<string>,
teamAliasMap?: Map<string, string>,
): ColumnDef<MCPServer>[] => [
{
accessorKey: "server_id",
@ -128,6 +129,30 @@ export const mcpServerColumns = (
);
},
},
{
accessorKey: "team_id",
header: () => (
<span className="flex items-center gap-1">
Team (Owner)
<Tooltip title="Shows the team that owns this MCP server. You can only see servers owned by teams where you have the mcp:read permission.">
<InfoCircleOutlined className="text-gray-400 cursor-help" style={{ fontSize: 12 }} />
</Tooltip>
</span>
),
enableSorting: true,
cell: ({ row }) => {
const tid = row.original.team_id;
if (!tid) {
return <span className="text-xs text-gray-400 italic">Global</span>;
}
const alias = teamAliasMap?.get(tid);
return (
<Tooltip title={tid}>
<span className="text-sm">{alias || tid.slice(0, 8) + "..."}</span>
</Tooltip>
);
},
},
{
accessorKey: "alias",
header: "Alias",

View file

@ -15,6 +15,7 @@ import MCPConnect from "./mcp_connect";
import { mcpServerColumns } from "./mcp_server_columns";
import { MCPServerView } from "./mcp_server_view";
import { DiscoverableMCPServer, MCPServer, MCPServerProps, Team } from "./types";
import { useTeams } from "@/app/(dashboard)/hooks/teams/useTeams";
import MCPSemanticFilterSettings from "../Settings/AdminSettings/MCPSemanticFilterSettings/MCPSemanticFilterSettings";
import MCPNetworkSettings from "./MCPNetworkSettings";
import MCPDiscovery from "./mcp_discovery";
@ -63,6 +64,16 @@ const MCPServers: React.FC<MCPServerProps> = ({ accessToken, userRole, userID })
const [isDeletingServer, setIsDeletingServer] = useState(false);
const [byokModalServer, setByokModalServer] = useState<MCPServer | null>(null);
const isInternalUser = userRole === "Internal User";
const { data: allTeams } = useTeams();
const teamAliasMap = React.useMemo(() => {
const map = new Map<string, string>();
if (allTeams) {
for (const t of allTeams) {
if (t.team_alias) map.set(t.team_id, t.team_alias);
}
}
return map;
}, [allTeams]);
useEffect(() => {
if (typeof window === "undefined") {
@ -171,8 +182,9 @@ const MCPServers: React.FC<MCPServerProps> = ({ accessToken, userRole, userID })
(server: MCPServer) => setByokModalServer(server),
recheckServerHealth,
recheckingServerIds,
teamAliasMap,
),
[userRole, isLoadingHealth, recheckServerHealth, recheckingServerIds],
[userRole, isLoadingHealth, recheckServerHealth, recheckingServerIds, teamAliasMap],
);
function handleDelete(server_id: string) {