Voltar as noticias
Projetando Ferramentas que um Agente Pode Realmente Chamar
MCP ProtocolAltaEN

Projetando Ferramentas que um Agente Pode Realmente Chamar

Dev.to - MCP·6 de setembro de 2026

Publicado originalmente em michael-kaminski.io.

Uma ferramenta que oculta a única variável que o usuário realmente altera não é uma ferramenta. É uma demonstração.

O servidor de corretagem MCP conectado ao meu agente expõe 34 ferramentas. Vinte delas são leituras: posições, saldos, resumo, negociações, histórico de preços, cadeias de opções. Nenhuma das 34 requer um identificador de conta. As três que mais importam — get_account_positions, get_account_summary, get_account_balances — têm um esquema de parâmetro vazio. Nenhum argumento.

Eu tenho três contas sob um login: um fundo tributável, uma IRA Roth e uma IRA Tradicional. O servidor está vinculado a qual delas estiver ativa. Cada pergunta que faço entre contas — dinheiro total, quais posições podem carregar uma chamada coberta, como as IRAs estão em relação ao fundo — é uma pergunta que a ferramenta não pode responder, e nenhum prompt corrige isso.

Então eu escrevi um script em Python de 228 linhas que chama diretamente a API do Portal do Cliente da corretora, e aprendi mais sobre design de ferramentas com a solução alternativa do que com a coisa que ela substituiu.

O parâmetro que o usuário varia deve ser um argumento

A afirmação é simples: se a pessoa que pergunta varia X entre as chamadas, X é um parâmetro. Não uma configuração, não um estado de sessão, não um login. Um parâmetro que o modelo pode ver e preencher.

Os designers do servidor MCP fizeram da conta uma propriedade de sessão. Essa é uma escolha razoável para um humano em um terminal que faz login em uma conta e permanece lá. É a escolha errada para um agente, porque o trabalho inteiro do agente é responder à pergunta "em todas elas".

A API do Portal do Cliente acerta isso, e a forma vale a pena copiar. GET /portfolio/accounts enumera cada conta sob o login. Então GET /portfolio/{id}/summary, /ledger, e /positions/{page} recebem o id explicitamente. O script faz um loop. Três contas, uma sessão, um arquivo JSON no final.

