Ir al contenido

Iconos

GitLab MCP Server asigna 50 iconos de dominio a las 1085 herramientas Enterprise/Premium autoalojadas (1091 en GitLab.com Enterprise/Premium con Orbit), 34 meta-herramientas base (51 enterprise autoalojadas, 52 GitLab.com Enterprise), 45 recursos y 37 prompts. Cada icono se almacena como tres data URIs base64 — un SVG escalable (Sizes: ["any"]) más variantes WebP clara/oscura de 16×16 sin pérdida (Sizes: ["16x16"]) para clientes que rechazan SVG — y ayuda a los clientes MCP a mostrar elementos de interfaz reconocibles para cada dominio de GitLab. Son metadatos de presentación opcionales, no una capacidad de protocolo MCP negociada: un cliente que no puede renderizar ninguno de los formatos simplemente los ignora, y el comportamiento de las herramientas no cambia.

¿Cómo se diseñan los iconos de GitLab MCP Server?

Sección titulada «¿Cómo se diseñan los iconos de GitLab MCP Server?»
  • Viewport 16×16 — tamaño mínimo optimizado para listas de herramientas y barras laterales
  • currentColor en la entrada SVG — los iconos se adaptan automáticamente a temas claro y oscuro
  • Variante WebP por tema — un WebP casi negro y otro casi blanco, de 16×16, etiquetados light/dark, para clientes que rechazan SVG
  • Data URIs en línea — embebidos en el binario, cero peticiones de red
  • Un icono por dominio — las herramientas relacionadas comparten el mismo icono para agrupación visual

Los 50 iconos de dominio a 32px de tamaño, agrupados por categoría de dominio. La columna Nombre muestra la variable Go usada en el código. Los iconos se adjuntan por grupo del catálogo, siendo un grupo una meta-herramienta como gitlab_branch o gitlab_issue: las herramientas individuales proyectadas desde sus acciones y las entradas de gitlab://tools en la superficie dinámica heredan el icono del grupo, así que un nombre de grupo más abajo representa a todas las herramientas que agrega. Los recursos y los prompts eligen su icono directamente. Doce iconos (IconAlert, IconBot, IconContainer, IconDiscussion, IconEpic, IconImport, IconIntegration, IconLink, IconNotify, IconSchedule, IconTodo, IconUpload) no tienen actualmente ningún consumidor en ninguna superficie servida: los dominios para los que se dibujaron se enrutan bajo un grupo más amplio y toman el icono de ese grupo.

