Policy Layer

Controles de gastos não custodiais para carteiras de agentes de IA — imponha limites, listas de permissão e interruptores de desligamento antes da execução de transações.

Documentação

Seu agente de IA acabou de fazer a 47ª cobrança no Stripe do dia. Cada uma parecia razoável isoladamente — US$ 12 aqui, US$ 35 ali — mas o total acumulado chegou a US$ 4.200 antes que alguém notasse. O agente estava fazendo exatamente o que lhe foi dito: processando pedidos. Só que ele nunca parou.

Adicionar controles de gastos ao seu agente MCP evita exatamente esse cenário. Servidores MCP como Stripe, AWS e Twilio dão aos agentes acesso direto a ferramentas que custam dinheiro real. O agente não sabe que tem um orçamento. O servidor MCP não impõe um. E o prompt de sistema dizendo "não gaste mais de US$ 500 por dia" é uma sugestão, não uma restrição.

O PolicyLayer resolve isso posicionando-se entre o agente e o servidor MCP como um proxy transparente. Cada requisição tools/call passa por ele, é avaliada contra um arquivo de política YAML e é encaminhada ou bloqueada. O agente não sabe que o PolicyLayer existe — mesmas ferramentas, mesmos esquemas, mesma interface.

Veja como configurá-lo.

A Arquitetura

┌──────────┐       ┌─────────────┐       ┌────────────┐
│ LLM/AI   │──────>│ PolicyLayer │──────>│ MCP Server │
│ Client   │<──────│   (proxy)   │<──────│ (upstream) │
└──────────┘       └─────────────┘       └────────────┘
                          │
                     ┌────┴────┐
                     │ Policy  │
                     │ Engine  │
                     └────┬────┘
                     ┌────┴────┐
                     │ State   │
                     │ Store   │
                     └─────────┘

O PolicyLayer faz proxy do tráfego MCP via HTTP. Ele intercepta requisições tools/call, avalia-as contra sua política e retorna uma mensagem de negação se alguma regra falhar. O armazenamento de estado persiste contadores entre reinicializações, para que seus limites diários de gastos sobrevivam ao ciclo de reinício do processo.

Passo 1: Escaneie o Servidor MCP

Antes de escrever políticas, você precisa saber quais ferramentas estão disponíveis. O PolicyLayer conecta-se a qualquer servidor MCP registrado, descobre suas ferramentas e gera um esqueleto YAML comentado listando cada ferramenta com seus parâmetros, agrupados por categoria. É um ponto de partida — tudo é permitido por padrão até que você adicione regras.

Passo 2: Adicione um Limite por Transação

O controle de gastos mais básico é limitar uma única transação. Se seu agente pode chamar create_charge, você provavelmente não quer que ele crie cobranças de US$ 10.000:

version: "1"
description: "Stripe spending controls"

tools:
  create_charge:
    rules:
      - name: "max single charge"
        conditions:
          - path: "args.amount"
            op: "lte"
            value: 50000
        on_deny: "Single charge cannot exceed $500.00"

Esta regra verifica o argumento amount em cada chamada de create_charge. Se exceder 50000 (o Stripe usa centavos), a chamada é bloqueada e o agente recebe a mensagem de negação. O agente pode então decidir o que fazer — pedir aprovação ao usuário, dividir a transação ou abandonar a tarefa.

O detalhe-chave: essa verificação acontece na camada de transporte, antes que a requisição chegue ao Stripe. A cobrança nunca é criada. Não há reembolso a processar, nem pagamento falho a conciliar. Isso é aplicação de política determinística — a mesma entrada sempre produz o mesmo resultado.

Passo 3: Adicione um Limite Diário de Gastos

Limites por transação não impedem o acúmulo. Um agente fazendo 200 cobranças de US$ 50 cada vai ultrapassar um limite de US$ 500 por cobrança enquanto acumula US$ 10.000 em gastos totais. Você precisa de rastreamento cumulativo.

O PolicyLayer lida com isso usando contadores com estado:

tools:
  create_charge:
    rules:
      - name: "max single charge"
        conditions:
          - path: "args.amount"
            op: "lte"
            value: 50000
        on_deny: "Single charge cannot exceed $500.00"

      - name: "daily spend cap"
        conditions:
          - path: "state.create_charge.daily_spend"
            op: "lte"
            value: 1000000
        on_deny: "Daily spending cap of $10,000.00 reached"
        state:
          counter: "daily_spend"
          window: "day"
          increment_from: "args.amount"

O bloco state cria um contador chamado daily_spend que é redefinido à meia-noite UTC. Em cada chamada permitida de create_charge, o contador é incrementado pelo valor de args.amount. Antes da próxima chamada, a condição verifica se o total acumulado excede o limite.

O campo increment_from é o que faz isso funcionar especificamente para gastos. Em vez de contar chamadas (o padrão), ele soma os valores monetários reais. Uma cobrança de US$ 50 incrementa em 5000, uma cobrança de US$ 200 em 20000. Quando o total acumulado excederia 1000000 (US$ 10.000), cobranças adicionais são negadas.

Os contadores persistem no armazenamento de estado. Se você reiniciar o PolicyLayer, o total diário continua de onde parou. E o modelo de duas fases significa que chamadas upstream com falha não consomem cota — se o Stripe retornar um erro, o incremento é revertido.

Passo 4: Restrinja Moedas e Argumentos

Controles de gastos não são apenas sobre valores. Você pode querer restringir em quais moedas um agente pode cobrar, em quais regiões ele pode operar ou quais produtos ele pode comprar:

- name: "allowed currencies"
  conditions:
    - path: "args.currency"
      op: "in"
      value: ["usd", "eur"]
  on_deny: "Only USD and EUR charges are permitted"

Isso usa o operador in para verificar contra uma lista de permissões. Você pode combinar múltiplas condições em uma única regra — elas são combinadas com E:

- name: "safe charge"
  conditions:
    - path: "args.amount"
      op: "lte"
      value: 50000
    - path: "args.currency"
      op: "in"
      value: ["usd", "eur"]
  on_deny: "Charge must be under $500 and in USD or EUR"

Ambas as condições devem passar. Se qualquer uma falhar, a chamada inteira é negada.

Passo 5: Bloqueie Operações Destrutivas

Algumas ferramentas nunca devem ser chamadas por um agente, independentemente dos argumentos. Excluir clientes, derrubar bancos de dados, remover infraestrutura — essas são operações exclusivas para humanos:

hide:
  - delete_customer
  - delete_product
  - delete_invoice

tools:
  delete_subscription:
    rules:
      - name: "block subscription deletion"
        action: "deny"
        on_deny: "Subscription deletion is not permitted via AI agents"

Há duas abordagens aqui. A lista hide remove ferramentas da visão do agente completamente — elas são removidas das respostas de tools/list, então o agente nunca sabe que existem. Isso economiza tokens de janela de contexto e impede que o agente sequer tente a chamada.

Para ferramentas que você quer que o agente veja, mas não use, use action: "deny". A ferramenta aparece em tools/list, mas qualquer chamada é incondicionalmente bloqueada com a mensagem de negação.

Passo 6: Adicione um Limite de Taxa Global

Mesmo com controles de gastos por ferramenta, você quer uma salvaguarda. Um limite de taxa global limita o número total de chamadas de ferramentas por janela de tempo em todas as ferramentas:

"*":
  rules:
    - name: "global rate limit"
      rate_limit: 60/minute

O curinga "*" aplica-se a toda chamada de ferramenta. Isso previne loops descontrolados em que um agente chama ferramentas centenas de vezes por minuto, independentemente de cada chamada individual passar em suas regras específicas. Para mais sobre estratégias de limitação de taxa, veja nosso guia prático.

Passo 7: Conecte Tudo

Roteie seu servidor MCP do Stripe através do PolicyLayer — aponte seu cliente MCP para a URL do gateway com um token de concessão por pessoa, e a política acima é executada em cada chamada antes de chegar ao Stripe:

{
  "mcpServers": {
    "stripe": {
      "url": "https://proxy.policylayer.com/mcp/<server-uuid>/",
      "headers": { "Authorization": "Bearer <grant-token>" }
    }
  }
}