A API também impõe a ordem — você deve chamar /portfolio/accounts antes de qualquer chamada /portfolio/{id}/* ou você recebe um 401 ou um 500. Essa é uma segunda lição escondida na primeira: uma ferramenta que precisa de uma chamada pré-requisito deve dizer isso em seu próprio erro, e o wrapper deve apenas fazê-lo. O meu faz.

Normalize na forma que a decisão precisa, não na forma que a API retorna

O registro de posição bruto da corretora tem uma dúzia de campos com três nomes diferentes para o ticker dependendo da classe de ativo. O consumidor do meu instantâneo — uma tela de chamada coberta — precisa exatamente de um número derivado: quantos lotes de 100 ações essa posição possui.

Então o script calcula isso no momento da coleta. Para qualquer posição de ações com quantidade acima de zero, covered_call_lots = quantity // 100, e covered_call_candidate é verdadeiro quando isso é pelo menos um. O agente que lê o arquivo nunca faz a divisão.

Essa é a regra geral. Pré-calcule os campos nos quais a decisão a ser tomada se baseia, nomeie-os de acordo com a decisão e mantenha os campos brutos ao lado para auditoria. Um agente que precisa derivar a variável de decisão de seis brutas errará tão frequentemente quanto uma pessoa fazendo isso na cabeça.

A advertência honesta está no código como um comentário: a contagem de lotes é baseada apenas na quantidade. Não verifica se o símbolo tem uma cadeia de opções listada. Uma posição em algo sem opções aparecerá como um candidato. Essa verificação está na lista de melhorias, não no script.

Somente leitura é uma propriedade do código, não do prompt

O servidor MCP envia nove ferramentas de escrita junto com suas leituras: criar, atualizar e excluir para alertas, listas de observação e instruções de ordem. create_order_instruction está bem ali na lista.

Minha regra constante é que nada que eu automatize faça uma negociação ou mova dinheiro. Eu poderia impor isso nas instruções do agente. Eu não confio nisso, e eu escrevi sobre por que: uma regra em prosa é uma frase que deixa de ser verdadeira no dia em que alguém adiciona um caminho de escrita.

O script impõe isso estruturalmente. Ele chama apenas endpoints GET. Os endpoints de ordem são nomeados no docstring como deliberadamente não utilizados. Não há função no arquivo que possa enviar uma ordem, então nenhuma mudança de instrução, nenhuma injeção de prompt e nenhuma chamada de ferramenta confusa pode produzir uma.

O custo é real. No momento em que eu quero que o agente, digamos, defina um alerta de preço, eu tenho que escrever esse caminho de propósito e colocar um bloqueio nele. Essa fricção é o ponto. É muito mais barato do que a alternativa.

Coloque a recuperação dentro da ferramenta

O caminho ao vivo depende de um processo de gateway local em https://localhost:5000 com um certificado autoassinado e uma sessão que expira. O script POSTa /tickle em cada execução para mantê-lo ativo, mas ainda falha.

Quando isso acontece, a ferramenta lida com isso, não o agente. Cinco tentativas com retrocesso exponencial limitado — 2, 4, 8 e 15 segundos entre elas — e então falha para um segundo caminho de dados inteiramente: o Serviço Web Flex da corretora. Essa é uma chamada REST autenticada por token que retorna uma declaração XML, sondada até dez vezes em intervalos de cinco segundos enquanto o relatório é gerado.

A recuperação tem 152 linhas e fornece dados de fim de dia em vez de ao vivo. O arquivo de saída carrega um campo source, cpapi_live ou flex_backup, para que o consumidor saiba qual recebeu.

A razão pela qual isso pertence à ferramenta é a taxa de transferência. Um agente que precisa notar uma falha, raciocinar sobre tentativas e escolher um caminho de backup consome uma volta completa do modelo em encanamento, e fará uma escolha diferente a cada vez. Uma função faz a mesma escolha toda vez e a registra.

Onde ainda está quebrado

O script foi escrito em 2026-06-19. Em 2026-09-06, o arquivo de instantâneo que deveria escrever não existe, e o diretório data/ nunca foi criado. Ele não completou uma única coleta.

A razão é a autenticação. O gateway precisa de um login de navegador com dois fatores, e a sessão morre após a inatividade. Um trabalho agendado não pode satisfazer isso, e eu também não sentei e fiz isso manualmente. O fallback Flex funcionaria sem cabeça — precisa apenas de um token — mas seu token e id de consulta ainda são strings vazias na configuração de exemplo.

Então, o estado honesto é: eu projetei a ferramenta corretamente e depois não terminei o único passo que a deixa funcionar sem mim. A correção certa é a chata. Preencher as credenciais Flex, torná-las o caminho principal para a coleta diária e reservar o gateway ao vivo para quando eu estiver lá.

Isso inverte o design original — ao vivo primeiro, em lote como backup — e é a inversão correta para um agente. O agente que consome isso roda às 9 da manhã nos dias de semana, em um cronograma. Não precisa de intradia. Precisa de um caminho que nunca peça a um humano um segundo fator.

As cinco regras, comprimidas

Regra Como parecia aqui
A variável que o usuário altera é um argumento Id da conta em cada chamada de portfólio, não estado de sessão
Enumere antes de buscar /portfolio/accounts primeiro, depois faça o loop
Retorne a variável de decisão, não o registro bruto covered_call_lots calculado no momento da coleta
Somente leitura é estrutural Não existe função de ordem no arquivo
Tente novamente e a recuperação vivem na ferramenta 5 tentativas, depois Flex, fonte marcada na saída

Nenhuma dessas são

Contexto Triplo Up

Empresas brasileiras que utilizam agentes de IA podem se beneficiar ao entender como projetar ferramentas que realmente atendam às necessidades dos usuários. A implementação correta de APIs pode melhorar a eficiência e a precisão das operações automatizadas. Isso é crucial para a competitividade no mercado digital.

Noticias relacionadas

Gostou do conteudo?

Receba toda semana as principais novidades sobre WebMCP.