8 min de leitura

O backpressure do MCP stdio pode travar seu agente?

O backpressure do MCP stdio pode bloquear um agente diante de resultados grandes de ferramentas. Reproduza travamentos de pipe, limite resultados, consuma a saída com segurança e teste a recuperação após cancelamentos.

O backpressure do MCP stdio pode travar seu agente?

Um resultado grande de uma ferramenta MCP pode travar um processo de agente mesmo quando todas as linhas da implementação do protocolo estão tecnicamente corretas. O problema surge quando tratamos stdio como um barramento de mensagens infinitamente rápido. Na verdade, ele é um fluxo de bytes limitado entre dois processos, e as duas direções podem parar quando um dos lados deixa de ler.

Isso importa mais para ferramentas de agentes do que para programas comuns de linha de comando. Uma ferramenta pode produzir um resultado enorme de busca, um arquivo codificado, um payload completo de API ou a transcrição detalhada de um comando. O agente pode então tokenizá-lo, resumir o conteúdo, esperar uma aprovação ou simplesmente decidir que já tem contexto suficiente. Se o host parar de consumir stdout do servidor durante qualquer uma dessas tarefas, o servidor pode bloquear no meio da resposta. Depois disso, talvez não consiga ler uma notificação de cancelamento nem uma solicitação posterior em stdin.

A solução não é uma única configuração. Você precisa de um contrato de resposta que mantenha os resultados pequenos, de um loop de transporte que consuma stdout independentemente do trabalho do agente e de um caminho de cancelamento que chegue até o trabalho que produz o resultado. Teste os três com payloads deliberadamente difíceis.

Um pipe bloqueado pode parecer um bug do agente

Um pipe stdio bloqueado produz sintomas que levam as equipes na direção errada. O agente parece travar depois de uma chamada de ferramenta. O servidor continua com o processo ativo. O uso de CPU pode ser baixo. Um timeout é acionado, mas uma nova tentativa também trava. Alguém culpa o runtime do modelo, o SDK do MCP ou um lock na implementação da ferramenta.

Muitas vezes, a ferramenta já terminou o trabalho. Ela está presa em write() tentando entregar uma resposta que o host deixou de consumir. A capacidade do pipe é limitada e depende da plataforma. A documentação de processos filhos do Node diz exatamente o que programadores de shell sabem há décadas: quando um subprocesso escreve mais do que cabe no pipe e o processo pai não captura a saída, o subprocesso bloqueia até que o pipe aceite mais bytes.

Há duas filas distintas nesse incidente, e confundi-las produz correções ruins.

  • O pipe do sistema operacional mantém os bytes brutos de stdout entre o servidor MCP e o host.
  • A fila da aplicação do host mantém as mensagens JSON-RPC analisadas, aguardando o código do agente, a interface, os logs ou a montagem do contexto.

Aumentar uma fila da aplicação não ajuda se ninguém lê o pipe. Aumentar o buffer do pipe ou do fluxo pode adiar o bloqueio, mas dá ao servidor mais espaço para criar uma resposta que o agente nunca deveria ter recebido. O orçamento de resultados decide o que pertence à conversa. O tratamento de backpressure decide o que acontece quando um dos lados fica mais lento. São problemas diferentes.

A orientação oficial de depuração do MCP também oferece uma fronteira diagnóstica simples: servidores locais via stdio precisam manter os logs fora de stdout. Coloque os diagnósticos em stderr. Se stdout contém um banner, um stack trace ou uma linha de progresso que não é dado do protocolo, existe uma falha de enquadramento antes mesmo do problema de resultados grandes.

stdout precisa continuar sendo lido enquanto o trabalho prossegue

O host controla a regra mais importante: conecte o leitor de stdout e mantenha-o em execução durante toda a vida do processo do servidor. Não o vincule a uma promise que espera o agente terminar de analisar um resultado. Não o pause durante uma janela de aprovação. Não espere um renderizador, uma gravação no banco ou uma solicitação ao modelo antes de aceitar os próximos bytes.

