14 KiB
MCP Multi-item — Guia do Desenvolvedor
Objetivo
Use este guia quando uma única intenção do usuário precisa operar sobre mais de um item do mesmo tipo — por exemplo, cancelar vários VAS/produtos, devolver ou consultar vários pedidos, alterar vários ativos ou processar várias faturas/linhas/contratos.
O framework já possui suporte genérico para resolução/canonicalização de múltiplos itens, confirmação transacional, execução MCP/workflow, preservação de evidência por item e normalização de SUCCESS / PARTIAL_SUCCESS / FAILED. O desenvolvedor não deve criar um segundo motor de multi-item dentro do agente.
Regra central: multi-item é uma característica da resolução, execução e resultado da operação. Não é definido pelo tipo do parâmetro de entrada. Uma tool pode receber
subject: string,id: string,items: arrayou outro contrato natural de domínio e ainda assim processar múltiplos itens.
Regra principal
Não faça loop de negócio no agente. O agente seleciona a intenção/tool e usa o runtime. A expansão para múltiplos itens pode ocorrer no pre-validator, na própria tool MCP ou em um workflow de domínio.
Fluxo recomendado:
Usuário cita N itens
-> Router/Agent seleciona a tool
-> Runtime coleta os parâmetros declarados pela tool
-> Entrada pode ser escalar ou coleção
-> (opcional) pre-validation resolve/expande/canonicaliza N itens
-> Runtime pede UMA confirmação coerente para o conjunto efetivo
-> MCP tool/workflow processa 1 ou N itens
-> Tool primária devolve results[] com success/ok por item
-> Framework normaliza SUCCESS / PARTIAL_SUCCESS / FAILED
-> Composição final relata sucessos e falhas individualmente
1. Declare o contrato natural da operação em tools.yaml
O framework não exige array/list para que uma operação seja multi-item.
Use o contrato que faz sentido para a tool e para o domínio:
- parâmetro escalar (
subject,id,query, etc.) quando a operação recebe uma expressão que pode representar uma ou várias entidades; array/listquando a interface MCP é naturalmente batch e recebe explicitamente uma coleção.
Padrão A — parâmetro escalar que pode representar vários itens
Este é o padrão usado pelo agente de Contas para cancelamento de VAS.
tools:
cancelar_vas_avulso:
description: Cancela um ou mais serviços VAS.
mcp_server: contas
enabled: true
tool_type: action
args_schema:
subject:
type: string
label: o serviço ou os serviços
description: Serviço ou expressão com um ou mais serviços a cancelar.
Entrada possível:
subject = "TIM Fashion, Aya Audiobooks, Neymar Jr"
O subject continua sendo uma string. O suporte multi-item aparece posteriormente quando o validator/tool resolve essa expressão em itens independentes.
Padrão B — coleção explícita
Também é válido quando a API/tool é naturalmente batch:
tools:
cancelar_produtos:
description: Cancela um ou mais produtos do cliente.
mcp_server: contas
enabled: true
tool_type: action
args_schema:
items:
type: array
label: os produtos
description: Lista de produtos que o cliente deseja cancelar.
Os dois padrões são suportados. Não altere uma interface escalar existente para array apenas para “habilitar multi-item”.
2. tool_policies.yaml não possui sintaxe especial de multi-item
tool_policies.yaml continua definindo tipo de operação, confirmação, parâmetros obrigatórios e pre-validation. Não é necessário criar multi_item: true, trocar subject por items ou introduzir outra configuração.
Exemplo realista do agente de Contas:
version: 1
defaults:
operation_type: read_only
require_confirmation: false
tool_policies:
cancelar_vas_avulso:
operation_type: transactional
require_confirmation: true
requires:
- subject
pre_validation:
enabled: true
tool: validar_vas_subject
fail_open: false
requires: [subject] significa apenas que a operação precisa saber o que será processado. Esse subject pode representar um item ou vários.
3. Pre-validation pode transformar um parâmetro escalar em múltiplos itens
Quando necessário, o pre-validator resolve nomes, canonicaliza entidades e pode materializar uma lista estrutural em transaction_decision.resolved_arguments.
Exemplo:
{
"eligible": true,
"subject": "TIM Fashion, Aya Audiobooks, Neymar Jr",
"resolved_subject": "TIM Fashion Mensal, Aya Audiobooks Premium, Neymar Jr",
"resolved_subjects": [
"TIM Fashion Mensal",
"Aya Audiobooks Premium",
"Neymar Jr"
],
"transaction_decision": {
"resolved_arguments": {
"subject": "TIM Fashion Mensal, Aya Audiobooks Premium, Neymar Jr",
"items": [
{"name": "TIM Fashion Mensal"},
{"name": "Aya Audiobooks Premium"},
{"name": "Neymar Jr"}
]
},
"target_tool": "cancelar_vas_avulso",
"confirmation_message": "Você confirma o cancelamento de TIM Fashion Mensal, Aya Audiobooks Premium e Neymar Jr?"
}
}
resolved_arguments.items[] é uma representação canônica útil para a execução, mas não obriga tools.yaml a declarar items como parâmetro de entrada.
Validação parcial e fail_open: false
eligible é global. Com fail_open: false, retornar eligible: false encerra a transação inteira.
Portanto, quando alguns itens são válidos e outros não:
- mantenha
eligible: truese existe pelo menos um item acionável; - preserve o estado individual dos itens resolvidos/rejeitados;
- deixe a tool primária produzir o resultado terminal por item em
results[].
Exemplo conceitual:
{
"eligible": true,
"status": "PARTIALLY_ELIGIBLE",
"transaction_decision": {
"resolved_arguments": {
"items": [
{"name": "TIM Fashion Mensal", "eligible": true},
{"name": "Aya Audiobooks Premium", "eligible": false, "reason": "item_nao_encontrado"},
{"name": "Neymar Jr", "eligible": true}
]
}
}
}
Se nenhum item puder ser processado, eligible: false é apropriado.
4. Contrato de entrada do MCP: uma operação lógica, não necessariamente uma coleção explícita
Prefira uma única operação lógica MCP para o agente. Ela pode ser implementada de três formas:
- receber um parâmetro escalar e expandi-lo no validator/workflow;
- receber uma coleção explícita (
array/list); - receber uma expressão/identificador e descobrir os itens dentro da própria tool/workflow.
O agente não deve fazer fan-out chamando a mesma tool repetidamente por conta própria.
Exemplo — escalar expandido
{
"tool_name": "cancelar_vas_avulso",
"arguments": {
"subject": "TIM Fashion Mensal, Aya Audiobooks Premium, Neymar Jr"
}
}
Exemplo — batch explícito
{
"tool_name": "cancelar_produtos",
"arguments": {
"items": [
{"name": "A", "id": "1001"},
{"name": "B", "id": "1002"}
]
}
}
Se o backend só possui API unitária, o fan-out deve ficar encapsulado no MCP Server ou workflow de domínio, preservando uma única operação lógica para o agente.
5. Contrato obrigatório de resultado por item
Para o framework reconhecer automaticamente o resultado como multi-item, a tool primária solicitada deve expor uma lista results com dois ou mais itens, e cada item deve possuir success ou ok booleano.
{
"results": [
{"subject": "TIM Fashion Mensal", "success": true},
{"subject": "Aya Audiobooks Premium", "success": false, "reason": "not_found"},
{"subject": "Neymar Jr", "success": true}
]
}
Campos como id, subject, name, reason, error, protocol e outros são de domínio e opcionais. O sinal estrutural do normalizador é success: true|false ou ok: true|false por item.
Workflow-backed tool
Se a tool é executada por workflow, o caminho preferencial e autoritativo é:
workflow.output[tool_name].results
Uma falha auxiliar posterior não deve apagar itens já concluídos pela tool primária.
6. O que o framework produz automaticamente
Com results[] válido, o runtime classifica o agregado como:
| Situação | multi_item_status |
|---|---|
| todos os itens concluíram | SUCCESS |
| parte concluiu e parte falhou | PARTIAL_SUCCESS |
| todos falharam | FAILED |
Exemplo:
{
"multi_item_status": "PARTIAL_SUCCESS",
"partial_success": true,
"metadata": {
"multi_item": {
"status": "PARTIAL_SUCCESS",
"items_count": 3,
"items_succeeded_count": 2,
"items_failed_count": 1,
"primary_tool": "cancelar_vas_avulso"
}
}
}
Se um wrapper/etapa posterior retornar erro depois de existirem resultados terminais válidos, o framework preserva os sucessos individuais e pode registrar o erro como secundário, em vez de converter tudo para falha total.
7. O que NÃO fazer
Não crie motor multi-item dentro do agente:
# NÃO
for product in products:
await tool_router.call("cancelar_produto", {"product": product})
Não reduza resultado misto a um único booleano global sem evidência por item:
{
"approved": false,
"error": "um item falhou"
}
Também não altere uma interface existente apenas para trocar:
subject: string
por:
items: array
quando o validator/workflow já consegue expandir corretamente o subject.
8. Exemplo completo — padrão escalar do Contas
tools.yaml
tools:
cancelar_vas_avulso:
description: Cancela um ou mais VAS.
mcp_server: contas
enabled: true
tool_type: action
args_schema:
subject:
type: string
tool_policies.yaml
tool_policies:
cancelar_vas_avulso:
operation_type: transactional
require_confirmation: true
requires:
- subject
pre_validation:
enabled: true
tool: validar_vas_subject
fail_open: false
Validator
{
"eligible": true,
"transaction_decision": {
"resolved_arguments": {
"subject": "TIM Fashion Mensal, Aya Audiobooks Premium, Neymar Jr",
"items": [
{"name": "TIM Fashion Mensal"},
{"name": "Aya Audiobooks Premium"},
{"name": "Neymar Jr"}
]
}
}
}
Resultado MCP/workflow
{
"results": [
{"subject": "TIM Fashion Mensal", "success": true},
{"subject": "Aya Audiobooks Premium", "success": false, "reason": "not_found"},
{"subject": "Neymar Jr", "success": true}
]
}
Resultado agregado: PARTIAL_SUCCESS.
9. Exemplo alternativo — API naturalmente batch
Quando o MCP já define coleção como contrato de entrada, array/list continua válido:
args_schema:
order_ids:
type: array
{
"results": [
{"order_id": "P-100", "success": true},
{"order_id": "P-101", "success": false, "reason": "already_shipped"},
{"order_id": "P-102", "success": true}
]
}
O ponto importante é: array é uma opção de contrato, não o gatilho do mecanismo multi-item.
10. Read-only, conversational e transactional podem ser multi-item
Multi-item é independente do operation_type.
É possível ter:
read_only + multi-item
conversational + multi-item
transactional + multi-item
internal + multi-item
O que muda é a política de confirmação e execução, não a capacidade de representar vários itens.
11. Idempotência e protocolos
Em operações com efeito colateral:
- use chave de idempotência de requisição e, quando necessário, por item;
- devolva protocolo/operation id no próprio item;
- preserve itens já concluídos em retry;
- não dependa apenas de mensagem textual agregada.
A política específica de idempotência do sistema de destino continua pertencendo ao MCP/workflow de domínio.
12. Checklist do desenvolvedor
- O agente seleciona a operação e não implementa fan-out/loop MCP de negócio.
tools.yamldeclara o contrato natural da operação, que pode ser escalar ou coleção.- Nenhuma chave especial
multi_item: truefoi criada ou é necessária. tool_policies.yamlusa osrequiresreais do domínio; não é necessário trocarsubjectporitems.- Se um escalar representar múltiplas entidades, validator/tool/workflow expande e canonicaliza os itens.
- A confirmação representa o conjunto efetivo resolvido.
- Com
fail_open: false, um item inválido não forçaeligible: falseglobal quando outros ainda são acionáveis. - A tool primária retorna
results[]comsuccessouokpor item quando há múltiplos resultados. - Workflow usa
output[tool_name].resultscomo evidência terminal preferencial da tool primária. - Resultado parcial não é reduzido a um único
approved=falseousuccess=falseglobal. - Testes cobrem todos-sucesso, parcial, todos-falha e falha auxiliar posterior.
- A apresentação final menciona sucessos e falhas individualmente quando houver
PARTIAL_SUCCESS.
13. Onde o comportamento existe no framework
libs/agent_framework/src/agent_framework/runtime/transaction_parameters.py
- suporte existente a coerção de array/list quando esse for o contrato declarado
libs/agent_framework/src/agent_framework/runtime/agent_runtime.py
- pre-validation e resolved_arguments
- _primary_multi_item_outcomes()
- _normalize_multi_item_tool_result()
- instrução de composição multi-item para o LLM
tests/test_multi_item_result_normalization.py
- regressões de SUCCESS/PARTIAL_SUCCESS e proteção contra falha auxiliar
14. Resumo de responsabilidade
| Camada | Responsabilidade |
|---|---|
| Agente | selecionar intenção/tool e usar o runtime; não implementar motor multi-item |
tools.yaml |
declarar o contrato natural da operação; pode ser escalar ou coleção |
tool_policies.yaml |
confirmação, requires e pre-validation; sem sintaxe especial de multi-item |
| Pre-validator MCP | identificar, resolver, canonicalizar e, quando necessário, expandir 1 parâmetro em N itens |
| Tool MCP/workflow | executar 1 ou N itens e produzir resultado por item |
| Framework runtime | manter estado/confirmação, interpretar results[], preservar evidência e calcular SUCCESS / PARTIAL_SUCCESS / FAILED |
| LLM/presentation | transformar evidências em resposta sem apagar sucesso/falha individual |