css-sota-mcp

Informa a los agentes qué CSS puedes implementar realmente hoy: estado de Baseline, soporte por navegador, auditorías de hojas de estilo y revisiones de UX, a partir de webstatus.dev en vivo y MDN browser-compat-data.

Documentación

css-sota-mcp

Un servidor MCP que responde qué CSS puedes usar realmente hoy — basado en datos en vivo de Baseline y MDN browser-compat-data, no en el conjunto de entrenamiento de un modelo.

Los agentes se equivocan con confianza sobre la compatibilidad de navegadores. Te dirán que anchor-name está bien, o que :has() necesita un polyfill, dependiendo de cuándo se congelaron sus pesos. Este servidor reemplaza la suposición con la respuesta actual.

Herramientas

HerramientaRespondeFuente
search_css_features"¿Qué características existen para esto, y son seguras ya?"webstatus.dev
whats_new"¿Qué puedo empezar a usar que antes no podía?"webstatus.dev
get_feature"Cuéntame todo sobre esta característica."webstatus.dev + mdn/content
check_support"¿Qué versiones de navegador soportan esto exactamente?"bundled browser-compat-data
audit_css"¿Funciona esta hoja de estilos para mis usuarios?"bundled browser-compat-data
dont_make_me_think"¿Cómo debería diseñarse esta interfaz — y es esta página buena?"bundled UX guidelines

check_support y audit_css responden sin ninguna llamada de red — los datos que necesitan están compilados en el Worker.

dont_make_me_think

Nombrado por la regla de Steve Krug: una página debería ser evidente por sí misma. Dos modos.

mode: "guidelines" devuelve los principios para diseñar — las 10 heurísticas de Nielsen, las leyes de Hick y Fitts, WCAG 2.2, diseño inclusivo de neurodiversidad, movimiento y microinteracciones (incluyendo cuándo Lottie o Rive justifican su costo de bundle), arte y animación SVG, tematización light-first, ligereza, capacidad de respuesta. Filtra con topic. La base de conocimiento es mcp/src/data/ux-guidelines.json; cada principio lleva su fundamento, reglas accionables y una fuente.

mode: "review" revisa HTML y CSS — o un url obtenido — e informa qué viola qué principio, con la línea y la evidencia.

Lee el código fuente; no lo renderiza. Un Worker no tiene motor de layout, por lo que la revisión no puede medir contraste calculado, tamaños de objetivo reales, o dónde aterriza realmente el foco. Detecta lo que es visible en el marcado: alt faltante, zoom bloqueado, animación sin ruta de movimiento reducido, un anillo de foco eliminado, una paleta solo oscura, texto de enlace vago, una navegación más allá del rango de Hick. Un resultado limpio es un piso, no una aprobación, y la herramienta lo dice en su propia salida.

Objetivos de audit_css

Dos estilos de objetivo, porque responden preguntas diferentes:

  • Un nivel de Baselinebaseline-widely, baseline-newly. Pregunta "¿es esto lo suficientemente interoperable para publicarlo?", juzgado contra el estado de Baseline de web-features.
  • Una lista de navegadores explícitachrome 120, safari 17.4, firefox 128. Pregunta "¿funciona esto para mis usuarios?", juzgado contra versiones por navegador.

Las consultas de Browserslist (last 2 versions, >0.5%) no se aceptan. Resolverlas necesita datos de uso que este servidor no lleva, y aproximarlas produciría auditorías incorrectas con confianza — exactamente el modo de fallo que el servidor existe para corregir. La herramienta lo dice en lugar de adivinar.

Conectar

claude mcp add --scope user --transport http css-sota https://css-sota-mcp.lusrodri.workers.dev/mcp

--scope user lo registra una vez para cada proyecto en la máquina. Déjalo fuera y el servidor se agrega solo al proyecto actual.

Claude Desktop

Los servidores remotos se agregan a través de Connectors, no a través de claude_desktop_config.json — ese archivo solo acepta servidores stdio locales. Abre Settings → Connectors → Add custom connector y pega:

https://css-sota-mcp.lusrodri.workers.dev/mcp

El endpoint no está autenticado, por lo que el conector no pide client id ni secret.

Cloudflare AI Playground

Abre playground.ai.cloudflare.com, pega el endpoint en el campo del servidor MCP y conéctate. Las seis herramientas aparecen inmediatamente.

MCP Inspector
npx @modelcontextprotocol/inspector@latest

Configura el transporte a Streamable HTTP y conéctate al endpoint.

Límites del endpoint alojado

El endpoint es público y sin autenticación a propósito: cada herramienta es de solo lectura sobre conjuntos de datos públicos, por lo que no hay nada que proteger de divulgación. Lo que vale la pena proteger es el presupuesto de solicitudes de la cuenta y la posición del servidor con los upstreams que proxya.

LímiteValorAl exceder
Solicitudes por IP de cliente120 / minuto, por ubicación de Cloudflare429 con Retry-After: 60
Cuerpo de solicitud1 MB413
Fuente de audit_css400 000 caractereserror de validación de esquema

