MÓDULO 5.1

📦 Empacotando Seu MCP Server

Transforme seu server em um pacote Python profissional — instalável, distribuível e pronto para publicação.

6
Tópicos
30
Minutos
Avançado
Nível
Prático
Tipo
1

📦 Por Que Empacotar

Ter um MCP Server funcionando como script é ótimo para desenvolvimento, mas para distribuir, versionar e permitir que outros usem seu trabalho, você precisa transformá-lo em um pacote Python profissional. Empacotar significa criar uma estrutura que permite instalar com pip ou uv, declarar dependências, definir versões e compartilhar com a comunidade de forma confiável.

💎 Conceito Principal

Empacotar seu MCP Server significa transformá-lo de um script solto em um projeto Python com estrutura formal: metadados declarados no pyproject.toml, dependências explícitas, versionamento semântico e um entry point que permite rodar o server com um único comando no terminal. Um pacote pode ser instalado com pip install ou uv pip install, distribuído via PyPI ou GitHub, e versionado com tags Git. A diferença entre um script solto e um pacote profissional é a diferença entre um protótipo e um produto.

❌ Evitar
  • Distribuir como arquivo .py solto por e-mail
  • Instalar dependências manualmente em cada máquina
  • Sem versionamento — impossível saber qual versão está rodando
  • Instruções de instalação: "copia esse arquivo e reza"
✅ Fazer
  • Estrutura com pyproject.toml e src layout
  • Dependências declaradas e versionadas
  • Instalação com um comando: uv pip install .
  • Versão clara e rastreável via semver
💡 Dica Prática

Pense no empacotamento como colocar seu server numa caixa profissional com manual de instruções. Sem a caixa, você tem peças soltas que só você sabe montar. Com a caixa, qualquer pessoa pode instalar e usar com um único comando. Comece com uv init para criar a estrutura básica automaticamente.

2

📄 pyproject.toml

O pyproject.toml é o arquivo central de qualquer projeto Python moderno. Ele substitui os antigos setup.py e setup.cfg com uma sintaxe declarativa limpa, padronizada pela PEP 621. É aqui que você define o nome do pacote, versão, descrição, dependências e como o pacote deve ser construído.

💎 Conceito Principal

Um pyproject.toml típico para um MCP Server:

[project]
name = "meu-mcp-server"
version = "0.1.0"
description = "MCP Server para consulta de dados"
requires-python = ">=3.10"
dependencies = [
    "fastmcp>=0.1.0",
    "httpx>=0.25",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project.scripts]
meu-server = "meu_server.server:main"

A seção [project] define metadados, [build-system] define como construir e [project.scripts] cria comandos executáveis no terminal.

💡 Dica Prática

Use hatchling como build backend — é moderno, rápido e funciona perfeitamente com uv. Se preferir, setuptools também funciona, mas o hatchling é a escolha recomendada para projetos novos. Nunca mais escreva um setup.py — o pyproject.toml é o padrão oficial desde a PEP 621.

📊 Dados e Pesquisa

A PEP 621 (2021) padronizou os metadados de projetos Python no pyproject.toml. Desde então, mais de 85% dos novos pacotes publicados no PyPI adotaram esse formato. O setup.py é considerado legado — funciona, mas não é recomendado para projetos novos. Ferramentas modernas como uv, hatch e rye trabalham nativamente com pyproject.toml.

3

📁 Organização de Diretórios

A organização de diretórios de um pacote Python segue convenções que facilitam a construção, os testes e a distribuição. O padrão src layout é a abordagem recomendada para evitar problemas de importação e garantir que os testes rodem contra o pacote instalado, não contra o código-fonte local.

💎 Conceito Principal

Estrutura recomendada para um MCP Server empacotado:

meu-mcp-server/
├── pyproject.toml
├── README.md
├── src/
│   └── meu_server/
│       ├── __init__.py
│       └── server.py
└── tests/
    └── test_server.py

O diretório src/ isola o código-fonte. O __init__.py marca o diretório como pacote Python. O server.py contém a lógica do MCP Server com a função main().

❌ Evitar
  • Colocar server.py na raiz do projeto
  • Esquecer o __init__.py no pacote
  • Misturar testes com código-fonte
  • Usar flat layout sem src/ para pacotes distribuíveis
✅ Fazer
  • Usar src layout para isolamento correto
  • Separar testes em diretório próprio
  • Incluir README.md na raiz
  • Manter pyproject.toml sempre na raiz
📋 Passos para criar a estrutura
Passo 1

Criar o diretório raiz do projeto e inicializar com uv init meu-mcp-server.

Passo 2

Criar src/meu_server/ com __init__.py e mover o código do server para server.py.

Passo 3

Criar diretório tests/ e configurar o pyproject.toml com metadados, dependências e entry points.

4

🔧 Entry Points

Entry points são a mágica que permite transformar seu MCP Server em um comando executável no terminal. Em vez de rodar python -m meu_server.server, o usuário simplesmente digita meu-server e o pacote é executado. Isso é configurado na seção [project.scripts] do pyproject.toml.

