Tutorial: crie um servidor MCP em Python com ferramentas financeiras seguras
O Model Context Protocol (MCP) padroniza a forma como aplicações de IA descobrem dados e ferramentas. Em vez de escrever uma integração diferente para cada assistente, um servidor descreve capacidades com schemas que clientes compatíveis conseguem entender. A analogia mais útil é a de uma porta USB para software: ela define como conectar, mas não torna automaticamente seguro tudo o que você pluga.
Neste tutorial, criaremos um servidor local com duas ferramentas somente leitura: listar transações de demonstração e calcular um resumo por categoria. Não haverá acesso a banco real, chaves bancárias ou ações de pagamento. Essa limitação é intencional e representa um bom ponto de partida.
Pré-requisitos e estrutura
A documentação oficial pede Python 3.10 ou superior e recomenda o gerenciador uv. O SDK Python oficial expõe FastMCP, que usa anotações de tipo e docstrings para gerar as definições das ferramentas.
uv init moneyia-mcp-demo
cd moneyia-mcp-demo
uv add "mcp[cli]"
Crie um arquivo server.py. Não instale sqlite3: ele já faz parte da biblioteca padrão do Python. Para manter o exemplo reproduzível, usaremos dados em memória.
Modele entradas pequenas e previsíveis
Ferramentas não devem receber comandos livres como “execute este SQL”. Elas devem expressar a intenção do produto com poucos parâmetros. Quanto menor o espaço de possibilidades, mais fácil é autorizar, testar e auditar.
from datetime import date
from decimal import Decimal
from typing import Literal
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("MoneyIA Demo", json_response=True)
TRANSACTIONS = [
{"date": "2026-07-02", "category": "moradia", "amount": "1450.00"},
{"date": "2026-07-08", "category": "alimentacao", "amount": "286.40"},
{"date": "2026-07-15", "category": "transporte", "amount": "119.90"},
]
Category = Literal["moradia", "alimentacao", "transporte"]
def valid_month(month: str) -> str:
parsed = date.fromisoformat(f"{month}-01")
if parsed.year < 2020 or parsed.year > 2030:
raise ValueError("Mês fora do intervalo permitido")
return month
Exponha ferramentas somente leitura
@mcp.tool()
def list_transactions(month: str, category: Category | None = None) -> list[dict]:
"""Lista transações de demonstração de um mês e categoria opcional."""
month = valid_month(month)
rows = [item for item in TRANSACTIONS if item["date"].startswith(month)]
if category:
rows = [item for item in rows if item["category"] == category]
return rows[:100]
@mcp.tool()
def spending_summary(month: str) -> dict:
"""Soma despesas de demonstração por categoria sem realizar alterações."""
rows = list_transactions(month)
totals: dict[str, Decimal] = {}
for item in rows:
category = item["category"]
totals[category] = totals.get(category, Decimal("0")) + Decimal(item["amount"])
return {
"month": month,
"currency": "BRL",
"totals": {key: str(value) for key, value in totals.items()},
}
if __name__ == "__main__":
mcp.run(transport="streamable-http")
O retorno usa strings para valores decimais, evitando a perda de precisão típica de números de ponto flutuante. A ferramenta limita o máximo de linhas e não aceita nomes arbitrários de tabela, arquivo ou conta.
Execute e inspecione localmente
uv run server.py
npx -y @modelcontextprotocol/inspector
Com o servidor ativo, conecte o Inspector ao endereço local exibido, normalmente http://localhost:8000/mcp. Teste meses válidos e inválidos, categorias aceitas e o limite de resultados. A documentação oficial recomenda Streamable HTTP para implantações; para servidores STDIO, nunca escreva logs no stdout, pois isso pode corromper as mensagens JSON-RPC.
Da demonstração para produção
| Demonstração | Exigência de produção |
|---|---|
| Dados em memória | Banco com usuário somente leitura e isolamento por cliente |
| Servidor local | TLS, proteção de rede, limites de requisição e observabilidade |
| Sem identidade | OAuth, validação de audiência do token e autorização por recurso |
| Uma organização | Tenant derivado da sessão, nunca de texto escolhido pelo modelo |
| Sem efeitos colaterais | Aprovação humana e idempotência para qualquer escrita |
Testes que valem mais que uma demo feliz
- Envie um mês inválido, enorme ou fora do intervalo e confirme a rejeição.
- Tente uma categoria não prevista e verifique a validação do schema.
- Simule indisponibilidade da fonte e retorne erro claro, sem detalhes sensíveis.
- Confirme que logs não contêm tokens, documentos ou dados pessoais.
- Garanta que um usuário não consiga selecionar o identificador de outro cliente.
O que isso significa na prática
Um bom servidor MCP não é o que expõe mais ferramentas, e sim o que representa poucas capacidades com contratos claros. Comece por leitura, valide tudo no servidor e mantenha a identidade fora do controle do modelo. Quando uma ferramenta precisar alterar dados, trate-a como uma API financeira tradicional: autenticação forte, autorização granular, idempotência, auditoria e confirmação proporcional ao risco.