120/minuto está dimensionado contra uso real en lugar de un número redondo: un agente trabajando en una tarea llama a un puñado de herramientas por turno, por lo que una ráfaga de veinte es normal y 120 deja espacio para una dirección compartida que ejecuta varios clientes.

La propia guía de Cloudflare prefiere limitar la tasa por id de usuario o tenant en lugar de por IP, ya que una IP puede compartirse detrás de NAT o un relay de privacidad. Este endpoint no tiene autenticación y por lo tanto no tiene tal id; el límite se establece generosamente para que el intercambio sea justo.

Si esperas tráfico sostenido por encima de esto, ejecuta tu propia instancia — todo es un solo Worker y se despliega en un minuto.

Diseño

mcp/       The MCP server — a Cloudflare Worker
landing/   Documentation site — Vite, on Cloudflare Pages

Lo que la página de inicio sirve a los rastreadores

El sitio de documentación es cómo un agente encuentra este servidor sin que se le diga, por lo que publica más que HTML:

RutaQué es
/robots.txtAbierto a todo, con una línea de Content Signals que otorga search, ai-input y ai-train
/sitemap.xmlGenerado en tiempo de compilación, por lo que lastmod es la fecha de despliegue en lugar de una mentira editada a mano
/llms.txtEl endpoint, las seis herramientas y el vocabulario de Baseline, como Markdown
/llms-full.txtToda la referencia — herramientas, objetivos, límites, fuentes de datos — en un archivo
/404.htmlSu presencia es el punto: sin él, Pages responde a cada ruta desconocida con la página de inicio bajo un 200, que es cómo /robots.txt solía devolver HTML
/og.pngLa tarjeta social, 1200×630

Dos cosas que la página no hace merecen ser mencionadas, porque ambas eran ciertas hasta hace poco. La URL del endpoint ya no se inyecta solo por script — está en el marcado, por lo que cualquier cosa que lea el HTML sin ejecutarlo aún aprende el único hecho que la página existe para transmitir. Y el origen del Worker ahora lleva un encabezado Link: …; rel="canonical" que apunta al sitio de documentación, por lo que los dos hostnames que describen este servidor no compiten por ser el que se cita.

La página hace ninguna solicitud de terceros. Las tres tipografías se sirven desde este origen, fijadas en landing/public/fonts/ y declaradas en landing/src/fonts.css — solo subconjuntos latinos, y un archivo por familia donde el upstream es variable. Vinieron de fonts.googleapis.com hasta que esa hoja de estilos resultó ser el polo más largo en la mayor pintura de contenido de la página: bloqueante de renderizado, en otro host, y en sí misma un salto a un tercer host para los archivos. Regenera con landing/scripts/fetch-fonts.js; deliberadamente no es un paso de compilación, ya que volver a obtener en cada compilación pondría a un tercero de vuelta en la ruta crítica un nivel más abajo.

Cómo se ensamblan los datos

@mdn/browser-compat-data se descomprime a ~20 MB, muy por encima del presupuesto de bundle de un Worker. En tiempo de compilación mcp/scripts/build-data.js extrae la porción CSS de él más el catálogo de web-features, elimina cada campo que el servidor nunca lee, y codifica el soporte por navegador posicionalmente. El resultado es aproximadamente 1 MB de JSON — 120 KB gzip — que viaja dentro del Worker.

Los archivos generados están en gitignore. Cada compilación, prueba y despliegue los regenera, por lo que los datos siempre coinciden con la versión que npm resolvió.

Dos detalles que vale la pena conocer, ambos encontrados de la manera difícil:

  • web-features codifica Baseline como "high" / "low" / false, mientras que api.webstatus.dev y toda la documentación de Baseline dicen widely / newly / limited. La compilación normaliza a esto último para que las dos mitades del servidor nunca discrepen.
  • MDN reorganizó su referencia CSS bajo Web/CSS/Reference/…. Los datos de compatibilidad registran el slug que una página tenía cuando se escribió la entrada, por lo que construir una ruta GitHub cruda desde mdn_url da 404. get_feature resuelve el slug canónico a través de MDN primero, luego lee la fuente.

Desarrollo

npm install

npm run dev --workspace mcp        # wrangler dev on :8787
npm test --workspace mcp           # vitest
npm run typecheck                  # both workspaces

node mcp/scripts/smoke.js          # real MCP protocol call against :8787
node mcp/scripts/smoke.js <url>    # ...or against a deployment

smoke.js habla el flujo Streamable HTTP de la era 2025 — el mismo que usan AI Playground y MCP Inspector — por lo que una ejecución exitosa significa que esos clientes también funcionarán.

Desplegar

Empujar a main despliega ambos. Cloudflare compila desde este repositorio directamente — no se almacena ningún token de API en GitHub, y Cloudflare emite su propia credencial de compilación.

