Iconos
GitLab MCP Server asigna 51 iconos de dominio a las 1088 herramientas de una instancia Ultimate autoalojada (1094 en GitLab.com Ultimate, con Orbit), 34 meta-herramientas base (51 en Ultimate autoalojado, 52 en GitLab.com Ultimate), 45 recursos y 37 prompts, y un icono 52.º, la marca, al propio servidor. Cada icono se almacena como tres data URIs base64, un SVG escalable (Sizes: ["any"]) seguido de variantes WebP clara y 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 para los 51 iconos de dominio, un tamaño mínimo adecuado para listas de herramientas y barras laterales (la marca conserva un viewBox de 24×24)
currentColoren la entrada SVG, así que un icono toma el color de texto del cliente y se adapta a los temas claro y oscuro sin declarar ninguno- Variante WebP por tema: un WebP casi negro y otro casi blanco, de 16×16, etiquetados
lightydark, para clientes que rechazan SVG - SVG pequeños y planos: 14 de los 51 iconos de dominio son un único
<path>, el resto usa como mucho siete elementos, todos ellospath,circle,ellipse,line,polylineorect, y el marcado de ningún icono llega a 700 bytes - Autocontenidos: sin
<script>, sin gestores de eventos, sinstyle, sin texto, sin referencias externas y sin imágenes incrustadas, así que dibujar un icono no hace que el cliente descargue ni ejecute nada - Data URIs en línea, embebidos en el binario, así que mostrar un icono no cuesta ninguna petición de red
- Un icono por grupo del catálogo: todas las herramientas de un grupo comparten el icono del grupo, y los grupos relacionados comparten uno (
gitlab_projectygitlab_project_alias, por ejemplo)
¿Qué formatos lleva cada icono?
Sección titulada «¿Qué formatos lleva cada icono?»La especificación MCP (revisión 2025-11-25) fija los tipos de imagen que tiene que aceptar un cliente que renderiza iconos:
| Tipo MIME | Soporte del cliente | Notas |
|---|---|---|
image/png | MUST | Compatibilidad universal |
image/jpeg (y image/jpg) | MUST | Compatibilidad universal |
image/svg+xml | SHOULD | Escalable, requiere precauciones de seguridad; la primera entrada de este servidor |
image/webp | SHOULD | Formato moderno y eficiente; las dos variantes de este servidor |
Cada icono que envía este servidor es un array de tres entradas, siempre en el mismo orden:
| Entrada | mimeType | sizes | theme | Color |
|---|---|---|---|---|
icons[0] | image/svg+xml | ["any"] | (ninguno) | currentColor |
icons[1] | image/webp | ["16x16"] | light | casi negro #1A1A1A |
icons[2] | image/webp | ["16x16"] | dark | casi blanco #FAFAFA |
El orden es un contrato estable, fijado por las pruebas unitarias del servidor: primero el SVG, luego el WebP claro y luego el oscuro. Un cliente debería elegir de todos modos por mimeType y theme, pero uno que lea por posición puede contar con él. SVG y WebP son solo de nivel SHOULD, así que un cliente que solo renderiza PNG y JPEG, el mínimo de nivel MUST, no renderiza ninguno de estos iconos.
¿Cómo se codifican los iconos?
Sección titulada «¿Cómo se codifican los iconos?»Cada entrada es una URI data: en línea con base64, nunca un enlace que el cliente tenga que descargar. Base64 en lugar del marcado en crudo porque el SVG contiene caracteres (<, >, ", #, espacios) que no son válidos en una data URI sin codificar, y porque la especificación describe un icono incrustado como una URI data: con los datos de la imagen codificados en base64:
data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIC4uLj4uLi48L3N2Zz4=data:image/webp;base64,UklGRiYAAABXRUJQVlA4...La entrada SVG se rellena con currentColor, así que toma el color del texto que la rodea y sirve para cualquier tema sin declarar ninguno. Una imagen rasterizada no puede hacerlo, así que las dos entradas WebP se dibujan una vez por tema: casi negro #1A1A1A para un fondo claro y casi blanco #FAFAFA para uno oscuro, en lugar de un único color saturado que chocaría con ambos. Son de 16×16 (la especificación reserva sizes: ["any"] para formatos escalables como SVG) y sin pérdida. Cuando se añadieron las variantes (#295), WebP sin pérdida midió alrededor de un 32% menos que PNG optimizado en todo el conjunto de iconos a ese tamaño; JPEG se descartó por no tener canal alfa, y GIF porque su paleta de 256 colores con alfa de un bit crea bandas en los bordes suavizados.
Galería de iconos
Sección titulada «Galería de iconos»Los 51 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 heredan el icono del grupo, así que un nombre de grupo más abajo representa a todas las herramientas que agrega. La superficie dinámica solo lista dos herramientas, gitlab_find_action (IconSearch) y gitlab_execute_action (IconServer), y ni sus resultados de búsqueda ni el manifiesto gitlab://tools llevan un icono por acción. Los recursos y los prompts eligen su icono directamente; la tabla que sigue a la galería los enumera. 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.
Control de versiones
Sección titulada «Control de versiones»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconBranch | gitlab_branch | |
IconCommit | ninguno (solo el recurso commit y el prompt audit_commit_hygiene; las acciones de commits se enrutan bajo gitlab_repository) | |
IconTag | gitlab_tag | |
IconRelease | gitlab_release | |
IconFile | gitlab_repository |
Issues y planificación
Sección titulada «Issues y planificación»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconIssue | gitlab_issue | |
IconLabel | ninguno (los recursos de etiquetas y el prompt label_distribution; las acciones de etiquetas se enrutan bajo gitlab_project y gitlab_group) | |
IconMilestone | ninguno (recursos y prompts de milestones; las acciones de milestones se enrutan bajo gitlab_project y gitlab_group) | |
IconBoard | ninguno (recurso board; las acciones de boards se enrutan bajo gitlab_project y gitlab_group) | |
IconLink | ninguno (los enlaces de issues y de releases se enrutan bajo gitlab_issue y gitlab_release) | |
IconTodo | ninguno (las acciones de tareas pendientes se enrutan bajo gitlab_user) | |
IconEpic | ninguno (las acciones de épicas se enrutan bajo gitlab_group) |
Merge requests
Sección titulada «Merge requests»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconMR | gitlab_merge_request, gitlab_mr_review | |
IconDiscussion | ninguno (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 previa | Nombre | Grupos del catálogo |
|---|---|---|
IconPipeline | gitlab_pipeline | |
IconJob | gitlab_job | |
IconSchedule | ninguno (las programaciones de pipelines se enrutan bajo gitlab_pipeline, los periodos de congelación bajo gitlab_environment) | |
IconVariable | gitlab_ci_variable | |
IconRunner | gitlab_runner |
Entornos y despliegues
Sección titulada «Entornos y despliegues»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconEnvironment | gitlab_environment | |
IconDeploy | ninguno (recurso deployment; las acciones de despliegues se enrutan bajo gitlab_environment) | |
IconInfra | gitlab_geo, gitlab_storage_move |
Proyectos y grupos
Sección titulada «Proyectos y grupos»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconProject | gitlab_project, gitlab_project_alias y la herramienta independiente gitlab_discover_project | |
IconGroup | gitlab_group, gitlab_group_scim | |
IconUser | gitlab_user, gitlab_enterprise_user | |
IconAchievement | gitlab_achievement | |
IconQueue | gitlab_merge_train | |
IconBot | ninguno (las cuentas de servicio se enrutan bajo gitlab_group, gitlab_project y gitlab_user) |
Paquetes y registro
Sección titulada «Paquetes y registro»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconPackage | gitlab_package, gitlab_dependency, gitlab_model_registry | |
IconContainer | ninguno (el registro de contenedores se enruta bajo gitlab_package) |
Búsqueda y analíticas
Sección titulada «Búsqueda y analíticas»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconSearch | gitlab_search, y gitlab_find_action en la superficie dinámica | |
IconAnalytics | gitlab_dora_metrics, gitlab_orbit (solo GitLab.com) |
Seguridad y acceso
Sección titulada «Seguridad y acceso»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconSecurity | gitlab_security_attribute, gitlab_security_category, gitlab_security_finding, gitlab_security_scan_profile | |
IconToken | gitlab_access | |
IconKey | ninguno (recurso deploy_key; las acciones de claves se enrutan bajo gitlab_access, gitlab_user y gitlab_group) | |
IconShield | gitlab_attestation, gitlab_external_status_check | |
IconVulnerability | gitlab_vulnerability | |
IconCompliance | gitlab_compliance_policy |
Documentación y contenido
Sección titulada «Documentación y contenido»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconWiki | gitlab_wiki, y los cinco recursos de guías de flujo de trabajo | |
IconSnippet | gitlab_snippet |
Configuración y administración
Sección titulada «Configuración y administración»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconConfig | gitlab_admin, gitlab_feature_flags, gitlab_member_role, los asistentes gitlab_interactive_* y los recursos del manifiesto gitlab://tools | |
IconServer | gitlab_execute_action en la superficie dinámica, y el valor de reserva para un grupo ausente del mapa de iconos, al que no llega ningún grupo que construya el catálogo: una prueba unitaria exige a cada grupo, en cada nivel en una instancia autoalojada y en GitLab.com, una entrada propia | |
IconTemplate | gitlab_template, gitlab_ci_catalog |
Notificaciones y eventos
Sección titulada «Notificaciones y eventos»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconNotify | ninguno (la configuración de notificaciones se enruta bajo gitlab_user) | |
IconEvent | gitlab_custom_emoji | |
IconAlert | ninguno (las acciones de alertas y de seguimiento de errores se enrutan bajo gitlab_admin) | |
IconAudit | gitlab_audit_event |
Integraciones y operaciones
Sección titulada «Integraciones y operaciones»| Vista previa | Nombre | Grupos del catálogo |
|---|---|---|
IconIntegration | ninguno (las acciones de integraciones se enrutan bajo gitlab_project, los system hooks bajo gitlab_admin) | |
IconHealth | gitlab_server (gitlab_server_status en la superficie individual) | |
IconUpload | ninguno (las acciones de subidas se enrutan bajo gitlab_project y gitlab_group) | |
IconImport | ninguno (las acciones de importación y exportación se enrutan bajo gitlab_project, gitlab_group y gitlab_admin) |
¿Qué iconos usan los recursos y los prompts?
Sección titulada «¿Qué iconos usan los recursos y los prompts?»Los recursos y los prompts nombran su icono directamente en lugar de heredarlo de un grupo del catálogo. Esta tabla enumera, por el name con el que el servidor los registra, cada icono que lleva al menos uno de los 45 recursos o 37 prompts; los otros 27 iconos de dominio no los usa ninguno.
| Icono | Recursos | Prompts |
|---|---|---|
IconAnalytics | ninguno | merge_velocity, project_activity_report, weekly_team_recap |
IconBoard | board | ninguno |
IconBranch | branch, project_branches | branch_mr_summary, compare_branches |
IconCommit | commit | audit_commit_hygiene |
IconConfig | feature_flag, tool_manifest, tool_detail | ninguno |
IconDeploy | deployment | ninguno |
IconEnvironment | environment | ninguno |
IconFile | file_blob | ninguno |
IconGroup | group, groups | team_overview |
IconHealth | ninguno | project_health_check |
IconIssue | issue, project_issues | my_issues, stale_items_report, unassigned_items |
IconJob | job, pipeline_jobs | ninguno |
IconKey | deploy_key | ninguno |
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 | ninguno |
IconRelease | release, project_releases | generate_release_notes, release_cadence, release_readiness |
IconSecurity | ninguno | audit_project_full, audit_project_workflow |
IconSnippet | snippet, project_snippet | ninguno |
IconTag | tag, project_tags | ninguno |
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, y las cinco guías de flujo de trabajo servidas bajo gitlab://guides/ | ninguno |
¿Qué icono lleva el propio servidor?
Sección titulada «¿Qué icono lleva el propio servidor?»IconBrand identifica al servidor y no a un dominio de GitLab. Es el icono 52.º, adjunto a la identidad propia del servidor (Implementation.Icons) y a ninguna herramienta, recurso o prompt. La marca es el “abanico” (fan-out): un nodo de origen que proyecta tres arcos de rama, cada uno terminado en un nodo, que se lee como un grafo de git y como el diseño del servidor, un único catálogo de acciones que llega a las superficies de herramientas dinámica, meta e individual. Es una obra original de este proyecto y la misma marca que el logotipo y el favicon del sitio, todos dibujados a partir de una sola geometría. Sustituyó primero a IconServer, que también es el icono de gitlab_execute_action, y después a un tanuki de GitLab, que es marca registrada de GitLab.
Un cliente la recibe en dos sitios:
- En la respuesta de
initialize, comoserverInfo.icons. - En cada resultado con la revisión de protocolo 2026-07-28 o posterior (SEP-2575), en la que un cliente no necesita enviar
initializeantes: el servidor se identifica en el_metadel resultado, bajoio.modelcontextprotocol/serverInfo, y esa entrada es elImplementationcompleto, con sus tres entradas de icono. Solo un resultado vacío, como la respuesta a unping, va sin ella.
Esa segunda vía es la razón de que la marca se quede en un puñado de primitivas, tres arcos y cuatro círculos. Dos detalles la distinguen de los iconos de dominio: conserva un viewBox de 24×24, porque se escala desde la geometría compartida de la marca en lugar de dibujarse a tamaño de glifo, y como ellos su entrada SVG usa currentColor sin theme, seguida del mismo par WebP claro y oscuro para los clientes que rechazan SVG.
¿Qué clientes MCP renderizan los iconos?
Sección titulada «¿Qué clientes MCP renderizan los iconos?»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 y contrastada con lo que cada cliente hace de verdad en lugar de con la redacción de nivel SHOULD de la especificación.
| Cliente MCP | Renderiza | Notas |
|---|---|---|
| VS Code (GitHub Copilot) | ✅ Sí | 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 |
| Cursor | ❓ Incierto | Acepta el formato SVG en validación, pero el renderizado del propio icono de servidor fue confirmado ausente por el equipo en marzo de 2026 (un indicio no confirmado de mejora llegó en junio de 2026); el renderizado de iconos de herramienta, recurso y prompt sigue sin verificar en ningún sentido |
| OpenAI Codex (CLI + núcleo IDE) | ❓ Incierto | Los iconos de servidor y de herramienta se capturan y reenvían por el protocolo interno de Codex, pero no se encontró en ninguna parte de la TUI de código abierto código que los vuelva a leer para renderizarlos; la extensión de VS Code y la app de escritorio de ChatGPT, de código cerrado, no se pudieron inspeccionar |
| Windsurf / Devin Desktop | ❓ Desconocido | No se encontró documentación de iconos en ningún sitio; código cerrado, sin cliente público que inspeccionar |
| JetBrains AI Assistant / Junie | ❌ No | Los 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, sin campo de icono propio del servidor; los recursos y prompts siguen sin soporte alguno (JUNIE-1606/1607, ambos abiertos) |
| Claude Desktop | ❌ No | Los campos Implementation.icons y Tool.icons del protocolo no se confirman renderizados en ningún sitio. Un icono distinto de manifiesto .mcpb sí se muestra para extensiones instaladas localmente, y el paquete de Claude Desktop de este proyecto declara uno, pero es el icono del propio paquete, no los iconos del protocolo que describe esta página |
| Claude Code | ❌ No | Interfaz solo texto: un marcador genérico y el nombre bruto de la herramienta, confirmado por varias peticiones de funcionalidad abiertas que piden exactamente esto |
| Kiro (AWS) | ❌ No | Los prompts y las plantillas de recursos muestran una insignia genérica “MCP” del protocolo junto a cada entrada, no el campo icons por elemento que rellena este proyecto |
| Zed | ❌ No | Verificado en el código fuente: ninguno de sus tipos Implementation/Tool/Resource/Prompt lleva un campo icons |
| Cline | ❌ No | No se encontró renderizado de iconos en ninguna parte del cliente (verificado en el código fuente) |
| Continue.dev | ❌ No | No lee el campo icons de MCP en ninguna versión ni formato; tiene en su lugar un ajuste propietario no relacionado, faviconUrl |
| Goose (Block) | ❌ No | El SDK rmcp subyacente lleva el campo; el propio código de cliente de Goose nunca lo vuelve a leer |
| LibreChat | ❌ No | No se encontró renderizado de iconos en ninguna parte del cliente |
| Open WebUI | ❌ No | No se encontró renderizado de iconos en ninguna parte del cliente |
| 5ire / Witsy | ❌ No | No se encontró renderizado de iconos en ninguno de los dos clientes |
| Clientes propios (API de LLM directa) | Depende | Renderiza 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 |
¿Construyes tu propio cliente MCP?
Sección titulada «¿Construyes tu propio cliente MCP?»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 cliente 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.
Dónde encontrar icons
Sección titulada «Dónde encontrar icons»El array aparece en cinco tipos de objeto, allí donde tu cliente ya lee su nombre/descripción:
| Portador | De dónde procede |
|---|---|
Implementation | serverInfo.icons en la respuesta de initialize, y con el protocolo 2026-07-28 o posterior la entrada io.modelcontextprotocol/serverInfo del _meta de cada resultado: la marca propia del servidor |
Tool | cada entrada de tools/list |
Resource | cada entrada de resources/list |
ResourceTemplate | cada entrada de resources/templates/list |
Prompt | cada entrada de prompts/list |
Cada Icon es { src, mimeType?, sizes?, theme? }. La especificación permite que src sea una URL HTTP o HTTPS o una URI data: con los datos de la imagen en base64, y exige a quien la consume aceptar solo https: y data: y rechazar esquemas inseguros como javascript:, file:, ftp: y ws:. Este servidor solo envía URIs data:. 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.
Algoritmo de selección
Sección titulada «Algoritmo de selección»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.
- 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ásimage/svg+xmlsolo si has construido la ruta de sanitización descrita más abajo. Filtra por elmimeTypedeclarado cuando esté presente; cuando falte, analiza los bytes reales (número mágico paradata:, o una comprobaciónHEAD/Content-Typeparahttps:) en lugar de adivinar por la extensión del archivo en la URI —mimeTypees un metadato suministrado por el servidor, no fiable, no una garantía. - Coincidencia de tema. Si tu cliente tiene un tema de interfaz claro/oscuro, prefiere los iconos cuyo
themecoincida. Importante: un icono sin campothemees 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 usacurrentColory 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 entradasIconpor icono — un SVG consizes: ["any"]y sintheme(se adapta víacurrentColor), más un par WebP consizes: ["16x16"]ytheme: "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 cuyothemecoincida con el tema actual de su interfaz. - 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 cadenaAnchoxAlto, 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.
Lista de comprobación de seguridad
Sección titulada «Lista de comprobación de seguridad»Los iconos proceden de un servidor que quizá no controlas, así que trata cada campo como entrada no confiable, como la especificación exige a todo consumidor:
- Lista blanca de esquemas. Acepta solo
data:yhttps:, como exige la especificación, y rechaza sin más cualquier otro, incluidohttp:sin cifrar junto confile:,javascript:,ftp:yws:. Rechaza una redirección que cambie el esquema o salga del origen. - Comprobación de origen en URLs remotas. La especificación pide a los consumidores verificar que una URL de icono
https:procede del mismo origen que el servidor, así que 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. Descarga un icono sin credenciales: sin cookies y sin cabeceraAuthorization. - 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 tú 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 admitirimage/svg+xmlen 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 atributoson*,<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 odangerouslySetInnerHTML. - Limita lo que evalúas. Un servidor hostil puede devolver cientos de entradas
Iconpor 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.
Lógica de selección, de principio a fin
Sección titulada «Lógica de selección, de principio a fin»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") { 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.
Detalles técnicos
Sección titulada «Detalles técnicos»- Fuente:
internal/toolutil/icons.go, generadores:cmd/gen_icon_webppara las variantes WebP ycmd/gen_brandpara la marca - Codificación: tres data URIs base64 por icono,
data:image/svg+xml;base64,...seguida dedata:image/webp;base64,...(clara) ydata:image/webp;base64,...(oscura). Las previsualizaciones de esta página usan SVG con codificación URL (data:image/svg+xml,%3Csvg ...) coloreado#888solo para renderizado en línea en el navegador; los iconos registrados están en base64 y usancurrentColor. - Viewport: los iconos de dominio usan 16×16 y la marca 24×24; la entrada SVG usa
currentColorpara adaptación automática al tema, las entradas WebP están prerasterizadas por tema (Theme: "light"casi negro,Theme: "dark"casi blanco) - Registro: cada grupo del catálogo tiene un icono (un grupo que faltara en el mapa de iconos recurriría a
IconServer, y una prueba unitaria exige una entrada a cada grupo que construye el catálogo, así que ninguno lo hace); una meta-herramienta lo lleva y cada herramienta individual proyectada desde las acciones del grupo lo hereda, mientras que las dos herramientas de la superficie dinámica llevanIconSearcheIconServer, y los recursos y los prompts nombran el suyo
Quien contribuya y tenga que regenerar las variantes WebP o la marca encontrará los comandos en gen_icon_webp y gen_brand en la referencia de comandos.
Preguntas frecuentes
¿Qué son los iconos en GitLab MCP Server?
GitLab MCP Server asigna 51 iconos de dominio a cada herramienta, recurso y prompt que expone, más una marca, la 52.ª, en la identidad del propio servidor, para que los clientes MCP puedan mostrar elementos de interfaz reconocibles para cada dominio de GitLab. Los iconos se adjuntan por grupo del catálogo, así que todas las herramientas de un grupo comparten uno: las herramientas de gitlab_branch usan IconBranch, mientras que todas las de gitlab_repository (el árbol, los commits, los archivos y los submódulos) usan IconFile. Cada icono lleva tres entradas, siempre en este orden: 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 de dominio 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. Los iconos se adjuntan por grupo del catálogo, no por acción: una meta-herramienta lleva el icono de su grupo, y cada herramienta individual proyectada desde las acciones de ese grupo lo hereda, así que las herramientas relacionadas se agrupan visualmente. La superficie dinámica solo lista gitlab_find_action (IconSearch) y gitlab_execute_action (IconServer); las acciones a las que llegan no llevan icono propio. Los recursos y los prompts nombran su propio icono. 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.