Rightshold™ Sign up

Answers · agent safety

How do I bind an approver and scope to an agent tool call, its result, and a timestamp?

Last updated

TL;DR: An approval that is not tied to the exact tool call, its result, and when it happened is weak evidence for audit. Build one outside-agent record that names the human approver (IdP subject, not a typed name), the scope that was granted, the tool name plus a hash of the canonical arguments, a digest of the tool result (or a typed error), and a wall-clock timestamp from a clock the agent cannot set. Fail closed if any of those fields is missing, mismatched, or arrives after the fact from chat memory. This is narrower than gateway grant-binding (which captures every tools/call under the live grant) and narrower than a full grant/spend/revocation trail: here the unit of evidence is one approved invocation sealed with who said yes, what scope covered it, what ran, what came back, and when. Pair request_human_approval for the yes, then record_ai_run (or your append-only store) for the sealed tuple; use precall_check before unfamiliar MCP servers.

What should I check, step by step?

1. Identify the human approver from your identity provider (subject, email, or employee id your IdP already asserts). Do not accept a free-text "approved by" string the agent typed.

  1. Freeze the granted scope on the same row: grant_id or approval_id, allowed actions/targets, policy_version, and expiry. Re-read it at execute time; do not copy it from the agent's paraphrase.
  2. Canonicalize the tool call: server/tool name, tool_call_id, and SHA-256 of sorted JSON arguments (redact secrets before hashing). Hash the same way at approve time and at seal time.
  3. After the tool returns, compute a result digest (SHA-256 of canonical success payload or of {isError, error_class}). Never seal "success" without a digest, and never let the model supply the digest.
  4. Stamp wall-clock time from your server or NTP-synced gateway (ISO-8601 with offset). Reject agent-supplied ran_at unless you treat it as advisory only and keep your own observed_at.
  5. Write one append-only record outside the session that joins: approver_id, scope/grant fields, tool+args hash, result digest, observed_at. Refuse to mark the action "approved" if any field is null.
  6. Call request_human_approval with summary plus action { tool, arguments_sha256, scope_grant_id, policy_version }; verify_human_approval again immediately before dispatch; then seal the post-result record.
  7. Fail closed on missing approver, missing scope, args drift, missing result digest, or clock skew beyond your policy. Log the denial the same way you would log a success.

Why the five fields have to travel together

MCP tools guidance: clients SHOULD show tool inputs before calling the server, prompt for confirmation on sensitive operations, and log tool usage for audit. Showing and logging still leave a gap if the yes is stored without the result digest and a trusted timestamp — an auditor cannot tell which output the human authorized, or when.

Approve the call, then seal the result

request_human_approval before dispatch with the tool name and arguments_sha256 (and grant/scope ids) in the action object. Show the human the real arguments, not the model's summary.

What can go wrong?

Approval lives in chat ("looks good") with no args hash, so the agent changes targets after the yes.

How do I ask Rightshold about this (free, no key)?

Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “Before this tool runs, ask me to approve the exact tool name and argument hash under the current scope grant, then record a signed receipt that also hashes the tool result and the wall-clock time after it returns.”

One-click setup

{
  "tool": "request_human_approval",
  "arguments": {
    "summary": "Approve mcp-crm.contacts.update (args sha256:9f3a…) under grant grnt_… policy_version 14; seal result digest after the call",
    "action": {
      "type": "tool_call_with_scope",
      "tool": "contacts.update",
      "server": "mcp-crm",
      "arguments_sha256": "9f3a…",
      "grant_id": "grnt_…",
      "policy_version": 14,
      "scope": "crm:contacts:write"
    },
    "expires_in_minutes": 10
  }
}

Rightshold records human approval requests, signed decisions, and AI-run receipts for agents that call it. It does not sit in your MCP gateway, assign IdP identities, hash your tool results, or stop a runner that never verifies. Enforce the five-field seal and fail-closed checks in your gateway and tool runner. Not legal advice.

What are the sources?

Related

Not legal advice. JSON · Markdown · All answers

Get a free API key in one call

No card and no email needed. 100 free credits; the license and policy checks stay free without a key.

curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_...   # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
  -H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'