ObjetivoProductoRaízCompilaciónDespliegue
WorkerWorkers Buildsmcpnpm run build:datanpx wrangler deploy
LandingPages Git integrationlandingnpm run buildsalida dist

El comando de compilación del Worker no es opcional: mcp/src/data/generated/ está en gitignore, y src/data/index.ts lo importa estáticamente, por lo que una compilación que lo omita falla al empaquetar.

Debido a que los dos son productos independientes, ninguno espera al otro. .github/workflows/verify.yml cubre esa brecha — prueba el endpoint en vivo en un horario y bajo demanda.

Publicar en el registro

server.json es el registro de este servidor. Debido a que el servidor es remoto, lleva una entrada remotes que apunta al Worker en lugar de una packages — no hay artefacto para instalar, y por lo tanto no hay marcador de propiedad de paquete para colocar en ningún lado.

.github/workflows/publish-mcp.yml lo republica en una etiqueta v*:

git tag v0.2.0 && git push origin v0.2.0

La etiqueta establece la versión, por lo que el valor propio de server.json es solo un respaldo para una ejecución manual de workflow_dispatch. El trabajo se autentica con OIDC — probar que se ejecuta en este repositorio es lo que otorga el espacio de nombres io.github.LuSrodri/* — por lo que no hay token almacenado en GitHub, coincidiendo con cómo se despliega el resto de este repositorio.

Deliberadamente no se ejecuta en cada push. El registro apunta a una URL, no a una compilación, por lo que permanece correcto entre despliegues; solo un cambio de metadatos necesita una nueva versión.

Previsualizar una solicitud de extracción

Cada push a una rama de PR sube una versión del Worker y compila el sitio de landing, cada uno alcanzable antes de la fusión:

URL
Worker, por ramahttps://<branch-with-dashes>-css-sota-mcp.lusrodri.workers.dev/mcp
Worker, por versiónhttps://<version-prefix>-css-sota-mcp.lusrodri.workers.dev/mcp
Landinghttps://<deployment-id>.css-sota-mcp.pages.dev

El alias de rama es el útil — permanece en su lugar mientras haces push. Una rama llamada fix/thing se convierte en fix-thing-css-sota-mcp.lusrodri.workers.dev. Apunta el AI Playground o MCP Inspector hacia él para probar el servidor de una PR de verdad; node mcp/scripts/smoke.js <url>/mcp también funciona contra él.

Una vista previa de landing llama al Worker de su propia rama, no a producción. landing/vite.config.ts deriva el alias de CF_PAGES_BRANCH en tiempo de compilación, por lo que una PR que toca ambas mitades se previsualiza como un par emparejado. Sin esto, la vista previa mostraría un nuevo front end contra el servidor antiguo — vista previa verde, rota en la fusión. Un VITE_MCP_ORIGIN explícito aún gana, y las compilaciones de producción caen al valor predeterminado.

El alias se deriva en lugar de buscarse, por lo que un desajuste apunta la demo a una URL que da 404. Eso falla visiblemente: el endpoint se imprime en la página y el héroe informa que no pudo alcanzar el servidor. El registro de compilación de Pages imprime el cableado en cada compilación de vista previa.

Queda una advertencia: sin comentario automático de PR. Cloudflare normalmente publica los enlaces de vista previa en la solicitud de extracción; esta cuenta no puede habilitar eso (12044: This account does not have access to Workers Previews). Las URLs funcionan — las construyes a partir del nombre de la rama.

Para desplegar manualmente en su lugar:

npm run deploy --workspace mcp      # Worker
npm run deploy --workspace landing  # Pages

Ambos necesitan credenciales de Cloudflare — ya sea wrangler login, o CLOUDFLARE_API_TOKEN y CLOUDFLARE_ACCOUNT_ID en el entorno. Ten en cuenta que wrangler login necesita una terminal real; en un shell no interactivo se niega y pide la variable de token en su lugar.

Requisitos previos de la cuenta

Cloudflare restringe Workers detrás de estos, y los errores solo aparecen en el momento del despliegue:

  • Workers habilitados en la cuenta. Hasta que el panel de Workers & Pages se haya abierto una vez, cada llamada a la API de Workers falla con 10034: You need to verify your email address to use Workers — lo cual es engañoso, ya que un correo verificado no lo soluciona. Abrir la página sí lo hace.
  • Un subdominio workers.dev, si quieres una URL *.workers.dev. Sin uno, la API responde 10007.
  • La aplicación de GitHub de Cloudflare instalada, para despliegues basados en Git. Sin ella, la API de conexión de repositorios responde 8000008, independientemente de los permisos de la cuenta.

Construido con

MCP TypeScript SDK v2 · Cloudflare Workers · webstatus.dev · @mdn/browser-compat-data · web-features

El servidor usa createMcpHandler, que devuelve un objeto { fetch } estándar web y atiende solicitudes sin estado — por lo que no hay Durable Object, ni KV, ni afinidad de sesión. Cualquier isolate puede responder a cualquier solicitud.

Licencia

MIT