Vista previaNombreGrupos del catálogo
RamaIconBranchgitlab_branch
CommitIconCommitninguno (solo el recurso commit y el prompt audit_commit_hygiene; las acciones de commits se enrutan bajo gitlab_repository)
TagIconTaggitlab_tag
ReleaseIconReleasegitlab_release
ArchivoIconFilegitlab_repository
Vista previaNombreGrupos del catálogo
IssueIconIssuegitlab_issue
EtiquetaIconLabelninguno (los recursos de etiquetas y el prompt label_distribution; las acciones de etiquetas se enrutan bajo gitlab_project y gitlab_group)
MilestoneIconMilestoneninguno (recursos y prompts de milestones; las acciones de milestones se enrutan bajo gitlab_project y gitlab_group)
TableroIconBoardninguno (recurso board; las acciones de boards se enrutan bajo gitlab_project y gitlab_group)
EnlaceIconLinkninguno (los enlaces de issues y de releases se enrutan bajo gitlab_issue y gitlab_release)
Tarea pendienteIconTodoninguno (las acciones de tareas pendientes se enrutan bajo gitlab_user)
ÉpicaIconEpicninguno (las acciones de épicas se enrutan bajo gitlab_group)
Vista previaNombreGrupos del catálogo
MRIconMRgitlab_merge_request, gitlab_mr_review
DiscusiónIconDiscussionninguno (las acciones de discusiones y notas se enrutan bajo el grupo de su padre: gitlab_issue, gitlab_mr_review, gitlab_repository, gitlab_group, gitlab_snippet)
Vista previaNombreGrupos del catálogo
PipelineIconPipelinegitlab_pipeline
JobIconJobgitlab_job
ProgramaciónIconScheduleninguno (las programaciones de pipelines se enrutan bajo gitlab_pipeline, los periodos de congelación bajo gitlab_environment)
VariableIconVariablegitlab_ci_variable
RunnerIconRunnergitlab_runner
Vista previaNombreGrupos del catálogo
EntornoIconEnvironmentgitlab_environment
DespliegueIconDeployninguno (recurso deployment; las acciones de despliegues se enrutan bajo gitlab_environment)
InfraestructuraIconInfragitlab_geo, gitlab_storage_move
Vista previaNombreGrupos del catálogo
ProyectoIconProjectgitlab_project, gitlab_project_alias y la herramienta independiente gitlab_discover_project
GrupoIconGroupgitlab_group, gitlab_group_scim
UsuarioIconUsergitlab_user, gitlab_enterprise_user
ColaIconQueuegitlab_merge_train
BotIconBotninguno (las cuentas de servicio se enrutan bajo gitlab_group y gitlab_project)
Vista previaNombreGrupos del catálogo
PaqueteIconPackagegitlab_package, gitlab_dependency, gitlab_model_registry
ContenedorIconContainerninguno (el registro de contenedores se enruta bajo gitlab_package)
Vista previaNombreGrupos del catálogo
BúsquedaIconSearchgitlab_search, y gitlab_find_action en la superficie dinámica
AnalíticaIconAnalyticsgitlab_dora_metrics, gitlab_orbit
Vista previaNombreGrupos del catálogo
SeguridadIconSecuritygitlab_security_attribute, gitlab_security_category, gitlab_security_finding, gitlab_security_scan_profile
TokenIconTokengitlab_access
ClaveIconKeyninguno (recurso deploy_key; las acciones de claves se enrutan bajo gitlab_access, gitlab_user y gitlab_group)
EscudoIconShieldgitlab_attestation, gitlab_external_status_check
VulnerabilidadIconVulnerabilitygitlab_vulnerability
CumplimientoIconCompliancegitlab_compliance_policy
Vista previaNombreGrupos del catálogo
WikiIconWikigitlab_wiki, y los cinco recursos de guías de flujo de trabajo
SnippetIconSnippetgitlab_snippet
Vista previaNombreGrupos del catálogo
ConfiguraciónIconConfiggitlab_admin, gitlab_feature_flags, gitlab_member_role, los asistentes gitlab_interactive_* y los recursos del manifiesto gitlab://tools
ServidorIconServergitlab_execute_action en la superficie dinámica, y el valor de reserva para un grupo ausente del mapa de iconos
PlantillaIconTemplategitlab_template, gitlab_ci_catalog
Vista previaNombreGrupos del catálogo
NotificaciónIconNotifyninguno (las acciones de notificaciones se enrutan bajo gitlab_user y gitlab_admin)
EventoIconEventgitlab_custom_emoji
AlertaIconAlertninguno (las acciones de alertas y de seguimiento de errores se enrutan bajo gitlab_admin)
AuditoríaIconAuditgitlab_audit_event
Vista previaNombreGrupos del catálogo
IntegraciónIconIntegrationninguno (las acciones de integraciones se enrutan bajo gitlab_project, los system hooks bajo gitlab_admin)
SaludIconHealthgitlab_server (gitlab_server_status en la superficie individual)
SubidaIconUploadninguno (las acciones de subidas se enrutan bajo gitlab_project y gitlab_group)
ImportaciónIconImportninguno (las acciones de importación y exportación se enrutan bajo gitlab_project, gitlab_group y gitlab_admin)

El renderizado de iconos depende del cliente MCP. El servidor adjunta los mismos metadatos de iconos en todos los casos; que aparezcan depende del cliente. Los iconos son opcionales, así que los clientes que no los renderizan no pierden nada funcional. Esta tabla refleja una investigación de fuentes primarias (código fuente del cliente y documentación oficial, no material de marketing) sobre 15 clientes, realizada el 2026-08-24.

