MCP em Python: Criando Servidores de IA com FastMCP

Aprenda a criar servidores MCP (Model Context Protocol) em Python com FastMCP. Tutorial prático com tools, resources, prompts e exemplos reais de integração.

7 min de leitura Equipe python.dev.br

Se você trabalha com inteligência artificial em Python, provavelmente já enfrentou o desafio de conectar LLMs a dados e ferramentas externas. Cada integração exigia código personalizado, cada API tinha seu próprio formato, e manter tudo funcionando era um pesadelo. O MCP (Model Context Protocol) resolve exatamente esse problema.

Criado pela Anthropic e adotado rapidamente pela comunidade, o MCP se tornou o padrão aberto para conectar modelos de linguagem a fontes de dados e funcionalidades externas. Pense nele como uma “USB-C para IA” — uma interface universal que qualquer aplicação pode implementar.

Neste artigo, vamos entender o protocolo, instalar o SDK oficial e criar um servidor MCP completo em Python usando o FastMCP.

O que é o Model Context Protocol?

O MCP é um protocolo aberto que padroniza a comunicação entre aplicações de IA (clientes) e fontes de dados ou ferramentas (servidores). Em vez de cada assistente de IA implementar integrações proprietárias, o MCP define uma interface comum com três primitivas:

  • Tools — funções que o LLM pode chamar para executar ações (similar a endpoints POST)
  • Resources — dados que o LLM pode ler para obter contexto (similar a endpoints GET)
  • Prompts — templates reutilizáveis para interações padronizadas

Essa arquitetura permite que um único servidor MCP funcione com qualquer cliente compatível — Claude Desktop, editores de código, agentes autônomos e qualquer outra aplicação que implemente o protocolo.

Por que o MCP importa para desenvolvedores Python?

O ecossistema Python já domina o desenvolvimento de IA, e o MCP potencializa isso de várias formas:

  1. Reutilização — um servidor MCP escrito uma vez funciona com qualquer cliente
  2. Segurança — o servidor controla exatamente quais dados e ações são expostos
  3. Tipagem — o SDK usa type hints nativamente
  4. Simplicidade — o FastMCP transforma funções Python comuns em tools MCP automaticamente

Se você já trabalha com APIs REST em FastAPI ou construiu agentes com LangGraph, o MCP é a próxima peça do quebra-cabeça.

Instalação do SDK

O SDK oficial do MCP para Python requer Python 3.10+. A forma recomendada de instalar é com o uv:

# Com uv (recomendado)
uv add "mcp[cli]"

# Com pip
pip install "mcp[cli]"

O pacote mcp[cli] inclui o SDK completo, o framework FastMCP e ferramentas de desenvolvimento como o MCP Inspector.

Criando seu primeiro servidor MCP

O FastMCP simplifica a criação de servidores. Vamos começar com um servidor que expõe uma ferramenta de cálculo:

from mcp.server.fastmcp import FastMCP

# Cria o servidor
mcp = FastMCP("Calculadora")


@mcp.tool()
def somar(a: float, b: float) -> float:
    """Soma dois números e retorna o resultado."""
    return a + b


@mcp.tool()
def calcular_porcentagem(valor: float, percentual: float) -> float:
    """Calcula a porcentagem de um valor.

    Args:
        valor: O valor base para o cálculo
        percentual: A porcentagem desejada (ex: 15 para 15%)
    """
    return valor * (percentual / 100)


if __name__ == "__main__":
    mcp.run()

O FastMCP usa as type hints e docstrings das suas funções para gerar automaticamente as definições de tools que o LLM vai entender. Você não precisa escrever schemas JSON manualmente.

Adicionando Resources

Resources são dados que o LLM pode consultar para obter contexto. Vamos adicionar um recurso que retorna informações de configuração:

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Meu Servidor")

# Resource estático
@mcp.resource("config://app")
def get_config() -> str:
    """Retorna a configuração atual da aplicação."""
    return """
    {
        "versao": "2.1.0",
        "ambiente": "producao",
        "banco": "PostgreSQL 16",
        "cache": "Redis 7"
    }
    """

# Resource dinâmico com parâmetro
@mcp.resource("usuarios://{user_id}/perfil")
def get_perfil_usuario(user_id: str) -> str:
    """Retorna o perfil de um usuário pelo ID."""
    # Em produção, buscaria no banco de dados
    usuarios = {
        "1": "Ana Silva - Desenvolvedora Senior",
        "2": "Carlos Souza - Tech Lead",
        "3": "Maria Santos - DevOps Engineer",
    }
    return usuarios.get(user_id, "Usuário não encontrado")

A diferença entre tools e resources é importante: tools executam ações (podem ter efeitos colaterais), enquanto resources fornecem dados (são somente leitura).

Prompts reutilizáveis

Prompts definem templates de interação que o cliente pode usar:

from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Code Reviewer")


