# recordings_list

Canonical HTML page: https://bitterclip.com/docs/assistants/tools/recordings_list

Surface: default model and app

Product release: 1dce717408a55fac1047e7d779177fa3ef8ede51
Public contract commit: 1ce47f7857ae3d9b6933fe83d5c33de3ae5efc64
Public contract SHA-256: 241d47d25e4b4c1dae9d2263793874d06fc4ba7bc3c78d4cf2bc63fbb32ed7dc
Descriptor SHA-256: 885d46f3ca3939dec2ace0cd6e93611c8b3f741f2d8f7a82e0adfe1452cc9a9e
Captured: 2026-09-24T16:39:30.100Z
Source: https://app.bitterclip.com/api/v1/mcp_descriptors.json

List standalone recordings (raw source media) — the drawer, not the editorial unit. Use for source/ingest/readiness asks ("latest searchable session", "what uploads are ready?") or to inspect and select recordings inside a project (project_id). For one Project reel whose useful footage spans separate recordings rather than one parent Episode, inspect selected recording pixels directly with recording_sample_frames when needed, then pass recording_id ranges directly to one episode_create without derived_from_id. Never create a throwaway Episode merely to inspect a Recording. `query` matches title, project, or who is in it ("the latest with Andrew" matches Andrew as a speaker). PAGINATED, newest first: one call returns up to 20 rows and says when more exist; continue with the returned next_cursor (same query/project_id) as `cursor`. One listing walk reaches at most the newest 50 recordings — anything older is reachable only by narrowing with query or project_id, and the result states which case you are in. Model rows carry both the exact tool-only recording_id and the episode-of-one episode_id, plus captured_at, searchability status/notes, and a compact indexed description. Prefer the newest `searchability_status:"searchable"` row for latest-session asks; episode_pending means the Recording may not have an Episode-of-one, not that direct source-time frame inspection must wait. Not for ordinary composition browsing (episodes_list) and not for searching what was SAID (transcript_search). Read-only.

The JSON blocks below are the exact MCP descriptor projections served by Rails for the named profiles at capture time. Security schemes and resource URIs may vary by connected host.

## Default model descriptor

