Icons
GitLab MCP Server assigns 51 unique domain icons to all 1088 tools of a self-managed Ultimate instance (1094 on GitLab.com Ultimate, with Orbit), 34 base meta-tools (51 on self-managed Ultimate, 52 on GitLab.com Ultimate), 45 resources, and 37 prompts, and a 52nd icon, the brand mark, to the server itself. Each icon is stored as three base64 data URIs, a scalable SVG (Sizes: ["any"]) followed by light and 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 for the 51 domain icons, a minimal size suited to tool lists and sidebars (the brand mark keeps a 24×24 viewBox)
currentColorfill on the SVG entry, so an icon takes the client’s text color and adapts to light and dark themes without declaring oneTheme-paired WebP fallback: a near-black and a near-white 16×16 WebP, taggedlightanddark, for clients that reject SVG- Small, flat SVGs: 14 of the 51 domain icons are a single
<path>, the rest use at most seven elements, all of thempath,circle,ellipse,line,polylineorrect, and no icon’s markup reaches 700 bytes - Self-contained: no
<script>, no event handlers, nostyle, no text, no external references and no embedded images, so drawing an icon makes the client fetch or run nothing - Inline data URIs, embedded in the binary, so showing an icon costs no network request
- One icon per catalog group: every tool of a group shares the group’s icon, and related groups share one (
gitlab_projectandgitlab_project_alias, for example)
Which formats does each icon carry?
Section titled “Which formats does each icon carry?”The MCP specification (revision 2025-11-25) sets the image types a client that renders icons has to accept:
| MIME type | Client support | Notes |
|---|---|---|
image/png | MUST | Universal compatibility |
image/jpeg (and image/jpg) | MUST | Universal compatibility |
image/svg+xml | SHOULD | Scalable, needs security precautions; this server’s first entry |
image/webp | SHOULD | Modern, efficient format; this server’s two fallbacks |
Every icon this server sends is an array of three entries, always in the same order:
| Entry | mimeType | sizes | theme | Color |
|---|---|---|---|---|
icons[0] | image/svg+xml | ["any"] | (none) | currentColor |
icons[1] | image/webp | ["16x16"] | light | near-black #1A1A1A |
icons[2] | image/webp | ["16x16"] | dark | near-white #FAFAFA |
The order is a stable contract, pinned by the server’s unit tests: the SVG comes first, then the light WebP, then the dark one. A client should still choose by mimeType and theme, but one that reads by position can rely on it. SVG and WebP are only SHOULD-level, so a client that renders PNG and JPEG alone, the MUST-level minimum, renders none of these icons.
How are the icons encoded?
Section titled “How are the icons encoded?”Every entry is an inline data: URI carrying base64, never a link a client has to fetch. Base64 rather than raw markup because SVG carries characters (<, >, ", #, spaces) that are not valid in an unencoded data URI, and because the specification describes an embedded icon as a data: URI with base64-encoded image data:
data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIC4uLj4uLi48L3N2Zz4=data:image/webp;base64,UklGRiYAAABXRUJQVlA4...The SVG entry fills with currentColor, so it takes the text color around it and serves every theme without declaring one. A raster image cannot do that, so the two WebP entries are drawn once per theme: near-black #1A1A1A for a light background and near-white #FAFAFA for a dark one, rather than one saturated color that would clash with both. They are 16×16 (the specification keeps sizes: ["any"] for scalable formats such as SVG) and lossless. When the fallbacks were added (#295), lossless WebP measured about 32% smaller than optimized PNG across the icon set at that size; JPEG was ruled out for having no alpha channel, and GIF because its 256-color palette with one-bit alpha bands antialiased edges.
Icon gallery
Section titled “Icon gallery”All 51 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 inherit the group’s icon, so a group name below stands for every tool it aggregates. The dynamic surface lists only two tools, gitlab_find_action (IconSearch) and gitlab_execute_action (IconServer), and neither its search results nor the gitlab://tools manifest carries an icon per action. Resources and prompts pick their icon directly; the table after the gallery lists them. 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 | |
IconAchievement | gitlab_achievement | |
IconQueue | gitlab_merge_train | |
IconBot | none (service accounts route under gitlab_group, gitlab_project and gitlab_user) |
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 (GitLab.com only) |
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, which no group the catalog builds reaches: a unit test holds every group, at every tier on a self-managed instance and on GitLab.com, to an entry of its own | |
IconTemplate | gitlab_template, gitlab_ci_catalog |
Notifications & events
Section titled “Notifications & events”| Preview | Name | Catalog groups |
|---|---|---|
IconNotify | none (notification settings route under gitlab_user) | |
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 icons do resources and prompts use?
Section titled “Which icons do resources and prompts use?”Resources and prompts name their icon directly instead of inheriting one from a catalog group. This table lists, by the name the server registers, every icon that at least one of the 45 resources or 37 prompts carries; the other 27 domain icons are used by none.
| Icon | Resources | Prompts |
|---|---|---|
IconAnalytics | none | merge_velocity, project_activity_report, weekly_team_recap |
IconBoard | board | none |
IconBranch | branch, project_branches | branch_mr_summary, compare_branches |
IconCommit | commit | audit_commit_hygiene |
IconConfig | feature_flag, tool_manifest, tool_detail | none |
IconDeploy | deployment | none |
IconEnvironment | environment | none |
IconFile | file_blob | none |
IconGroup | group, groups | team_overview |
IconHealth | none | project_health_check |
IconIssue | issue, project_issues | my_issues, stale_items_report, unassigned_items |
IconJob | job, pipeline_jobs | none |
IconKey | deploy_key | none |
IconLabel | label, group_label, project_labels | label_distribution |
IconMR | merge_request, merge_request_notes, merge_request_discussions | group_mr_dashboard, mr_description_quality, mr_discussion_health, mr_risk_assessment, my_open_mrs, my_pending_reviews, review_mr, suggest_mr_reviewers, summarize_mr_changes, summarize_open_mrs |
IconMilestone | milestone, group_milestone, project_milestones | group_milestone_progress, milestone_progress |
IconPipeline | pipeline, latest_pipeline | summarize_pipeline_status |
IconProject | project, group_projects | none |
IconRelease | release, project_releases | generate_release_notes, release_cadence, release_readiness |
IconSecurity | none | audit_project_full, audit_project_workflow |
IconSnippet | snippet, project_snippet | none |
IconTag | tag, project_tags | none |
IconUser | current_user, group_members, project_members | daily_standup, my_activity_summary, project_contributors, reviewer_workload, team_member_workload, user_activity_report, user_stats |
IconWiki | wiki_page, and the five workflow guides served under gitlab://guides/ | none |
What icon does the server itself carry?
Section titled “What icon does the server itself carry?”IconBrand identifies the server rather than a GitLab domain. It is the 52nd icon, attached to the server’s own identity (Implementation.Icons) and to no tool, resource or prompt. The mark is the “fan-out”: a source node projecting three branch arcs, each ending in a node, which reads as a git graph and as the server’s design, one action catalog reaching the dynamic, meta and individual tool surfaces. It is original artwork for this project and the same mark as the site’s logo and favicon, all drawn from one geometry. It replaced first IconServer, which is also the icon of gitlab_execute_action, and then a GitLab tanuki, which is GitLab’s trademark.
A client receives it in two places:
- In the
initializeresponse, asserverInfo.icons. - In every result on protocol revision 2026-07-28 or later (SEP-2575), where a client need not send
initializefirst: the server identifies itself in the result’s_meta, underio.modelcontextprotocol/serverInfo, and that entry is the wholeImplementation, its three icon entries included. Only an empty result, such as the answer to aping, goes without it.
That second path is why the mark stays a handful of primitives, three arcs and four circles. Two details differ from the domain icons: it keeps a 24×24 viewBox, because it is scaled from the shared brand geometry rather than drawn at glyph size, and like them its SVG entry uses currentColor with no theme, followed by the same light and dark WebP pair for clients that reject SVG.
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, cross-checked against what each client actually does rather than against the specification’s SHOULD-level wording.
| MCP Client | Renders | Notes |
|---|---|---|
| VS Code (GitHub Copilot) | ✅ Yes | Rejects the SVG entry (image/svg+xml not in its MIME allowlist) but renders the Theme-matched WebP fallback |
| Cursor | ❓ Unclear | Accepts the SVG format in validation, but server-icon rendering itself was staff-confirmed absent as of March 2026 (an unconfirmed hint of improvement followed in June 2026); tool, resource and prompt icon rendering unverified either way |
| OpenAI Codex (CLI + IDE core) | ❓ Unclear | Server and tool icons are captured and forwarded through Codex’s internal protocol, but no code that reads them back out for rendering was found anywhere in the open-source TUI; the closed-source VS Code extension and ChatGPT desktop app could not be inspected |
| 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, with no server-supplied icon field; resources and prompts remain wholly unsupported (JUNIE-1606/1607, both open) |
| Claude Desktop | ❌ No | The protocol-level Implementation.icons and Tool.icons fields are not confirmed rendered anywhere. A separate .mcpb manifest icon does show for locally installed extensions, and this project’s Claude Desktop bundle declares one, but that is the bundle’s own icon, not the protocol-level icons this page describes |
| Claude Code | ❌ No | Text-only interface: a generic placeholder and the raw tool name, confirmed by several open feature requests asking for exactly this |
| Kiro (AWS) | ❌ No | Prompts and resource templates show a generic “MCP” protocol badge next to every entry, not the per-item icons field this project populates |
| 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 (verified in source) |
| Continue.dev | ❌ No | Does not read the MCP icons field in any version, in any format; has an unrelated proprietary faviconUrl setting instead |
| Goose (Block) | ❌ No | The underlying rmcp SDK carries the field; Goose’s own client code never reads it back out |
| 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 client 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 five object types, wherever your client already reads their name/description:
| Carrier | Where it comes from |
|---|---|
Implementation | serverInfo.icons in the initialize response, and on protocol 2026-07-28 or later the io.modelcontextprotocol/serverInfo entry of each result’s _meta: the server’s own brand mark |
Tool | each entry in tools/list |
Resource | each entry in resources/list |
ResourceTemplate | each entry in resources/templates/list |
Prompt | each entry in prompts/list |
Each Icon is { src, mimeType?, sizes?, theme? }. The specification lets src be an HTTP or HTTPS URL or a data: URI with base64 image data, and it requires a consumer to accept only https: and data: and to reject unsafe schemes such as javascript:, file:, ftp: and ws:. This server only ever sends data: URIs. 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, as the specification requires of every consumer:
- Scheme allowlist. Accept only
data:andhttps:, as the specification requires, and reject everything else outright, plainhttp:included along withfile:,javascript:,ftp:andws:. Refuse a redirect that changes the scheme or leaves the origin. - Origin check on remote URLs. The specification asks consumers to verify that an
https:icon URL comes from the same origin as the server, so 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. Fetch an icon without credentials: no cookies, noAuthorizationheader. 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") { 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, generators:cmd/gen_icon_webpfor the WebP fallbacks andcmd/gen_brandfor the brand mark - Encoding: three base64 data URIs per icon,
data:image/svg+xml;base64,...followed bydata:image/webp;base64,...(light) anddata:image/webp;base64,...(dark). The previews on this page use URL-encoded SVG (data:image/svg+xml,%3Csvg ...) colored#888for inline browser rendering only; the registered icons are base64 and usecurrentColor. - Viewport: the domain icons use 16×16 and the brand mark 24×24; 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: each catalog group has one icon (a group missing from the icon map would fall back to
IconServer, and a unit test holds every group the catalog builds to an entry, so none does); a meta-tool carries it and every individual tool projected from the group’s actions inherits it, while the dynamic surface’s two tools carryIconSearchandIconServer, and resources and prompts name their own
Contributors regenerating the WebP fallbacks or the brand mark will find the commands under gen_icon_webp and gen_brand in the command reference.
Frequently asked questions
What are the icons in GitLab MCP Server?
GitLab MCP Server assigns 51 unique domain icons to every tool, resource, and prompt it exposes, plus a 52nd brand mark on the server identity itself, so MCP clients can render recognizable UI elements for each GitLab domain. Icons are attached per catalog group, so every tool of a group shares one: the tools of gitlab_branch use IconBranch, while every tool of gitlab_repository (the tree, commits, files, and submodules) uses IconFile. Each icon carries three entries, always in this order: 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 domain 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. Icons are attached per catalog group, not per action: a meta-tool carries its group's icon, and every individual tool projected from that group's actions inherits it, so related tools group visually. The dynamic surface lists only gitlab_find_action (IconSearch) and gitlab_execute_action (IconServer); the actions they reach carry no icon of their own. Resources and prompts name their own icon. 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.