@mcp.prompt()
def revisar_codigo(codigo: str, linguagem: str = "python") -> str:
    """Prompt para revisão de código com boas práticas."""
    return f"""Revise o seguinte código {linguagem} considerando:
- Boas práticas e padrões da linguagem
- Possíveis bugs ou vulnerabilidades
- Legibilidade e manutenibilidade
- Performance

Código para revisão:
```{linguagem}
{codigo}

Forneça sugestões específicas com exemplos de como melhorar."""


## Exemplo prático: servidor de consulta a banco de dados

Vamos criar um servidor mais realista que permite ao LLM consultar um banco [SQLite](/blog/python-e-banco-de-dados-sqlite/):

```python
import sqlite3
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Database Explorer")
DB_PATH = "minha_aplicacao.db"


def get_conexao():
    """Cria conexão com o banco de dados."""
    return sqlite3.connect(DB_PATH)


@mcp.resource("schema://tabelas")
def listar_tabelas() -> str:
    """Lista todas as tabelas do banco de dados."""
    conn = get_conexao()
    cursor = conn.execute(
        "SELECT name FROM sqlite_master WHERE type='table'"
    )
    tabelas = [row[0] for row in cursor.fetchall()]
    conn.close()
    return "\n".join(tabelas)


@mcp.resource("schema://tabela/{nome}")
def schema_tabela(nome: str) -> str:
    """Retorna o schema de uma tabela específica."""
    conn = get_conexao()
    cursor = conn.execute(f"PRAGMA table_info({nome})")
    colunas = cursor.fetchall()
    conn.close()
    resultado = f"Tabela: {nome}\n\nColunas:\n"
    for col in colunas:
        resultado += f"  - {col[1]} ({col[2]})"
        if col[5]:
            resultado += " [PK]"
        resultado += "\n"
    return resultado


@mcp.tool()
def consultar(sql: str) -> str:
    """Executa uma consulta SELECT no banco de dados.

    Args:
        sql: Query SQL (apenas SELECT é permitido)
    """
    sql_limpo = sql.strip().upper()
    if not sql_limpo.startswith("SELECT"):
        return "Erro: apenas consultas SELECT são permitidas."

    conn = get_conexao()
    try:
        cursor = conn.execute(sql)
        colunas = [desc[0] for desc in cursor.description]
        linhas = cursor.fetchall()
        resultado = " | ".join(colunas) + "\n"
        resultado += "-" * len(resultado) + "\n"
        for linha in linhas:
            resultado += " | ".join(str(v) for v in linha) + "\n"
        return resultado
    except Exception as e:
        return f"Erro na consulta: {e}"
    finally:
        conn.close()

Esse servidor permite que qualquer assistente de IA explore a estrutura do banco e execute consultas de leitura, sem nunca ter acesso direto de escrita.

Testando com o MCP Inspector

O SDK inclui o MCP Inspector, uma interface web para testar servidores sem precisar de um cliente real:

# Inicia o Inspector apontando para seu servidor
mcp dev meu_servidor.py

O Inspector abre no navegador e mostra todos os tools, resources e prompts disponíveis. Você pode chamar cada um interativamente e verificar as respostas.

Transportes: stdio vs HTTP

O MCP suporta diferentes mecanismos de transporte:

  • stdio — comunicação via entrada/saída padrão (ideal para integrações locais como Claude Desktop)
  • Streamable HTTP — comunicação via HTTP com suporte a streaming (ideal para servidores remotos)
# Servidor com transporte HTTP
if __name__ == "__main__":
    mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)

Para a maioria dos casos de uso local, o stdio é suficiente e mais simples. Para deploys em produção, o Streamable HTTP oferece mais flexibilidade.

Boas práticas para servidores MCP

Depois de construir vários servidores MCP, algumas práticas se destacam:

  1. Docstrings claras — o LLM usa as docstrings para entender quando e como usar cada tool
  2. Validação de entrada — sempre valide parâmetros antes de executar ações
  3. Princípio do menor privilégio — exponha apenas o mínimo necessário
  4. Tratamento de erros — retorne mensagens de erro úteis em vez de exceções
  5. Resources para contexto — use resources para dados que o LLM precisa consultar frequentemente

Se você trabalha com tratamento de erros e Pydantic para validação, essas práticas já são familiares.

Próximos passos

O ecossistema MCP está crescendo rapidamente. Além de criar seus próprios servidores, você pode:

  • Explorar servidores MCP prontos da comunidade no GitHub
  • Integrar com OpenAI Agents SDK que suporta MCP nativamente
  • Combinar múltiplos servidores MCP em um único agente
  • Adicionar autenticação OAuth para servidores HTTP em produção

O MCP está se tornando a camada de integração padrão entre LLMs e o mundo real. Se você desenvolve em Python e trabalha com IA, dominar esse protocolo é um diferencial competitivo importante em 2026.

Se quiser explorar mais sobre como conectar Python com modelos de linguagem, confira também nosso artigo sobre Go para backends de alta performance que complementam servidores MCP, ou veja como Rust pode otimizar extensões Python para processamento intensivo.

E

Equipe python.dev.br

Contribuidor do Python Brasil — Aprenda Python em Português