# User Studies MCP

Use the site's Chat, brief idea generation, Task, Desire, and Storyboard workflows from an agent. Generated responses are synthetic hypotheses, not real customer evidence.

## Endpoint

- Hosted: `https://userstudies.ai/api/mcp` (Streamable HTTP, MCP SDK 2.0.0)
- Local dev: `http://127.0.0.1:8780/api/mcp`

## Auth (direct Bearer, not OAuth)

1. Open `https://userstudies.ai/agents.html` in your browser.
2. Click Generate agent token. This binds your current anonymous browser owner to the token.
3. Token lasts 30 days, revocable. Generating again replaces the previous token.
4. Send `Authorization: Bearer <token>` on every MCP and HTTP fallback request. Your MCP client must support a configurable Authorization header.
5. No global shared token. Never put tokens in downloadable files.

## Skill vs MCP registration

- Installing the skill (`GET /skills/userstudies/SKILL.md`) teaches the agent when and how to call studies. It does not connect anything.
- MCP registration connects the agent to `/api/mcp` with the Bearer token above. Both steps are required.

## Tools (names are exact)

### chat_with_persona — Chat tab

Send one turn to the same backend as the site's Chat tab. The MCP conversation is stateless: pass the returned `completePersona` and the prior user/assistant messages on the next call. It does not create a study ID; existing backend tracing may still apply.

```json
{"persona":"Freelance designer","message":"How do you gather client feedback?","history":[],"model":"openai/gpt-oss-120b"}
```

