# Claude Code, Cursor and MCP

Usero runs a remote [Model Context Protocol](https://modelcontextprotocol.io) server at `https://usero.io/mcp`. Point Claude Code,
Cursor, Claude Desktop, Windsurf or VS Code 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 and your API key. 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

You do not need a Usero account, an API key or a dashboard visit to start. Add the server without a key and ask the agent to set
you up:

```bash
claude mcp add --transport http usero https://usero.io/mcp
claude -p "set me up with usero, my email is you@example.com"
```

Without a key the server exposes two tools, `start_signup` and `check_signup`, and the agent runs this flow:

1. `start_signup(email, clientName)` emails you a sign-in link and returns a poll token. The email names the agent that asked
   ("Claude Code", "Cursor", or "an MCP client" for anything we do not recognise) and the IP it came from. Any earlier link for
   the same address stops working the moment a new one is sent.
2. You open the link. The page repeats who asked, from where, and for which account, and has one button, "Yes, connect Claude
   Code", plus "This was not me". Opening the page does nothing on its own (link scanners open emailed URLs); pressing the button
   signs you in, creating the account if the email is new. The page never shows a key.
3. The agent polls `check_signup(pollToken)`. After you press the button it receives an API key named after the agent, minted at
   that moment and exactly once. The poll token is dead after that, and both the link and the token expire 15 minutes after
   `start_signup`. No key exists until the agent collects it, so an unpolled confirmation leaves nothing behind.
4. The agent saves the key into its MCP config (for Claude Code, `claude mcp remove usero` then `claude mcp add` with the
   `--header` from the next section, since Claude Code will not overwrite a server name in place) and, now authenticated, calls
   `create_client(name, repo?)` for your product and `connect_github(clientId)` for the GitHub App install URL, then
   `check_github(clientId)` until the install lands.

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

1. Sign in and open [your profile](/profile).
2. Under API keys, create a key. Name it after the tool that will use it ("Claude Code on my laptop").
3. 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

Replace `usk_live_...` with your key in each snippet.

### Claude Code

```bash
claude mcp add --transport http usero https://usero.io/mcp --header "Authorization: Bearer usk_live_..."
```

Add `--scope user` to make it available in every project, or `--scope project` to commit a `.mcp.json` for your team (put the key
in an environment variable in that case, not in the file). Check it with `claude mcp list`, then try
`claude -p "list my usero clients"`.

### Cursor

Create or edit `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` for every project):

```json
{
	"mcpServers": {
		"usero": {
			"url": "https://usero.io/mcp",
			"headers": {
				"Authorization": "Bearer usk_live_..."
			}
		}
	}
}
```

Open Cursor Settings, then MCP, and confirm "usero" shows its tools.

### Claude Desktop

Settings, then Connectors, then Add custom connector. Enter `https://usero.io/mcp` as the URL. When asked for authentication, add
a header named `Authorization` with the value `Bearer usk_live_...`. If your version of Claude Desktop has no header field, use
the `claude_desktop_config.json` form below with `mcp-remote`:

```json
{
	"mcpServers": {
		"usero": {
			"command": "npx",
			"args": ["-y", "mcp-remote", "https://usero.io/mcp", "--header", "Authorization: Bearer usk_live_..."]
		}
	}
}
```

### Windsurf

Edit `~/.codeium/windsurf/mcp_config.json`:

```json
{
	"mcpServers": {
		"usero": {
			"serverUrl": "https://usero.io/mcp",
			"headers": {
				"Authorization": "Bearer usk_live_..."
			}
		}
	}
}
```

### VS Code (GitHub Copilot agent mode)

Create `.vscode/mcp.json`:

```json
{
	"servers": {
		"usero": {
			"type": "http",
			"url": "https://usero.io/mcp",
			"headers": {
				"Authorization": "Bearer usk_live_..."
			}
		}
	}
}
```

### 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:

```bash
curl -s https://usero.io/mcp \
  -H "Authorization: Bearer usk_live_..." \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

## Tools

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.                                                                                                                                 |
| `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.                                                                                     |
| `create_feedback`     | `clientId`, `environment?`, `title`, `body`, `pageUrl?`, `userEmail?`                                                                                                                                      | Files a feedback item with source `mcp`. It is classified and clustered like any other item.                                                                                                                                          |
| `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`. Capped at 5 per key per day.                                                   |
| `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.                                                                                                                                                                               |

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.

## 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 as `list_clusters`.
- `usero://feedback/{id}`: one feedback item, same JSON as `get_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 call `request_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; request an AI pull request on a client that has GitHub connected.

Cannot: resolve or delete feedback, change client settings, connect other integrations, 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](/contact?subject=MCP%20tools).

## 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. |
| `request_ai_pr`           | 5 per API key per UTC day         | The tool returns an error; open the PR from the dashboard.      |
| 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](/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. Your key is hashed at rest; we never see it after creation. 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.

## Changelog

| Date       | Change                                                                                                                                                                                                                                                                                                                                                                                                                 |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 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.