Cliente MCPRenderizaNotas
VS Code (GitHub Copilot)✅ SíRechaza la entrada SVG (image/svg+xml no está en su lista de MIME permitidos), renderiza la variante WebP que coincide con su tema
Cursor❓ InciertoAcepta el formato SVG en validación, pero el renderizado del icono de servidor fue confirmado ausente por el equipo en marzo de 2026 (un indicio no confirmado de mejora llegó en junio); iconos de herramienta/recurso/prompt sin verificar
OpenAI Codex (CLI + núcleo IDE)❓ InciertoLos iconos de servidor/herramienta se capturan y reenvían internamente, pero no se encontró código de renderizado en la TUI de código abierto; la extensión de VS Code y la app de escritorio de ChatGPT, de código cerrado, no se pudieron inspeccionar
Windsurf / Devin Desktop❓ DesconocidoNo se encontró documentación de iconos en ningún sitio; código cerrado, sin cliente público que inspeccionar
JetBrains AI Assistant / Junie❌ NoLos documentos de configuración solo enumeran iconos genéricos de botones de acción (añadir/eliminar/editar/reconectar) y un indicador de estado de conexión — no hay campo de icono propio del servidor; los recursos y prompts siguen sin soporte alguno (JUNIE-1606/1607, ambos abiertos)
Claude Desktop❌ NoLos iconos a nivel de protocolo no se confirman renderizados en ningún sitio; un mecanismo distinto y no relacionado de icono de manifiesto .mcpb sí funciona para extensiones locales, que no es lo que este proyecto usa
Claude Code❌ NoInterfaz solo texto — un marcador genérico y el nombre bruto de la herramienta
Kiro (AWS)❌ NoPrompts/recursos muestran una insignia genérica “MCP”, no el icono por elemento de este proyecto
Zed❌ NoVerificado en el código fuente: ninguno de sus tipos Implementation/Tool/Resource/Prompt lleva un campo icons
Cline❌ NoNo se encontró renderizado de iconos en ninguna parte del cliente
Continue.dev❌ NoNo renderiza iconos MCP en ninguna versión ni formato; ajuste de favicon aparte
Goose (Block)❌ NoSu SDK lleva el campo; el propio cliente de Goose nunca lo lee
LibreChat❌ NoNo se encontró renderizado de iconos en ninguna parte del cliente
Open WebUI❌ NoNo se encontró renderizado de iconos en ninguna parte del cliente
5ire / Witsy❌ NoNo se encontró renderizado de iconos en ninguno de los dos clientes
Clientes propios (API de LLM directa)DependeRenderiza las entradas que su propia implementación de cliente MCP admita — consulta ¿Construyes tu propio cliente MCP? más abajo para un algoritmo de selección concreto

Si hablas directamente con un servidor MCP por JSON-RPC — sin VS Code, Claude Desktop o Cursor de por medio — el renderizado de iconos es responsabilidad exclusiva de tu cliente. icons son metadatos opcionales y aditivos (SEP-973, revisión de protocolo 2025-11-25): un servidor que los ignora (Zed, Continue.dev y la mayoría de clientes propios hoy en día) sigue siendo totalmente conforme a la especificación. Todo lo que sigue es para clientes que sí quieren renderizar una interfaz.

El array aparece en cuatro tipos de objeto, allí donde tu cliente ya lee su nombre/descripción:

PortadorDe dónde procede
ImplementationserverInfo.icons en la respuesta de initialize — la marca propia del servidor
Toolcada entrada de tools/list
Resource / ResourceTemplatecada entrada de resources/list
Promptcada entrada de prompts/list

Cada Icon es { src, mimeType?, sizes?, theme? }. src es una URI data: o https:/http:. Trata un array icons ausente o vacío como “sin icono para este objeto” y recurre a un glifo genérico por tipo (una llave inglesa para herramientas, un documento para recursos, etc.) — nunca falles la llamada por ello.

Pasa cada array de iconos candidato por tres filtros, en este orden. Detente en cuanto un candidato sobreviva; si ninguno lo hace, recurre a tu glifo genérico.

  1. Soporte de formato. Decide de antemano qué puede mostrar tu renderizador — normalmente formatos rasterizados que tu toolkit de interfaz/decodificador de imágenes maneja de forma nativa (image/png, image/jpeg, image/webp, image/gif), más image/svg+xml solo si has construido la ruta de sanitización descrita más abajo. Filtra por el mimeType declarado cuando esté presente; cuando falte, analiza los bytes reales (número mágico para data:, o una comprobación HEAD/Content-Type para https:) en lugar de adivinar por la extensión del archivo en la URI — mimeType es un metadato suministrado por el servidor, no fiable, no una garantía.
  2. Coincidencia de tema. Si tu cliente tiene un tema de interfaz claro/oscuro, prefiere los iconos cuyo theme coincida. Importante: un icono sin campo theme es agnóstico al tema, no “sin tema” — está diseñado para renderizarse correctamente sin importar el tema del anfitrión (por ejemplo, un SVG que usa currentColor y hereda el color de texto de tu interfaz). Hazlo coincidir en ambos modos, claro y oscuro, en lugar de omitirlo o tratarlo como una opción por defecto al azar. En concreto: gitlab-mcp-server envía tres entradas Icon por icono — un SVG con sizes: ["any"] y sin theme (se adapta vía currentColor), más un par WebP con sizes: ["16x16"] y theme: "light" / theme: "dark" explícitos (renderizados de antemano en casi negro / casi blanco). Un cliente correcto o bien renderiza el SVG (ya es correcto para cualquier tema, así que este paso es un no-op), o bien, si no puede con SVG, elige el WebP cuyo theme coincida con el tema actual de su interfaz.
  3. Coincidencia de tamaño, con reserva. sizes: ["any"] significa escalable/vectorial — satisface cualquier tamaño solicitado, así que trátalo como primera opción siempre que tu filtro de formato admita SVG. Para candidatos rasterizados, analiza cada cadena AnchoxAlto, ordénalas de forma ascendente y elige la más pequeña que siga siendo >= tu tamaño de renderizado objetivo (así lo hace VS Code) en lugar de la más cercana por diferencia absoluta — un icono más grande de lo necesario se reduce de forma limpia; uno más pequeño no se amplía limpiamente. Si ninguno alcanza el objetivo, toma el disponible más grande en lugar de fallar.