Use um loop de transporte com responsabilidades bem delimitadas:

  1. Leia stdout como bytes sempre que o sistema operacional os fornecer.
  2. Entregue esses bytes ao analisador de frames do protocolo.
  3. Rejeite frames malformados ou grandes demais como falhas de transporte.
  4. Encaminhe mensagens completas para um despachante limitado, separado do leitor.
  5. Continue consumindo ou encerre o processo filho deliberadamente quando o despachante não puder aceitar mais trabalho.

A palavra importante é «separado». Um leitor que executa o tratamento caro da mensagem de forma síncrona acabará se tornando um leitor que para de ler. O próprio parsing de JSON pode ser problemático quando a mensagem é enorme, mas o erro mais comum acontece antes: o leitor espera um callback que está fazendo um trabalho sem relação com a leitura.

O host deve registrar pelo menos estes valores por sessão do servidor: bytes recebidos em stdout, maior frame completo, falhas de parsing, tempo aguardando espaço para o despachante, cancelamentos enviados e encerramentos do processo. Esses números resolvem discussões rapidamente. Se os bytes de stdout param de aumentar no meio de um resultado e o servidor continua ativo, suspeite do lado de escrita do servidor. Se os bytes continuam chegando, mas o despacho de mensagens completas para, suspeite da fila do host ou de quem a consome.

Não faça o fluxo de stdout depender de a resposta da ferramenta ser útil para o modelo. O leitor precisa receber a mensagem inteira do protocolo antes de poder descartá-la, reportá-la ou encaminhá-la com segurança. Um host que decide no meio de um frame que a mensagem é grande demais e então para de ler criou o próprio deadlock.

Um limite de resultado precisa de duas fronteiras

Defina um limite de transporte e um limite de conteúdo. Uma única contagem de caracteres não protege o processo, porque o escape de JSON, a codificação base64 e a estrutura da resposta alteram a quantidade de bytes em stdout.

O limite de transporte é o tamanho máximo em bytes de uma mensagem JSON-RPC serializada completa. Aplique-o no analisador de frames, antes de analisar JSON arbitrário. Isso protege a memória e o tempo do parser no host. O limite de conteúdo é a quantidade máxima útil que uma ferramenta retorna em content ou structuredContent. Aplique-o no manipulador da ferramenta, antes de serializar o resultado. Isso protege o contexto do agente e mantém a resposta relevante.

Nenhum dos dois limites deve existir apenas na descrição da ferramenta. Às vezes, um modelo pedirá uma busca sem limite, uma listagem recursiva ou um documento completo. O servidor precisa lidar com essa solicitação de forma previsível.

Uma resposta prática informa o que foi omitido e como o agente pode continuar. Isso é melhor do que cortar uma string silenciosamente, porque o truncamento silencioso parece evidência completa.

{
  "jsonrpc": "2.0",
  "id": 41,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Returned 50 of 4,382 matching records. Results are sorted by updated time. Use cursor \"eyJvZmZzZXQiOjUwfQ\" to continue, or add a narrower path or query."
      }
    ],
    "structuredContent": {
      "items": [
        {"path": "src/auth.ts", "line": 18, "summary": "reads token from environment"}
      ],
      "nextCursor": "eyJvZmZzZXQiOjUwfQ",
      "truncated": true,
      "totalEstimate": 4382
    }
  }
}

O texto dá ao modelo uma explicação simples. O conteúdo estruturado oferece ao cliente um token estável de continuação e um sinal de truncamento legível por máquina. Não envie um total inventado se contar todos os registros for caro ou impossível. Informe truncated: true e omita a contagem. Uma precisão falsa desperdiça mais tempo do que um resultado incompleto, mas honesto.

