Usero runs a remote Model Context Protocol server at https://usero.io/mcp. Point Claude Code,
Cursor, Claude Desktop, OpenCode or Codex at it and the agent can read your feedback inbox, pull the clusters with verbatim
quotes, file feedback, and ask Usero to open an AI-written pull request, all from inside your editor.
Nothing to install. One config block with the URL, plus an API key only on clients that need a static header. Fixes ship on our side. No account yet? The agent can sign you up itself, see the next section.
Set up from inside the agent
No account, no key, no dashboard visit. Pick your client:
Codex: codex mcp login starts the browser login.
Then send your agent this:
What happens next depends on the client.
OAuth clients (Claude Code, Cursor, Claude Desktop, OpenCode, Codex). The client registers itself with the server, you approve the connection in the browser (it names the permission: read and file feedback, open pull requests, nothing else), and the credential stays with the client. Nothing to paste, no key to store, and the agent skips the key-mint flow below. After you approve, the agent finishes setup itself: your product client plus the GitHub App install.
Key clients (older builds, anything needing a static header). Without a key the server exposes two tools, start_signup and
check_signup, and the agent runs this flow:
- The agent sends a one-button email to your address. Press it within 60 minutes. That signs you in, creating the account if the email is new.
- The agent collects its API key and finishes setup itself: your product client plus the GitHub App install.
An existing account signing in this way gets a new key and nothing else changes. Limits: 5 links per email per hour, 10 per IP per hour. Every other tool answers 401 until a key is sent.
Get an API key
- Sign in and open your profile.
- Under API keys, create a key. Name it after the tool that will use it ("Claude Code on my laptop").
- Copy it once. Keys look like
usk_live_...and are only shown at creation.
The key acts as you: the agent sees every client you are a member of and nothing else. Revoke it from the same page.
Connect your client
Same blocks with your key in the header. Replace usk_live_... with your key:
Claude Code: the single quotes matter, the shell leaves ${USERO_API_KEY} alone and the command stores it as written (check with
claude mcp get usero). Add --scope user for every project, verify with claude mcp list, then try
claude -p "list my usero clients". For a team config, commit .mcp.json instead (that is the only form Anthropic promises
expansion for):
Cursor: reload the window, Settings then MCP should show a green dot and a tool count.
Desktop, step by step: Settings → Connectors → Add custom connector, name it Usero, paste https://usero.io/mcp. Authentication →
Sign in now. OAuth client → Register automatically (not the Recommended published identity, the server does not support it yet).
Add: the browser opens, approve, click the email button, approve again. "Sign in when needed" also works but starts you keyless
with only the signup tools, which just routes you back here. No request headers needed, OAuth carries the credential. Restart
Desktop and ask again to prove the token refreshes.
Anything else
Any client that speaks MCP over streamable HTTP works. The server is stateless JSON-RPC 2.0 over POST, no session id, no SSE. A raw call looks like this:
Every tool is scoped to the clients your key can access. Read tools are marked read-only so clients that ask before running side
effects can skip the prompt. Argument schemas are strict: an unknown argument is an error, not a silent no-op. Date arguments
accept a full ISO datetime or a bare YYYY-MM-DD (read as midnight UTC).
| Tool | Arguments | What it returns |
|---|---|---|
start_signup |
email, clientName? |
No key needed. Emails a sign-in link naming the agent and replaces any earlier pending link for that address; returns pollToken and expiresInMinutes. 5 per email per hour, 10 per IP per hour. |
check_signup |
pollToken |
No key needed. pending until the user confirms on the emailed page, then ready with apiKey (minted at that moment) exactly once; the token is dead afterwards. Expired tokens return an error naming the fix. |
create_client |
name, repo? |
Creates a client (one per product) and returns its clientId and dashboard URL. repo only works if the GitHub App already reaches it; otherwise leave it out and use connect_github. |
connect_github |
clientId, repo? |
Returns the GitHub App install URL bound to the client. Once installed, repo picks which of the covered repositories PRs go to (single-repo installs are picked automatically). |
check_github |
clientId |
pending until the install lands, then connected with the chosen repo (or null) and every repos the installation covers. |
list_clients |
nameContains?, limit? (default 25, max 100), offset? |
A page of your clients, newest first, each with id, name, open feedback count, environment names (busiest first) and dashboard URL, plus totalCount, hasMore and nextOffset. Call this first. |
search_feedback |
clientId, environment?, query?, status? (open, resolved, all), source?, since? (created), resolvedSince? (resolved), sort? (newest, oldest, severity), hasScreenshot?, limit? (max 50) |
Feedback with AI summary, category, severity, verbatim quotes, sender, screenshot count, replay flag, resolvedAt and resolutionMessage, and dashboard URL. Defaults to open items, newest first. Comment bodies cut at 400 chars. |
get_feedback |
id |
One item in full: comment, quotes, person, screenshots, session replay link, clusters, pull requests, and linked tracker issues (issues: [{ tracker, identifier, url, status }]). |
list_clusters |
clientId, includeAddressed?, limit? (max 100) |
Feedback clusters biggest first with severity, urgency, AI summary, up to three sample verbatim quotes each, and PR state. Clusters span environments. |
get_cluster |
clusterId, memberLimit? (default 50, max 200) |
The cluster with its members (highest confidence first), each with quotes and sender, open and total member counts, plus its pull request if any. |
list_unanswered_board_posts |
clientId, minDaysSilent? (default 0), limit? (default 25, max 100) |
Public board posts with no official team reply and no status change since they were posted (merged and hidden posts excluded), most voted first then oldest, each with its public URL, votes and daysSilent. Also total, boardName, boardUrl and the reminder setting (enabled, days). |
create_feedback |
clientId, environment?, title, body, pageUrl?, userEmail? |
Files a feedback item with source mcp. It is classified and clustered like any other item. |
note_replay_moment |
clientId, sessionReplayId? or userTestSessionId? (exactly one), replayAtMs, title, description?, severity? (high, medium, low), pageUrl?, quote? |
Files a feedback item with source replay-note, pinned to a millisecond of a session replay or a human user test recording; the replay link on the item opens at that second and the quote is stored as evidence. Identity comes from the replay's person (or the tester for a user test). Classified and clustered like any other item. |
send_feedback_about_usero |
title, body, pageUrl?, userEmail? |
Files feedback about Usero itself into the Usero team inbox with source mcp. No clientId needed; any authenticated key may call it. It returns the id and creation time only, no dashboard link. Use this for Usero bugs and ideas, create_feedback for the caller's own product. |
connect_app_reviews |
clientId, appleAppId?, appleCountry? (default us), playPackageName? (at least one store id required) |
Connects App Store or Google Play review sync through the same path as the dashboard Integrations page, then returns at once while the import runs in the background; poll app_reviews_status for progress. Additive only, disconnect stays in the dashboard. Apple RSS blocks Workers egress, so prod Apple syncs often report a 403 in lastSyncError while Play imports land first. |
app_reviews_status |
clientId |
Read-only status of app review sync: connected config, per-store imported counts, lastSyncAt, lastSyncError and the sync phase with live per-store progress. |
intercom_status |
clientId |
Read-only status of the Intercom integration: status (connected, disconnected, never_connected), workspaceId, the saved filter (tagAllowlist, includeTickets, ticketTypeAllowlist), lastSyncedAt (wall clock of the last sync run), lastPolledAt (the incremental cursor: updated_at of the newest item ingested, not the run time), importedCount with importedTickets and importedConversations, a plain-language diagnosis of the latest run, and the last 5 syncRuns (fetched, matched, new, duplicate, error). Never returns tokens. |
sync_intercom |
clientId |
Queues an Intercom sync now through the same background path as the dashboard's Sync now, then returns queued: true at once; poll intercom_status for the new run and counts. Errors when Intercom is not connected; connecting (OAuth) stays in the dashboard Integrations page. |
get_pr_status |
feedbackId |
Whether an AI pull request exists for the item, its status, URL and progress. |
request_ai_pr |
feedbackId, guidance? |
Usero's agent writes and opens a pull request server-side on the client's connected GitHub repo; the caller needs no local checkout. Returns a prId. Counts against the plan's monthly PR allowance. |
create_issue |
feedbackId, title?, body?, tracker? (github, linear; default is the client's selected tracker) |
Creates a GitHub or Linear issue from a feedback item through the same path as the dashboard's "Create issue" button and links it. Title and body default to the dashboard draft (comment, page, severity, link back). Returns the identifier (#123 or ENG-12), URL and tracker; a feedback item that already has an issue on that tracker comes back with alreadyLinked: true. Needs GitHub or Linear connected; the error names the connected trackers otherwise. |
list_forms |
clientId |
Hosted forms and surveys with response counts and public URLs. |
list_form_responses |
clientId, formId, page?, limit? (max 50) |
Responses to one form, newest first, with every answer. |
get_form |
formId |
One form in full: fields with ids, types and options, settings, published state, response count, public URL, embed URL, builder URL. |
create_form |
clientId, title, description?, fields, settings?, published? |
Creates a form or survey and returns it with its public URL, live immediately. fields is a typed list (see below); settings.surveyMetric scores it as NPS, CSAT or CES. |
update_form |
formId, title?, description?, fields?, settings?, published? |
Edits a form. Only passed arguments change; fields replaces the whole list (keep ids from get_form), settings merges. published: false closes it without losing responses. |
delete_form |
formId |
Deletes a form and every response to it. Irreversible; announced as destructive so clients ask first. |
get_form_theme_options |
formId? |
Read-only reference pack for theming: the appearance schema, every preset as a full object, the texture library, layouts, font pairings, contrast rules and three worked briefs. With formId, that form's current appearance too. |
preview_form_theme |
formId, appearance (full object or { preset }) |
Validates the theme, runs the contrast gate and returns a signed one-hour previewUrl that renders the form with it. Nothing is saved; the preview page cannot be submitted. ok is false when a row blocks saving. |
get_form_analytics |
clientId, formId |
Aggregate funnel for one form: sessions (unique visitors), views (page loads), submit attempts and successes, completion rate, average session duration, per-field completions and response count. Use list_form_responses for individual answers. Events capped at the most recent 10,000 (truncated says when hit). |
import_github_issue |
clientId, issueUrl |
Imports a GitHub issue as a feedback item (title as comment, body and labels in metadata) that appears in inbox search and clusters. Use only for a GitHub issue URL; use create_feedback for pasted text. The URL must belong to the client's connected repo; repeats return the existing item with alreadyImported: true. Needs GitHub connected. |
list_ai_user_test_runs |
clientId, environment? (default environment when omitted), limit? (default 20, max 50) |
AI user test runs newest first with verdict (clean is the only pass), summary, finding counts and schedule flag. Read-only; starting runs and scheduling stay in the dashboard. |
get_ai_user_test_run |
clientId, runId, includeSteps? (default false) |
One AI user test run with verdict (clean means no issues found), summary, whether on a schedule, and every finding (severity, category, what happened, timestamp to jump to in the replay); the step trace only when includeSteps is true. Starting runs and scheduling stay in the dashboard. |
create_user_test |
clientId, name, targetUrl, tasks (1 to 20 prompts), introMessage?, rewardDollars?, rewardCurrency?, minDurationSeconds? (default 30) |
Creates a human user test and returns it with the participant shareUrl (/ut/<slug>), live immediately. Omit rewardDollars for an unpaid test. |
list_user_tests |
clientId, limit? (default 20, max 50) |
Tests newest first with share URL, reward, task count, session counts by status and the readyToPayCount awaiting payout. |
get_user_test |
clientId, testId |
One test in full: tasks in order, session counts, plus the 20 most recent sessions with status, payment state, quality flag and duration. |
list_user_test_sessions |
clientId, testId, status?, paymentStatus?, limit? (default 20, max 50) |
Sessions newest first with tester, status, payment state, quality flag, duration, audio flag, completed-task and note counts, and auto-release deadline. |
get_user_test_session |
clientId, sessionId |
One session in full: tester, payment and payout details, per-task completions, notes with timestamps, first 2000 chars of transcript, findings list (each with verbatim quote, replayAtMs and the inbox feedbackId it was filed as), replay id plus the audio offsetMs (never audio bytes), muted segments, end note. Needs only sessionId, no testId. |
update_user_test |
clientId, testId, name?, targetUrl?, introMessage?, tasks? (1 to 20 prompts), rewardDollars?, rewardCurrency?, minDurationSeconds? |
Edits a test. Only passed arguments change; tasks replaces the whole list (refused once the test has sessions, to protect completion history). introMessage: "" clears it, rewardDollars: "" makes the test unpaid. |
delete_user_test |
clientId, testId |
Deletes a test and its tasks; the share link stops resolving. Irreversible; announced as destructive so clients ask first. Refused when the test has any sessions, keeping session history. |
release_payment |
clientId, sessionId |
Confirm with the user first, naming the tester and reward. Marks a ready_to_pay session paid and returns the new status with paidAt. Anything else returns an error naming the current status. This only marks paid, actual money movement happens off-platform. |
The environment argument takes the environment name you send from the widget. Omit it to search every environment. Use the
literal no-env for feedback that was sent without one.
Build a form from the agent
create_form takes the questions as a typed list, so an agent can build a survey from a sentence without reading any source. Each
field is an object with a type and the options that type supports:
type |
Extra arguments | Answer stored as |
|---|---|---|
text, textarea, email |
placeholder? |
string |
number |
placeholder?, min?, max? |
number |
select, radio |
options (1 to 50 strings) |
the chosen option text |
multiselect, checkbox |
options (1 to 50 strings) |
array of option texts |
rating |
max? (stars, default 5) |
integer 1 to max |
scale |
min? (default 1), max? (default 5), minLabel?, maxLabel? |
integer min to max |
Every field also takes label (required), description? (help text), required? (default false), id? and condition?. Ids
are the keys answers are stored under; omit them and they are generated from the label. A condition
({ fieldId, operator, value? }, operators equals, not_equals, contains, not_empty) shows the field only when an earlier
field's answer matches.
settings is optional: surveyMetric (nps needs a scale 0 to 10, csat a rating, ces a scale 1 to 7; turns on the score
panel and mirrors responses into the feedback inbox), routeResponsesToInbox, themeColor, successMessage, submitButtonText,
notifyOnSubmission, and appearance, the brand theme of the public page. Pass a preset,
{ "preset": "minimal" | "dark-slate" | "warm-editorial" | "clean-saas" | "high-contrast" }, and the server stores the expanded
theme; get_form returns it in full (colorMode, background, surface, colors, typography, motion, optional https
logoUrl) so an agent can change one key and send the object back through update_form. appearance: null returns the form to
the plain themeColor rendering. A theme whose text contrast fails is refused on a published form; unpublish first or fix the
colors.
Ask the agent for "an NPS survey with a follow-up question" and it calls:
The result carries publicUrl (https://usero.io/f/<slug>, live at once), embedUrl for an iframe, and builderUrl for the
dashboard. To change it later the agent calls get_form, edits the field list and sends it back whole with update_form, reusing
the ids so responses already collected stay attached to their questions. update_form with published: false pauses collection;
delete_form removes the form and its responses for good. The same field shape is accepted by the
REST forms API.
Theme a form from a brief
Ask for "make the signup survey feel like a warm print newsletter" and the agent works in three steps, none of which needs the dashboard:
get_form_theme_options(once per session, optionally with theformId) returns everything the theme can be built from: the appearance schema with its enums and ranges, the six presets as complete objects, twenty Usero-authored page textures with a one-line blurb and strength range each, the three layouts (card,hero,focused), six font pairings, the contrast rules, and three worked briefs already turned into appearance objects.- The agent composes an appearance (usually a preset or example with a few keys changed) and calls
preview_form_theme. The response carries the contrast report and apreviewUrlof the formhttps://usero.io/f/<slug>?preview=<token>. The token is an HMAC-signed copy of the theme, valid for one hour and bound to that form; opening it renders the real form with the candidate theme, a "Preview, not saved" strip,noindex, and a disabled submit button. Nothing is written and no response can be filed through it. Expired or altered links show a friendly expiry page, never the stored theme. - When the user likes it,
update_formwithsettings: { appearance }saves it. A published form refuses a theme with a blocking contrast row (below 3:1 on body, input, error, button, or page text for the hero and focused layouts), so the agent fixes those from the report before saving. Embeds (?embed=1) always render the card layout on a transparent page, so the texture and layout only show on the hosted page.
Resources
Two resource templates let an agent pin data into its context without a tool call:
usero://clients/{clientId}/clusters: the open clusters for a client, same JSON aslist_clusters.usero://feedback/{id}: one feedback item, same JSON asget_feedback.
Prompts
Three prompt templates. Each takes an optional clientId; when omitted and your key has exactly one client, that client is used,
otherwise the prompt tells the agent to pick one via list_clients:
triage_inbox: read the open feedback, group it into themes with verbatim quotes, recommend what to fix first.fix_top_complaint: pick the biggest concrete cluster, find the cause in the current repo, fix it or callrequest_ai_pr.write_changelog_from_feedback: turn the last two weeks of resolved feedback into a short user-facing changelog entry.
In Claude Code they appear as /usero:triage_inbox and so on once the server is added.
What agents can and cannot do
Can: sign you up and mint their own key; create clients and connect GitHub to them; read every feedback item, cluster, form and response for your clients; file new feedback; connect App Store and Google Play review sync and read its status; read Intercom sync status and queue an Intercom sync; build, edit, close and delete hosted forms and surveys; read form analytics and AI user test runs with findings; import a GitHub issue as feedback; create a GitHub or Linear issue from a feedback item; run paid human user tests (create, edit and delete tests, review sessions, release payment); request an AI pull request on a client that has GitHub connected.
Cannot: resolve or delete feedback, change client settings, connect integrations other than GitHub and app reviews (Intercom connects in the dashboard, the agent can only sync it), invite members, touch billing, or see clients you are not a member of. Those stay in the dashboard on purpose. If your workflow needs one of them from an agent, tell us through the contact page.
Rate limits and caps
| Limit | Value | What happens past it |
|---|---|---|
| Tool calls | 120 per API key per minute | The tool returns an error naming the seconds to wait. |
start_signup |
5 per email and 10 per IP, hourly | The tool returns an error; check the inbox for an earlier link. |
| AI pull requests overall | your plan's monthly allowance | Same as the dashboard and REST API; the error names the plan. |
search_feedback results |
50 per call | Narrow with query, since, resolvedSince or environment. |
get_cluster members |
50 by default, 200 max | membersTruncated is true and memberCount has the full size. |
Troubleshooting
HTTP 401 on every call. The Authorization header is missing or the key is wrong. It must read exactly Bearer usk_live_....
Keys are shown once at creation; if you lost it, create a new one on your profile, or remove the header and let the
agent call start_signup for a fresh one.
check_signup says the token is unknown or expired. Links and poll tokens last 15 minutes from start_signup, and sending a
new link expires the previous one. Ask the agent to call start_signup again and open the newest email.
HTTP 406 from curl. The transport requires Accept: application/json, text/event-stream on every POST (both types, in one
header). Copy the curl example above.
list_clients returns an empty list. The key is valid but its user is not a member of any client. Sign in to the dashboard
with the same account and check you can see the client there. Keys from a teammate's account see the teammate's clients, not
yours.
A tool says "Client ... not found". Either the id is mistyped (ids start with client_) or the key's user is not a member of
that client. The same message covers both so ids cannot be probed.
request_ai_pr says GitHub is not connected. Connect the repo on the client's Integrations page (the error includes the
link), then call again. The PR is opened by the Usero GitHub App, not by your agent's credentials.
Claude Code shows the server but no tools. Run claude mcp list and check the transport is http, not sse. Remove and
re-add with --transport http if needed.
Cursor shows a red dot. Cursor reads .cursor/mcp.json on startup. Reload the window after editing it, and make sure the file
is valid JSON (a trailing comma is the usual culprit).
Responses are slow the first time. The first call after a quiet period warms the Worker and the database. Later calls in the same minute are fast.
Privacy and security
The MCP server is the same Worker and database as the dashboard. Only the SHA-256 hash of your key and its first 12 characters are stored; each request's key is hashed and matched against that, never written. The server makes no LLM calls of its own: it is a deterministic interface over your data, and the agent on your side does the thinking.
FAQ
OAuth or API key? Claude Code, Cursor, Claude Desktop, OpenCode and Codex connect with OAuth: the client registers itself (dynamic client registration, no client ID to configure), you approve in the browser, and the tokens expire. There is nothing to paste and no secret lands in chat transcripts or config files. Older builds that still need a static header use API keys instead: create them one at a time on your profile, make one per client, name it after the machine, and revoke exactly that one when the machine goes. Usero stores the SHA-256 hash of the key plus its first 12 characters for display. On each request the key in the header is hashed and matched against that hash; the raw key is never written anywhere. Either credential acts as you, so the agent sees the clients you are a member of and nothing more.
I signed up through the agent. How do I sign in to the dashboard? The browser tab where you pressed "Yes, connect" is already signed in, so open usero.io there. From any other browser or device, the account has no password yet (the agent flow never asked for one): use Forgot password with the same email to set one, then sign in as normal. Accounts created through the OAuth browser flow already have a password and sign in normally.
How much of my context does this use? Measured against the live server on 2026-09-05 with cl100k tokenisation, so treat the
numbers as approximate: about 300 tokens in Claude Code, about 3,200 in Cursor or Claude Desktop. Claude Code 2.1 defers MCP tool
definitions and loads only the tool names and the server instructions at session start
(tool search), which for the 13 tools an authenticated key sees
is 43 tokens of names plus 252 of instructions. Clients that load every schema up front take the whole tools/list response,
2,957 tokens of JSON, plus the instructions.
What does a real session look like? A full claude -p transcript against the live Usero inbox, every tool call included, is
in the blog post.
Changelog
| Date | Change |
|---|---|
| 2026-09-18 | v1.15.0: Intercom from the agent. intercom_status reads connection status, workspace id, the saved tag and ticket filter, lastSyncedAt (run wall clock) and lastPolledAt (newest item cursor), imported conversation and ticket counts, a plain-language diagnosis and the last 5 sync runs; sync_intercom queues a sync through the dashboard's Sync now path and returns at once. Connecting stays in the dashboard. Server instructions gain an Intercom line. |
| 2026-09-17 | v1.14.0: list_unanswered_board_posts lists public board posts still waiting on a team reply (no official comment, no status change), most voted first, with public URLs, days silent and the client's reply-reminder setting. Server instructions gain a Board line. |
| 2026-09-12 | v1.13.0: create_issue opens a GitHub or Linear issue from a feedback item through the dashboard's create path and links it (alreadyLinked: true when one exists on that tracker); get_feedback now lists linked tracker issues under issues. |
| 2026-09-12 | v1.12.0: note_replay_moment files a feedback item pinned to a moment of a session replay or a human user test recording (source replay-note). Same helper as the dashboard's "Note this moment"; the item's replay link opens at that second. |
| 2026-09-09 | v1.11.0: app review sync from the agent. connect_app_reviews saves the store config and queues a background sync through the same path as the dashboard (additive only, disconnect stays dashboard-only); app_reviews_status reads the connected config, per-store imported counts, last sync time and error, and the sync phase. Apple RSS blocks Workers egress, so prod Apple syncs often report a 403 while Play imports land first. |
| 2026-09-09 | v1.10.0: onboarding surface slimmed. Server instructions are a one-line-per-workflow router with the no-key bootstrap first; start_signup names check_signup and the two-click confirm, check_signup names key saving and create_client, connect_github names the check_github call, and the check_signup key-saving steps are client-neutral with a pointer to the per-client setup docs. |
| 2026-09-09 | v1.9.0: send_feedback_about_usero files feedback about Usero itself into the Usero team inbox. No clientId needed, any authenticated key may call it, and it returns no dashboard link. create_feedback stays scoped to the caller's own product inbox. |
| 2026-09-07 | v1.8.0: full user-test lifecycle from the agent. update_user_test edits a test (partial patch, tasks replaced whole and refused once sessions exist so completion history survives); delete_user_test removes a session-less test and its tasks (destructive, refused when sessions exist). |
| 2026-09-06 | v1.7.0: REST parity plus AI test reads. get_form_analytics returns sessions, views, completion rate and per-field completions for one form; import_github_issue files a GitHub issue as feedback (same-repo guard, idempotent on repeats); list_ai_user_test_runs and get_ai_user_test_run review runs with verdicts and findings (starting runs and scheduling stay dashboard-only). |
| 2026-09-06 | v1.6.0: run paid human user tests from the agent. create_user_test returns the participant share link (/ut/<slug>); list_user_tests and get_user_test review tests with session states and counts; list_user_test_sessions and get_user_test_session review sessions (transcript excerpt, replay pointer, findings, quality flags, no audio bytes); release_payment marks a ready_to_pay session paid with the same guard as the dashboard, confirm with the user first. |
| 2026-09-05 | v1.5.0: theme a form from a brief. get_form_theme_options returns the appearance schema, presets, textures, layouts, pairings, contrast rules and worked examples; preview_form_theme validates a theme and returns a signed one-hour preview URL (/f/<slug>?preview=<token>, HMAC-SHA256, no database write, submissions disabled). update_form stays the only write. |
| 2026-09-05 | v1.4.0: create_form and update_form accept settings.appearance (a preset name or the full theme, null to clear); get_form returns it. The contrast gate that guards publishing in the dashboard applies to MCP edits too. |
| 2026-09-05 | Signup email redesigned around one button; start_signup returns emailSentTo and emailSubject, check_signup pending says which inbox to check, and ready leads with the USERO_API_KEY form of claude mcp add, removes an existing usero server only when one is configured, and returns docsUrl. |
| 2026-09-05 | v1.3.0: build forms from the agent. create_form (typed field list, survey scoring via settings.surveyMetric), get_form, update_form (partial patch, fields replaced whole, settings merged) and delete_form (announced destructive). The REST forms API now also accepts fields and settings as JSON, not only as JSON strings. |
| 2026-09-04 | v1.2.1: the emailed link opens a confirm page with a button; opening the page alone no longer signs anyone in, and the key is minted only when check_signup collects it. A new start_signup replaces any earlier pending link for that address. list_clients pages (limit, offset, nameContains) and returns totalCount and hasMore; per-client feedbackCount, githubRepo and createdAt dropped. |
| 2026-09-04 | v1.2.0: sign up from inside the agent. start_signup and check_signup work with no API key (emailed confirm page, key minted when the agent collects it, once). create_client, connect_github and check_github finish setup. Server instructions lead with the no-key path. |
| 2026-09-04 | v1.1.0: create_pr renamed request_ai_pr. search_feedback gains resolvedSince, sort, hasScreenshot, screenshotCount, resolvedAt, resolutionMessage and 400-char bodies. list_clusters gains sampleQuotes. get_cluster gains memberLimit (default 50). list_clients gains openFeedbackCount and dashboardUrl. Strict argument schemas, server instructions. |
| 2026-09-04 | v1.0.0: server launched with 10 tools, 2 resources, 3 prompts. API key auth, 120 calls/min, create_pr capped at 5 per key per day. |
Tools are never removed inside 90 days of being announced. A tool on its way out gets "deprecated" in its description first.
create_pr was renamed before launch, so no deprecation window applies.