css-sota-mcp
Informa aos agentes o que você pode realmente entregar hoje em CSS — status de Baseline, suporte por navegador, auditorias de folhas de estilo e revisões de UX — a partir do webstatus.dev ao vivo e do MDN browser-compat-data.
Documentação
css-sota-mcp
Um servidor MCP que responde qual CSS você pode realmente usar hoje — com base em dados ao vivo de Baseline e MDN browser-compat-data, não do conjunto de treinamento de um modelo.
Agentes erram com confiança sobre suporte de navegadores. Eles dirão que anchor-name está ok, ou
que :has() precisa de polyfill, dependendo de quando seus pesos foram congelados. Este servidor substitui
o palpite pela resposta atual.
- Endpoint —
https://css-sota-mcp.lusrodri.workers.dev/mcp(Streamable HTTP, sem autenticação) - Docs — css-sota-mcp.pages.dev
- Registry —
io.github.LuSrodri/css-sota-mcp, listado no registro oficial de MCP
Ferramentas
| Ferramenta | Responde | Fonte |
|---|---|---|
search_css_features | "Quais recursos existem para isso, e eles já são seguros?" | webstatus.dev |
whats_new | "O que posso começar a usar que antes não podia?" | webstatus.dev |
get_feature | "Me conte tudo sobre este recurso específico." | webstatus.dev + mdn/content |
check_support | "Quais versões de navegador suportam isso exatamente?" | browser-compat-data incluído |
audit_css | "Esta folha de estilo funciona para meus usuários?" | browser-compat-data incluído |
dont_make_me_think | "Como esta UI deveria ser projetada — e esta página é boa?" | diretrizes de UX incluídas |
check_support e audit_css respondem sem nenhuma chamada de rede — os dados de que precisam estão compilados
dentro do Worker.
dont_make_me_think
Nomeado em homenagem à regra de Steve Krug: uma página deve ser autoevidente. Dois modos.
mode: "guidelines" retorna os princípios para projetar — as 10 heurísticas de Nielsen, as leis de Hick
e Fitts, WCAG 2.2, design inclusivo para neurodiversidade, movimento e microinterações
(incluindo quando Lottie ou Rive justificam seu custo de bundle), arte e animação em SVG, theming
light-first, leveza, responsividade. Filtre com topic. A base de conhecimento é
mcp/src/data/ux-guidelines.json; cada princípio carrega sua
justificativa, regras acionáveis e uma fonte.
mode: "review" verifica HTML e CSS — ou um url buscado — e reporta o que viola qual
princípio, com a linha e a evidência.
Ele lê o código-fonte; não o renderiza. Um Worker não tem engine de layout, então a revisão não pode
medir contraste calculado, tamanhos reais de alvo, ou onde o foco realmente cai. Ele captura o que é
visível no markup: alt ausente, zoom bloqueado, animação sem caminho de reduced-motion, um
anel de foco removido, uma paleta só-escura, texto de link vago, uma nav além do limite de Hick. Um resultado limpo
é um piso, não uma aprovação, e a ferramenta diz isso em sua própria saída.
Alvos de audit_css
Dois estilos de alvo, porque respondem perguntas diferentes:
- Um nível de Baseline —
baseline-widely,baseline-newly. Pergunta "isso é interoperável o suficiente para lançar?", julgado pelo status de Baseline deweb-features. - Uma lista explícita de navegadores —
chrome 120, safari 17.4, firefox 128. Pergunta "isso funciona para meus usuários?", julgado por versões de navegador individuais.
Consultas Browserslist (last 2 versions, >0.5%) não são aceitas. Resolvê-las precisa de dados de uso
que este servidor não carrega, e aproximá-las produziria auditorias erradas com confiança —
exatamente o modo de falha que o servidor existe para corrigir. A ferramenta diz isso em vez de adivinhar.
Conectar
claude mcp add --scope user --transport http css-sota https://css-sota-mcp.lusrodri.workers.dev/mcp
--scope user o registra uma vez para todos os projetos na máquina. Deixe-o de fora e o servidor será
adicionado apenas ao projeto atual.
Claude Desktop
Servidores remotos entram por Connectors, não por claude_desktop_config.json — esse arquivo só
aceita servidores stdio locais. Abra Settings → Connectors → Add custom connector e cole:
https://css-sota-mcp.lusrodri.workers.dev/mcp
O endpoint não tem autenticação, então o conector não pede client id nem secret.
Cloudflare AI Playground
Abra playground.ai.cloudflare.com, cole o endpoint no campo de servidor MCP e conecte. As seis ferramentas aparecem imediatamente.
MCP Inspector
npx @modelcontextprotocol/inspector@latest
Defina o transporte como Streamable HTTP e conecte ao endpoint.
Limites do endpoint hospedado
O endpoint é público e sem autenticação de propósito: toda ferramenta é somente leitura sobre conjuntos de dados públicos, então não há nada para proteger de divulgação. O que vale proteger é o orçamento de requisições da conta e a reputação do servidor com os upstreams que ele faz proxy.
| Limite | Valor | Ao exceder |
|---|---|---|
| Requisições por IP de cliente | 120 / minuto, por localização Cloudflare | 429 com Retry-After: 60 |
| Corpo da requisição | 1 MB | 413 |
Fonte de audit_css | 400 000 caracteres | erro de validação de schema |
120/minuto é dimensionado contra uso real, não um número redondo: um agente trabalhando em uma tarefa chama algumas ferramentas por turno, então uma rajada de vinte é normal e 120 deixa espaço para um endereço compartilhado rodando vários clientes.
A própria orientação da Cloudflare prefere limitar por usuário ou tenant id em vez de IP, já que um IP pode ser compartilhado atrás de NAT ou relay de privacidade. Este endpoint não tem autenticação e portanto não tem tal id; o limite é generoso o suficiente para que a troca seja justa.
Se você espera tráfego sustentado acima disso, rode sua própria instância — a coisa toda é um único Worker e faz deploy em um minuto.
Layout
mcp/ The MCP server — a Cloudflare Worker
landing/ Documentation site — Vite, on Cloudflare Pages
O que a landing page serve para crawlers
O site de docs é como um agente encontra este servidor sem ser informado sobre ele, então ele publica mais do que HTML:
| Caminho | O que é |
|---|---|
/robots.txt | Aberto a tudo, com uma linha de Content Signals concedendo search, ai-input e ai-train |
/sitemap.xml | Gerado no build, então lastmod é a data de deploy em vez de uma mentira editada à mão |
/llms.txt | O endpoint, as seis ferramentas e o vocabulário de Baseline, como Markdown |
/llms-full.txt | Toda a referência — ferramentas, alvos, limites, fontes de dados — em um arquivo |
/404.html | Sua presença é o ponto: sem ele, Pages responde a todo caminho desconhecido com a home page sob um 200, que é como /robots.txt costumava retornar HTML |
/og.png | O cartão social, 1200×630 |
Duas coisas que a página não faz merecem ser ditas, porque ambas eram verdade até recentemente. A
URL do endpoint não é mais injetada apenas por script — ela está no markup, então qualquer coisa que leia o
HTML sem executá-lo ainda aprende o único fato que a página existe para transmitir. E a origem do Worker
agora carrega um cabeçalho Link: …; rel="canonical" apontando para o site de docs, então os dois hostnames
que descrevem este servidor não competem para ser o citado.
A página faz nenhuma requisição de terceiros. As três tipografias são servidas desta origem, fixadas
em landing/public/fonts/ e declaradas em landing/src/fonts.css — apenas subconjuntos latinos, e um
arquivo por família onde o upstream é variável. Elas vieram de fonts.googleapis.com até que essa
stylesheet se tornasse o maior gargalo no maior contentful paint da página: bloqueante de renderização,
em outro host, e ela própria um salto para um terceiro host pelos arquivos. Regere-as com
landing/scripts/fetch-fonts.js; deliberadamente não é uma etapa de build, já que buscar novamente a cada
build colocaria um terceiro de volta no caminho crítico um nível abaixo.
Como os dados são montados
@mdn/browser-compat-data descompacta para ~20 MB, muito além do orçamento de bundle de um Worker. No build,
mcp/scripts/build-data.js extrai a fatia de CSS dele mais o catálogo web-features, descarta
todo campo que o servidor nunca lê, e codifica o suporte por navegador posicionalmente. O resultado é
cerca de 1 MB de JSON — 120 KB gzip — que viaja dentro do Worker.
Os arquivos gerados são gitignored. Todo build, teste e deploy os regenera, então os dados sempre correspondem à versão que o npm resolveu.
Dois detalhes que valem saber, ambos descobertos do jeito difícil:
web-featurescodifica Baseline como"high"/"low"/false, enquanto api.webstatus.dev e toda a documentação de Baseline dizemwidely/newly/limited. O build normaliza para o último para que as duas metades do servidor nunca discordem.- MDN reorganizou sua referência de CSS sob
Web/CSS/Reference/…. Os dados de compat registram o slug que uma página tinha quando a entrada foi escrita, então construir um caminho GitHub bruto a partir demdn_urldá 404.get_featureresolve o slug canônico através do MDN primeiro, depois lê a fonte.
Desenvolvimento
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 fala o fluxo Streamable HTTP da era 2025 — o mesmo que o AI Playground e o MCP
Inspector usam — então uma execução bem-sucedida significa que esses clientes também funcionarão.
Deploy
Enviar para main faz deploy de ambos. Cloudflare compila deste repositório diretamente — nenhum token de API é
armazenado no GitHub, e Cloudflare emite sua própria credencial de build.
| Alvo | Produto | Raiz | Build | Deploy |
|---|---|---|---|---|
| Worker | Workers Builds | mcp | npm run build:data | npx wrangler deploy |
| Landing | Pages Git integration | landing | npm run build | saída dist |
O comando de build do Worker não é opcional: mcp/src/data/generated/ é gitignored, e
src/data/index.ts o importa estaticamente, então um build que o pula falha ao empacotar.
Como os dois são produtos independentes, nenhum espera o outro. .github/workflows/verify.yml
cobre essa lacuna — ele faz smoke-test do endpoint ao vivo em um cronograma e sob demanda.
Publicando no registro
server.json é o registro deste servidor. Como o servidor é remoto,
ele carrega uma entrada remotes apontando para o Worker em vez de uma packages — não há
artefato para instalar, e portanto nenhum marcador de propriedade de pacote para colocar em lugar algum.
.github/workflows/publish-mcp.yml o republica em uma tag v*:
git tag v0.2.0 && git push origin v0.2.0
A tag define a versão, então o valor de server.json é apenas um fallback para uma execução manual de
workflow_dispatch. O job autentica com OIDC — provar que roda neste repositório é
o que concede o namespace io.github.LuSrodri/* — então não há token armazenado no GitHub, combinando
com como o resto deste repo faz deploy.
Ele deliberadamente não roda em todo push. O registro aponta para uma URL, não para um build, então ele permanece correto entre deploys; apenas uma mudança de metadados precisa de uma nova versão.
Pré-visualizando um pull request
Todo push para um branch de PR envia uma versão do Worker e compila o site de landing, cada um acessível antes do merge:
| URL | |
|---|---|
| Worker, por branch | https://<branch-with-dashes>-css-sota-mcp.lusrodri.workers.dev/mcp |
| Worker, por versão | https://<version-prefix>-css-sota-mcp.lusrodri.workers.dev/mcp |
| Landing | https://<deployment-id>.css-sota-mcp.pages.dev |
O alias de branch é o útil — ele permanece enquanto você envia. Um branch chamado
fix/thing torna-se fix-thing-css-sota-mcp.lusrodri.workers.dev. Aponte o
AI Playground ou MCP Inspector para ele para testar o servidor de um PR de verdade; node mcp/scripts/smoke.js <url>/mcp também funciona contra ele.
Uma pré-visualização de landing chama o Worker do seu próprio branch, não produção. landing/vite.config.ts
deriva o alias de CF_PAGES_BRANCH no build, então um PR que toca ambas as metades é pré-visualizado
como um par combinado. Sem isso, a pré-visualização mostraria um novo front end contra o servidor antigo —
pré-visualização verde, quebrado no merge. Um VITE_MCP_ORIGIN explícito ainda vence, e builds de produção
caem no padrão.
O alias é derivado em vez de consultado, então uma incompatibilidade aponta a demo para uma URL que dá 404. Isso falha visivelmente: o endpoint é impresso na página e o hero reporta que não conseguiu alcançar o servidor. O log de build do Pages imprime a fiação em todo build de pré-visualização.
Uma ressalva permanece: nenhum comentário automático de PR. Cloudflare normalmente posta os links de pré-visualização no
pull request; esta conta não pode habilitar isso (12044: This account does not have access to Workers Previews). As URLs funcionam — você as constrói a partir do nome do branch.
Para fazer deploy manualmente:
npm run deploy --workspace mcp # Worker
npm run deploy --workspace landing # Pages
Ambos precisam de credenciais da Cloudflare — ou wrangler login, ou CLOUDFLARE_API_TOKEN e
CLOUDFLARE_ACCOUNT_ID no ambiente. Observe que wrangler login precisa de um terminal real; em um
shell não interativo, ele recusa e pede a variável de token em vez disso.
Pré-requisitos da conta
A Cloudflare restringe Workers por trás destes requisitos, e os erros só aparecem no momento do deploy:
- Workers habilitados na conta. Até que o painel Workers & Pages seja aberto uma vez,
toda chamada à API de Workers falha com
10034: You need to verify your email address to use Workers— o que é enganoso, já que um e-mail verificado não resolve isso. Abrir a página resolve. - Um subdomínio
workers.dev, se você quiser uma URL*.workers.dev. Sem um, a API responde10007. - O GitHub App da Cloudflare instalado, para deploys baseados em Git. Sem ele, a API de
conexão de repositório responde
8000008, independentemente das permissões da conta.
Construído com
MCP TypeScript SDK v2 · Cloudflare Workers · webstatus.dev · @mdn/browser-compat-data · web-features
O servidor usa createMcpHandler, que retorna um objeto { fetch } padrão da web e atende
requisições sem estado — portanto, não há Durable Object, nem KV, nem afinidade de sessão. Qualquer
isolate pode responder a qualquer requisição.
Licença
MIT