Los iconos proceden de un servidor que quizá no controlas, así que trata cada campo como entrada no confiable, según las recomendaciones (“SHOULD”) de la propia especificación:

  • Lista blanca de esquemas. Acepta solo data: y https: (trata http: sin más como no confiable salvo que admitas deliberadamente servidores locales/de desarrollo con transporte HTTP). Rechaza cualquier otro esquema (file:, javascript:, etc.) sin más.
  • Comprobación de dominio en URLs remotas. La especificación indica que los consumidores DEBERÍAN verificar que una URL de icono https:/http: pertenece al mismo dominio que el cliente/servidor o es de confianza por otro motivo — no renderices a ciegas un <img src> que apunte a un tercero arbitrario. El enfoque de VS Code es un buen listón concreto: para un servidor alcanzado por transporte HTTP, solo acepta URLs de icono cuya autoridad coincida con la de ese mismo servidor; rechaza cualquier otra.
  • Las URIs data: también necesitan validación. Verifica que el MIME declarado/detectado sea uno que realmente admites, limita el tamaño en bytes decodificado antes de entregarlo a tu decodificador de imágenes (un servidor malicioso puede incrustar una carga sobredimensionada o malformada como DoS barato contra tu renderizador), y rechaza ante cualquier error de decodificación en lugar de dejarlo pasar en el mejor de los casos.
  • Las descargas remotas son peticiones de red reales. Un icono https: no es un metadato inerte — resolverlo filtra la IP del espectador y habilita patrones de seguimiento/baliza, y si lo descargas del lado del servidor (por ejemplo, para hacer proxy o cachearlo) eso es una descarga de URL controlada por el usuario y necesita las mismas protecciones SSRF que cualquier otra: bloquear rangos privados/link-local, limitar redirecciones, establecer un tiempo límite y un tope de tamaño en bytes.
  • SVG es el formato de mayor riesgo — la especificación lo señala explícitamente: SVG puede incrustar <script> y atributos de gestor de eventos. Dos rutas aceptables: (a) no admitir image/svg+xml en absoluto y pasar directamente al siguiente candidato (así lo hace VS Code — la opción segura más simple), o (b) si quieres iconos vectoriales nítidos, sanitiza antes de renderizar — elimina <script>, todos los atributos on*, <foreignObject> y referencias externas (por ejemplo con una configuración de DOMPurify de perfil SVG) antes de incrustar el marcado o pasarlo a tu DOM/renderizador. Nunca pases bytes SVG en crudo procedentes de un servidor no confiable directamente a un sumidero de tipo <svg> inline o dangerouslySetInnerHTML.
  • Limita lo que evalúas. Un servidor hostil puede devolver cientos de entradas Icon por objeto; acota cuántas inspeccionas por llamada de selección para que una respuesta malformada no convierta el renderizado de iconos en un vector de amplificación.
type Icon = {
src: string;
mimeType?: string;
sizes?: string[];
theme?: "light" | "dark";
};
const SUPPORTED_MIME = new Set([
"image/png",
"image/jpeg",
"image/webp",
"image/gif",
]);
// Cambia a true solo cuando hayas implementado la ruta de sanitizar-antes-de-renderizar de abajo.
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. lista blanca de esquemas + comprobación de dominio
.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. soporte de formato (analiza los bytes, no confíes ciegamente en la etiqueta)
.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. tema: coincidencia exacta O agnóstico al tema (sin campo `theme`)
const themed = candidates.filter(
(i) => i.theme === undefined || i.theme === opts.uiTheme,
);
const pool = themed.length ? themed : candidates;
// 4. tamaño: prefiere escalable ("any"), si no el rasterizado más pequeño >= objetivo, si no el mayor disponible
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]
);
}
// Paso de renderizado (solo se alcanza cuando icon.mimeType === "image/svg+xml"):
// svgMarkup = fetchOrDecode(icon.src)
// safeMarkup = sanitizeSvg(svgMarkup) // elimina <script>, on*, <foreignObject>, referencias externas
// renderInline(safeMarkup)