Evite a recomendação popular de «simplesmente devolver um caminho de arquivo». Isso só funciona quando o host e o servidor compartilham um sistema de arquivos, o caminho é autorizado, o agente pode lê-lo e o artefato continua presente. Em ambientes remotos ou isolados, é uma promessa quebrada. Uma referência pode ser útil, mas precisa de uma operação correspondente de leitura ou exportação, com seus próprios limites.

Devolva decisões, não todo o excesso bruto

A maioria das respostas grandes vem de ferramentas cujo modelo de saída foi copiado de uma linha de comando. grep -R, git diff, uma API de listagem na nuvem e uma consulta ao banco fazem sentido para uma pessoa no terminal. Elas não se tornam boas interfaces para agentes apenas porque foram envolvidas em JSON.

Em geral, um agente precisa de evidências suficientes para escolher a próxima ação. Dê a ele um conjunto limitado de correspondências, os campos relevantes e uma maneira de restringir a solicitação. Guarde o artefato completo para uma operação explícita de exportação ou recuperação, na qual o chamador escolha paginação ou um intervalo limitado.

Para buscas em repositórios, devolva caminhos de arquivos, intervalos de linhas, pequenos trechos e a consulta usada. Não devolva todas as linhas correspondentes de um monorepo. Para um cliente HTTP, devolva o status, cabeçalhos selecionados, uma prévia limitada do corpo e um identificador de resposta se o produto puder mantê-lo com segurança. Não transforme um download arbitrário em base64 dentro de content. Para SSH, devolva uma parte final limitada de stdout e stderr, além do status de saída. Um comando que imprime um arquivo gerado enorme informou que produziu um arquivo enorme. Raramente o agente precisa de todos os bytes no contexto imediato.

Coloque os limites perto da origem da expansão. Um servidor que chama uma API remota deve enviar paginação e seletores de campos para a própria API. Um servidor que executa um processo deve limitar a captura do subprocesso enquanto continua consumindo stdout e stderr. Um servidor que busca arquivos deve parar ao atingir seu orçamento de resultados, em vez de coletar todas as correspondências e cortar a string final.

Essa distinção importa porque truncar depois da coleta protege o transporte MCP, mas não protege a máquina que executa o trabalho. Um comando recursivo ainda pode consumir memória, disco e CPU antes que a camada de resposta descarte sua saída.

O Sallyport é útil aqui porque mantém as credenciais HTTP e SSH fora do agente enquanto as ações passam pelo gateway local. Essa fronteira não torna seguro devolver um corpo de API ou uma transcrição de shell sem limite, portanto os autores das ferramentas ainda precisam definir orçamentos de saída explícitos na fronteira da ação.

Reproduza o travamento antes de dizer que ele foi corrigido

Verifique a atividade do agente offline
Use sp audit verify para verificar a cadeia de hashes criptografada offline, sem a chave do cofre.

Você não pode testar essa falha chamando uma ferramenta e verificando se um resultado grande aparece depois de algum tempo. Crie um harness que pare deliberadamente de consumir stdout e prove que o servidor entra no estado bloqueado. Depois, prove que o host normal nunca se comporta assim.

Este pequeno fixture do Node escreve uma resposta JSON-RPC válida com um payload grande o bastante para exceder a capacidade comum de um pipe quando o processo pai ignora stdout. Ele recebe uma linha de solicitação em stdin e escreve a resposta em blocos. A espera por drain é a evidência: ela mostra quando o runtime aplicou backpressure ao escritor de stdout do servidor.

// oversized-server.mjs
import readline from "node:readline";
import { once } from "node:events";

const rl = readline.createInterface({ input: process.stdin });

for await (const line of rl) {
  const request = JSON.parse(line);
  const text = "x".repeat(8 * 1024 * 1024);
  const response = JSON.stringify({
    jsonrpc: "2.0",
    id: request.id,
    result: { content: [{ type: "text", text }] }
  }) + "\n";

  for (let start = 0; start < response.length; start += 16 * 1024) {
    const chunk = response.slice(start, start + 16 * 1024);
    if (!process.stdout.write(chunk)) {
      process.stderr.write("stdout backpressure observed\n");
      await once(process.stdout, "drain");
    }
  }
}