```json
{
  "name": "recordings_list",
  "title": "List recordings",
  "description": "List standalone recordings (raw source media) — the drawer, not the editorial unit. Use for source/ingest/readiness asks (\"latest searchable session\", \"what uploads are ready?\") or to inspect and select recordings inside a project (project_id). For one Project reel whose useful footage spans separate recordings rather than one parent Episode, inspect selected recording pixels directly with recording_sample_frames when needed, then pass recording_id ranges directly to one episode_create without derived_from_id. Never create a throwaway Episode merely to inspect a Recording. `query` matches title, project, or who is in it (\"the latest with Andrew\" matches Andrew as a speaker). PAGINATED, newest first: one call returns up to 20 rows and says when more exist; continue with the returned next_cursor (same query/project_id) as `cursor`. One listing walk reaches at most the newest 50 recordings — anything older is reachable only by narrowing with query or project_id, and the result states which case you are in. Model rows carry both the exact tool-only recording_id and the episode-of-one episode_id, plus captured_at, searchability status/notes, and a compact indexed description. Prefer the newest `searchability_status:\"searchable\"` row for latest-session asks; episode_pending means the Recording may not have an Episode-of-one, not that direct source-time frame inspection must wait. Not for ordinary composition browsing (episodes_list) and not for searching what was SAID (transcript_search). Read-only.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "Optional case-insensitive filter — returns only recordings whose TITLE, a composited SOURCE TITLE, or a diarized SPEAKER NAME contains this text (substring). The filter scans the FULL catalog before the newest-50 listing window applies, so it also reaches recordings a bare walk cannot. Each kept recording carries a `match_reason` (\"title\" / \"source: …\" / \"speaker: …\") explaining why. Composes with project_id, limit, and cursor. Use it to find a recording by who is in it or what it's called, e.g. query: \"Andrew\"."
      },
      "project_id": {
        "type": "string",
        "description": "Optional project public ID — scope the list to a single project's recordings."
      },
      "limit": {
        "type": "integer",
        "description": "Rows per page. Default 20, which is also the model-context page ceiling (a larger value still pages at 20 with a next_cursor to continue; app hydration callers may receive up to 50 in one call)."
      },
      "cursor": {
        "type": "string",
        "description": "Opaque continuation returned as next_cursor by the previous page of this listing. Keep query and project_id identical when continuing; omit cursor to restart from the newest recordings. Never invent or edit a cursor."
      },
      "result_profile": {
        "type": "string",
        "enum": [
          "app",
          "model"
        ],
        "description": "Caller profile. \"app\" (widgets/apps) keeps full structured rows for hydration; \"model\" returns the complete row story as prose only. Omit to use the server default."
      }
    },
    "required": [],
    "additionalProperties": false
  },
  "annotations": {
    "readOnlyHint": true,
    "destructiveHint": false,
    "idempotentHint": true,
    "openWorldHint": false
  },
  "securitySchemes": [
    {
      "type": "noauth"
    }
  ],
  "_meta": {
    "securitySchemes": [
      {
        "type": "noauth"
      }
    ],
    "ui": {
      "visibility": [
        "model",
        "app"
      ]
    },
    "openai/widgetAccessible": true
  }
}
```

## App descriptor

```json
{
  "name": "recordings_list",
  "title": "List recordings",
  "description": "List standalone recordings (raw source media) — the drawer, not the editorial unit. Use for source/ingest/readiness asks (\"latest searchable session\", \"what uploads are ready?\") or to inspect and select recordings inside a project (project_id). For one Project reel whose useful footage spans separate recordings rather than one parent Episode, inspect selected recording pixels directly with recording_sample_frames when needed, then pass recording_id ranges directly to one episode_create without derived_from_id. Never create a throwaway Episode merely to inspect a Recording. `query` matches title, project, or who is in it (\"the latest with Andrew\" matches Andrew as a speaker). PAGINATED, newest first: one call returns up to 20 rows and says when more exist; continue with the returned next_cursor (same query/project_id) as `cursor`. One listing walk reaches at most the newest 50 recordings — anything older is reachable only by narrowing with query or project_id, and the result states which case you are in. Model rows carry both the exact tool-only recording_id and the episode-of-one episode_id, plus captured_at, searchability status/notes, and a compact indexed description. Prefer the newest `searchability_status:\"searchable\"` row for latest-session asks; episode_pending means the Recording may not have an Episode-of-one, not that direct source-time frame inspection must wait. Not for ordinary composition browsing (episodes_list) and not for searching what was SAID (transcript_search). Read-only.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "Optional case-insensitive filter — returns only recordings whose TITLE, a composited SOURCE TITLE, or a diarized SPEAKER NAME contains this text (substring). The filter scans the FULL catalog before the newest-50 listing window applies, so it also reaches recordings a bare walk cannot. Each kept recording carries a `match_reason` (\"title\" / \"source: …\" / \"speaker: …\") explaining why. Composes with project_id, limit, and cursor. Use it to find a recording by who is in it or what it's called, e.g. query: \"Andrew\"."
      },
      "project_id": {
        "type": "string",
        "description": "Optional project public ID — scope the list to a single project's recordings."
      },
      "limit": {
        "type": "integer",
        "description": "Rows per page. Default 20, which is also the model-context page ceiling (a larger value still pages at 20 with a next_cursor to continue; app hydration callers may receive up to 50 in one call)."
      },
      "cursor": {
        "type": "string",
        "description": "Opaque continuation returned as next_cursor by the previous page of this listing. Keep query and project_id identical when continuing; omit cursor to restart from the newest recordings. Never invent or edit a cursor."
      },
      "result_profile": {
        "type": "string",
        "enum": [
          "app",
          "model"
        ],
        "description": "Caller profile. \"app\" (widgets/apps) keeps full structured rows for hydration; \"model\" returns the complete row story as prose only. Omit to use the server default."
      }
    },
    "required": [],
    "additionalProperties": false
  },
  "annotations": {
    "readOnlyHint": true,
    "destructiveHint": false,
    "idempotentHint": true,
    "openWorldHint": false
  },
  "securitySchemes": [
    {
      "type": "noauth"
    }
  ],
  "_meta": {
    "securitySchemes": [
      {
        "type": "noauth"
      }
    ],
    "ui": {
      "visibility": [
        "model",
        "app"
      ]
    },
    "openai/widgetAccessible": true
  }
}
```

## Live Workspace descriptor

```json
{
  "name": "recordings_list",
  "title": "List recordings",
  "description": "List standalone recordings (raw source media) — the drawer, not the editorial unit. Use for source/ingest/readiness asks (\"latest searchable session\", \"what uploads are ready?\") or to inspect and select recordings inside a project (project_id). For one Project reel whose useful footage spans separate recordings rather than one parent Episode, inspect selected recording pixels directly with recording_sample_frames when needed, then pass recording_id ranges directly to one episode_create without derived_from_id. Never create a throwaway Episode merely to inspect a Recording. `query` matches title, project, or who is in it (\"the latest with Andrew\" matches Andrew as a speaker). PAGINATED, newest first: one call returns up to 20 rows and says when more exist; continue with the returned next_cursor (same query/project_id) as `cursor`. One listing walk reaches at most the newest 50 recordings — anything older is reachable only by narrowing with query or project_id, and the result states which case you are in. Model rows carry both the exact tool-only recording_id and the episode-of-one episode_id, plus captured_at, searchability status/notes, and a compact indexed description. Prefer the newest `searchability_status:\"searchable\"` row for latest-session asks; episode_pending means the Recording may not have an Episode-of-one, not that direct source-time frame inspection must wait. Not for ordinary composition browsing (episodes_list) and not for searching what was SAID (transcript_search). Read-only.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "Optional case-insensitive filter — returns only recordings whose TITLE, a composited SOURCE TITLE, or a diarized SPEAKER NAME contains this text (substring). The filter scans the FULL catalog before the newest-50 listing window applies, so it also reaches recordings a bare walk cannot. Each kept recording carries a `match_reason` (\"title\" / \"source: …\" / \"speaker: …\") explaining why. Composes with project_id, limit, and cursor. Use it to find a recording by who is in it or what it's called, e.g. query: \"Andrew\"."
      },
      "project_id": {
        "type": "string",
        "description": "Optional project public ID — scope the list to a single project's recordings."
      },
      "limit": {
        "type": "integer",
        "description": "Rows per page. Default 20, which is also the model-context page ceiling (a larger value still pages at 20 with a next_cursor to continue; app hydration callers may receive up to 50 in one call)."
      },
      "cursor": {
        "type": "string",
        "description": "Opaque continuation returned as next_cursor by the previous page of this listing. Keep query and project_id identical when continuing; omit cursor to restart from the newest recordings. Never invent or edit a cursor."
      },
      "result_profile": {
        "type": "string",
        "enum": [
          "app",
          "model"
        ],
        "description": "Caller profile. \"app\" (widgets/apps) keeps full structured rows for hydration; \"model\" returns the complete row story as prose only. Omit to use the server default."
      }
    },
    "required": [],
    "additionalProperties": false
  },
  "annotations": {
    "readOnlyHint": true,
    "destructiveHint": false,
    "idempotentHint": true,
    "openWorldHint": false
  },
  "securitySchemes": [
    {
      "type": "noauth"
    }
  ],
  "_meta": {
    "securitySchemes": [
      {
        "type": "noauth"
      }
    ]
  }
}
```

## Errors

```json
[]
```

## Examples

```json
[
  {
    "label": "List recent recordings",
    "input": {
      "limit": 10
    }
  },
  {
    "label": "Find a recording by speaker or title",
    "input": {
      "query": "Andrew"
    }
  },
  {
    "label": "List the recordings in a project",
    "input": {
      "project_id": "proj_..."
    }
  }
]
```
