MCP Server
Last updated: September 13, 2026
BetterReviews is an MCP server (Model Context Protocol, Streamable HTTP transport, protocol version 2025-06-18). Instead of writing curl calls, an AI client gets a small set of tools over your store: search the review corpus, read a review, record and manage marketing claims, link supporting reviews, and ask a reviewer for permission to feature their review.
The server is stateless and plain JSON: every POST carries one JSON-RPC 2.0 message and gets one JSON response; a notification gets 202 with no body. There are no sessions, no server-sent events and no batching.
Two ways to connect
| Door | URL | Auth | Tools |
|---|---|---|---|
| Header | https://api.betterreviews.app/api/v1/mcp | X-API-Key header with a store API key | All eight (four need Read & Write) |
| Connector URL | https://api.betterreviews.app/api/v1/mcp/c/<token> | The URL itself (a 90-day connector token) | Read-only four |
Claude Code
claude mcp add --transport http betterreviews https://api.betterreviews.app/api/v1/mcp \
--header "X-API-Key: YOUR_API_KEY" Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"betterreviews": {
"type": "http",
"url": "https://api.betterreviews.app/api/v1/mcp",
"headers": { "X-API-Key": "YOUR_API_KEY" }
}
}
} claude.ai custom connector
claude.ai connectors cannot send headers, so you use a connector URL instead. Mint one with a Read & Write API key (201):
curl -X POST https://api.betterreviews.app/api/v1/mcp/connector-tokens \
-H "X-API-Key: YOUR_API_KEY" {
"id": "…",
"name": "mcp-connector",
"prefix": "ppo_AbCd",
"expires_at": "2026-12-12T10:00:00Z",
"url": "https://api.betterreviews.app/api/v1/mcp/c/ppo_…"
} Paste url as the connector URL in claude.ai. It is shown once. Then:
- Treat the URL as a password. Anyone who has it can read your reviews and claims until it expires or you revoke it.
- It is read-only: only
search_reviews,get_review,list_claimsandpermission_previeware available. Mutating tools are not listed and returnread_only_tokenif called. - It expires after 90 days; at most two are active per store (
422 too_many_connector_tokens). - It only works at its own URL. Presented as a header, Bearer token or query parameter anywhere on the REST API it is refused with
401. - Revoke it from Settings → Developer in the BetterReviews app (it appears as
mcp-connector) or withDELETE /api/v1/mcp/connector-tokens/:id. Revocation is immediate.
Managing connector tokens requires a Read & Write API key: POST mints, GET /api/v1/mcp/connector-tokens lists the active ones as {"data": [...]} (id, prefix, last used, expiry — never the URL), DELETE /:id revokes.
Tools
| Tool | Auth | Arguments | Returns |
|---|---|---|---|
search_reviews | either | query (required, ≤500 chars), product_id, min_rating 1–5, limit 1–50 | reviews[], total, has_more. Natural-language search over the corpus. Requires an active subscription (subscription_required otherwise). |
get_review | either | review_id | Rating, title, content, display name, status, stage, rights_status, tags, media count. Never the reviewer's email. |
list_claims | either | product_id, status, collect_enabled, include_archived, limit, offset | Same shape as GET /claims. |
permission_preview | either | review_id | {reachable, masked_email} — the full address never leaves the server. |
upsert_claim | header + write | Create: product_id, claim_text, topic, source (+ optional ask_phrasings, status, collect_enabled). Update: claim_id + fields. | {claim}. Same validation as the REST API (invalid_prompt_text, product_not_found, another_claim_active). |
set_claim_collection | header + write | claim_id, enabled | {claim}. One collect-enabled claim per product. |
link_reviews_to_claim | header + write | claim_id, reviews[] of {review_id, evidence_quote?, confidence?} (≤50) | {claim_id, reviews[], links_total} — the links written by this call plus the claim's total link count. |
request_review_permission | header + write | review_id, scope (text | photo | both, default both) | {permission_request_id, status}. Consent rules apply: unreachable, opted-out or suppressed reviewers are refused. |
The four header + write tools also require the key's Read & Write scope — a Read-only key sees them in tools/list but calling one returns insufficient_scope.
Claim and permission tools are entitlement-gated (claim_collection, rights_management) exactly like the equivalent REST operations; without the entitlement the tool returns entitlement_required. Current plans (Unlimited, Studio) include them. On legacy plans (no longer sold), they are available on Growth and above, and on legacy Pro and Enterprise; stores on the legacy Starter plan do not have them. A store with no active subscription — never subscribed, or cancelled — is in the free state and holds none of the gated entitlements.
Errors
Two layers, matching the MCP specification:
- JSON-RPC errors for protocol problems:
-32601unknown method,-32602unknown tool or invalid arguments (wrong type, over-long string, out-of-range number, too many items — checked before any tool runs),-32600for batch arrays or malformed requests,-32700for an empty body. - Tool results with
isError: truefor domain outcomes. The text content andstructuredContentcarry{"error": "snake_case_code"}using the same codes as the REST API:review_not_found,claim_not_found,claim_archived,product_not_found,another_claim_active,invalid_prompt_text,validation_error,missing_fields(with afieldsarray —upsert_claimcreate needsproduct_id,claim_text,topicandsource),invalid_search,entitlement_required,subscription_required,read_only_token,insufficient_scope(mutating tool with a Read-only key),immutable_fields(product_id/sourcecannot change on update),rate_limited,search_unavailable, and the permission-request outcomes (no_reachable_email,consent_blocked,suppressed,already_requested).
HTTP-level: 401 bad/expired/revoked key or token, 403 credential without a store, 413 body over 256 KB, 429 rate limited (120 requests/minute per store on each door; request_review_permission is additionally capped at 10/minute and 200/day per store and returns rate_limited as a tool result). GET returns 405; DELETE returns 204.
Workflow: does our corpus support this claim?
With the header door connected in Claude Code, a typical exchange is:
search_reviews— "keeps drinks hot for hours", filtered to the product.get_reviewon the promising hits to read the full text.upsert_claim— record the claim with a neutraltopicand exampleask_phrasings.link_reviews_to_claim— attach the supporting reviews with the quoted sentence and a confidence.- Not enough evidence?
set_claim_collectionso the AI review chat can ask happy customers about the topic. Enough?permission_preview+request_review_permissionbefore quoting a review in ads.
See the Claims API for field semantics and the API keys guide for creating and revoking keys.