MCP Client — Agent Loop
Visao Geral
Seção intitulada “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
Seção intitulada “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
Seção intitulada “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
Seção intitulada “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 forward_headers: ["x-tenant-id", "x-trace-id"] 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
Seção intitulada “Referencia de Campos”mcp_servers[]
Seção intitulada “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 |
forward_headers | string[] | nao | Nomes dos headers da requisicao de entrada a encaminhar para este servidor em cada chamada de ferramenta (correspondencia sem distincao de maiusculas/minusculas). Headers reservados (authorization, cookie, host e headers de enquadramento) nunca sao encaminhados. Padrao: []. |
Use forward_headers para repassar headers selecionados da requisicao original do cliente para um servidor MCP especifico — por exemplo um tenant id, um trace id ou um token por usuario final que sua ferramenta precise. Os headers sao resolvidos a cada rodada e enviados apenas para o servidor em que foram configurados, nunca para os outros servidores do plugin. Por seguranca, o gateway nunca encaminha authorization, cookie, host ou headers de enquadramento, de modo que sua chave de API do Floopy nunca vaza para o servidor upstream.
| Tipo de auth | Campos | Descricao |
|---|---|---|
bearer | secret_ref | Envia Authorization: Bearer <segredo> |
api_key | header, secret_ref | Envia o segredo em um header customizado |
oauth | token_url, client_id, secret_ref, scopes | Grant OAuth 2.1 client credentials — o Floopy gera um access token e o envia como Authorization: Bearer <token> |
hmac | secret_ref, algorithm | Assina o corpo da requisicao (SHA-256 padrao) |
none | — | Sem autenticacao |
OAuth 2.1 (client credentials)
Seção intitulada “OAuth 2.1 (client credentials)”Para servidores MCP machine-to-machine que emitem tokens de curta duracao, use type: oauth. O Floopy executa o grant OAuth 2.1 client_credentials no endpoint de token do servidor, faz cache do access token em memoria ate pouco antes de expirar e o injeta como bearer token em cada chamada de ferramenta. Nao ha redirecionamento de usuario, PKCE ou refresh token — e uma troca de credenciais servidor-a-servidor.
mcp_servers: - id: billing_tools url: "https://mcp.example.com/billing" auth: type: oauth token_url: "https://idp.example.com/oauth/token" # precisa ser HTTPS client_id: "floopy-agent" secret_ref: "secret.mcp_oauth_client_secret" # o client secret OAuth scopes: ["billing.read", "billing.write"] # opcional tools: "*"| Campo | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
token_url | string | sim | Endpoint de token OAuth. Precisa ser HTTPS e passar pelo validador SSRF. |
client_id | string | sim | Identificador do client OAuth emitido pelo provedor. |
secret_ref | string | sim | Referencia no Floopy Vault para o client secret OAuth. |
scopes | string[] | nao | Scopes solicitados na troca de token (unidos por espaco no protocolo). |
O token e cacheado por (organizacao, servidor) e renovado automaticamente ~60s antes do expires_in. Uma troca de token mal-sucedida (non-2xx, timeout ou corpo grande demais) aborta a chamada de ferramenta em vez de cair para uma requisicao sem autenticacao.
No dashboard, selecione OAuth 2.1 client credentials como tipo de auth em MCP → Servers e preencha Token URL, Client ID, Scopes e uma entrada de Client secret no vault.
| 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
Seção intitulada “Gerenciamento de Segredos”Nunca coloque chaves de API diretamente no YAML. Armazene-as no Floopy Vault e referencie-as pelo nome.
Armazenando um Segredo
Seção intitulada “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
Seção intitulada “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
Seção intitulada “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
Seção intitulada “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
Seção intitulada “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
Seção intitulada “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
Seção intitulada “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.