use cases

Limiting a REST Maintenance Agent to One Record Change

Not every agent speaks MCP. Plenty of useful work is a plain REST call to an internal service: update a note on a customer record, close a ticket, change a flag. The service account behind those calls can usually touch every record. Tokening’s REST templates bring that down to the one record the task is about.

Here’s a worked example against an imaginary internal API. The endpoint and fields are made up, so adapt them to your own service.

The template

The service accepts PATCH /records/{id} with a JSON body. Our task only ever needs to change a short note.

"records.update-note": {
  "target": "records",
  "method": "PATCH",
  "path": "/records/{id}",
  "args": {
    "id":   { "bind": "required" },
    "note": { "type": "string", "max_bytes": 1024 }
  },
  "additional_args": "refuse",
  "max_uses": 1,
  "max_ttl": "10m"
}

The {id} in the path works like any other argument. It gets bound when the grant is issued, so the agent can’t point the call at a different record. Only note can be in the body, and only up to 1 KB.

Add a records target with the service’s base URL and store its credential in the vault, then run tokening check on the policy before you start the gateway.

The grant and the call

tokening grant issue records.update-note \
  --bind id=42 --uses 1 --ttl 10m \
  --to maintenance-bot --by me --reason "add renewal note to record 42"

The agent calls Tokening instead of the service:

curl -X PATCH http://127.0.0.1:8080/http/records/records/42 \
  -H "Authorization: Bearer GRANT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"note": "Renewal confirmed by phone."}'

Tokening strips any credential the agent sent, checks the call, spends the use, adds the real credential and forwards it to PATCH /records/42 on the service.

What gets refused

Agent sends Result
PATCH /records/43 Refused, the grant is bound to record 42
DELETE /records/42 Refused, the grant allows PATCH /records/{id} only
Body with note and owner Refused, owner isn’t an allowed field
A 5 KB note Refused, the grant allows up to 1024 bytes
The same valid call twice The second is refused, the use is gone

None of these reach the service.

Keep the body simple

Version 0.1 checks top-level scalar fields. Nested objects, arrays and rules that compare two fields come later. If your API needs a nested body for a simple change, that’s worth knowing before you write the template.

And as with any write, a timeout after an allowed call leaves the use spent. Look at record 42 before you issue another grant to try again.

The reference lists every REST rule, and the quick start covers running the gateway.