The gateway
stalwart gateway is an MCP gateway that checks every tool call an agent makes on its way to the tool. The
agent connects to the gateway; the gateway connects to your MCP servers.
tools/listreturns only the tools in your catalogue that the connecting agent may reach.tools/callis checked first: against the catalogue, the argument schema, the session's history and order rules, your rulebook and the trust labels. It is dispatched only onallow. A refused call never reaches the server.- A call that needs a person becomes an MCP elicitation carrying the confirmation's
wording. A client that cannot be asked gets
confirmation_unavailable, never an unconfirmed write. - Every write carries an idempotency key in
_meta. - Each agent session gets an MCP session of its own on each server, opened with
initializebefore its first call and ended with it. One session's calls never ride in another's. - After a tool that reads the outside world, every later call in the session carries its label. This is coarser than the in-process tool node, because the gateway cannot see the model's context.
- The session's writes are undone last-in first-out on
POST /admin/sessions/{id}/rollback, or when the session is ended withDELETE /mcp?abort=1. - Every decision is written in the gating record's form,
qls-decision/1.
$ pip install stalwart-agents
$ stalwart gateway --config gateway.yaml
catalogue: ./catalogue.json
upstreams:
"*": http://tools.internal:8080/mcp
agents:
desk: ${DESK_TOKEN}
billing: ${BILLING_TOKEN}
admin_token: ${GATEWAY_ADMIN_TOKEN}
audit: /var/log/stalwart/decisions.jsonl
elicitation_timeout: 600 # seconds a person has to answer a confirmation
listen: 0.0.0.0:8800
Each agent connects with its own bearer token, so the gateway knows which agent is calling and what it may reach.
A confirmation not answered within elicitation_timeout seconds (600 by default) is
declined, and so is one whose client disconnects first. The session's other calls wait
while a person is asked, because the check and its confirmation must see the same history.
The gateway is an enforcement point only if the tools are reachable through it
alone. network-policy.yaml is a
Kubernetes NetworkPolicy that lets only the gateway reach the tool servers. Apply it, or its
equivalent in your network. To put the check in front of your tools from Kong AI Gateway instead,
see the Kong recipe.