# agentfabric.dev > Human-in-the-loop review and approval layer for AI agents. Agents send generated > output (URLs, images, PDFs, text, HTML) to human reviewers, enforce approval > policies, and receive a full audit trail. Integrate over MCP (recommended for > agents) or REST. agentfabric.dev is designed to be consumed by AI agents. The fastest integration is the Model Context Protocol (MCP) server, which exposes human review as a set of tools. Humans are not required for signup — only for reviewing content. ## Connect over MCP (recommended for agents) MCP endpoint: https://mcp.agentfabric.dev Transport: Streamable HTTP only (not legacy SSE). Example MCP client configuration: ```json { "mcpServers": { "agentfabric": { "url": "https://mcp.agentfabric.dev", "type": "http" // Optional: call create_tenant (no auth) to get an API key, // then reconnect with it to authenticate other requests: // "headers": { "x-api-key": "ak_your_api_key" } } } } ``` OpenClaw: set `"transport": "streamable-http"` in `mcp.servers` (not `mcpServers`). ### Auth / tool scopes Pass your API key as the `x-api-key` header on MCP requests: - No API key: only `create_tenant` - Consumer API key: review tools only; tenant is already set up - Admin API key: review + user/API-key management tools (not `create_tenant`) When `x-api-key` is set, do not pass `api_key` in tool arguments. ### Agent flow 1. Connect without a key and call `create_tenant` (`tenantName`, `ownerEmail`, `password` min 8, optional `ownerName`). 2. Save `adminApiKey` and `consumerApiKey` from the response. 3. Reconnect with `x-api-key` set to the consumer key (prefer consumer for day-to-day work). 4. Call `create_review_request`, then poll `get_review_request` until status leaves `pending`. ### Available MCP tools Onboarding (no auth): - create_tenant — create a tenant; returns admin + consumer API keys Consumer+: - create_review_request — send content to human reviewers; optional subscribers get verdict emails - get_review_request — poll full state + outcome - list_review_requests — list requests (optional external_id) - list_review_items — list items by external_id (required; newest first) - get_review_comments — list comments (optional item_id, status open|resolved) - resolve_review_comment / unresolve_review_comment - cancel_review_request - add_reviewer — email + optional name - remind_reviewers — pending reviewers only; optional emails filter Admin: - create_user / list_users - create_api_key / list_api_keys Tool results are the REST `data` payload for the matching endpoint. ## Connect over REST Base URL: https://rest.agentfabric.dev Auth: `x-api-key: ak_…` or `Authorization: Bearer ak_…` (or Cognito bearer / `x-access-token` for dashboard users). Success: `{ "data": … }` · Error: `{ "errors": [{ "title", "path?" }] }` ### Core endpoints - POST /v1/signup — create tenant; returns adminApiKey + consumerApiKey - GET /v1/me — current principal + role - POST /v1/review-requests — create review request - GET /v1/review-requests — list (?filter[externalId]=); includes outcome - GET /v1/review-requests/{id} — detail: request, items, reviewers, comments, events, outcome - GET /v1/review-items?filter[externalId]=… — items across requests (filter required) - GET /v1/review-requests/{id}/comments — optional ?itemId= & ?status=open|resolved - POST /v1/review-requests/{id}/comments/{commentId}/resolve|unresolve - POST /v1/review-requests/{id}/reviewers — { reviewers: [{ email, name? }] } · 409 duplicate - POST /v1/review-requests/{id}/remind — optional { emails } · 410 if cancelled/expired - POST /v1/review-requests/{id}/cancel Admin: /v1/users, /v1/api-keys (+ revoke/rotate). Rotate issues a new admin key. Reviewer app (usually not called by agents): POST /v1/review/exchange, GET/POST /v1/review/{id}/… ## Resources (JSON shapes) Tenant: `{ tenantId, name, ownerEmail, ownerName?, status: active|suspended, createdAt, updatedAt }` AppUser: `{ tenantId, userId, email, name?, role: admin|consumer, cognitoSub, status: active|disabled, createdAt, updatedAt }` ApiKeyRecord: `{ tenantId, keyId, label, scope: admin|consumer, status: active|revoked, createdAt, lastUsedAt? }` — plaintext `ak_…` only on create/signup/rotate Document: `{ type: url|image|pdf|text|html, url?, title?, content?, metadata? }` Policy: `{ type: ALL_APPROVE|ANY_APPROVE|ANY_REJECT|QUORUM, quorum?, rejectionThreshold?, decisionScope?: request|item }` ReviewRequest: `{ tenantId, requestId, title, description?, policy, status, subscribers[], externalId?, metadata?, createdAt, updatedAt }` ReviewItem: `{ itemId, title, document, status, order, externalId?, metadata? }` Reviewer: `{ reviewerId, email, name?, decision, authCodeExpiresAt, openedAt?, decidedAt? }` ReviewItemDecision: `{ requestId, tenantId, itemId, reviewerId, decision, decidedAt }` ReviewComment: `{ commentId, requestId, tenantId, itemId?, reviewerId?, authorEmail?, body, status: open|resolved, createdAt, resolvedAt?, resolvedBy?, metadata? }` AuditEvent: `{ eventId, tenantId, requestId, itemId?, reviewerId?, type, createdAt, metadata? }` Outcome: `{ status, summary, tally: { approved, rejected, changes_required, pending } }` (+ `evaluationScope`, optional `itemOutcomes`) ## Create review request ```json { "title": "Approve landing page", "description": "optional", "externalId": "landing-page-v2", "policy": { "type": "ALL_APPROVE", "decisionScope": "request" }, "reviewers": [{ "email": "reviewer@example.com", "name": "Alex" }], "subscribers": ["ops@example.com"], "items": [{ "title": "Preview", "externalId": "preview-asset-1", "document": { "type": "url", "url": "https://example.com/page" }, "metadata": { "branch": "main" } }], "metadata": { "env": "staging" } } ``` Create response `data`: `{ request, items, reviewers, next_actions }`. Get response `data`: `{ request, items, reviewers, itemDecisions, comments, events, outcome, evaluationScope, itemOutcomes? }`. externalId: `/^[A-Za-z0-9._:-]+$/`, 1–128 chars; reusable; list newest first. metadata: opaque; stored/returned; not searchable. subscribers: notified on approved | rejected | changes_required only (set at create). ## Approval policies ```json { "type": "ALL_APPROVE" | "ANY_APPROVE" | "ANY_REJECT" | "QUORUM", "quorum": 2, "rejectionThreshold": 1, "decisionScope": "request" | "item" } ``` - ALL_APPROVE — every reviewer must approve; any rejection rejects - ANY_APPROVE — first approval wins - ANY_REJECT — first rejection wins - QUORUM — approvals ≥ quorum (default: reviewer count); impossible quorum → rejected - rejectionThreshold — optional early reject after N rejections (all types) - decisionScope — `request` (default) or `item` (per-item then rollup) List/detail include `outcome`: `{ status, summary, tally }`. Item scope tallies items. ## Statuses Request/item: pending | approved | rejected | changes_required | cancelled | expired Comment: open | resolved Reviewer decision: pending | approved | rejected | changes_required ## Key facts - Agents self-signup via create_tenant (MCP) or POST /v1/signup (REST). No human onboarding. - Prefer consumer API keys for agents; admin for tenant management. - Human reviewers do NOT need an account; they use a personal emailed link (auth code rrc_…). - Reviewer auth codes are not returned on create in production. - Every comment, approval, and rejection is recorded in an audit trail. ## Links - Docs: https://agentfabric.dev/docs/ - Concepts: https://agentfabric.dev/docs/concepts/ - MCP guide: https://agentfabric.dev/docs/mcp/ - REST reference: https://agentfabric.dev/docs/rest/ - Sign up: https://agentfabric.dev/signup/ - MCP: https://mcp.agentfabric.dev - REST: https://rest.agentfabric.dev