Required: `persona` plus a nonblank `message` or `image`. Optional: `problem`, `promise`, `product` (each up to 4,000 characters), `history` (up to 50 `{role:"user"|"assistant",content}` turns), `completePersona` (the prior response's string), `model` (`openai/gpt-oss-120b` default, `openai/gpt-6-luna`, or `meta/muse-spark-1.3-contributor`), and `image` (inline PNG/JPEG/WebP data URL, up to 1 MB decoded). Returns `{text,completePersona,suggestedQuestions}`. An image can select the Chat backend's vision model. Client history is supplied with each turn; no chat ID is returned.

Hosted agent Chat turns share the hourly admission budget with studies; a full budget returns 429 before calling the provider. The same JSON body is available as a same-origin browser fallback at `POST /api/studies/chat`.

### generate_brief_idea — left sidebar Autofill

Suggest text for exactly one brief field using the same `/api/autofill` backend as the site's Persona, Problem, Promise, and Product links.

```json
{"fieldToAutofill":"problem","conversation":[{"role":"user","content":"Client comments arrive in email and chat."}],"currentInputs":{"persona":"Freelance brand designers","product":"A review link"}}
```

Required: `fieldToAutofill` (`persona`, `problem`, `promise`, or `product`) and `currentInputs` (an object with any known brief fields). `conversation` is optional, up to 50 user/assistant turns. Each brief field and turn is at most 4,000 characters. Returns `{suggestedInput}`. This is a draft suggestion: the tool neither writes the sidebar nor starts a study. The underlying backend uses its fixed default model; there is no model picker for autofill. Hosted agent calls share the hourly admission budget with studies and Chat (429 when full). Same-origin JSON fallback: `POST /api/studies/brief-idea`.

### start_study

Start an async study. Returns a study handle; poll `get_study` for results.

```json
{
  "mode": "interview | desirability | browser_task | storyboard",
  "persona": "target-customer description (required)",
  "question": "research question (interview requires question or problem)",
  "url": "https URL (browser_task, required)",
  "task": "task for simulated participants (browser_task, required)",
  "participantCount": "1-5, default 1",
  "turns": "1-12, default 6 (interview)",
  "problem": "optional context",
  "promise": "optional concept (introduced late in interview)",
  "product": "optional concept",
  "stimuli": "[{id, label, text?, image?}] 1-8 items, desirability requires it. image must be an inline data URL (PNG/JPEG/WebP, <=1MB each). No remote URLs.",
  "proposition": "optional follow-up proposition (desirability)",
  "intendedAttributes": "optional string[<=20]",
  "feedback": "storyboard revision feedback; requires parentStudyId",
  "parentStudyId": "completed storyboard UUID; requires feedback",
  "idempotencyKey": "required; reuse returns the same study"
}
```

### get_study

```json
{ "studyId": "required", "detail": "summary | transcript | evidence (default summary)", "participantId": "optional", "cursor": "integer >=0, default 0", "limit": "1-100, default 20" }
```

Use `summary` for status plus findings, `transcript` for interview turns or browser events, and `evidence` for desirability responses/SVG visuals or browser latest frames/outcomes. Browser transcript/evidence cursors are event sequence IDs, not offsets; follow nextCursor even if a participant filter yields an empty page. Historical frame events are available in both transcript and evidence pages. The first evidence page also includes up to two current snapshots per participant (latest frame and outcome), in addition to the bounded event page.

### stop_study

```json
{ "studyId": "required" }
```

Stops the run and preserves completed work.

### list_storyboards — Storyboard history

```json
{"cursor":0,"limit":20}
```

Both fields are optional (`cursor` 0–10000; `limit` 1–20). Returns the current owner's generations newest first with status, saved brief, feedback, parent ID and preview image reference. Follow `nextCursor` until null. Use `get_study` on an item to open all six panels. A fresh variation uses the saved brief and a new idempotency key without feedback or parent ID. A revision passes both `feedback` and the completed `parentStudyId`; the previous generation remains accessible. Panel image references are owner-checked `GET https://userstudies.ai/api/studies/<studyId>/assets/<index>` (`index` 0–5). Send the same Bearer token; the URLs are not public.

## Modes

- interview: end-to-end adaptive interview (default 6 turns), isolated personas. Discovery first; promise/product introduced as a hypothetical concept late.
- desirability: initial reaction first (up to 5 balanced words per stimulus, proposition withheld), then proposition follow-up. Results include per-stimulus word counts plus an SVG visual. Counts describe synthetic selections only; never report prevalence or demand.
- browser_task: uses the existing durable task-run infrastructure. Qwen generates the synthetic persona and step captions; Jev chooses observed browser actions. Evidence includes real frames, synthetic cursor targets, and synthetic before/after narration. A separate final-page judgment checks Jev's completion claim. Treat both the participant and judgment as simulated evidence.
- storyboard: six-panel illustrated journey from required `persona`, `problem`, `promise`, and `product`. Rejects `participantCount`, `turns`, `stimuli`, and `proposition`. Text and images arrive as partial results; incomplete drawings stay visible. The outcome is imagined, not observed.

## HTTP fallback

Same bodies and Bearer header:

```bash
curl -X POST https://userstudies.ai/api/studies/start \
  -H "Authorization: Bearer $AGENT_TOKEN" -H "Content-Type: application/json" \
  -d '{"mode":"interview","persona":"freelance designer","question":"How do you collect client feedback?","participantCount":1,"turns":6,"idempotencyKey":"demo-001"}'

curl -X POST https://userstudies.ai/api/studies/get \
  -H "Authorization: Bearer $AGENT_TOKEN" -H "Content-Type: application/json" \
  -d '{"studyId":"<id>","detail":"summary"}'

curl -X POST https://userstudies.ai/api/studies/stop \
  -H "Authorization: Bearer $AGENT_TOKEN" -H "Content-Type: application/json" \
  -d '{"studyId":"<id>"}'
```

## Data handling

- Storage: local SQLite / hosted Postgres for studies; Chat history and brief context are supplied by the caller and the existing backend's tracing still applies. Browser-task models: Jev/TypeSafe and Qwen/Cerebras through the hosted execution-scoped gateway. Chat, brief ideas, interview, desirability, and storyboard generation use the configured OpenRouter models. Hosted browser sessions remain isolated Modal sandboxes.
- Qwen receives bounded visible page text and control values to narrate and judge steps. Use test accounts and avoid sensitive form data or private pages.
- No new retention promise. Studies are labeled SYNTHETIC or ILLUSTRATIVE; Chat persona replies are synthetic.

## Verified compatibility

- Official TypeScript SDK 2.0.0 implements MCP 2026-07-28 through its request-scoped HTTP handler. The SDK supplies stateless compatibility with 2025-era clients. Both modern and legacy client discovery/calls are tested locally; see repository verification evidence for the final test results.
- Pending primary verification: production deployment, native browser WebMCP compatibility. Registration and shared HTTP dispatch are covered by an isolated browser-API fixture; this is not a native-browser compatibility claim.

## Install the skill

Download `/skills/userstudies/SKILL.md` using the link on `/agents.html`. Put it in a folder named `userstudies` in your agent client's supported skills directory. This is plain UTF-8 Markdown and requires no installation script. Preserve any existing skill before replacing it.

For a client supporting remote MCP URL plus headers, configure the endpoint and token separately:

```json
{"url":"https://userstudies.ai/api/mcp","headers":{"Authorization":"Bearer <your-private-token>"}}
```

This is the connection object, not a universal client configuration file. Use your client's documented MCP settings; no active client configuration is modified by downloading the skill. OAuth-only clients are not supported by this direct-token integration.

## Runtime and deployment

The existing `/api/*` rewrite carries MCP and study calls to the hosted coordinator. A deployment must be verified at the public hostname before claiming these new tools are live. If a reverse proxy forwards its upstream hostname, explicitly configure that hostname in `STUDY_ALLOWED_HOSTS`; do not accept arbitrary forwarded host headers.

Research jobs run with two local execution slots and a ten-minute deadline. They preserve partial responses on failure/stop. Hosted research uses the existing hourly participant admission budget. Queued work is durable; expired running leases are interrupted, never replayed as fresh paid runs. Browser jobs retain their existing sandbox time limits. Browser screenshot URLs require owner authentication; MCP evidence provides references rather than making private images public.

Research requests are capped at 150 moderator/participant/analysis calls per study, in addition to the existing profile-generation request. Oversized designs/turn combinations are rejected before execution. Aggregate inline image data URLs must fit within 6,000,000 characters; each image also retains its 1,000,000-byte decoded limit.
