A receita do Kong
Duas formas de colocar a verificação na frente das suas ferramentas a partir do Kong AI Gateway. Cada arquivo que a receita aplica pode ser baixado separadamente:
| Arquivo | O que é |
|---|---|
kong-tool-check.yaml |
rota 2: a rota das ferramentas com a sua pre-function |
pre-function.lua |
a própria pre-function, como a rota a carrega |
kong-opa.yaml |
rota 1: as configurações do plugin OPA |
opa-input.example.json |
a entrada com que o OPA é consultado |
network-policy.yaml |
a NetworkPolicy do Kubernetes que faz do Kong o único caminho até as ferramentas |
As duas formas colocam o Kong entre os seus agentes e os seus servidores de ferramentas. A
verificação da rota 2 é o seu próprio qls-router enterprise, que você executa no seu próprio
ambiente, em uma URL que você escolhe: as verificações de ferramentas e os recibos leem as
chamadas que os seus agentes fazem, por isso a API hospedada da Stalwart (api.stalwart.it) não
os serve. Nenhuma das duas formas funciona se as ferramentas não puderem ser alcançadas só pelo
Kong, então aplique a política de rede em
network-policy.yaml (com os pods do
Kong como gateway), ou o equivalente.
1. O portão do rulebook no OPA
Emita o portão do seu rulebook como um pacote Rego:
$ RulebookTranslator emit policy.co --target rego --out-dir ./opa
wrote ./opa/rulebook.ir.json
wrote ./opa/Rulebook.rego
O pacote é stalwart.<the policy file's name> (stalwart.policy aqui), e a sua decision é
{"decision": "allow" | "refuse" | "clarify" | "silent", "rule": ...} para input.tool sob
input.context. Carregue Rulebook.rego no servidor OPA que o plugin OPA do Kong consulta,
defina opa_path em kong-opa.yaml como o
seu pacote e aplique-o.
opa-input.example.json mostra a
entrada. Um refuse é um 403; trate clarify como uma chamada que precisa de uma pessoa, a quem
esta rota não pode perguntar, e recuse-a também.
O Rego é o portão e apenas o portão. O esquema dos argumentos, a origem dos argumentos, o
histórico da sessão e as regras de ordem, os rótulos de confiança, as confirmações e as reversões
não estão nele, e o cabeçalho do arquivo emitido diz isso. Use a rota 2, ou o
stalwart gateway, para isso.
2. Uma rota que chama a verificação completa
kong-tool-check.yaml coloca uma
pre-function na rota das ferramentas
(pre-function.lua). Ela lê cada
tools/call MCP (ou uma solicitação simples {"tool", "arguments"}); toda outra mensagem MCP --
initialize, tools/list, uma notificação -- segue sem verificação, já que não executa nada.
Uma chamada de um agente que verifica as próprias chamadas -- um agente stalwart-agents
cuja fonte de ferramentas diz receipts: true, ou um agente LangGraph no nosso nó de ferramentas
protegido -- leva o seu recibo: o histórico da sessão do agente, terminando na verificação que
permitiu esta chamada, no _meta.stalwart do MCP ou no cabeçalho X-Stalwart-Receipt. A rota o
envia ao POST /v1/tool-receipts do seu roteador, que diz se o token do histórico confere e se a
sua última entrada permite exatamente esta chamada. A chamada é admitida pela verificação do
próprio agente, de modo que uma escrita que a pessoa aprovou no agente não é perguntada uma
segunda vez; um recibo para outros argumentos, outra ferramenta ou uma chamada já relatada é um
403.
O agente é o que está assinado na última entrada do histórico: a rota não envia nenhum agente
próprio, e um recibo não pode ser apresentado como de outro agente. Um recibo admite uma chamada.
O roteador o gasta na primeira chamada que admite e guarda só os digests do token do histórico e
dessa chamada. Apresentado de novo, o recibo é um 403 receipt_spent, a menos que seja a mesma
chamada -- com os mesmos argumentos e a mesma chave de idempotência -- e que reenviá-la seja
seguro: uma leitura, uma ferramenta declarada idempotente ou uma escrita cuja chave vai em um
argumento. Essa é a nova tentativa do próprio agente. A repetição de uma escrita sob uma chave
nova é recusada.
Uma chamada sem recibo é verificada por completo no POST /v1/tool-checks do seu roteador e
só passa com allow. confirm volta ao cliente como um 409 com o texto e o token da
confirmação; o cliente os mostra a uma pessoa e, depois, envia a chamada de novo com o token em
X-Stalwart-Confirmation. O histórico da sessão trafega em X-Stalwart-History, e a entrada e o
token de cada resposta voltam em X-Stalwart-Entry e X-Stalwart-History-Token para o cliente
acrescentá-los a ele, de modo que nenhum estado fica no Kong.
Defina STALWART_ROUTER_URL (a URL base do seu qls-router, como
https://qls-router.internal:8080) e QLS_API_KEY no ambiente do Kong. A rota consulta
/v1/tool-checks e /v1/tool-receipts sob ela. Com STALWART_ROUTER_URL não definida, toda
chamada é recusada com um 503 router_not_configured: a rota nunca recorre a outra verificação.
Como a receita é testada
A própria suíte do pacote lê as duas configurações e executa o próprio pre-function.lua em uma
fase de acesso emulada: chamadas MCP de um agente com e sem recibo, um recibo adulterado, as
mensagens que não chamam nada, uma verificação inalcançável e uma configuração que não nomeia
nenhum roteador.