💎 Conceito Principal

A configuração de entry point no pyproject.toml:

[project.scripts]
meu-server = "meu_server.server:main"

Isso diz ao Python: "quando alguém digitar meu-server no terminal, execute a função main() do arquivo server.py dentro do pacote meu_server." Após a instalação, o comando fica disponível globalmente no ambiente virtual ativo.

💡 Dica Prática

Certifique-se de que sua função main() no server.py chama mcp.run(). É essa função que será invocada quando o usuário rodar o comando no terminal. Teste sempre com uv pip install -e . (modo editável) durante o desenvolvimento — assim, alterações no código são refletidas imediatamente sem reinstalar.

🚨 Alerta

O nome do comando (antes do =) usa hifens: meu-server. O caminho do módulo (depois do =) usa underscores: meu_server.server:main. Misturar os dois é um erro comum que resulta em ModuleNotFoundError. Lembre-se: hifens no terminal, underscores no Python.

5

📋 Dependências e Versões

Declarar dependências corretamente é essencial para que seu pacote funcione em qualquer máquina. No pyproject.toml, você lista todas as bibliotecas que seu server precisa, com restrições de versão que garantem compatibilidade sem travar atualizações. O uv lock gera um lockfile que fixa as versões exatas para reprodutibilidade.

💎 Conceito Principal

Dependências são declaradas na seção [project] com versionamento semântico (semver):

dependencies = [
    "fastmcp>=0.1.0",      # mínimo 0.1.0
    "httpx>=0.25,<1.0",    # entre 0.25 e 1.0
    "pydantic>=2.0",       # mínimo 2.0
]

Semver (versionamento semântico) usa o formato MAJOR.MINOR.PATCH: MAJOR muda quando há breaking changes, MINOR para novas features, PATCH para correções de bugs. Use >= para mínimos e < para tetos de compatibilidade.

❌ Evitar
  • Fixar versões exatas: fastmcp==0.1.0
  • Não declarar versão mínima: httpx
  • Esquecer dependências que "já estão instaladas"
  • Não rodar uv lock para gerar lockfile
✅ Fazer
  • Usar ranges: >=0.1.0,<1.0
  • Listar TODAS as dependências diretas
  • Rodar uv lock e commitar o uv.lock
  • Testar em ambiente limpo antes de publicar
📊 Dados e Pesquisa

Segundo análises do PyPI, 23% dos problemas de instalação de pacotes Python são causados por dependências mal especificadas — versões incompatíveis, dependências faltando ou restrições muito rígidas. O uso de lockfiles (uv.lock) reduz falhas de reprodutibilidade em mais de 90%, garantindo que todos os desenvolvedores e ambientes de produção usem exatamente as mesmas versões.

6

🧪 Testando o Pacote

Antes de distribuir seu pacote, você precisa verificar que ele funciona quando instalado — não apenas quando rodado diretamente do código-fonte. Isso significa construir o pacote com uv build, instalar o arquivo .whl gerado e testar que o entry point funciona corretamente.

💎 Conceito Principal

O processo de build gera arquivos distribuíveis na pasta dist/:

# Construir o pacote
$ uv build
Successfully built meu_server-0.1.0-py3-none-any.whl

# Instalar o .whl gerado
$ uv pip install dist/meu_server-0.1.0-py3-none-any.whl

# Testar o entry point
$ meu-server
MCP Server rodando...

O arquivo .whl (wheel) é o formato padrão de distribuição Python. Ele contém seu código, metadados e informações de entry points — tudo que o pip/uv precisa para instalar corretamente.

📋 Checklist de teste do pacote
Passo 1

Rodar uv build e verificar que o .whl é gerado sem erros na pasta dist/.

Passo 2

Criar um ambiente virtual limpo e instalar o .whl com uv pip install — simula uma instalação real.

Passo 3

Executar o comando do entry point e verificar que o server inicia corretamente e responde a requisições MCP.

💡 Dica Prática

Sempre teste em um ambiente virtual limpo — não no mesmo onde você desenvolveu. Isso garante que todas as dependências estão corretamente declaradas no pyproject.toml. Se algo funciona no seu ambiente de dev mas falha no limpo, significa que você esqueceu de declarar uma dependência.

📝 Resumo do Módulo

  • Empacotar transforma seu server de script solto em pacote profissional — instalável, distribuível e versionado.
  • O pyproject.toml é o arquivo central: metadados, dependências, build system e entry points em um só lugar.
  • O src layout isola o código-fonte e evita problemas de importação durante testes e distribuição.
  • Entry points criam comandos executáveis no terminal — o usuário roda seu server com um único comando.
  • Dependências devem ser declaradas com ranges de versão e travadas com uv lock para reprodutibilidade.
  • Sempre teste o pacote construído em ambiente limpo antes de distribuir.

Próximo Módulo: 5.2 — Publicando no GitHub