Pular para o conteúdo

Tutorial 3 de 3 · Intermediário · 15 min

Como criar um servidor MCP em Python

O servidor de validação de CPF em menos de 30 linhas de Python, com o SDK oficial e o uv. O código desta página foi executado antes da publicação, e a resposta registrada está abaixo.

Testado em com mcp 2.3.0, Python 3.12.10, uv 0.12.15.

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

Terminal
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:

servidor.py
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

Terminal
uv run servidor.py

O 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):

Teste por stdio
→ {"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

claude_desktop_config.json
{
  "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.environ e declare-as em env na configuração do cliente.
  • Compare os formatos de cada cliente no gerador e revise os riscos em Segurança no MCP.

Perguntas frequentes

Preciso do uv, ou posso usar pip?

O tutorial oficial usa o uv, e foi com ele que este exemplo rodou. Com pip também funciona: crie um ambiente virtual, instale o pacote mcp e aponte o cliente para o python desse ambiente.

Por que a ferramenta não tem esquema escrito à mão?

O SDK de Python gera a definição da ferramenta a partir das anotações de tipo e da docstring da função. Por isso vale escrever uma docstring clara: ela vira a descrição que o modelo lê.

Posso usar print para depurar?

Não em um servidor stdio: print escreve na saída padrão, que é o canal do protocolo. Use o módulo logging ou print(..., file=sys.stderr).

Qual versão do Python?

O tutorial oficial pede Python 3.10 ou mais recente. Este exemplo foi testado com 3.12.10.

Na sequência

Continue por aqui