O que vamos construir
O mesmo servidor do tutorial em TypeScript: utilitarios-br, com a ferramenta validar_cpf. Você precisa do Python 3.10 ou mais recente e do uv.
1. Crie o projeto
uv init utilitarios-br
cd utilitarios-br
uv add "mcp[cli]"O uv init cria a pasta com um pyproject.toml; o uv add cria o ambiente virtual e instala o SDK.
2. Escreva o servidor
Crie o arquivo servidor.py na pasta do projeto:
from mcp.server import MCPServer
mcp = MCPServer("utilitarios-br")
def _digito(numeros: str, n: int) -> int:
soma = sum(int(numeros[i]) * (n + 1 - i) for i in range(n))
resto = (soma * 10) % 11
return 0 if resto == 10 else resto
@mcp.tool()
def validar_cpf(cpf: str) -> str:
"""Confere os dígitos verificadores de um CPF. Não consulta a Receita Federal.
Args:
cpf: CPF com ou sem pontuação, ex.: 529.982.247-25
"""
d = "".join(c for c in cpf if c.isdigit())
if len(d) != 11 or d == d[0] * 11:
return "CPF inválido."
ok = _digito(d, 9) == int(d[9]) and _digito(d, 10) == int(d[10])
return "CPF com dígitos válidos." if ok else "CPF inválido."
if __name__ == "__main__":
mcp.run(transport="stdio")O que cada parte faz:
MCPServer("utilitarios-br")cria o servidor com o nome que o cliente vai mostrar.@mcp.tool()registra a função como ferramenta. O nome vem do nome da função, os parâmetros vêm das anotações de tipo e a descrição vem da docstring.mcp.run(transport="stdio")inicia o servidor na entrada e saída padrão.
3. Teste
uv run servidor.pyO processo fica à espera de mensagens, sem imprimir nada: é o comportamento certo. Encerre com Ctrl+C. No nosso teste, enviamos tools/call ao processo e registramos esta resposta (os campos _meta foram abreviados):
→ {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"validar_cpf","arguments":{"cpf":"529.982.247-25"},"_meta":{…}}}
← {"jsonrpc":"2.0","id":2,"result":{"content":[{"text":"CPF com dígitos válidos.","type":"text"}],"isError":false,"resultType":"complete","structuredContent":{"result":"CPF com dígitos válidos."},…}}Note o campo structuredContent: como a função declara que devolve str, o SDK também entrega o resultado em formato estruturado.
4. Ligue ao cliente
{
"mcpServers": {
"utilitarios-br": {
"command": "uv",
"args": ["--directory", "<CAMINHO_ABSOLUTO>/utilitarios-br", "run", "servidor.py"]
}
}
}Troque o marcador pelo caminho absoluto da pasta. Se o cliente não encontrar o uv, escreva o caminho completo do executável em command (descubra com which uv no macOS e Linux, where uv no Windows). Reinicie o cliente e pergunte: “O CPF 529.982.247-25 é válido?”.
Próximos passos
- Funções assíncronas (
async def) também podem ser ferramentas, o que é útil para chamar APIs. - Leia credenciais de
os.environe declare-as emenvna configuração do cliente. - Compare os formatos de cada cliente no gerador e revise os riscos em Segurança no MCP.