---
title: MCP tool reference
description: Inputs, scopes, and results for OpenTester feedback, change request, and PR tools.
---

# MCP tool reference {#mcp-tool-reference}

Inputs are JSON objects. Unknown fields are rejected. Use actual OpenTester UUIDs. All tools target the one app configured for the connection.

| Tool | Required scope | Operation |
| --- | --- | --- |
| `list_feedback` | `feedback:read` | List feedback |
| `get_feedback` | `feedback:read` | Get feedback details |
| `create_change_request` | `work-items:write` | Create work |
| `list_change_requests` | `work-items:read` | List work |
| `get_change_request` | `work-items:read` | Get work details |
| `attach_pull_request` | `work-items:write` | Link an existing GitHub PR URL |

## Common results {#common-results}

Success returns the REST response in `structuredContent` and as JSON text in `content`. For example, `get_feedback` returns `{ "feedback": { ... } }`. See the [feedback](/api/feedback) and [change request](/api/change-requests) APIs for full object fields.

API/transport failures return `isError: true` and an `error` object. Invalid inputs may be rejected by MCP before execution. See [troubleshooting](/mcp/troubleshooting).

## `list_feedback` {#list-feedback}

Lists newest feedback first. Omitted filters include all feedback for the app.

| Input | Type | Default and range |
| --- | --- | --- |
| `kind` | Optional string | `bug` or `feedback` |
| `status` | Optional string | `open`, `confirmed`, `fixed`, `closed` |
| `limit` | Optional integer | Default `20`, range `1`–`50` |
| `offset` | Optional integer | Default `0`, range `0`–`100000` |

```json
{
  "kind": "bug",
  "status": "open",
  "limit": 10,
  "offset": 0
}
```

Returns `{ feedback: Feedback[], total, limit, offset }`. Use `offset + limit` for the next page. `total` counts all matching reports.

## `get_feedback` {#get-feedback}

```json
{
  "issueId": "22222222-2222-4222-8222-222222222222"
}
```

`issueId` is a required UUID. Returns `{ feedback: Feedback }` with title, description, steps, expected/actual results, app version, device details, kind, and status. Reporter names, emails, and reward records are excluded.

## `create_change_request` {#create-change-request}

Records a goal and links one or more reports:

| Input | Type | Constraint |
| --- | --- | --- |
| `title` | Required string | `1–160` characters after trimming |
| `instructions` | Required string | `1–10000` characters after trimming |
| `acceptanceCriteria` | Optional string | At most `10000` characters; default empty |
| `issueIds` | Required UUID array | `1–20` distinct reports from the same app |
| `clientRequestId` | Required UUID | Retry identifier for this creation request |

```json
{
  "title": "Improve report submission errors while offline",
  "instructions": "Preserve input and show retry guidance if the connection fails during submission.",
  "acceptanceCriteria": "Input survives network failure and the report is submitted only once after reconnection.",
  "issueIds": ["22222222-2222-4222-8222-222222222222"],
  "clientRequestId": "33333333-3333-4333-8333-333333333333"
}
```

Returns `{ changeRequest: ChangeRequest }`, initially `open` with `pullRequestUrl: null`. Use the returned `changeRequest.id` as `changeRequestId` in later calls.

::: warning Keep the ID when retrying
Generate a fresh UUID for a new request instead of reusing the example. For retries, keep the original `clientRequestId` and input. The same app/creator/ID with different content returns `conflict`. Different IDs may create separate work for the same issue, so check existing work first.
:::

This saves a work record; it does not modify code or start an agent.

## `list_change_requests` {#list-change-requests}

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

Both inputs are optional with the same ranges as `list_feedback`. Returns `{ changeRequests: ChangeRequest[], total, limit, offset }`, newest first. No status filter is provided.

## `get_change_request` {#get-change-request}

```json
{
  "changeRequestId": "44444444-4444-4444-8444-444444444444"
}
```

Takes one required UUID and returns `{ changeRequest: ChangeRequest }`: instructions, acceptance criteria, report IDs, `open` or `pr_linked` status, and PR URL.

## `attach_pull_request` {#attach-pull-request}

```json
{
  "changeRequestId": "44444444-4444-4444-8444-444444444444",
  "url": "https://github.com/example/android-app/pull/42"
}
```

| Input | Type | Constraint |
| --- | --- | --- |
| `changeRequestId` | Required UUID | Change request ID |
| `url` | Required string | At most `2048` characters; `https://github.com/owner/repo/pull/positive-integer` |

Only GitHub.com PR URLs are supported. Queries, fragments, credentials, ports, GitHub Enterprise, and GitLab URLs are rejected. Owner/repository names are lowercased and trailing slashes removed.

Returns `{ changeRequest: ChangeRequest }` with status `pr_linked`. Each request permits one PR. Repeating the same URL is allowed; attaching a different URL returns `conflict`.

Linking does not verify PR existence, ownership, or merge state, and does not change feedback status or rewards. Create, review, merge, and deploy using your separate GitHub and CI/CD workflow.