Agora inicie o processo com stdout em um pipe e deixe deliberadamente child.stdout sem leitura. Continue lendo stderr para ver o marcador de backpressure. Envie uma solicitação e aguarde brevemente. O processo filho deve continuar ativo e não terminar a escrita. Esse é o comportamento esperado, não um defeito do Node.

// blocked-parent.mjs
import { spawn } from "node:child_process";

const child = spawn(process.execPath, ["oversized-server.mjs"], {
  stdio: ["pipe", "pipe", "pipe"]
});

child.stderr.setEncoding("utf8");
child.stderr.on("data", chunk => process.stderr.write(chunk));

child.stdin.write(JSON.stringify({
  jsonrpc: "2.0",
  id: 1,
  method: "tools/call",
  params: { name: "large", arguments: {} }
}) + "\n");

setTimeout(() => {
  console.error("child still running:", child.exitCode === null);
  child.kill("SIGTERM");
}, 1000);

Não copie esse padrão de processo pai para produção. O objetivo é tornar a falha evidente. Substitua o consumidor ausente de stdout pelo seu analisador de frames real e execute o mesmo fixture. O processo filho deve concluir a resposta, ou o cliente deve rejeitá-la por exceder o limite definido. Ele não pode continuar travado porque o processo pai ignorou stdout.

Execute o teste com payloads que contenham aspas, caracteres multibyte e strings longas sem quebras. Esses casos encontram analisadores que contam caracteres JavaScript em vez de bytes UTF-8 ou presumem que toda leitura termina no limite de uma mensagem.

Rejeite um frame enorme sem recriar o bloqueio

Há uma armadilha na verificação do tamanho do frame: um cliente que para de consumir o frame grande bloqueia o servidor tão seguramente quanto um cliente que nunca conectou um leitor. O cliente precisa de uma regra de recuperação.

Se o protocolo de enquadramento oferece um marcador claro de fim, continue lendo até esse marcador enquanto descarta o frame problemático. Depois, informe uma violação de protocolo e decida se a sessão pode continuar. Se a codificação do protocolo não permitir recuperar o enquadramento com segurança depois do limite, encerre o processo do servidor, feche stdin e inicie uma sessão nova. Parece uma medida severa, mas tentar adivinhar onde termina uma mensagem JSON corrompida é pior.

O MCP stdio usa mensagens JSON-RPC sobre um fluxo local de bytes. Sua implementação precisa tratar o enquadramento como código de transporte, não como uma chamada conveniente a split("\n") depois de acumular texto sem limite. Mantenha um contador de bytes enquanto acumula uma mensagem candidata. A cada bloco recebido, encontre os limites de frames completos e encaminhe-os, ou falhe assim que o candidato ultrapassar o máximo.

Não analise uma mensagem gigantesca apenas para descobrir que ela é gigantesca. JSON.parse precisa de uma string completa na memória e pode alocar mais do que o tamanho da entrada. O objetivo de um limite de transporte é impedir esse trabalho.

Se você controla os dois lados e usa JSON delimitado por novas linhas, exija um objeto JSON por linha, rejeite novas linhas literais dentro de strings por meio da codificação JSON normal e escreva exatamente um delimitador depois de cada objeto serializado completo. O servidor nunca deve escrever diagnósticos humanos em stdout. A própria documentação de depuração do MCP orienta servidores locais a enviar logs para stderr, porque stdout pertence ao protocolo.

O leitor também deve impor um limite ao número de mensagens completas aguardando o tratamento da aplicação. Se essa fila ficar cheia, não pause stdout indefinidamente. Você pode rejeitar novas solicitações, cancelar trabalhos quando houver suporte ou encerrar a sessão. A ação correta de sobrecarga depende do host, mas deixar stdout sem leitura nunca é um padrão seguro.

