# List files

`list_files`

| Through | Form |
|---|---|
| HTTP | `GET https://api.markdownbrain.ai/v1/files` |
| MCP | tool `list_files` |
| CLI | `mdbrain call list_files` |

The file/folder tree of a workspace (id, parent, name, type), with each node's `path` (its workspace-relative address, which every file tool accepts in place of an id), `updated_at` (create/rename/move) and `content_updated_at` (the text itself) — a file's effective last-modified is the LATER of the two. Pass `changed_since` (ISO) to get only what changed after it; with `last_checkin_at` from whoami, that's "what changed since I was last here". Narrow a large tree with `name_contains` (case-insensitive substring of the node's own name) and `under` (a folder path — return only that subtree); they compose with each other and with `changed_since`. Each markdown file also carries `title` (what the document calls itself — a front-matter `title:`, else its first heading, else its file name tidied up) and `summary` (a front-matter `description:`, else its opening prose, truncated), so you can tell what a document is without opening it. `summary` is null where a document yields no prose; folders and images carry both as null. ARCHIVED nodes are absent — a node someone put away, and everything inside it. They are not gone: [`list_archived`](/docs/operations/list_archived) lists them and [`read_file`](/docs/operations/read_file) still returns an archived document's content.

**Who may call it:** agents and people.

**Writes:** no, it only reads.

## Arguments

| Name | Type | Required | Travels in | Description |
|---|---|---|---|---|
| `workspace_id` | string | yes | query string | Workspace id |
| `changed_since` | string | no | query string | ISO timestamp — only files whose content or node changed after this are returned |
| `name_contains` | string | no | query string | Case-insensitive substring of the node's own name — for when you know roughly what it is called |
| `under` | string | no | query string | Folder path; return only that subtree. "" or omitted means the whole workspace |

## Success

`200` with `application/json`.

## Example request

```sh
curl 'https://api.markdownbrain.ai/v1/files?workspace_id=00000000-0000-4000-8000-000000000010&under=specs&changed_since=2026-03-14T09%3A30%3A00Z' \
  -H "Authorization: Bearer $MDBRAIN_API_KEY"
```

```sh
mdbrain call list_files \
  --workspace-id 00000000-0000-4000-8000-000000000010 \
  --under specs \
  --changed-since 2026-03-14T09:30:00Z
```

## Example response

```json
[
  {
    "id": "00000000-0000-4000-8000-000000000102",
    "parent_id": "00000000-0000-4000-8000-000000000101",
    "name": "12-onboarding.md",
    "type": "file",
    "updated_at": "2026-03-02T10:15:00.000000+00:00",
    "content_updated_at": "2026-03-15T16:42:08.000000+00:00",
    "path": "specs/12-onboarding.md",
    "title": "Onboarding",
    "summary": "How a new member goes from the invitation to their first edit, and what each step shows them. - The…"
  }
]
```

## Refusals

A refusal is a status code with `{ error: { code, message } }`. See [Errors](/docs/errors).
