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.

Ferramentas

FerramentaRespondeFonte
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 de web-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.

LimiteValorAo exceder
Requisições por IP de cliente120 / minuto, por localização Cloudflare429 com Retry-After: 60
Corpo da requisição1 MB413
Fonte de audit_css400 000 caractereserro 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:

CaminhoO que é
/robots.txtAberto a tudo, com uma linha de Content Signals concedendo search, ai-input e ai-train
/sitemap.xmlGerado no build, então lastmod é a data de deploy em vez de uma mentira editada à mão
/llms.txtO endpoint, as seis ferramentas e o vocabulário de Baseline, como Markdown
/llms-full.txtToda a referência — ferramentas, alvos, limites, fontes de dados — em um arquivo
/404.htmlSua 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.pngO 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-features codifica Baseline como "high" / "low" / false, enquanto api.webstatus.dev e toda a documentação de Baseline dizem widely / 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 de mdn_url dá 404. get_feature resolve 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.

AlvoProdutoRaizBuildDeploy
WorkerWorkers Buildsmcpnpm run build:datanpx wrangler deploy
LandingPages Git integrationlandingnpm run buildsaí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 branchhttps://<branch-with-dashes>-css-sota-mcp.lusrodri.workers.dev/mcp
Worker, por versãohttps://<version-prefix>-css-sota-mcp.lusrodri.workers.dev/mcp
Landinghttps://<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 responde 10007.
  • 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