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.
- Endpoint —
https://css-sota-mcp.lusrodri.workers.dev/mcp(Streamable HTTP, sin autenticación) - Docs — css-sota-mcp.pages.dev
- Registro —
io.github.LuSrodri/css-sota-mcp, listado en el Registro oficial de MCP
Herramientas
| Herramienta | Responde | Fuente |
|---|---|---|
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 Baseline —
baseline-widely,baseline-newly. Pregunta "¿es esto lo suficientemente interoperable para publicarlo?", juzgado contra el estado de Baseline deweb-features. - Una lista de navegadores explícita —
chrome 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ímite | Valor | Al exceder |
|---|---|---|
| Solicitudes por IP de cliente | 120 / minuto, por ubicación de Cloudflare | 429 con Retry-After: 60 |
| Cuerpo de solicitud | 1 MB | 413 |
Fuente de audit_css | 400 000 caracteres | error 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:
| Ruta | Qué es |
|---|---|
/robots.txt | Abierto a todo, con una línea de Content Signals que otorga search, ai-input y ai-train |
/sitemap.xml | Generado en tiempo de compilación, por lo que lastmod es la fecha de despliegue en lugar de una mentira editada a mano |
/llms.txt | El endpoint, las seis herramientas y el vocabulario de Baseline, como Markdown |
/llms-full.txt | Toda la referencia — herramientas, objetivos, límites, fuentes de datos — en un archivo |
/404.html | Su 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.png | La 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-featurescodifica Baseline como"high"/"low"/false, mientras que api.webstatus.dev y toda la documentación de Baseline dicenwidely/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 desdemdn_urlda 404.get_featureresuelve 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.
| Objetivo | Producto | Raíz | Compilación | Despliegue |
|---|---|---|---|---|
| Worker | Workers Builds | mcp | npm run build:data | npx wrangler deploy |
| Landing | Pages Git integration | landing | npm run build | salida 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 rama | https://<branch-with-dashes>-css-sota-mcp.lusrodri.workers.dev/mcp |
| Worker, por versión | https://<version-prefix>-css-sota-mcp.lusrodri.workers.dev/mcp |
| Landing | https://<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 responde10007. - 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