Como Publicar ai-catalog.json: Torne Seus Agentes Descobríveis
Guia prático para criar e hospedar um ai-catalog.json — o manifesto que permite que agentes de IA descubram seus serviços em runtime.
Como Publicar ai-catalog.json: Torne Seus Agentes Descobríveis
Você construiu um MCP server, publicou uma skill, expôs uma API com capacidades de IA. Mas como um agente descobre que seu serviço existe? A resposta, desde junho de 2026, é o ai-catalog.json — um manifesto padronizado que funciona como o DNS do ecossistema de agentes. Você hospeda, agentes descobrem. Sem cadastro em marketplace, sem intermediários.
O ai-catalog.json é para agentes o que o robots.txt foi para crawlers: um contrato público que diz “aqui estão minhas capacidades, é assim que você se conecta”. A diferença é que, em vez de dizer o que não acessar, você declara o que pode ser usado.
Pré-requisitos
Antes de criar seu catálogo, você precisa ter algo para expor. O ai-catalog.json é um manifesto — ele descreve o que existe, não cria funcionalidade. Você precisa de pelo menos um destes:
- Um MCP server rodando (local ou remoto)
- Uma skill publicada em repositório
- Um agente A2A com endpoint acessível
- Uma API que agentes podem consumir
Se você ainda não tem nenhum desses, volte quando tiver. O catálogo vem depois da implementação.
Anatomia do ai-catalog.json
O manifesto tem uma estrutura enxuta: um objeto host que identifica quem publica, e um array entries com os serviços disponíveis.
{
"specVersion": "1.0",
"host": {
"displayName": "Nome do Publicador"
},
"entries": []
}Esse é o esqueleto mínimo válido. Vamos detalhar cada parte.
O objeto host
O host descreve quem está publicando o catálogo. Apenas displayName é obrigatório — o resto é opcional mas recomendado para catálogos em produção.
| Campo | Obrigatório | Descrição |
|---|---|---|
displayName | Sim | Nome legível do publicador |
identifier | Não | DID ou domínio do publicador |
documentationUrl | Não | URL da documentação geral |
logoUrl | Não | URL do logotipo |
trustManifest | Não | Manifesto de confiança para verificação |
Cada entry no array
Cada item em entries representa um serviço, agente ou skill que você expõe. Quatro campos são obrigatórios:
| Campo | Obrigatório | Descrição |
|---|---|---|
identifier | Sim | URN único no formato urn:air:<publisher>:<namespace>:<agent-name> |
displayName | Sim | Nome legível para humanos e agentes |
type | Sim | Media type do serviço |
url ou data | Sim (um dos dois) | Referência externa OU dados inline — mutuamente exclusivos |
Os campos opcionais adicionam contexto para melhorar o discovery:
| Campo | Descrição |
|---|---|
description | Texto livre sobre o que o serviço faz |
tags | Array de tags para categorização |
capabilities | Capacidades específicas do serviço |
representativeQueries | 2-5 exemplos de perguntas que o serviço responde |
version | Versão semântica do serviço |
updatedAt | Timestamp ISO 8601 da última atualização |
metadata | Objeto livre para dados extras |
trustManifest | Manifesto de confiança específico da entry |
O formato URN
O identificador segue o padrão AIR (Agent Identifier Registry):
urn:air:<publisher>:<namespace>:<agent-name>Exemplos reais:
urn:air:hf.co:alice-dev:weather-agent— publicado no Hugging Faceurn:air:github.com:meu-user:minha-skill— publicado no GitHuburn:air:meudominio.com:tools:api-converter— publicado em domínio próprio
Media types válidos
O campo type define que tipo de serviço a entry representa:
| Media Type | Para quê |
|---|---|
application/mcp-server-card+json | MCP servers |
application/a2a-agent-card+json | Agentes A2A (Agent-to-Agent) |
application/ai-skill | Skills de agentes |
application/ai-catalog+json | Catálogos nested (federação) |
application/ai-registry+json | Registries dinâmicos |
Passo 1: Criar o Manifesto
Vamos a três exemplos práticos cobrindo os casos mais comuns.
Exemplo 1: MCP server com dados inline
Se seu MCP server é simples e você quer que os metadados fiquem direto no catálogo, use o campo data:
{
"specVersion": "1.0",
"host": {
"displayName": "Alice's AI Tools",
"documentationUrl": "https://alice-dev.github.io/docs"
},
"entries": [
{
"identifier": "urn:air:hf.co:alice-dev:weather-agent",
"displayName": "Weather Agent",
"type": "application/mcp-server-card+json",
"description": "Simple weather lookup using open data",
"tags": ["weather", "open-data", "lookup"],
"representativeQueries": [
"What's the weather in São Paulo?",
"Current temperature in Berlin",
"Will it rain tomorrow in Tokyo?"
],
"data": {
"name": "Weather Agent",
"description": "Simple weather lookup using open data",
"tools": [
{
"name": "get_weather",
"description": "Get current weather for a city",
"inputSchema": {
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}
}
]
}
}
]
}O campo data contém a estrutura completa do MCP server card — nome, descrição e lista de tools com seus schemas. Agentes que encontram esse catálogo já sabem exatamente como invocar seu server.
Exemplo 2: Skill referenciada por URL
Se sua skill vive em um repositório e você não quer duplicar metadados, use url:
{
"specVersion": "1.0",
"host": {
"displayName": "Alice's AI Tools"
},
"entries": [
{
"identifier": "urn:air:github.com:alice-dev:pptx-creator",
"displayName": "pptx-creator",
"type": "application/ai-skill",
"url": "https://github.com/alice-dev/pptx-creator",
"description": "Create professional PowerPoint presentations following brand guidelines.",
"tags": ["presentations", "pptx", "automation"],
"representativeQueries": [
"Create a slide deck for my quarterly review",
"Generate a pitch presentation with 10 slides"
],
"version": "2.1.0",
"updatedAt": "2026-07-15T10:00:00Z"
}
]
}Com url, o agente sabe onde buscar os detalhes completos. Você mantém o catálogo leve e a fonte da verdade no repositório.
Exemplo 3: Agente A2A com endpoint
Para um agente que aceita comunicação Agent-to-Agent:
{
"specVersion": "1.0",
"host": {
"displayName": "Minha Empresa IA",
"identifier": "minhaempresa.com.br",
"logoUrl": "https://minhaempresa.com.br/logo.png"
},
"entries": [
{
"identifier": "urn:air:minhaempresa.com.br:agents:tradutor-juridico",
"displayName": "Tradutor Jurídico PT-EN",
"type": "application/a2a-agent-card+json",
"url": "https://api.minhaempresa.com.br/.well-known/agent.json",
"description": "Traduz documentos jurídicos entre português e inglês com terminologia especializada.",
"tags": ["translation", "legal", "pt-br", "en"],
"capabilities": ["document-translation", "terminology-glossary"],
"representativeQueries": [
"Traduza este contrato para inglês",
"Qual a tradução jurídica de 'cláusula resolutória'?",
"Revise a tradução deste parecer"
],
"version": "1.0.0",
"updatedAt": "2026-07-20T14:30:00Z"
}
]
}Note que url e data são mutuamente exclusivos — use um ou outro, nunca os dois na mesma entry.
Catálogo com múltiplas entries
Na prática, você vai ter mais de um serviço. Basta adicionar ao array:
{
"specVersion": "1.0",
"host": {
"displayName": "DevTools Corp",
"identifier": "devtools.io",
"documentationUrl": "https://docs.devtools.io"
},
"entries": [
{
"identifier": "urn:air:devtools.io:mcp:code-reviewer",
"displayName": "Code Reviewer",
"type": "application/mcp-server-card+json",
"url": "https://devtools.io/.well-known/mcp/code-reviewer.json",
"description": "Automated code review with security focus",
"representativeQueries": [
"Review this pull request for security issues",
"Find potential SQL injection vulnerabilities"
]
},
{
"identifier": "urn:air:devtools.io:skills:test-generator",
"displayName": "Test Generator",
"type": "application/ai-skill",
"url": "https://github.com/devtools-io/test-generator",
"description": "Generate comprehensive test suites from source code",
"representativeQueries": [
"Generate unit tests for this module",
"Create integration tests for the auth flow"
]
}
]
}Passo 2: Hospedar em /.well-known/
O local canônico para o manifesto é /.well-known/ai-catalog.json. É o primeiro lugar que agentes vão procurar — a mesma convenção que .well-known/security.txt ou .well-known/openid-configuration.
O Content-Type deve ser application/json.
Nginx
Adicione ao bloco server do seu domínio:
location /.well-known/ai-catalog.json {
alias /var/www/meusite/ai-catalog.json;
default_type application/json;
add_header Access-Control-Allow-Origin "*";
add_header Cache-Control "public, max-age=3600";
}O header CORS (Access-Control-Allow-Origin: *) é importante — agentes fazem requisições de domínios diferentes. O Cache-Control de 1 hora é um bom default; ajuste conforme a frequência de atualização do seu catálogo.
Cloudflare Pages
Se seu site está no Cloudflare Pages, crie o arquivo na pasta public/.well-known/:
public/
└── .well-known/
└── ai-catalog.jsonAdicione um _headers na raiz do public/ para configurar os headers:
/.well-known/ai-catalog.json
Content-Type: application/json
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=3600O Cloudflare Pages serve arquivos estáticos da pasta public/ sem necessidade de configuração de rotas.
Vercel
No Vercel, coloque o arquivo em public/.well-known/ai-catalog.json e adicione ao vercel.json:
{
"headers": [
{
"source": "/.well-known/ai-catalog.json",
"headers": [
{ "key": "Content-Type", "value": "application/json" },
{ "key": "Access-Control-Allow-Origin", "value": "*" },
{ "key": "Cache-Control", "value": "public, max-age=3600" }
]
}
]
}Confirmação rápida
Depois do deploy, teste com curl:
curl -I https://seudominio.com/.well-known/ai-catalog.jsonVocê deve ver 200 OK com Content-Type: application/json. Se vir 404, o arquivo não está no path certo. Se vir 301/302, garanta que o redirect final chega no JSON.
Passo 3: Adicionar Sinais de Discovery
O well-known URI é o mecanismo primário, mas existem sinais complementares que aumentam a probabilidade de agentes encontrarem seu catálogo. Pense neles como redundância — cada um cobre um cenário diferente de discovery.
robots.txt
Adicione a diretiva Agentmap ao seu robots.txt:
User-agent: *
Allow: /
Agentmap: https://seudominio.com/.well-known/ai-catalog.jsonCrawlers de agentes que respeitam o robots.txt vão encontrar seu catálogo mesmo sem acessar o well-known path diretamente. Funciona de forma análoga ao Sitemap: que você já usa para SEO.
HTML link tag
No <head> das suas páginas (especialmente a homepage), adicione:
<link rel="ai-catalog" href="/.well-known/ai-catalog.json">Agentes que renderizam ou parsam HTML vão detectar essa tag. É útil quando o agente está navegando seu site e precisa descobrir o catálogo a partir de qualquer página.
DNS Service Binding
Para discovery no nível de infraestrutura, sem depender de HTTP:
_catalog._agents.seudominio.com. IN SVCB 1 seudominio.com. (
alpn="h2,h3" path="/.well-known/ai-catalog.json"
)O record DNS _catalog._agents permite que agentes descubram seu catálogo via resolução DNS antes mesmo de fazer uma requisição HTTP. É o mecanismo mais robusto, mas também o mais avançado — implemente apenas se já tem familiaridade com records SRV/SVCB.
Qual usar?
Para a maioria dos casos, o well-known URI + robots.txt + HTML link cobrem 99% dos cenários. O DNS é para quem quer cobertura total em ambientes enterprise ou redes privadas.
Passo 4: Validar com Ferramentas Oficiais
Antes de considerar o deploy feito, valide a estrutura do seu manifesto.
Validação de schema com ajv-cli
O repositório do ai-catalog standard inclui schemas JSON Schema que você pode usar diretamente:
npx ajv-cli validate \
-s spec/schemas/ai-catalog.schema.json \
-d ./ai-catalog.jsonSe o manifesto estiver correto, a saída será limpa. Se houver erros — campo obrigatório faltando, tipo errado, URL e data na mesma entry — o ajv mostra exatamente onde está o problema.
Teste de conformance completo
Para uma verificação mais rigorosa que vai além da estrutura (testa resolução de URLs, formatos de URN, media types válidos):
./conformance/bin/conformance-test manifest ./ai-catalog.jsonEsse teste é mais pesado — faz requisições reais para URLs declaradas e valida que respondem corretamente. Use em staging antes de publicar.
Validação manual rápida
Se quiser apenas checar se o JSON é válido e tem a estrutura básica:
cat ai-catalog.json | python3 -m json.tool > /dev/null && echo "JSON válido"E uma checagem rápida dos campos obrigatórios:
cat ai-catalog.json | python3 -c "
import json, sys
data = json.load(sys.stdin)
assert 'specVersion' in data, 'Falta specVersion'
assert 'host' in data, 'Falta host'
assert 'displayName' in data['host'], 'Falta host.displayName'
assert 'entries' in data, 'Falta entries'
for i, e in enumerate(data['entries']):
assert 'identifier' in e, f'Entry {i}: falta identifier'
assert 'displayName' in e, f'Entry {i}: falta displayName'
assert 'type' in e, f'Entry {i}: falta type'
assert ('url' in e) != ('data' in e), f'Entry {i}: precisa de url OU data (não ambos, não nenhum)'
print(f'✓ Válido: {len(data[\"entries\"])} entries')
"Passo 5: Testar com Hugging Face Discover
O Hugging Face Discover é um search engine que indexa ai-catalog.json de domínios públicos. É a forma mais rápida de verificar se seu catálogo está acessível e bem formatado “do lado de fora”.
Verificar se o HF já tem seu catálogo
Faça um POST para o endpoint de busca:
curl -X POST https://huggingface-hf-discover.hf.space/search \
-H "Content-Type: application/json" \
-d '{
"query": {
"text": "nome-do-seu-servico"
},
"pageSize": 5
}'Se seu catálogo já foi indexado, a resposta vai incluir suas entries. Se não aparecer nada, o indexador ainda não passou pelo seu domínio — pode levar algumas horas após a primeira publicação.
Como funciona o discovery no HF
O Hugging Face mantém um crawler que periodicamente busca /.well-known/ai-catalog.json em domínios conhecidos. O próprio HF publica o seu em:
https://huggingface.co/.well-known/ai-catalog.jsonO Discover também expõe um endpoint MCP para que outros agentes possam buscar programaticamente:
https://huggingface-hf-discover.hf.space/mcpIsso significa que um agente conectado ao MCP do HF Discover pode buscar seus serviços em runtime — exatamente o cenário que o ai-catalog.json resolve.
Teste end-to-end
Para simular o que um agente faria ao encontrar seu catálogo:
# 1. Busca o catálogo
curl -s https://seudominio.com/.well-known/ai-catalog.json | jq '.entries[].displayName'
# 2. Verifica se o HF Discover encontra
curl -s -X POST https://huggingface-hf-discover.hf.space/search \
-H "Content-Type: application/json" \
-d '{"query": {"text": "weather agent"}, "pageSize": 3}' | jq '.results[:3]'Se os dois passos funcionam, seu catálogo está operacional.
Boas Práticas para representativeQueries
O campo representativeQueries é opcional, mas é o que mais impacta a qualidade do discovery. Agentes usam essas queries para decidir se seu serviço é relevante para o que o usuário pediu. Pense nelas como os exemplos de invocação de uma skill — quanto mais realistas, melhor o matching.
Regras de ouro
2 a 5 queries por entry. Menos que 2 não dá contexto suficiente. Mais que 5 dilui a relevância.
Use linguagem natural, não comandos técnicos. O agente vai comparar a query do usuário com seus exemplos. Usuários não dizem “invoke get_weather with params city=SP” — dizem “como está o tempo em São Paulo?”.
// ❌ Ruim — linguagem de desenvolvedor
"representativeQueries": [
"call get_weather API",
"fetch weather data for location"
]
// ✓ Bom — linguagem de usuário
"representativeQueries": [
"What's the weather in São Paulo?",
"Will it rain tomorrow in New York?",
"Current temperature in Berlin"
]Cubra cenários diferentes, não variações da mesma pergunta. Cada query deve representar um caso de uso distinto.
// ❌ Ruim — três formas de dizer a mesma coisa
"representativeQueries": [
"Translate this document",
"Can you translate this?",
"Please translate"
]
// ✓ Bom — três cenários diferentes
"representativeQueries": [
"Translate this contract to English",
"What's the legal term for 'cláusula resolutória' in English?",
"Review the translation accuracy of this legal brief"
]Inclua o idioma que seus usuários realmente usam. Se seu serviço atende brasileiros, queries em português. Se é global, misture.
Seja específico sobre o domínio. “Analyze this” não ajuda. “Analyze the SEO performance of this landing page” ajuda muito.
Próximos Passos: trustManifest para Enterprise
Para uso pessoal ou projetos open-source, o catálogo básico é suficiente. Mas em contextos enterprise — onde agentes precisam decidir se confiam no seu serviço — existe o trustManifest.
O trust manifest é um objeto que pode aparecer tanto no host (nível do publicador) quanto em cada entry (nível do serviço). Ele declara informações verificáveis sobre identidade e procedência.
Estrutura do trustManifest
| Campo | Obrigatório | Descrição |
|---|---|---|
identity | Sim | Identificador verificável (DID, domínio, org ID) |
identityType | Não | Tipo do identificador (e.g., “domain”, “did:web”) |
attestations | Não | Array de atestações de terceiros |
provenance | Não | Array de informações de procedência |
signature | Não | Assinatura criptográfica do manifesto |
Exemplo prático
{
"specVersion": "1.0",
"host": {
"displayName": "Empresa Verificada Ltda",
"identifier": "did:web:empresa-verificada.com.br",
"trustManifest": {
"identity": "did:web:empresa-verificada.com.br",
"identityType": "did:web",
"attestations": [
{
"type": "domain-verification",
"verifier": "cloudflare.com",
"issuedAt": "2026-06-01T00:00:00Z"
}
],
"provenance": [
{
"type": "source-repository",
"url": "https://github.com/empresa-verificada/ai-services"
}
]
}
},
"entries": []
}O trust manifest permite que agentes enterprise apliquem políticas de confiança — “só conectar a serviços com domínio verificado”, “exigir assinatura criptográfica”, “aceitar apenas atestações de CAs conhecidas”. Na prática, é o que separa um ecossistema de “confia em tudo” de um que opera com critério.
Para começar, publique sem trust manifest. Quando seus consumidores forem organizações com políticas de segurança, adicione. O padrão é progressivo — funciona sem, melhora com.
Resumo do Fluxo
Cinco passos para tornar seus serviços descobríveis:
- Crie o
ai-catalog.jsoncom host + entries - Hospede em
/.well-known/ai-catalog.jsoncom CORS habilitado - Sinalize via robots.txt, HTML link tag e (opcionalmente) DNS
- Valide com ajv-cli ou conformance test
- Teste com Hugging Face Discover
O ai-catalog.json é a primitiva mais simples do ecossistema de interoperabilidade de agentes. Um arquivo JSON estático, sem auth, sem SDK, sem vendor lock-in. Publique o seu, teste com o HF Discover, e veja agentes encontrarem seus serviços sem que você precise fazer mais nada.