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.

Registro MCP: GitHub, server.json e como listar seu servidor
Cristian Da Conceicao
Fundador do Picasso IA

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

Vista aérea de um porto de contêineres com contêineres de carga empilhados em grades organizadas durante a hora dourada

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 loginFormato do nomeExemplo
GitHubio.github.username/* ou io.github.orgname/*io.github.alice/weather-server
Domínio (DNS ou HTTP)Forma invertida do seu domíniocom.example/acme-analytics

Nomes do GitHub para ganhos rápidos

Close de caixas de correio de latão antigas com pequenas etiquetas de papel com nomes no saguão de um apartamento antigo

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:

  1. 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.
  2. 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

Desenvolvedora de moletom cinza digitando em uma mesa em pé ao lado de uma lista de verificação em papel e uma pequena suculenta

Esta é a estrutura que a documentação usa para um servidor npm local:

{
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
  "name": "io.github.my-username/weather",
  "description": "An MCP server for weather information.",
  "repository": {
    "url": "https://github.com/my-username/mcp-weather-server",
    "source": "github"
  },
  "version": "1.0.1",
  "packages": [
    {
      "registryType": "npm",
      "identifier": "@my-username/mcp-weather-server",
      "version": "1.0.1",
      "transport": {
        "type": "stdio"
      }
    }
  ]
}

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ãoSituação
1.0.0, 1.0.0-beta.1, 3.0.0-rc.2Recomendada
2025-06-18, v1.0Permitida
^1.2.3, ~1.2.3, >=1.2.3, 1.xProibida

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

Vista de baixo para cima de um corredor silencioso de data center ladeado por racks de servidores pretos e altos

Servidores hospedados usam um array remotes no lugar de, ou junto com, packages:

{
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
  "name": "com.example/acme-analytics",
  "description": "Real-time business intelligence and reporting platform",
  "version": "2.0.0",
  "remotes": [
    {
      "type": "streamable-http",
      "url": "https://analytics.example.com/mcp",
      "headers": [
        {
          "name": "Authorization",
          "description": "Bearer token for your account",
          "isRequired": true,
          "isSecret": true
        }
      ]
    }
  ]
}

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

Close de um carimbo de notário de latão pressionando uma marca fresca de tinta sobre papel creme espesso

Tipo de pacoteregistryTypeProva de propriedade
npmnpmmcpName em package.json igual ao nome do servidor
PyPIpypimcp-name: <server name> no README, comentário oculto permitido
NuGetnugetmcp-name: <server name> no README, comentário oculto permitido
Cargo (crates.io)cargomcp-name: <server name> como texto visível no README
Imagem Docker ou OCIociLABEL io.modelcontextprotocol.server.name="<server name>"
Arquivo MCPBmcpbURL contém "mcp", mais um hash fileSha256 em server.json

Para o npm, fica assim em package.json:

{
  "name": "@my-username/mcp-weather-server",
  "version": "1.0.1",
  "mcpName": "io.github.my-username/weather"
}

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

Mulher de jaqueta jeans sentada à mesa junto à janela de um café numa tarde chuvosa, segurando o celular ao lado de um notebook aberto

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

Vista na altura dos olhos de uma vitrine de livraria na hora dourada, com um livro novo de capa dura sobre um suporte de madeira

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:

curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.my-username/weather"

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

Vista de cima de caixas de papelão em uma esteira transportadora dentro de um galpão de triagem

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:

VERSION=${GITHUB_REF#refs/tags/v}
jq --arg v "$VERSION" '.version = $v | .packages[0].version = $v' server.json > server.tmp && mv server.tmp server.json

Quais segredos você precisa

  • 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

Vista de cima de uma mesa com uma página impressa marcada a lápis vermelho, uma lupa e notas adesivas

A maioria das publicações que falham se resume a cinco mensagens:

Mensagem de erroCorreçã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.

Como usar o Sonnet 5 no PicassoIA

  1. Abra a página do Claude Sonnet 5 no PicassoIA e inicie um novo chat.
  2. Cole seus campos package.json (nome, versão, descrição, repositório) mais a linha $schema que mcp-publisher init produziu.
  3. Peça somente JSON, diga ao modelo para deixar $schema intacto e proíba campos inventados.
  4. Copie o resultado para server.json e confira manualmente se name é igual ao seu mcpName.
  5. 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:

"environmentVariables": [
  {
    "name": "PICASSOIA_TOKEN",
    "description": "Bearer credential for api.picassoia.com/v1",
    "isRequired": true,
    "isSecret": true,
    "format": "string"
  }
]

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.

Compartilhe este artigo

Escolha seu idioma