Você define e ajusta a política no painel do PolicyLayer — sem proxy local para instalar ou executar.

O agente conecta-se ao PolicyLayer pensando que é o servidor MCP do Stripe. O PolicyLayer encaminha tudo, exceto violações de política.

A Política Completa

Aqui está a política completa combinando todas as regras acima:

Clique para expandir a política YAML completa

version: "1"
description: "Stripe MCP server spending controls"

hide:
  - delete_customer
  - delete_product
  - delete_invoice

tools:
  create_charge:
    rules:
      - name: "max single charge"
        conditions:
          - path: "args.amount"
            op: "lte"
            value: 50000
        on_deny: "Single charge cannot exceed $500.00"

      - name: "daily spend cap"
        conditions:
          - path: "state.create_charge.daily_spend"
            op: "lte"
            value: 1000000
        on_deny: "Daily spending cap of $10,000.00 reached"
        state:
          counter: "daily_spend"
          window: "day"
          increment_from: "args.amount"

      - name: "allowed currencies"
        conditions:
          - path: "args.currency"
            op: "in"
            value: ["usd", "eur"]
        on_deny: "Only USD and EUR charges are permitted"

  create_refund:
    rules:
      - name: "refund amount cap"
        conditions:
          - path: "args.amount"
            op: "lte"
            value: 10000
        on_deny: "Refunds over $100.00 require manual processing"

      - name: "daily refund count"
        rate_limit: 10/day
        on_deny: "Daily refund limit (10) reached"

  "*":
    rules:
      - name: "global rate limit"
        rate_limit: 60/minute

Recarga a Quente

As políticas são recarregáveis a quente. Edite a política no painel enquanto o PolicyLayer está em execução e as mudanças são aplicadas imediatamente — sem reinicialização, sem conexões interrompidas. Isso significa que você pode apertar os limites em resposta ao comportamento observado sem interromper o agente.

O PolicyLayer também valida políticas antes de colocá-las em produção, detectando erros de sintaxe, operadores inválidos, contadores ausentes e conflitos lógicos antes que cheguem à produção.

O Que o Agente Vê

Quando uma chamada é negada, o agente recebe uma mensagem como:

[POLICYLAYER POLICY DENIED] Daily spending cap of $10,000.00 reached

Isso é deliberado. O agente sabe por que a chamada falhou e pode adaptar seu comportamento — informar o usuário, tentar um valor menor ou esperar até que a janela seja redefinida. É um ciclo de feedback, não uma falha silenciosa.

Além do Stripe

O mesmo padrão funciona para qualquer servidor MCP que envolva dinheiro ou recursos. Controles de custos da AWS, limites de mensagens do Twilio, limites de escrita em bancos de dados, orçamentos de chamadas de API — se a ferramenta tem argumentos que você pode validar e chamadas que você pode contar, o PolicyLayer pode impor limites sobre ela.

FAQ

Como os controles de gastos MCP persistem entre reinicializações?

O PolicyLayer armazena o estado dos contadores em um armazenamento de estado persistente. Quando você reinicia o PolicyLayer, os totais diários de gastos, contadores de limite de taxa e todo o rastreamento com estado continuam exatamente de onde pararam. Nenhum estado é perdido.

Agentes MCP podem contornar limites de gastos?

Não através do PolicyLayer. Como os controles de gastos são aplicados na camada de transporte — entre o agente e o servidor MCP — o agente não tem como contorná-los. O agente nem sabe que o PolicyLayer existe. Ele vê as mesmas ferramentas e esquemas, mas cada requisição tools/call é avaliada contra a política antes de chegar ao servidor upstream.

O que acontece quando um agente MCP atinge um limite de gastos?

O agente recebe uma mensagem de negação explicando por que a chamada foi bloqueada, por exemplo, [POLICYLAYER POLICY DENIED] Daily spending cap of $10,000.00 reached. O agente pode então se adaptar — informar o usuário, tentar um valor menor ou esperar até que a janela de tempo seja redefinida. O servidor MCP upstream nunca recebe a requisição bloqueada.