Files
agent_platform_oci/docs/MCP_MULTI_ITEM_DEVELOPER_GUIDE.md

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: array ou 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/list quando 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:

  1. mantenha eligible: true se existe pelo menos um item acionável;
  2. preserve o estado individual dos itens resolvidos/rejeitados;
  3. 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:

  1. receber um parâmetro escalar e expandi-lo no validator/workflow;
  2. receber uma coleção explícita (array/list);
  3. 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.yaml declara o contrato natural da operação, que pode ser escalar ou coleção.
  • Nenhuma chave especial multi_item: true foi criada ou é necessária.
  • tool_policies.yaml usa os requires reais do domínio; não é necessário trocar subject por items.
  • 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ça eligible: false global quando outros ainda são acionáveis.
  • A tool primária retorna results[] com success ou ok por item quando há múltiplos resultados.
  • Workflow usa output[tool_name].results como evidência terminal preferencial da tool primária.
  • Resultado parcial não é reduzido a um único approved=false ou success=false global.
  • 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