O cancelamento só funciona quando chega ao produtor

Use um único app local para Mac
Execute um único app assinado para Mac na barra de menus, com o núcleo do cofre no próprio processo, sem um daemon separado.

Um timeout na interface do agente não é cancelamento. Ele apenas muda a opinião da interface sobre a solicitação. O servidor pode continuar consultando um banco, baixando uma resposta, executando um processo e escrevendo megabytes em stdout.

O MCP define notifications/cancelled para uma solicitação emitida anteriormente na mesma direção. A notificação inclui o ID da solicitação original e pode incluir um motivo. O esquema do MCP diz que o receptor deve interromper o processamento associado, liberar recursos e tratar o resultado como não utilizado. Também alerta que o cancelamento pode concorrer com a conclusão. Por isso, o cliente precisa aceitar uma resposta tardia, e o servidor precisa aceitar um cancelamento para uma solicitação que já terminou.

Para uma chamada tools/call, o cliente envia uma notificação como esta pela mesma sessão stdio:

{
  "jsonrpc": "2.0",
  "method": "notifications/cancelled",
  "params": {
    "requestId": 41,
    "reason": "result exceeded the client budget"
  }
}

O servidor precisa manter um mapa do ID da solicitação para o trabalho ativo. Cada entrada deve conter um controlador de interrupção ou equivalente da linguagem, um estado de conclusão e qualquer processo filho, solicitação HTTP ou cursor que ele possua. Quando a notificação de cancelamento chegar, interrompa o trabalho, pare de produzir conteúdo do resultado, limpe a entrada do mapa e evite enviar uma resposta normal se ela ainda não tiver começado.

É aqui que as equipes cometem um erro sutil. Elas adicionam um sinal de interrupção ao manipulador da ferramenta, mas o manipulador espera um processo filho cuja captura de stdout ignora esse sinal. Ou cancelam um fetch HTTP e deixam uma transformação continuar serializando um array enorme na memória. O cancelamento só é real quando chega a todos os produtores e a todas as operações que estão aguardando.

Trate o ponto depois que o servidor começa a escrever uma resposta como um estado separado. Um cancelamento pode chegar depois que os bytes já entraram no pipe. Não é possível retirá-los. O host deve continuar consumindo o suficiente para preservar a saúde da sessão e depois ignorar a resposta tardia associada ao ID cancelado. O servidor deve parar o trabalho adicional assim que perceber o cancelamento, mas não pode prometer que nenhum byte tardio existe.

Um teste de cancelamento precisa de uma segunda solicitação

Um bom teste de cancelamento comprova recuperação, não apenas que um timer disparou. Inicie uma ferramenta que produza saída lentamente o bastante para que o cliente possa cancelá-la enquanto está ativa. Envie o cancelamento. Depois, envie uma solicitação pequena e independente na mesma sessão MCP. Essa segunda solicitação precisa terminar rapidamente.

A sequência abaixo encontra as falhas que importam:

  1. Inicie uma chamada tools/call cujo manipulador emite uma resposta grande em blocos ou chama um produtor deliberadamente lento.
  2. Espere o harness observar bytes suficientes em stdout para saber que a resposta começou.
  3. Envie notifications/cancelled para o ID dessa solicitação.
  4. Verifique se o produtor termina ou informa o caminho de interrupção dentro do prazo escolhido.
  5. Envie uma solicitação pequena com um novo ID, como uma ferramenta de saúde ou uma ferramenta de eco limitada.

A solicitação final é o teste. Ela revela se o servidor ainda está bloqueado escrevendo, se o leitor de stdin ficou sem tempo de execução, se uma tarefa cancelada reteve um lock global ou se o host parou de consumir stdout depois de decidir cancelar.

Teste também o cancelamento antes do início do trabalho, no meio de uma operação de I/O remoto, enquanto um subprocesso está em execução e depois que a resposta final começou. São estados diferentes. Uma implementação que trata um deles corretamente pode falhar em outro.

