check_request
check_request is the status half of the request lane. Give it a request_id and it tells you where the request stands, how a steward resolved it, and — when an exception was granted — the exception_id to cite on a retry.
It is an operationally pure read: it records nothing, and it requires only the read scope. Protocol alias: check-request.
Subject-verifiedDirect link to Subject-verified
A token sees only its own requests. A request belonging to another token, another workspace, or nothing at all is asset_not_found — all three are indistinguishable, so the tool cannot be used to probe what other agents have asked for.
This is also why the tool needs only read: a token that never held the request scope simply owns no requests, so it fails safe to not-found rather than needing the write scope to be told "no".
Because the subject is a specific token id, a rotated token cannot see its predecessor's requests. Resolve or re-file after a rotation.
InputDirect link to Input
| Field | Type | Required | Description |
|---|---|---|---|
request_id | string (UUID) | Yes | The request_id returned by request_access. |
Strict — unknown keys are rejected.
OutputDirect link to Output
A single object (no state discriminator — this is a status read, not a decision):
| Field | Description |
|---|---|
request_id | Echo. |
status | open, resolved, withdrawn, or expired. Derived at read time — see below. |
eligibility | exception_grantable or not_waiverable, as derived when the request was filed. |
resolution_kind | exception_granted, denied, policy_change_required, or null while open. |
exception | {exception_id, expires_at, state} when an exception was granted; null otherwise. |
asset | The canonical db.schema.table[.column] key. |
scenario_key | The scenario, or null. |
purpose_category | The purpose category recorded on the cited authorization, or null. |
created_at | When the request was filed. |
resolved_at | When it was resolved, or null. |
request_expires_at | The request's own 30-day expiry. Distinct from the exception's expiry. |
Never returned: the request note, the steward's resolution note, and the steward's identity. Notes exist only in a protected admin/owner store, and no MCP surface echoes them.
Statuses are derived at read timeDirect link to Statuses are derived at read time
An open request past its request_expires_at reports expired, whether or not a background sweep has stamped the row yet. You always get the truth, not a stale stored value.
Exception state is derived at read time tooDirect link to Exception state is derived at read time too
When resolution_kind is exception_granted, exception.state is one of:
| State | Meaning |
|---|---|
active | Live and consumable right now. |
expired | Past its expires_at. A retry citing it will not verify. |
revoked | A steward revoked it. Immediate and terminal; there is no un-revoke. |
This is read from the live exception row, never from an assumption stored at grant time.
Two expiries, do not confuse themDirect link to Two expiries, do not confuse them
| Expiry | Field | Set by | Default |
|---|---|---|---|
| The request expiry | request_expires_at | Server, at creation | 30 days, not configurable |
| The exception expiry | exception.expires_at | The steward, at grant | 30 days by default in the app, 90 days maximum |
A request can expire while unattended; an exception expires after it was granted. They are independent.
Consuming a granted exceptionDirect link to Consuming a granted exception
A granted exception is consumable. Retry the original authorize_use call with:
"satisfied_conditions": [{ "kind": "approval", "exception_id": "<exception_id>" }]
The server verifies it in SQL before anything is satisfied: subject must be the calling token, it must be live, and its asset, scenario, and purpose scope must match. Gate your automation on the retry's can_proceed_now, never on the mere presence of an exception_id here.
Two resolutions produce no exception at all, by design:
denied— terminal. Re-filing later is allowed; published state may legitimately have changed.policy_change_required— the remedy is authoring and republishing. Retryauthorize_useafter the next publication. It is a first-class outcome rather than a dead end, and it is the constructive resolution available for answers a waiver can never fix: conflicted published state, missing or unresolved coverage, and hard denies. (A steward may still choosedeniedfor any of those instead.)
ExampleDirect link to Example
{ "request_id": "b1d4c0a7-5e88-4d21-8a0e-3c6b9f2e1d55" }
While a steward has not looked at it yet:
{
"request_id": "b1d4c0a7-5e88-4d21-8a0e-3c6b9f2e1d55",
"status": "open",
"eligibility": "exception_grantable",
"resolution_kind": null,
"exception": null,
"asset": "master.public.customers",
"scenario_key": "residency.cross_border_transfer",
"purpose_category": null,
"created_at": "2026-07-29T10:20:00.000Z",
"resolved_at": null,
"request_expires_at": "2026-08-28T10:20:00.000Z"
}
After a grant:
{
"request_id": "b1d4c0a7-5e88-4d21-8a0e-3c6b9f2e1d55",
"status": "resolved",
"eligibility": "exception_grantable",
"resolution_kind": "exception_granted",
"exception": {
"exception_id": "0b7a9e2c-6c1f-4f5f-9f2e-2a2d0c9f4a11",
"expires_at": "2026-08-28T12:00:00.000Z",
"state": "active"
},
"asset": "master.public.customers",
"scenario_key": "residency.cross_border_transfer",
"purpose_category": null,
"created_at": "2026-07-29T10:20:00.000Z",
"resolved_at": "2026-07-29T12:00:00.000Z",
"request_expires_at": "2026-08-28T10:20:00.000Z"
}
After a revocation, the same call returns the same shape with exception.state: "revoked" — and a retry citing that id answers not_verified.
Polling guidanceDirect link to Polling guidance
A request is a human review, so poll on a human timescale — minutes, not seconds. Every call consumes one metered MCP call. Terminal states (resolved, withdrawn, expired) never change again, so stop polling once you reach one; the only state worth re-reading after that is a granted exception's state, which can move from active to expired or revoked.
ErrorsDirect link to Errors
| Code | When |
|---|---|
asset_not_found | The request does not resolve for this token — unknown, foreign-workspace, and foreign-token cases are indistinguishable. |
invalid_parameters | A non-UUID request_id or an unknown key. Not metered. |
RelatedDirect link to Related
request_access— filing the requestauthorize_use— retrying with the granted exception- Review requests in the app — how a steward resolves one
- MCP tool schemas — full input/output schemas