# Members tools

> MCP tools for Members: members_list, members_remove, members_update.

- `members_list`: List members
- `members_remove`: Remove a member
- `members_update`: Change a member's role or scope

## `members_list`

**List members.** Operation [`members.list`](https://ownrecord.io/docs/reference/members-list.md) · Organization level · permission `members:read` · risk tier `read` · since M1

Lists the organization's memberships, newest first: who (with their email address and name), which role,
at which scope (the whole organization, one legal entity or one brand) and whether they have live-mode
access. A person can hold several memberships, one per scope. Filter with `userId`.

Needs `members:read` (organization owners and admins, or an org management key).

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument         | Type         | Required | Description |
| ---------------- | ------------ | -------- | ----------- |
| `userId`         | ID (`usr_…`) | no       | –           |
| `limit`          | integer      | no       | (1–100)     |
| `starting_after` | ID (`mem_…`) | no       | –           |

- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A filter or pagination value is malformed.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't see this organization's members.

### Example

**An owner and a brand developer**

Arguments:

```json
{}
```

Result `output`:

```json
{
  "object": "list",
  "data": [
    {
      "id": "mem_01m4tx5nj8emwbyf7y9vcf47x6",
      "object": "membership",
      "orgId": "org_01m4tx5nj7ekd958x53w4bntcg",
      "userId": "usr_01m4tx5nj8emwbyf7y9vcf47xb",
      "role": "developer",
      "scope": {
        "type": "brand",
        "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4"
      },
      "livemodeAccess": false,
      "invitedBy": "usr_01m4tx5nj8emwbyf7y9vcf47xa",
      "user": {
        "email": "dev@acme.example",
        "name": "Dana Developer"
      },
      "createdAt": "2026-10-13T12:00:00.000Z",
      "updatedAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "mem_01m4tx5nj8emwbyf7y9vcf47x7",
      "object": "membership",
      "orgId": "org_01m4tx5nj7ekd958x53w4bntcg",
      "userId": "usr_01m4tx5nj8emwbyf7y9vcf47xa",
      "role": "org_owner",
      "scope": {
        "type": "org"
      },
      "livemodeAccess": true,
      "invitedBy": null,
      "user": {
        "email": "owner@acme.example",
        "name": "Olivia Owner"
      },
      "createdAt": "2026-10-13T12:00:00.000Z",
      "updatedAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

## `members_remove`

**Remove a member.** Operation [`members.remove`](https://ownrecord.io/docs/reference/members-remove.md) · Organization level · permission `members:admin` · risk tier `security` · since M1

Removes one membership. The person loses the access it gave at once (their other memberships stay), and
can be invited again later. Returns the removed membership. Give a `reason`: it goes to the audit log.

You can only remove memberships you could have granted (an admin can't remove an owner), and the
organization always keeps at least one owner (`last_owner`). Needs `members:admin`; a security-tier
change.

Annotations: `readOnlyHint: false` · `destructiveHint: true` · `idempotentHint: false` · `openWorldHint: false`

### Arguments

| Argument          | Type         | Required | Description                                                                                                                                                                                              |
| ----------------- | ------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID (`mem_…`) | yes      | –                                                                                                                                                                                                        |
| `reason`          | string       | no       | (1–500 characters)                                                                                                                                                                                       |
| `idempotency_key` | string       | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean      | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No such membership in this organization.
- [`role_not_grantable`](https://ownrecord.io/docs/reference/errors.md#role_not_grantable): The membership has more access than you.
- [`last_owner`](https://ownrecord.io/docs/reference/errors.md#last_owner): It's the organization's last owner.
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The membership changed at the same time; retry.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't manage members of this organization.

### Example

**Remove a developer who left the team**

Arguments:

```json
{
  "id": "mem_01m4tx5nj8emwbyf7y9vcf47x6",
  "reason": "Left the company",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "mem_01m4tx5nj8emwbyf7y9vcf47x6",
  "object": "membership",
  "orgId": "org_01m4tx5nj7ekd958x53w4bntcg",
  "userId": "usr_01m4tx5nj8emwbyf7y9vcf47xb",
  "role": "developer",
  "scope": {
    "type": "brand",
    "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4"
  },
  "livemodeAccess": false,
  "invitedBy": "usr_01m4tx5nj8emwbyf7y9vcf47xa",
  "user": {
    "email": "dev@acme.example",
    "name": "Dana Developer"
  },
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-13T12:00:00.000Z"
}
```

## `members_update`

**Change a member's role or scope.** Operation [`members.update`](https://ownrecord.io/docs/reference/members-update.md) · Organization level · permission `members:admin` · risk tier `security` · since M1

Changes a membership's role, its scope (the whole organization, one legal entity or one brand) or its
live-mode access. Owners, admins and billing admins work at organization scope; finance and tax managers
at the organization or one entity; support, developers and viewers also at one brand.

You can't grant more than you have: an admin can't make anyone an owner, can't change an owner's
membership, and can't grant live access without having it. The organization always keeps at least one
owner (`last_owner`). Needs `members:admin` (owners and admins); a security-tier change.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument          | Type                                                                                                         | Required | Description                                                                                                                                                                                              |
| ----------------- | ------------------------------------------------------------------------------------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID (`mem_…`)                                                                                                 | yes      | –                                                                                                                                                                                                        |
| `role`            | one of `org_owner`, `org_admin`, `billing_admin`, `finance`, `tax_manager`, `support`, `developer`, `viewer` | no       | –                                                                                                                                                                                                        |
| `scope`           | object or object or object                                                                                   | no       | –                                                                                                                                                                                                        |
| `livemodeAccess`  | boolean                                                                                                      | no       | –                                                                                                                                                                                                        |
| `idempotency_key` | string                                                                                                       | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean                                                                                                      | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): Nothing to change was sent, a field is malformed, or the role isn't allowed at the scope.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No such membership, or the new scope's entity or brand doesn't exist.
- [`role_not_grantable`](https://ownrecord.io/docs/reference/errors.md#role_not_grantable): The current or new access goes beyond your own.
- [`last_owner`](https://ownrecord.io/docs/reference/errors.md#last_owner): The change would leave the organization without an owner.
- [`membership_exists`](https://ownrecord.io/docs/reference/errors.md#membership_exists): The person already has a membership at the new scope.
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The membership changed at the same time; retry.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't manage members of this organization.

### Examples

**Give a brand developer live-mode access**

Arguments:

```json
{
  "id": "mem_01m4tx5nj8emwbyf7y9vcf47x6",
  "livemodeAccess": true,
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "mem_01m4tx5nj8emwbyf7y9vcf47x6",
  "object": "membership",
  "orgId": "org_01m4tx5nj7ekd958x53w4bntcg",
  "userId": "usr_01m4tx5nj8emwbyf7y9vcf47xb",
  "role": "developer",
  "scope": {
    "type": "brand",
    "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4"
  },
  "livemodeAccess": true,
  "invitedBy": "usr_01m4tx5nj8emwbyf7y9vcf47xa",
  "user": {
    "email": "dev@acme.example",
    "name": "Dana Developer"
  },
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-14T09:30:00.000Z"
}
```

**Move a developer to the whole entity**

Arguments:

```json
{
  "id": "mem_01m4tx5nj8emwbyf7y9vcf47x6",
  "scope": {
    "type": "entity",
    "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2"
  },
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "mem_01m4tx5nj8emwbyf7y9vcf47x6",
  "object": "membership",
  "orgId": "org_01m4tx5nj7ekd958x53w4bntcg",
  "userId": "usr_01m4tx5nj8emwbyf7y9vcf47xb",
  "role": "developer",
  "scope": {
    "type": "entity",
    "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2"
  },
  "livemodeAccess": false,
  "invitedBy": "usr_01m4tx5nj8emwbyf7y9vcf47xa",
  "user": {
    "email": "dev@acme.example",
    "name": "Dana Developer"
  },
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-14T09:30:00.000Z"
}
```