Não afirme que o cancelamento sempre impede uma resposta. A especificação MCP permite condições de corrida. Afirme que o host continua correto se uma resposta chegar depois do cancelamento e que o trabalho do servidor para quando o cancelamento chega a tempo de fazer diferença.

A saída de processos precisa de seu próprio caminho de leitura

Rastreie cada ação de ferramenta
O diário Activity registra cada chamada HTTP e SSH no registro de auditoria criptografado.

Servidores MCP frequentemente chamam ferramentas de linha de comando. Isso adiciona outro par de pipes dentro do servidor: ele precisa consumir stdout e stderr do processo filho enquanto executa o trabalho MCP. Se ler apenas uma quantidade limitada de um fluxo filho e depois parar, o processo filho pode bloquear antes de terminar. O servidor MCP externo pode então parecer ignorar o cancelamento porque está esperando um processo filho que não consegue avançar.

Capture uma prévia limitada, mas continue consumindo depois do limite. Marque a saída como truncada e descarte os bytes restantes. Se o comando aceitar seu próprio limite de resultados, passe-o antes de iniciar o comando. Por exemplo, peça a uma ferramenta de busca um número máximo de correspondências, peça ao banco uma página limitada ou restrinja um comando de logs às últimas linhas. Consumir depois do limite é a rede de segurança, não a estratégia principal de resultados.

Mantenha stderr separado de stdout. Uma ferramenta pode escrever diagnósticos úteis em stderr e ainda retornar um status de saída normal. Limite e consuma os dois fluxos de forma independente. Nunca misture saída arbitrária de um processo ao stdout do servidor MCP. O canal externo de stdout tem uma única função: mensagens MCP serializadas.

A mesma regra vale para comandos SSH. Um comando remoto pode imprimir até o canal bloquear. Capture dados limitados, continue consumindo os fluxos remotos até a conclusão ou o cancelamento e seja honesto no resumo sobre o que foi descartado. Uma transcrição completa pertence a um fluxo de artefatos próprio, não a um resultado casual de ferramenta.

Inclua a falha no critério de lançamento

É fácil remover limites de resultado e cancelamento por acidente. Uma refatoração pode trocar um leitor em streaming por readFile, transformar uma chamada paginada em uma chamada sem limite ou mover o parsing para um callback da interface. Mantenha o fixture de resultado grande na suíte de testes.

Seu critério de lançamento deve cobrir uma resposta válida logo abaixo do limite de transporte, uma resposta logo acima dele, um campo único enorme, muitos blocos pequenos de conteúdo, JSON malformado, stderr ruidoso, um log acidental em stdout e cancelamento durante a saída. Execute esses testes no caminho real de criação do processo, não apenas em um transporte em memória. Testes em memória não mostram o backpressure do pipe.

Registre o comportamento esperado em linguagem simples: o cliente consome stdout continuamente; nunca analisa uma mensagem acima do limite de frame configurado; informa uma falha de resultado limitado; o cancelamento chega ao trabalho ativo; e outra solicitação pode prosseguir depois da recuperação. Os engenheiros podem alterar detalhes da implementação sem enfraquecer essas garantias.

Se você fizer apenas uma mudança, faça esta: separe o leitor de stdout do processamento do agente e teste-o com um servidor que escreva muito mais do que qualquer ferramenta sensata deveria devolver. Esse teste transforma um relato vago de «o agente travou» em uma falha que você pode reproduzir, medir e manter fora do próximo lançamento.

FAQ

Por que um servidor MCP trava depois de devolver um resultado grande de ferramenta?

Isso acontece quando o servidor escreve mais rápido do que o host consegue consumir stdout, ou quando o host bloqueia ao analisar, armazenar ou encaminhar um resultado. O servidor então espera espaço no pipe e pode parar de ler stdin. Uma solicitação posterior, inclusive o cancelamento, pode ficar presa atrás desse bloqueio.

