Registro MCP: GitHub, server.json e como listar seu servidor
O Registro MCP é onde clientes e marketplaces encontram seu servidor, e entrar na lista exige um único server.json, um namespace verificado e um comando. Este artigo acompanha o login no GitHub, as verificações de propriedade do pacote, os servidores remotos e um fluxo de lançamento com tags.
Um bom servidor MCP que ninguém consegue encontrar poderia simplesmente não existir. O Registro MCP oficial resolve isso com um arquivo JSON, um nome verificado e um comando, e o GitHub aparece em três pontos separados do caminho: o login, o namespace e a automação de lançamento. Este artigo segue os arquivos e comandos exatos da documentação do registro, para que seu servidor entre no registro na primeira tentativa, e não na quinta.
💡 Resposta rápida: escreva um server.json, comprove que você é dono do pacote para o qual ele aponta, execute mcp-publisher login github e depois execute mcp-publisher publish. Tudo abaixo explica por que cada etapa existe e o que quebra quando você a pula.
O que é de fato o Registro MCP
O Registro MCP é o repositório oficial e centralizado de metadados para servidores MCP acessíveis publicamente, apoiado pela Anthropic, GitHub, PulseMCP e Microsoft. Ele abriu em prévia em setembro de 2025, a API está congelada na v0.1 desde o final de outubro de 2025, e a documentação ainda traz um aviso de prévia, então espere pequenas mudanças. O serviço em funcionamento fica em registry.modelcontextprotocol.io.
Metadados, não código
O registro nunca armazena seu código. Ele guarda um registro que aponta para um pacote no npm, PyPI, NuGet, crates.io, um registro de contêineres ou um lançamento (release) no GitHub. Pense em um porto de contêineres: o manifesto diz o que há em cada caixa e de onde ela veio, enquanto a carga fica em outro lugar. Por isso a ordem importa. Você publica o pacote primeiro e só depois a entrada no registro.
Onde o GitHub entra
O GitHub participa do processo em três pontos:
Identidade. Faça login com o GitHub e o nome do seu servidor precisa começar com io.github.username/, ou com o nome da sua organização no lugar do nome de usuário.
Metadados.server.json carrega um objeto repository com "source": "github" e a URL do repositório.
Automação. O GitHub Actions pode se autenticar no registro por OIDC, sem nenhum segredo armazenado.
Existe ainda uma vitrine separada. O GitHub mantém o próprio Registro MCP em github.com/mcp, e anunciou que os servidores publicados por conta própria no registro comunitário de código aberto "vão aparecer automaticamente" ali. Trate isso como um bônus, não como promessa: depois de publicar, confira você mesmo a listagem no GitHub.
Quem pode listar um servidor
Servidores de código aberto e de código fechado são bem-vindos, com uma condição: o servidor precisa estar acessível publicamente. Isso significa um pacote público (um pacote npm, uma imagem Docker em um registro público) ou um endpoint remoto que não esteja preso dentro de uma rede privada. Servidores em um host interno como mcp.acme-corp.internal, ou atrás de um registro privado de pacotes, estão fora do escopo. Para esses casos, mantenha seu próprio registro privado.
Também vale saber: os aplicativos hospedeiros não devem ler o registro oficial diretamente. Marketplaces e agregadores o consultam em intervalos regulares, por exemplo a cada hora, e acrescentam sua própria curadoria e avaliações. Sua listagem passa por eles.
Escolha seu namespace primeiro
O campo name em server.json é a identidade permanente do seu servidor, e o método de login decide quais nomes você tem permissão para usar.
Método de login
Formato do nome
Exemplo
GitHub
io.github.username/* ou io.github.orgname/*
io.github.alice/weather-server
Domínio (DNS ou HTTP)
Forma invertida do seu domínio
com.example/acme-analytics
Nomes do GitHub para ganhos rápidos
Escolha a rota do GitHub quando você for um desenvolvedor individual ou um projeto de código aberto. A CLI executa um fluxo de dispositivo OAuth, você aprova no navegador e pronto, em alguns minutos. Sem painel de DNS, sem arquivos para hospedar. A contrapartida está no nome: io.github.alice/weather-server funciona bem para um projeto paralelo, mas uma marca de empresa geralmente quer um domínio próprio.
Nomes de domínio com DNS ou HTTP
Nomes baseados em domínio usam a forma invertida de um domínio que você controla, como com.example/acme-analytics. Você comprova o controle de uma de duas maneiras:
DNS. Gere um par Ed25519 (ou ECDSA P-384) com openssl e depois publique a metade pública como um registro TXT no formato example.com. IN TXT "v=MCPv1; k=ed25519; p=<base64>". Aguarde alguns minutos para a propagação.
HTTP. Hospede a mesma linha v=MCPv1; ... como um arquivo em https://example.com/.well-known/mcp-registry-auth.
Depois, faça login com mcp-publisher login dns --domain example.com ou mcp-publisher login http --domain example.com, adicionando a metade privada do seu par conforme mostrado na documentação de autenticação. Equipes que preferem não manter um arquivo privado em um notebook podem assinar pelos serviços de assinatura em nuvem do Google ou do Azure.
Escreva o server.json passo a passo
Gere o esqueleto
Instale o publicador com o Homebrew (brew install mcp-publisher) ou baixe um binário nas versões do GitHub do registro. Depois, dentro da pasta do seu projeto de servidor:
mcp-publisher --help
mcp-publisher init
O comando init cria um modelo server.json e preenche o que consegue a partir do seu projeto.
Um arquivo mínimo funcional
Esta é a estrutura que a documentação usa para um servidor npm local:
Mantenha a linha $schema que init gera, já que a data do esquema muda com o tempo. Três campos causam a maior parte dos problemas. O name precisa coincidir com a prova de propriedade dentro do seu pacote (mais sobre isso abaixo). O packages[].identifier precisa apontar para algo já publicado. E transport.type informa aos clientes como conversar com o servidor, com stdio indicando um processo local.
Precisa de variáveis de ambiente? Adicione-as à entrada do pacote com as flags isRequired e isSecret, para que os clientes as solicitem e mascarem o que for digitado.
Regras de versão que causam problemas
Cada publicação precisa de um version exclusivo, e, depois de publicada, essa versão e seus metadados não podem ser alterados. O versionamento semântico é recomendado, embora qualquer string seja aceita. Intervalos de versão são rejeitados de propósito.
String de versão
Situação
1.0.0, 1.0.0-beta.1, 3.0.0-rc.2
Recomendada
2025-06-18, v1.0
Permitida
^1.2.3, ~1.2.3, >=1.2.3, 1.x
Proibida
Dois hábitos evitam problemas. Primeiro, alinhe a versão do servidor com a versão do pacote, de modo que 1.2.3 em server.json coincida com 1.2.3 no npm. Segundo, se você só precisa corrigir metadados do registro sem mexer no pacote, publique uma pré-versão como 1.2.3-1. Atenção à armadilha: o semver ordena uma pré-versão antes da versão regular, então publicar 1.2.3-1 depois de 1.2.3 não será marcado como a mais recente.
Servidores remotos com remotes
Servidores hospedados usam um array remotes no lugar de, ou junto com, packages:
Um remoto precisa estar acessível publicamente na sua URL. Prefira o Streamable HTTP; o transporte SSE está obsoleto, então adicione um remoto "sse" apenas para clientes já existentes. Configurações multilocatário podem usar variáveis de URL como https://{tenant_id}.analytics.example.com/mcp, cada uma descrita com isRequired, default ou choices. E se você entregar tanto um pacote quanto um remoto, liste os dois: o aplicativo hospedeiro escolhe o método de instalação que preferir.
Comprove que você é dono do pacote
O registro verifica se o pacote realmente pertence ao nome que você está reivindicando. Se pular essa etapa, a publicação falha com "Registry validation failed for package". Cada tipo de pacote tem sua própria prova.
Uma verificação por tipo de pacote
Tipo de pacote
registryType
Prova de propriedade
npm
npm
mcpName em package.json igual ao nome do servidor
PyPI
pypi
mcp-name: <server name> no README, comentário oculto permitido
NuGet
nuget
mcp-name: <server name> no README, comentário oculto permitido
Cargo (crates.io)
cargo
mcp-name: <server name> como texto visível no README
Alguns detalhes causam tropeços. A verificação do npm usa somente o registro público do npm, e PyPI e NuGet também se limitam aos seus registros oficiais. O crates.io remove comentários HTML, então o token do Cargo precisa ser texto visível, não um comentário oculto. Para imagens de contêiner, o identifier segue registry/namespace/repository:tag, e os hosts suportados são Docker Hub, GitHub Container Registry (ghcr.io), Google Artifact Registry, Azure Container Registry e Microsoft Container Registry. Para arquivos MCPB hospedados em versões do GitHub ou do GitLab, calcule o hash com openssl dgst -sha256 your-file.mcpb. O registro não verifica esse hash, mas os clientes o verificam antes de instalar.
💡 Dica: o nome do servidor em server.json e a prova dentro do pacote precisam coincidir caractere por caractere. Uma letra maiúscula fora do lugar já basta para a validação falhar.
Publique a partir do seu terminal
Faça login com o GitHub
Execute o login a partir da pasta do seu projeto:
mcp-publisher login github
A CLI exibe um código de uso único e uma URL:
To authenticate, please:
1. Go to: https://github.com/login/device
2. Enter code: ABCD-1234
3. Authorize this application
Waiting for authorization...
Abra o link, cole o código, aprove, e o terminal confirma o login. Se depois você vir "Invalid or expired Registry JWT token", a sessão expirou. Execute o login de novo.
Publique e verifique
Com o pacote publicado no npm e server.json salvo, publique:
mcp-publisher publish
Uma execução saudável exibe a URL do registro e o nome do seu servidor com sua versão. Confirme pela API pública:
Os metadados do seu servidor devem aparecer no JSON retornado. Os marketplaces que consomem o registro se atualizam no próprio ritmo, então dê um tempo antes de esperar ver a listagem lá, e procure também em github.com/mcp.
As atualizações seguem o mesmo caminho. Aumente a versão do pacote, publique no npm, ajuste server.json para coincidir e execute mcp-publisher publish de novo. Cada publicação é uma versão imutável própria, e o registro marca a versão semântica mais nova como a mais recente, então os clientes que pedirem a versão atual receberão a correta.
Lance versões com GitHub Actions
Um fluxo de lançamento com tags
Quando a execução manual funcionar, leve-a para o CI para que cada tag de versão publique o pacote e a entrada no registro juntos. Este fluxo usa o OIDC do GitHub, o método que a documentação recomenda:
name: Publish to MCP Registry
on:
push:
tags: ["v*"]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: "lts/*"
- name: Install dependencies
run: npm ci
- name: Build package
run: npm run build --if-present
- name: Publish package to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Install mcp-publisher
run: |
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
- name: Authenticate to MCP Registry
run: ./mcp-publisher login github-oidc
- name: Publish server to MCP Registry
run: ./mcp-publisher publish
Lance com dois comandos: git tag v1.0.0 e git push origin v1.0.0. Uma coisa que o modelo deixa opcional é a atualização da versão. Se server.json tiver uma versão fixa no código, o registro rejeitará uma nova publicação igual, então defina-a a partir da tag antes da etapa de publicação. Para um servidor de pacote único, esta linha jq atualiza os dois campos de versão:
OIDC do GitHub: nenhum segredo do registro. Você só precisa da permissão id-token: write.
Token de acesso pessoal do GitHub: armazene-o como segredo e execute mcp-publisher login github --token, com os escopos read:org e read:user.
Login por DNS: armazene a metade privada do seu par Ed25519 como segredo e passe-a para mcp-publisher login dns.
Registro de pacotes: o fluxo acima também precisa de um segredo NPM_TOKEN para npm publish.
Corrija erros antes que os usuários vejam
A maioria das publicações que falham se resume a cinco mensagens:
Mensagem de erro
Correção provável
"Registry validation failed for package"
O pacote não tem a prova de propriedade, como mcpName em package.json.
"Invalid or expired Registry JWT token"
Faça login de novo com mcp-publisher login github.
"You do not have permission to publish this server"
Seu método de login não corresponde ao prefixo do nome. O login pelo GitHub precisa de io.github.your-username/.
"Authentication failed"
No Actions, confirme se id-token: write está definido ou revise seus segredos.
"Package validation failed"
O pacote ainda não está no seu registro, ou não tem a prova de propriedade.
Antes de cada lançamento, percorra esta lista curta:
O name em server.json é igual ao mcpName (ou ao token do README, ou ao rótulo da imagem).
A versão do pacote em server.json já existe no npm, no PyPI ou no seu host de contêineres.
A versão version do servidor nunca foi publicada antes e não é um intervalo.
Qualquer URL remota responde a partir da internet pública, e não apenas da rede do seu escritório.
O servidor é destinado ao público. Servidores privados pertencem a um registro privado.
Rascunhe e ilustre com o PicassoIA
Um LLM é uma máquina rápida para primeiros rascunhos de server.json, desde que o registro faça a validação final. O PicassoIA hospeda modelos de linguagem (LLM) que você pode usar direto no navegador, incluindo Claude Sonnet 5, GPT 5.6 Sol e Gemini 3.5 Flash.
Abra a página do Claude Sonnet 5 no PicassoIA e inicie um novo chat.
Cole seus campos package.json (nome, versão, descrição, repositório) mais a linha $schema que mcp-publisher init produziu.
Peça somente JSON, diga ao modelo para deixar $schema intacto e proíba campos inventados.
Copie o resultado para server.json e confira manualmente se name é igual ao seu mcpName.
Execute mcp-publisher publish. Se a validação reclamar, cole o erro exato de volta no chat.
Prompts curtos com o código-fonte colado vencem prompts longos com descrições, porque os modelos inventam campos plausíveis quando não veem o arquivo real. Quer também o fluxo do Actions montado? O GPT 5.6 Sol é uma boa segunda opinião para isso.
O PicassoIA também mantém uma API para desenvolvedores, e ela serve de exemplo prático para mostrar para que servem environmentVariables. A API fica em https://api.picassoia.com/v1 e funciona como outras APIs de previsão: você cria uma previsão, consulta o status e depois busca o resultado, com até 5 previsões simultâneas por conta (a partir do início de outubro de 2026). Um servidor-wrapper hipotético pediria a cada usuário sua própria credencial uma única vez, por meio de uma entrada como esta dentro do pacote:
Uma entrada no registro é apenas texto, mas o README, a imagem de compartilhamento e o post de lançamento precisam de imagens. Abra o PicassoIA, escolha um modelo de imagem ou de vídeo e gere uma imagem principal ou um clipe curto de demonstração para o seu servidor. O catálogo completo de modelos está em picassoia.com/en/all-models. Teste três prompts, guarde o melhor e envie-o junto com sua primeira mcp-publisher publish.