Esto te da una degradación gradual en cada capa: sin campo icons → tu glifo genérico; iconos presentes pero ninguno pasa tus filtros de formato/esquema/dominio → el mismo glifo genérico; una coincidencia completa → la variante correcta en tema y tamaño, renderizada a través de una ruta que nunca confía en los bytes suministrados por el servidor más de lo necesario.

  • Fuente: internal/toolutil/icons.go, generador: cmd/gen_icon_webp
  • Codificación: tres data URIs base64 por icono — data:image/svg+xml;base64,... más data:image/webp;base64,... (clara) y data:image/webp;base64,... (oscura). Las previsualizaciones de esta página usan SVG con codificación URL (data:image/svg+xml,%3Csvg ...) solo para renderizado en línea en el navegador — los iconos registrados en internal/toolutil/icons.go están en base64.
  • Viewport: Todos los iconos usan 16×16; la entrada SVG usa currentColor para adaptación automática al tema, las entradas WebP están prerasterizadas por tema (Theme: "light" casi negro, Theme: "dark" casi blanco)
  • Registro: Los iconos se asignan mediante specs de acciones y grupos del catálogo, y luego se proyectan en las superficies meta, individual y dinámica

Preguntas frecuentes

¿Qué son los iconos en GitLab MCP Server?

GitLab MCP Server asigna 50 iconos de dominio a cada herramienta, recurso y prompt que expone, más una marca —la 51.ª— en la identidad del propio servidor, para que los clientes MCP puedan mostrar elementos de interfaz reconocibles para cada dominio de GitLab. Las herramientas relacionadas comparten un mismo icono para agrupación visual — por ejemplo, branches, repository y submodules usan todos IconBranch. Cada icono lleva tres entradas: un SVG escalable (Sizes: ["any"], relleno currentColor, se adapta a cualquier tema automáticamente) más dos variantes WebP de 16×16 sin pérdida etiquetadas Theme: "light"/"dark", para clientes que rechazan SVG pero respetan la pista de tema. Son metadatos de presentación opcionales, no una capacidad de protocolo MCP negociada.

¿Cómo se diseñan y codifican los iconos de GitLab MCP Server?

Cada icono usa un viewport mínimo de 16×16 optimizado para listas de herramientas y barras laterales. La entrada principal es un SVG con relleno currentColor que se adapta a los temas claro y oscuro automáticamente; se incrusta como data URI base64 (data:image/svg+xml;base64,...) directamente en el binario, sin peticiones de red. Otras dos entradas son variantes WebP prerasterizadas y sin pérdida (data:image/webp;base64,..., 16×16, casi negro para Theme: "light" y casi blanco para Theme: "dark") generadas por cmd/gen_icon_webp para clientes cuya lista de MIME permitidos excluye SVG. Se comparte un icono por dominio para que las herramientas relacionadas se agrupen visualmente. Se registran mediante specs de acciones y grupos del catálogo, y luego se proyectan en las superficies meta, individual y dinámica. El código fuente está en `internal/toolutil/icons.go`, más la marca del proyecto generada en internal/toolutil/brandmark_gen.go (emitida por cmd/gen_brand).

¿Qué clientes MCP renderizan los iconos de herramientas?

El renderizado de iconos varía según el cliente. VS Code con GitHub Copilot renderiza iconos de herramientas, servidor y recursos — rechaza la entrada SVG (image/svg+xml no está en su lista de MIME permitidos) pero renderiza la variante WebP que coincide con su tema. Continue.dev no renderiza iconos del protocolo MCP en ninguna versión actual, en ningún formato; tiene un ajuste de favicon por servidor no relacionado que a veces se confunde con soporte de iconos. Claude Desktop no renderiza iconos de herramientas, y Claude Code es una interfaz solo de texto que no los muestra. Como los iconos son metadatos opcionales, los clientes que no admiten su renderizado simplemente los ignoran y la funcionalidad de las herramientas no se ve afectada.

¿Afectan los iconos a la funcionalidad de las herramientas?

No. Los iconos son metadatos de presentación opcionales adjuntos a herramientas, recursos y prompts. Los clientes que no pueden renderizar iconos los ignoran, y cada herramienta se comporta de forma idéntica se muestre o no su icono. Los iconos existen únicamente para ayudar a los usuarios a reconocer visualmente los dominios de GitLab en clientes que admiten el renderizado SVG o WebP; nunca cambian los parámetros, el comportamiento ni los resultados de una herramienta.