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.