MCP Client — Agent Loop
Visao Geral
O Floopy pode atuar como cliente MCP: ele se conecta a servidores MCP externos em nome dos seus agentes e injeta as ferramentas deles na conversa. Quando o LLM decide chamar uma ferramenta, o Floopy a executa, adiciona o resultado a conversa e volta ao modelo — tudo de forma transparente.
Este e o agent loop: o modelo raciocina, chama ferramentas, observa resultados e raciocina novamente ate chegar a uma resposta final.
O Agent Loop
flowchart TD
A[Mensagem do usuario] --> B[Chamada LLM]
B --> C{Tool call solicitado?}
C -- Nao --> D[Retornar resposta final]
C -- Sim --> E[Executar tools via servidor MCP]
E --> F[Pos-processamento dos resultados]
F --> G[Adicionar resultados as mensagens]
G --> H{Round < max_rounds?}
H -- Sim --> B
H -- Nao --> I[Retornar ultima resposta do modelo]O loop e limitado por max_rounds para evitar execucao infinita. Quando o limite e atingido, o Floopy retorna a ultima resposta do modelo. Um timeout global (padrao 120s) tambem se aplica a todo o loop.
Schema do Plugin YAML
Configure o agent loop com um plugin YAML vinculado a sua regra de roteamento ou enviado como header de requisicao (floopy-mcp-plugin).
Exemplo Completo
version: "1"
mcp_servers: - id: pesquisa_web url: "https://mcp.example.com/search" auth: type: bearer secret_ref: "secret.mcp_search_api_key" # resolvido do Floopy Vault tools: - search_web - fetch_page timeout_ms: 5000 max_retries: 2
- id: interpretador_codigo url: "https://mcp.example.com/code" auth: type: api_key header: "X-Api-Key" secret_ref: "secret.mcp_code_api_key" tools: "*" # expoe todas as ferramentas deste servidor timeout_ms: 15000
agent: max_rounds: 10 stream_mode: final_only # final_only | disabled tool_call_parallel: true # executa chamadas independentes em paralelo tool_cache_ttl_seconds: 300 # cache de resultados de ferramentas (0 = desativado) # prompt_guard_on_tool_output era o scan ONNX pre-migracao dos # resultados — atualmente no-op enquanto a interface sync→async do # firewall e refeita. Campo aceito para compatibilidade.Referencia de Campos
mcp_servers[]
| Campo | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
id | string | sim | Identificador unico deste servidor no plugin |
url | string | sim | Endpoint HTTP(S) do servidor MCP (deve passar o validador SSRF) |
auth | objeto | nao | Autenticacao para usar ao chamar o servidor |
tools | string[] ou "*" | nao | Ferramentas a expor. Padrao: "*" (todas) |
timeout_ms | inteiro | nao | Timeout por requisicao. Padrao: 5000 |
max_retries | inteiro | nao | Tentativas em erros transientes. Padrao: 1 |
auth
| Tipo de auth | Campos | Descricao |
|---|---|---|
bearer | secret_ref | Envia Authorization: Bearer <segredo> |
api_key | header, secret_ref | Envia o segredo em um header customizado |
hmac | secret_ref, algorithm | Assina o corpo da requisicao (SHA-256 padrao) |
none | — | Sem autenticacao |
agent
| Campo | Tipo | Padrao | Descricao |
|---|---|---|---|
max_rounds | inteiro | 5 | Iteracoes maximas antes de retornar |
stream_mode | enum | final_only | Quando transmitir: final_only ou disabled |
tool_call_parallel | booleano | true | Executa chamadas de ferramenta independentes em paralelo |
tool_cache_ttl_seconds | inteiro | 0 | Cache de chamadas identicas (por hash de args) |
prompt_guard_on_tool_output | booleano | false | Scan ONNX dos resultados (pre-migracao). Atualmente no-op enquanto a interface sync Validator e refeita. Campo aceito para compatibilidade. |
Gerenciamento de Segredos
Nunca coloque chaves de API diretamente no YAML. Armazene-as no Floopy Vault e referencie-as pelo nome.
Armazenando um Segredo
- Abra o dashboard do Floopy e navegue ate Configuracoes > Segredos
- Clique em Adicionar Segredo
- Digite o nome (por exemplo,
mcp_search_api_key) e o valor - Clique em Salvar
O segredo e criptografado em repouso (AES-256) e injetado em tempo de execucao — ele nunca e registrado em logs nem retornado em respostas da API.
Referenciando um Segredo
Use o prefixo secret. seguido do nome que voce armazenou:
auth: type: bearer secret_ref: "secret.mcp_search_api_key"O formato e sempre secret.<nome> onde <nome> corresponde exatamente ao que voce armazenou no dashboard. Somente caracteres alfanumericos, hifens e underscores sao permitidos (maximo 64 caracteres). Caracteres como :, / e . (alem do prefixo) sao rejeitados por seguranca.
Internamente, cada segredo e isolado por organizacao — seus segredos nunca sao acessiveis por outros tenants.
Modos de Streaming
| Modo | Comportamento |
|---|---|
final_only | Transmite a resposta LLM final apos todas as chamadas de ferramentas serem concluidas. Chamadas intermediarias nao sao transmitidas. |
disabled | Retorna a resposta completa como um unico objeto JSON quando o loop termina. |
As etapas intermediarias sempre ficam disponiveis no log de requisicoes em Observabilidade, independentemente do modo de streaming.
Limites do Loop e Timeouts
Defina max_rounds de acordo com seu caso de uso:
| Caso de uso | max_rounds recomendado |
|---|---|
| Consulta a ferramenta unica | 2–3 |
| Pesquisa em multiplas etapas | 5–8 |
| Agente autonomo complexo | 10–15 |
Cada rodada adiciona latencia do LLM mais tempo de execucao da ferramenta. Mantenha timeout_ms baixo por servidor para evitar travamentos no loop.
Um timeout de gateway rigido de 120 segundos se aplica a todo o agent loop. Requisicoes que excedem esse limite sao encerradas e a resposta parcial e retornada com finish_reason: timeout.
Enviando o Plugin via Header
Em vez de vincular o plugin a uma regra de roteamento, voce pode envia-lo inline por requisicao usando o header floopy-mcp-plugin com o valor YAML codificado em base64:
import { OpenAI } from "openai";import { Buffer } from "buffer";
const plugin = `version: "1"mcp_servers: - id: pesquisa url: "https://mcp.example.com/search" auth: type: bearer secret_ref: "secret.mcp_search_api_key"agent: max_rounds: 5`;
const client = new OpenAI({ baseURL: "https://api.floopy.ai/v1", apiKey: process.env.FLOOPY_API_KEY, defaultHeaders: { "floopy-mcp-plugin": Buffer.from(plugin).toString("base64"), },});
const response = await client.chat.completions.create({ model: "gpt-4o", messages: [{ role: "user", content: "Qual e o preco atual do BTC?" }],});import base64, osfrom openai import OpenAI
plugin = """version: "1"mcp_servers: - id: pesquisa url: "https://mcp.example.com/search" auth: type: bearer secret_ref: "secret.mcp_search_api_key"agent: max_rounds: 5"""
client = OpenAI( base_url="https://api.floopy.ai/v1", api_key=os.environ["FLOOPY_API_KEY"], default_headers={ "floopy-mcp-plugin": base64.b64encode(plugin.encode()).decode(), },)
response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "Qual e o preco atual do BTC?"}],)Exemplo Completo
O exemplo a seguir conecta um servidor MCP de busca na web a um agente GPT-4o que responde perguntas de pesquisa.
Plugin YAML (vinculado a regra de roteamento “Agente de Pesquisa”):
version: "1"
mcp_servers: - id: brave_search url: "https://mcp.brave.com/search" auth: type: bearer secret_ref: "secret.brave_api_key" tools: - web_search timeout_ms: 8000
agent: max_rounds: 6 stream_mode: final_only tool_call_parallel: false # prompt_guard_on_tool_output e no-op atualmente (veja a Referencia de Campos)Requisicao:
const response = await client.chat.completions.create({ model: "gpt-4o", messages: [ { role: "user", content: "Quais sao os tres artigos mais citados sobre atencao em transformers publicados em 2024?", }, ],});
console.log(response.choices[0].message.content);// O modelo pesquisou na web, leu os resultados e sintetizou uma resposta final.O que aconteceu internamente:
- GPT-4o chamou
web_search("transformer attention papers 2024") - O Floopy executou a ferramenta via servidor MCP do Brave
- Os resultados foram adicionados a conversa
- GPT-4o chamou
web_search("citation counts transformer 2024")para aprofundar - O Floopy retornou a resposta final sintetizada apos a rodada 2
Observabilidade
Cada execucao do agent loop e registrada completamente:
- Chamadas de ferramentas realizadas (nome, argumentos, duracao)
- Resultados das ferramentas (sanitizados — segredos reduzidos)
- Numero de rodadas concluidas
- Total de tokens consumidos em todas as rodadas
- Se o loop atingiu
max_rounds
Veja os logs em Observabilidade > Requisicoes no dashboard. Filtre por has_tool_calls: true para isolar sessoes agenticas.