
Adicionei WebMCP ao Meu Blog 19 Dias Após o Lançamento. Aqui está o Código Exato
📅 23 de fevereiro de 2026 | Por Chudi Nnorukam | Tradução: TriploHub
Adicionei WebMCP ao Meu Blog 19 Dias Após o Lançamento. Aqui Está o Código Exato.
#WebMCP #SvelteKit #IA #ClaudeCode
Publicado originalmente em dev.to
Meu blog agora conversa com agentes de IA. Não com um arquivo estático. Com chamadas de função ao vivo.
Adicionei o WebMCP ao chudi.dev em 23 de fevereiro de 2026 — 19 dias após o Google lançá-lo no Chrome 146. Não havia tutorial para SvelteKit. Nenhuma thread no Stack Overflow. Apenas o rascunho da especificação W3C, um pacote npm e noventa minutos.
Este post é o tutorial que eu gostaria que existisse.
Se você rodar isso no console do navegador em chudi.dev agora:
Object.keys(navigator.modelContext._registeredTools)
Você receberá de volta:
["searchPosts", "listPosts", "getAuthorContext"]
Nenhum outro blog em SvelteKit pode dizer isso ainda. Aqui está exatamente como foi construído.
O Que É WebMCP?
WebMCP é um rascunho de padrão W3C (fevereiro de 2026, Google e Microsoft) que adiciona navigator.modelContext aos navegadores. Sites registram ferramentas estruturadas com schemas de entrada tipados. Agentes de IA navegando no site descobrem e chamam essas ferramentas diretamente, retornando JSON estruturado — sem capturas de tela, sem parsing de DOM, sem adivinhar seletores CSS.
A comparação que esclarece mais rápido: WebMCP está para agentes de IA assim como o RSS estava para leitores de feed. Em vez de fazer scraping da sua página para descobrir o que há nela, o agente simplesmente pergunta.
Antes do WebMCP: O Que os Agentes Realmente Faziam
Quando um agente de IA visita seu blog hoje sem WebMCP:
Agente → tira screenshot (~2.000 tokens) → analisa o DOM visualmente →
adivinha a estrutura do conteúdo → talvez acerte
São 5-10 segundos por página. Uma taxa de erro de 15-20% em layouts complexos. E custa tokens proporcionais ao tamanho do screenshot, não ao tamanho da resposta.
Depois do WebMCP
Agente → navigator.modelContext.callTool('searchPosts', { query: 'ADHD' }) →
recebe JSON estruturado em menos de 2 segundos
De acordo com os benchmarks do próprio WebMCP, chamadas de ferramentas estruturadas usam aproximadamente 89% menos tokens do que interação baseada em screenshots.
Duas APIs, Ambas Suportadas
O WebMCP oferece dois caminhos de implementação:
Declarativa (atributos HTML) — sem JavaScript necessário, funciona para formulários padrão:
<form toolname="subscribeNewsletter" tooldescription="Inscreva-se no digest semanal">
<input name="email" type="email" required>
</form>
Imperativa (JavaScript) — para ferramentas complexas com lógica customizada. Foi essa a abordagem usada.
Ambas são suportadas pelo polyfill @mcp-b/global, o que significa que funcionam no Firefox e Safari hoje, não apenas no Chrome 146.
Por Que um Blog Precisa de WebMCP?
Um blog habilitado com WebMCP expõe ferramentas estruturadas que agentes de IA chamam diretamente. Em vez de fazer parsing por screenshot da lista de posts, um agente chama listPosts() e recebe JSON tipado com slugs, títulos, descrições e pilares de conteúdo.
A questão sobre citações de IA: Perplexity, ChatGPT e Claude não pesquisam seu conteúdo da mesma forma que o Google. Eles recuperam passagens. Se a passagem vem de um fragmento bruto de DOM capturado por screenshot, a citação é imprecisa. Se vem de uma chamada de ferramenta estruturada retornando dados tipados, a citação é exata.
💡 Insight: WebMCP é uma alavanca de GEO (Generative Engine Optimization), não apenas uma melhoria na experiência do desenvolvedor. Seu llms.txt diz aos crawlers de IA sobre o que é seu site. O WebMCP diz aos agentes de IA o que seu site pode fazer. Ambos devem existir.
Como Adicionar WebMCP ao SvelteKit: Os Três Arquivos
Passo 1: Instalar o polyfill
pnpm add @mcp-b/global zod-to-json-schema
zod-to-json-schema é uma dependência peer requerida pelo @mcp-b/webmcp-ts-sdk. Omiti-la produz um erro de build.
Passo 2: Criar src/lib/webmcp.ts
Este é o arquivo de definições de ferramentas. Ele fica em $lib para poder ser importado do layout.
import type { ContentPillar } from './types';
interface LeanPost {
slug: string;
title: string;
description: string;
tags: string[];
pillar?: ContentPillar;
tldr?: string;
updated?: string;
date: string;
}
export async function initWebMCP(posts: LeanPost[]) {
// Import dinâmico mantém @mcp-b/global fora do bundle do servidor.
await import('@mcp-b/global');
const mc = (navigator as Navigator & {
modelContext?: { provideContext: (opts: unknown) => void }
}).modelContext;
if (!mc) return;
mc.provideContext({
tools: [
{
name: 'searchPosts',
description:
'Pesquisa posts do blog por palavra-chave. Retorna até 5 posts.',
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', description: 'Palavra-chave de busca' },
pillar: {
type: 'string',
enum: ['ai-building', 'neurodivergent', 'automation', 'philosophy'],
description: 'Opcional: filtrar por pilar de conteúdo'
}
},
required: ['query']
},
async execute({ query, pillar }: { query: string; pillar?: string }) {
const q = query.toLowerCase();
const results = posts
.filter((p) => !pillar || p.pillar === pillar)
.filter(
(p) =>
p.title.toLowerCase().includes(q) ||
p.description.toLowerCase().includes(q) ||
p.tags.some((t) => t.toLowerCase().includes(q))
)
.slice(0, 5)
.map((p) => ({
slug: p.slug,
title: p.title,
description: p.description,
pillar: p.pillar,
url: `https://seusite.com/blog/${p.slug}`,
tldr: p.tldr
}));
return { content: [{ type: 'text', text: JSON.stringify(results) }] };
}
},
{
name: 'listPosts',
description: 'Lista todos os posts publicados, do mais novo ao mais antigo.',
inputSchema: {
type: 'object',
properties: {
pillar: {
type: 'string',
enum: ['ai-building', 'neurodivergent', 'automation', 'philosophy'],
description: 'Opcional: filtrar por pilar de conteúdo'
}
}
},
async execute({ pillar }: { pillar?: string }) {
const results = posts
.filter((p) => !pillar || p.pillar === pillar)
.map((p) => ({
slug: p.slug, title: p.title,
description: p.description, pillar: p.pillar,
url: `https://seusite.com/blog/${p.slug}`,
date: p.date, updated: p.updated
}));
return { content: [{ type: 'text', text: JSON.stringify(results) }] };
}
},
{
name: 'getAuthorContext',
description: 'Informações estruturadas sobre o autor e o site.',
inputSchema: { type: 'object', properties: {} },
async execute() {
return {
content: [{
type: 'text',
text: JSON.stringify({
name: 'Seu Nome',
title: 'Seu Título Profissional',
background: 'Sua descrição.',
expertise: ['suas', 'áreas', 'de', 'expertise'],
site: 'https://seusite.com',
contact: 'contato@seusite.com'
})
}]
};
}
}
]
});
}
O await import('@mcp-b/global') é a proteção contra SSR. O SvelteKit renderiza no servidor primeiro e o navigator não existe lá. O import dinâmico dentro de onMount garante que o polyfill nunca toque o bundle do servidor.
Passo 3: Criar src/routes/+layout.server.ts
Carrega os dados dos posts. Para um site SvelteKit pré-renderizado, roda no momento do build.
import type { LayoutServerLoad } from './$types';
import { getAllPosts } from '$lib/content';
export const load: LayoutServerLoad = async () => {
const posts = await getAllPosts();
return {
webmcpPosts: posts
.filter((p) => !p.draft)
.map((p) => ({
slug: p.slug, title: p.title,
description: p.description, tags: p.tags,
pillar: p.pillar, tldr: p.tldr,
updated: p.updated, date: p.date
}))
};
};
O .filter((p) => !p.draft) é importante — você não quer que rascunhos apareçam nos resultados de busca dos agentes.
Passo 4: Atualizar src/routes/+layout.svelte
<script lang="ts">
import { onMount } from 'svelte';
import { initWebMCP } from '$lib/webmcp';
export let data;
onMount(() => initWebMCP(data.webmcpPosts));
</script>
Quatro linhas. É isso. O SvelteKit conecta os dados automaticamente via $types.
Passo 5: Build e deploy
pnpm build
Um build bem-sucedido significa que o code-split funcionou. O chunk do polyfill tem ~308KB descomprimido, carregado de forma lazy após o mount — não no caminho crítico. Faça deploy normalmente.
As 3 Ferramentas Expostas e Por Quê
Foram escolhidas searchPosts, listPosts e getAuthorContext especificamente — apenas as três que respondem ao que um agente de IA realmente precisa.
searchPosts — o cavalo de batalha. Quando um usuário pergunta ao ChatGPT ou Perplexity algo que seu site poderia responder, o agente visita o site e precisa encontrar o post relevante. Busca por palavra-chave cobre 90% dos casos.
listPosts — contexto cronológico. Alguns agentes querem entender a produção completa de um site antes de citá-lo — verificando frescor, cobertura e volume.
getAuthorContext — sinal de confiança. Uma página "Sobre" estruturada que o agente pode interpretar. Quando o Perplexity decide se cita seu site ou um listicle genérico, o contexto do autor torna o sinal de confiança legível por máquina.
O que não foi exposto: conteúdo completo dos posts. Retornar corpos completos em markdown tornaria a resposta grande demais. O padrão correto é usar searchPosts para encontrar um post, depois navegar até a URL do slug.
Como Verificar se o WebMCP Está Funcionando
Abra o console do navegador no site publicado (não localhost):
// Verificar se navigator.modelContext existe
typeof navigator.modelContext
// Ver quais ferramentas estão registradas
Object.keys(navigator.modelContext._registeredTools)
// Chamar uma ferramenta
navigator.modelContext.callTool('searchPosts', { query: 'casamento' })
.then(r => JSON.parse(r.content[0].text))
Se receber undefined, o polyfill não está carregando. Causas mais comuns: o import dinâmico não está dentro do onMount, ou initWebMCP não está sendo chamado com o argumento correto.
⚠️ Dica: O método callTool é o que um agente de IA invocaria. Você pode testar a ida e volta completa do console do navegador da mesma forma que qualquer agente experimentaria.
O WebMCP Está Pronto para Produção?
O WebMCP (rascunho W3C, fevereiro de 2026) está pronto para produção via o polyfill @mcp-b/global para qualquer site HTTPS. O Chrome 146 tem suporte nativo e o polyfill cobre todos os outros navegadores.
A principal ressalva: a especificação ainda é um rascunho — a superfície da API pode mudar antes da ratificação (esperada para meados a final de 2026). Mas as ferramentas registradas usam a interface estável provideContext, tratada como fundamental pela especificação.
Para um site ou blog, o perfil de risco é direto: no pior caso, uma revisão futura requer uma tarde de trabalho. No melhor caso, você teve acesso estruturado de agentes de IA ao seu conteúdo por meses antes da maioria dos desenvolvedores saber o que é WebMCP.
O Contexto Mais Amplo
O padrão que se repete e reforça a importância de agir rápido:
2011 — Dados estruturados (schema.org). Early adopters dominaram rich results por anos.
2019 — FAQ schema. Sites com ele ganharam featured snippets antes do Google mudar as regras.
2025 — llms.txt. Quem adicionou cedo já está nos índices de crawlers de IA.
2026 — WebMCP.
Cada um é o mesmo playbook. A especificação é lançada. A adoção mainstream leva 12-18 meses. Os early adopters acumulam autoridade de citação, rankings de busca e conhecimento institucional antes do mercado alcançar.
🚀 Resumo: Otimização AEO dá ao seu site conteúdo estruturado que IA pode ler. WebMCP dá ferramentas estruturadas que IA pode chamar. A janela está aberta agora. Noventa minutos. Três arquivos. Um pacote npm.
Artigo original de Chudi Nnorukam — Traduzido para português por TriploHub. Os três arquivos de produção estão neste post na íntegra. A única modificação necessária é substituir o domínio nos códigos pelo seu.
Essa é uma oportunidade crítica: WebMCP acaba de ser lançado (Chrome 146, fevereiro 2026) e ainda há pouquíssimos tutoriais disponíveis. Se seu site não tiver WebMCP implementado nos próximos 6-12 meses, agentes de IA terão dificuldade em acessar suas funcionalidades principais, perdendo visibilidade em buscas por IA e recomendações de agentes. Este artigo mostra que a implementação é viável e rápida (90 minutos), removendo a desculpa técnica. A Triplo Up pode ajudar sua empresa a implementar WebMCP estrategicamente, garantindo que seus serviços sejam descobertos e utilizados por agentes de IA antes que a concorrência se adeque.