Qual é um tamanho máximo seguro para um resultado de ferramenta MCP?

Não existe um único número seguro no MCP, porque o limite útil depende do cliente, do orçamento de contexto do modelo, da codificação do resultado e do trabalho executado. Escolha um limite em bytes para toda a resposta JSON-RPC serializada e um limite semântico menor para o conteúdo da ferramenta. Deixe o truncamento explícito e ofereça ao chamador um cursor, caminho, consulta ou ferramenta de continuação para recuperar o restante.

Aumentar o buffer de stdout corrige o backpressure do MCP?

Não. Aumentar um buffer na memória apenas adia a falha e pode transformar uma saída bloqueada em um pico de memória. O host precisa continuar consumindo o pipe, e o servidor deve evitar construir objetos de resposta absurdamente grandes desde o início.

Como funciona o cancelamento de ferramentas MCP via stdio?

A notificação de cancelamento do MCP é notifications/cancelled, com o ID da solicitação original e um motivo opcional. Ela é uma solicitação de interrupção e pode concorrer com a conclusão. Por isso, o servidor precisa conectá-la a um sinal de interrupção real, e o cliente ainda deve aceitar uma resposta que já tenha sido escrita.

O host MCP deve continuar lendo stdout enquanto o agente está ocupado?

Leia stdout continuamente em um analisador de enquadramento, imponha um tamanho máximo de frame enquanto os bytes chegam e encaminhe as mensagens completas para uma fila de trabalho limitada e separada. Nunca pare de ler stdout apenas porque o agente está processando um resultado anterior. Se a fila ficar cheia, aplique uma ação de sobrecarga definida em vez de deixar o transporte sem leitura.

Posso registrar mensagens de depuração em stdout em um servidor MCP?

Registre os detalhes operacionais em stderr, não em stdout. stdout transporta apenas mensagens do protocolo MCP, e uma única linha de log pode corromper o enquadramento. A documentação oficial de depuração do MCP afirma isso claramente para servidores locais via stdio.

O que um cliente deve fazer quando uma resposta MCP ultrapassa seu limite?

Não pare de ler depois de atingir o limite. Continue consumindo e descartando bytes até o fim do frame problemático, ou encerre o processo do servidor e reinicie a sessão. Parar exatamente no limite recria o bloqueio do pipe que você queria evitar.

Como testar o cancelamento do MCP em vez de apenas esperar um timeout?

Teste três propriedades separadas: o servidor percebe o cancelamento, o trabalho filho é interrompido e o cliente continua utilizável depois da solicitação cancelada. Um teste que apenas encontra uma notificação de cancelamento no log prova muito pouco. É preciso enviar uma segunda solicitação pequena e verificar se ela termina rapidamente depois que a solicitação grande é cancelada.

Como as ferramentas MCP devem devolver arquivos grandes ou respostas de APIs?

Use paginação, filtros, resumos, referências estáveis e ferramentas de exportação explícitas. Uma ferramenta que devolve uma árvore de diretórios, um diff de repositório, um resultado de consulta ou um corpo HTTP deve retornar a parte necessária para a decisão atual e oferecer uma forma de solicitar mais. Enviar um artefato inteiro só porque foi fácil serializá-lo é um design ruim de ferramenta.

Usar um gateway de ações elimina os riscos de backpressure do MCP stdio?

O Sallyport executa ações HTTP e SSH por meio do app local e do shim sp mcp, para que o agente não receba as credenciais subjacentes. Isso protege o uso dos segredos, mas não muda as características de stdout. Ferramentas e clientes ainda precisam de limites de resultado, cancelamento e testes que comprovem que uma resposta grande não pode travar a sessão.

Sallyport

O Sallyport executa chamadas de API e comandos SSH pelo seu agente de IA. As chaves ficam em um cofre local no seu Mac; você aprova cada execução e toda ação vai para um registro selado.

© 2026 Sallyport · Código aberto sob Apache-2.0 · Oleg Sotnikov