Icons
GitLab MCP Server assigns 50 unique domain icons to all 1085 self-managed Enterprise/Premium tools (1091 on GitLab.com Enterprise/Premium with Orbit), 34 base meta-tools (51 self-managed Enterprise, 52 GitLab.com Enterprise), 45 resources, and 37 prompts. Each icon is stored as three base64 data URIs — a scalable SVG (Sizes: ["any"]) plus light/dark 16×16 lossless WebP fallbacks (Sizes: ["16x16"]) for clients that reject SVG — and helps MCP clients render recognizable UI elements for each GitLab domain. They are optional presentation metadata, not a negotiated MCP protocol capability: a client that cannot render any of the formats simply ignores them, and tool behavior is unchanged.
How are GitLab MCP Server icons designed?
Section titled “How are GitLab MCP Server icons designed?”- 16×16 viewport — minimal size optimized for tool lists and sidebars
currentColorfill on the SVG entry — icons adapt to light and dark themes automaticallyTheme-paired WebP fallback — a near-black and a near-white 16×16 WebP, taggedlight/dark, for clients that reject SVG- Inline data URIs — embedded in the binary, zero network requests
- One icon per domain — related tools share the same icon for visual grouping
Icon gallery
Section titled “Icon gallery”All 50 domain icons at 32px display size, grouped by domain category. The Name column shows the Go variable used in code. Icons are attached per catalog group, a group being a meta-tool such as gitlab_branch or gitlab_issue: the individual tools projected from its actions and the gitlab://tools entries on the dynamic surface inherit the group’s icon, so a group name below stands for every tool it aggregates. Resources and prompts pick their icon directly. Twelve icons (IconAlert, IconBot, IconContainer, IconDiscussion, IconEpic, IconImport, IconIntegration, IconLink, IconNotify, IconSchedule, IconTodo, IconUpload) currently have no consumer on any served surface: the domains they were drawn for route under a broader group and take that group’s icon.
Source control
Section titled “Source control”| Preview | Name | Catalog groups |
|---|---|---|
IconBranch | gitlab_branch | |
IconCommit | none (resource commit and prompt audit_commit_hygiene only; commit actions route under gitlab_repository) | |
IconTag | gitlab_tag | |
IconRelease | gitlab_release | |
IconFile | gitlab_repository |
Issues & planning
Section titled “Issues & planning”| Preview | Name | Catalog groups |
|---|---|---|
IconIssue | gitlab_issue | |
IconLabel | none (label resources and the label_distribution prompt; label actions route under gitlab_project and gitlab_group) | |
IconMilestone | none (milestone resources and prompts; milestone actions route under gitlab_project and gitlab_group) | |
IconBoard | none (resource board; board actions route under gitlab_project and gitlab_group) | |
IconLink | none (issue and release links route under gitlab_issue and gitlab_release) | |
IconTodo | none (todo actions route under gitlab_user) | |
IconEpic | none (epic actions route under gitlab_group) |
Merge requests
Section titled “Merge requests”| Preview | Name | Catalog groups |
|---|---|---|
IconMR | gitlab_merge_request, gitlab_mr_review | |
IconDiscussion | none (discussion and note actions route under their parent’s group: gitlab_issue, gitlab_mr_review, gitlab_repository, gitlab_group, gitlab_snippet) |
| Preview | Name | Catalog groups |
|---|---|---|
IconPipeline | gitlab_pipeline | |
IconJob | gitlab_job | |
IconSchedule | none (pipeline schedules route under gitlab_pipeline, freeze periods under gitlab_environment) | |
IconVariable | gitlab_ci_variable | |
IconRunner | gitlab_runner |
Environments & deployments
Section titled “Environments & deployments”| Preview | Name | Catalog groups |
|---|---|---|
IconEnvironment | gitlab_environment | |
IconDeploy | none (resource deployment; deployment actions route under gitlab_environment) | |
IconInfra | gitlab_geo, gitlab_storage_move |
Projects & groups
Section titled “Projects & groups”| Preview | Name | Catalog groups |
|---|---|---|
IconProject | gitlab_project, gitlab_project_alias, and the standalone gitlab_discover_project | |
IconGroup | gitlab_group, gitlab_group_scim | |
IconUser | gitlab_user, gitlab_enterprise_user | |
IconQueue | gitlab_merge_train | |
IconBot | none (service accounts route under gitlab_group and gitlab_project) |
Packages & registry
Section titled “Packages & registry”| Preview | Name | Catalog groups |
|---|---|---|
IconPackage | gitlab_package, gitlab_dependency, gitlab_model_registry | |
IconContainer | none (the container registry routes under gitlab_package) |
Search & analytics
Section titled “Search & analytics”| Preview | Name | Catalog groups |
|---|---|---|
IconSearch | gitlab_search, and gitlab_find_action on the dynamic surface | |
IconAnalytics | gitlab_dora_metrics, gitlab_orbit |
Security & access
Section titled “Security & access”| Preview | Name | Catalog groups |
|---|---|---|
IconSecurity | gitlab_security_attribute, gitlab_security_category, gitlab_security_finding, gitlab_security_scan_profile | |
IconToken | gitlab_access | |
IconKey | none (resource deploy_key; key actions route under gitlab_access, gitlab_user and gitlab_group) | |
IconShield | gitlab_attestation, gitlab_external_status_check | |
IconVulnerability | gitlab_vulnerability | |
IconCompliance | gitlab_compliance_policy |
Documentation & content
Section titled “Documentation & content”| Preview | Name | Catalog groups |
|---|---|---|
IconWiki | gitlab_wiki, and the five workflow guide resources | |
IconSnippet | gitlab_snippet |
Configuration & administration
Section titled “Configuration & administration”| Preview | Name | Catalog groups |
|---|---|---|
IconConfig | gitlab_admin, gitlab_feature_flags, gitlab_member_role, the gitlab_interactive_* wizards, and the gitlab://tools manifest resources | |
IconServer | gitlab_execute_action on the dynamic surface, and the fallback for a group missing from the icon map | |
IconTemplate | gitlab_template, gitlab_ci_catalog |
Notifications & events
Section titled “Notifications & events”| Preview | Name | Catalog groups |
|---|---|---|
IconNotify | none (notification actions route under gitlab_user and gitlab_admin) | |
IconEvent | gitlab_custom_emoji | |
IconAlert | none (alert and error-tracking actions route under gitlab_admin) | |
IconAudit | gitlab_audit_event |
Integrations & operations
Section titled “Integrations & operations”| Preview | Name | Catalog groups |
|---|---|---|
IconIntegration | none (integration actions route under gitlab_project, system hooks under gitlab_admin) | |
IconHealth | gitlab_server (gitlab_server_status on the individual surface) | |
IconUpload | none (upload actions route under gitlab_project and gitlab_group) | |
IconImport | none (import and export actions route under gitlab_project, gitlab_group and gitlab_admin) |
Which MCP clients render icons?
Section titled “Which MCP clients render icons?”Icon rendering depends on the MCP client. The server attaches the same icon metadata in every case; whether it appears is up to the client. Icons are optional, so clients that do not render them lose nothing functional. This table reflects a primary-source (client source code and official docs) survey of 15 clients from 2026-08-24, not vendor marketing.
| MCP Client | Renders | Notes |
|---|---|---|
| VS Code (GitHub Copilot) | ✅ Yes | Rejects the SVG entry (image/svg+xml not in its MIME allowlist), renders the Theme-matched WebP fallback |
| Cursor | ❓ Unclear | Accepts the SVG format in validation, but server-icon rendering was staff-confirmed absent as of March 2026 (an unconfirmed hint of improvement followed in June); tool/resource/prompt icons unverified |
| OpenAI Codex (CLI + IDE core) | ❓ Unclear | Server/tool icons are captured and forwarded internally, but no rendering code was found in the open-source TUI; the closed-source VS Code extension and ChatGPT desktop app were not inspectable |
| Windsurf / Devin Desktop | ❓ Unknown | No icon documentation found anywhere; closed source, no public client to inspect |
| JetBrains AI Assistant / Junie | ❌ No | Settings docs enumerate only generic action-button icons (add/remove/edit/reconnect) and a connection-status glyph — no server-supplied icon field; resources and prompts remain wholly unsupported (JUNIE-1606/1607, both open) |
| Claude Desktop | ❌ No | Protocol-level icons are not confirmed rendered anywhere; a separate, unrelated .mcpb manifest icon mechanism works for local extensions, which is not what this project ships |
| Claude Code | ❌ No | Text-only interface — a generic placeholder and the raw tool name |
| Kiro (AWS) | ❌ No | Prompts/resources show a generic “MCP” protocol badge, not this project’s per-item icon |
| Zed | ❌ No | Verified in source: no icons field on any of its Implementation/Tool/Resource/Prompt types |
| Cline | ❌ No | No icon rendering found anywhere in the client |
| Continue.dev | ❌ No | No MCP icon rendering in any version, in any format; separate favicon setting |
| Goose (Block) | ❌ No | Its SDK carries the field; Goose’s own client never reads it |
| LibreChat | ❌ No | No icon rendering found anywhere in the client |
| Open WebUI | ❌ No | No icon rendering found anywhere in the client |
| 5ire / Witsy | ❌ No | No icon rendering found in either client |
| Custom clients (direct LLM API) | Depends | Renders whichever entries its own MCP client implementation honors — see Building a custom MCP client? below for a concrete selection algorithm |
Building a custom MCP client?
Section titled “Building a custom MCP client?”If you’re talking to an MCP server directly over JSON-RPC — no VS Code, Claude Desktop, or Cursor in between — icon rendering is entirely your client’s job. icons is optional, additive metadata (SEP-973, protocol revision 2025-11-25): a server that ignores it (Zed, Continue.dev, and most hand-rolled clients today) is still fully spec-compliant. Everything below is for clients that do want to render a UI.
Where to find icons
Section titled “Where to find icons”The array shows up on four object types, wherever your client already reads their name/description:
| Carrier | Where it comes from |
|---|---|
Implementation | serverInfo.icons in the initialize response — the server’s own brand mark |
Tool | each entry in tools/list |
Resource / ResourceTemplate | each entry in resources/list |
Prompt | each entry in prompts/list |
Each Icon is { src, mimeType?, sizes?, theme? }. src is a data: or https:/http: URI. Treat an absent or empty icons array as “no icon for this object” and fall back to a generic per-type glyph (wrench for tools, document for resources, etc.) — never fail the call over it.
Selection algorithm
Section titled “Selection algorithm”Run every candidate icon array through three filters, in this order. Stop as soon as one candidate survives; if none do, fall back to your generic glyph.
- Format support. Decide up front what your renderer can display — typically raster formats your UI toolkit/image decoder handles natively (
image/png,image/jpeg,image/webp,image/gif), plusimage/svg+xmlonly if you’ve built the sanitization path below. Filter on the declaredmimeTypewhen present; when it’s absent, sniff the actual bytes (magic number fordata:, or aHEAD/Content-Typecheck forhttps:) rather than guessing from the URI’s file extension —mimeTypeis server-supplied, untrusted metadata, not a guarantee. - Theme match. If your client has a light/dark UI theme, prefer icons whose
themematches it. Critically: an icon with nothemefield is theme-agnostic, not unthemed — it’s designed to render correctly regardless of host theme (e.g. an SVG usingcurrentColorthat inherits your UI’s text color). Match it in both light and dark modes rather than skipping it or treating it as a coin-flip default. Concretely: gitlab-mcp-server ships threeIconentries per icon — one SVG withsizes: ["any"]and notheme(adapts viacurrentColor), plus a WebP pair withsizes: ["16x16"]and explicittheme: "light"/theme: "dark"(pre-rendered near-black / near-white). A correct client either renders the SVG (it’s already theme-correct, so this step is a no-op) or, if it can’t do SVG, picks the WebP whosethemeequals its current UI theme. - Size match, with fallback.
sizes: ["any"]means scalable/vector — it satisfies any requested size, so treat it as your first choice whenever your format filter allows SVG. For raster candidates, parse eachWxHstring, sort ascending, and pick the smallest one that’s still>= your target render size(this is what VS Code does) rather than the nearest by absolute difference — an oversized icon downscales cleanly; an undersized one doesn’t upscale cleanly. If nothing meets the target, take the largest available rather than failing.
Security checklist
Section titled “Security checklist”Icons come from a server you may not control, so treat every field as untrusted input, per the spec’s own SHOULDs:
- Scheme allowlist. Accept only
data:andhttps:(treat plainhttp:as untrusted unless you’re deliberately supporting local/dev HTTP-transport servers). Reject everything else (file:,javascript:, etc.) outright. - Domain check on remote URLs. The spec says consumers SHOULD verify an
https:/http:icon URL is same-domain as the client/server or otherwise trusted — don’t blindly render an<img src>pointing at an arbitrary third party. VS Code’s approach is a good concrete bar: for a server reached over HTTP transport, only accept icon URLs whose authority matches that same server’s authority; reject anything pointing elsewhere. data:URIs still need validation. Verify the declared/sniffed MIME is one you actually allow, cap the decoded byte size before handing it to your image decoder (a malicious server can embed an oversized or malformed payload as a cheap DoS against your renderer), and reject on any decode error rather than best-effort passing it through.- Remote fetches are real network requests. An
https:icon isn’t inert metadata — resolving it leaks the viewer’s IP and enables tracking/beacon patterns, and if you fetch it server-side (e.g. to proxy or cache it) that’s a user-controlled URL fetch and needs the same SSRF guards as any other: block private/link-local ranges, cap redirects, set a timeout and a byte-size ceiling. - SVG is the highest-risk format — the spec calls this out explicitly: SVG can embed
<script>and event-handler attributes. Two acceptable paths: (a) don’t supportimage/svg+xmlat all and drop straight to the next candidate (this is what VS Code does — simplest safe default), or (b) if you want crisp vector icons, sanitize before rendering — strip<script>, allon*attributes,<foreignObject>, and external references (e.g. with an SVG-profile DOMPurify config) before inlining the markup or handing it to your DOM/renderer. Never pass raw SVG bytes from an untrusted server straight into an inline<svg>/dangerouslySetInnerHTML-style sink. - Cap what you evaluate. A hostile server can return hundreds of
Iconentries per object; bound how many you inspect per selection call so a malformed response can’t turn icon rendering into an amplification vector.
Selection logic, end to end
Section titled “Selection logic, end to end”type Icon = { src: string; mimeType?: string; sizes?: string[]; theme?: "light" | "dark";};
const SUPPORTED_MIME = new Set([ "image/png", "image/jpeg", "image/webp", "image/gif",]);// Flip to true only once you've wired the sanitize-before-render path below.const SUPPORTS_SANITIZED_SVG = false;
function selectIcon( icons: Icon[] | undefined, opts: { uiTheme: "light" | "dark"; targetPx: number; serverAuthority: string; },): Icon | undefined { if (!icons?.length) return undefined;
const candidates = icons // 1. scheme allowlist + domain check .filter((i) => { const uri = safeParseUri(i.src); if (!uri) return false; if (uri.scheme === "data") return true; if (uri.scheme === "https" || uri.scheme === "http") { return ( uri.authority.toLowerCase() === opts.serverAuthority.toLowerCase() ); } return false; }) // 2. format support (sniff, don't trust the label blindly) .filter((i) => { const mime = i.mimeType ?? sniffMimeType(i.src); if (mime === "image/svg+xml") return SUPPORTS_SANITIZED_SVG; return mime !== undefined && SUPPORTED_MIME.has(mime); });
if (!candidates.length) return undefined;
// 3. theme: exact match OR theme-agnostic (no `theme` field at all) const themed = candidates.filter( (i) => i.theme === undefined || i.theme === opts.uiTheme, ); const pool = themed.length ? themed : candidates;
// 4. size: prefer scalable ("any"), else smallest raster >= target, else largest available const scalable = pool.find((i) => i.sizes?.includes("any")); if (scalable) return scalable;
const bySize = pool .flatMap((i) => (i.sizes ?? []).map((s) => ({ icon: i, ...parseWxH(s) }))) .sort((a, b) => a.width - b.width);
return ( bySize.find((c) => c.width >= opts.targetPx)?.icon ?? bySize[bySize.length - 1]?.icon ?? pool[0] );}
// Render step (only reached for icon.mimeType === "image/svg+xml"):// svgMarkup = fetchOrDecode(icon.src)// safeMarkup = sanitizeSvg(svgMarkup) // strip <script>, on*, <foreignObject>, external refs// renderInline(safeMarkup)This gives you graceful degradation at every layer: no icons field → your generic glyph; icons present but none pass your format/scheme/domain filters → same generic glyph; a full match → the theme- and size-correct variant, rendered through a path that never trusts server-supplied bytes further than necessary.
Technical details
Section titled “Technical details”- Source:
internal/toolutil/icons.go, generator:cmd/gen_icon_webp - Encoding: three base64 data URIs per icon —
data:image/svg+xml;base64,...plusdata:image/webp;base64,...(light) anddata:image/webp;base64,...(dark). The previews on this page use URL-encoded SVG (data:image/svg+xml,%3Csvg ...) for inline browser rendering only — the registered icons ininternal/toolutil/icons.goare base64. - Viewport: All icons use 16×16; the SVG entry uses
currentColorfor automatic theme adaptation, the WebP entries are pre-rasterized per theme (Theme: "light"near-black,Theme: "dark"near-white) - Registration: Icons are assigned through catalog action specs and group specs, then projected into meta, individual, and dynamic tool surfaces
Frequently asked questions
What are the icons in GitLab MCP Server?
GitLab MCP Server assigns 50 unique domain icons to every tool, resource, and prompt it exposes, plus a 51st brand mark on the server identity itself, so MCP clients can render recognizable UI elements for each GitLab domain. Related tools share one icon for visual grouping — for example, branches, repository, and submodules all use IconBranch. Each icon carries three entries: a scalable SVG (Sizes: ["any"], currentColor fill, adapts to any theme automatically) plus two 16×16 lossless WebP fallbacks tagged Theme: "light"/"dark", for clients that reject SVG but honor the theme hint. They are optional presentation metadata, not a negotiated MCP protocol capability.
How are GitLab MCP Server icons designed and encoded?
Each icon uses a minimal 16×16 viewport optimized for tool lists and sidebars. The primary entry is an SVG with a currentColor fill so it adapts to light and dark themes automatically; it is embedded as a base64 data URI (data:image/svg+xml;base64,...) directly in the binary, requiring zero network requests. Two more entries are pre-rasterized, lossless WebP fallbacks (data:image/webp;base64,..., 16×16, near-black for Theme: "light" and near-white for Theme: "dark") generated by cmd/gen_icon_webp for clients whose MIME allowlist excludes SVG. One icon is shared per domain so related tools group visually. Icons are registered through catalog action specs and group specs, then projected into the meta, individual, and dynamic tool surfaces. The source lives in `internal/toolutil/icons.go`, plus the generated project mark in internal/toolutil/brandmark_gen.go (emitted by cmd/gen_brand).
Which MCP clients render tool icons?
Icon rendering varies by client. VS Code with GitHub Copilot renders tool, server, and resource icons — it rejects the SVG entry (image/svg+xml is not in its MIME allowlist) but renders the theme-matched WebP fallback instead. Continue.dev does not render MCP protocol icons in any current version, in any format; it has a separate, unrelated per-server favicon setting that is sometimes mistaken for icon support. Claude Desktop does not render tool icons, and Claude Code is a text-only interface that does not display them. Because icons are optional metadata, clients that do not support icon rendering simply ignore them and tool functionality is unaffected.
Do icons affect tool functionality?
No. Icons are optional presentation metadata attached to tools, resources, and prompts. Clients that cannot render icons ignore them, and every tool behaves identically whether or not its icon is displayed. Icons exist purely to help users visually recognize GitLab domains in clients that support SVG or WebP rendering; they never change a tool's parameters, behavior, or results.