# The MCP tools

> Every factorin_* tool a connected AI app can call — reading, searching, writing, skills, attachments and archive — and what each one takes.

Source: https://factor.in/docs/mcp-tools/
Updated: September 30, 2026


A connected AI app sees one list of tools, all named `factorin_*`. The prefix is deliberate: a model choosing between your library and the host app's own features needs to tell them apart, and a bare word like "search" loses that contest every time.

Three rules hold across the whole list. No tool mixes a read with a write. Every write saves immediately as a new version, and earlier versions are kept. Nothing destroys content: `factorin_archive` is the only tool marked destructive, and it hides a row rather than removing it.

One connection reaches every library the person is a member or guest of. A tool that takes an `id` already knows its library. A tool that does not takes a `library` slug, which can be left out when only one library is reachable.

## Reading

**`factorin_list_libraries`.** List every library the person can reach, with the slug to pass as `library` to other tools and whether each can be written. Call it when a tool refuses for want of a library, or when the list given at connection time may be out of date.

**`factorin_list`.** List what is in a library as a tree: folders, skills, notes, prompts and attachments, every line with the id that addresses it. Narrow with `kinds` (`note`, `prompt`, `attachment`, `skill`), or with `content_type`, `min_bytes` and `max_bytes` to ask about attachments ("every image", "anything over 5 MB"). Narrowing also drops folders holding nothing you asked for.

**`factorin_search`.** Search a library by content and by name. Matching lines come back with their id, the way grep would. A file whose name matches comes back too, which is the only way to find an attachment. Use it whenever you would otherwise guess at a name or assume something does not exist. Takes `query` (literal text, case-insensitive), and optionally `folder_id`, `kinds`, `library` and `limit`.

**`factorin_list_skills`.** List every skill with its description, its path, the size of its `SKILL.md` and the folder id that addresses it. Skills can sit at any depth, so this finds them all. Read one with `factorin_read` and follow it where it is. Skills are not installed into the client. The library stays the one copy.

**`factorin_read`.** Read a file or skill by `id` or by `path`. A path may be a library path (`Prompts/Setup library.md`), a bare file name, or a link exactly as written inside another file, relative ones included. Pass `origin_id` with a relative link so it anchors to the file it was written in. A note, prompt or skill file returns its `payload`, which is what `factorin_write` takes back. A skill returns its `SKILL.md` and the names of its files. An image returns as an image, any other attachment as base64, and anything over 8 MB as a short-lived download URL.

## Writing

**`factorin_create`.** Create a `note` or a `prompt`, at the library root or in a `folder_id`. A note is something to read. A prompt is an instruction to run later, and may carry `input_schema` and `output_schema` as JSON Schemas.

**`factorin_create_skill`.** Create an agent skill: a folder holding a `SKILL.md` manifest plus support files. Takes a `name` (normalized to kebab-case, like `pdf-extraction`), a `description` (what the skill does and when to use it, which is what a model reads when deciding to invoke it), and the `body` of the manifest.

**`factorin_create_folder`.** Create a folder. Pass the id it returns as `folder_id` to the create and write tools so output lands somewhere sensible rather than at the root.

**`factorin_write`.** Save a new version of an existing note, prompt or skill file. Send `edits`, a list of `{old_text, new_text}` replacements applied in order, each `old_text` matching exactly once, to change part of a file cheaply. Or send `payload`, the whole payload `factorin_read` returned with your changes, since anything left out is removed. Earlier versions are kept.

**`factorin_write_attachment`.** Create or replace a binary file: image, audio, PDF, archive, data file. For bytes already in context, send `content_base64` (up to 8 MB). For a file on disk at any size, send `byte_size` to get an upload URL, PUT the file there, then call again with the `upload_id` to save it. The bytes never pass through the model's context.

**`factorin_move`.** Rename a file, folder or skill, move it into a different folder, or both. A folder or skill moves with everything inside it.

**`factorin_archive`.** The library's "delete". The row leaves the tree, a folder or skill takes everything inside it, and nothing is destroyed. History is kept and the row can be restored from the web app.

## Run-scoped tools

A cloud run, which is a model the platform executes on the team's behalf, sees four more tools that a person's connection never does: read and write a scratchpad that belongs to that run, schedule a continuation so a long external job can be waited for without polling, and create a workspace to build in. They spend money or hold run state, so they are offered only to a credential that is a run.

## Style the tools ask for

Write markdown prose as one line per paragraph. A display wraps it, and hard-wrapped lines are painful to edit later with `edits`. Line breaks belong only where they are content: code fences, tables and list items.

## What a connection can and cannot do

- A member of a library on an active plan reads, writes and runs.
- A member looking at a GitHub mirror, or at a library whose plan has lapsed, reads only. Nothing under a mirror is written locally; only the sync gets through.
- A guest under a grant reads one folder and everything under it, writes only in their own dropbox, and sees no version history and no runs.
- A library past its first 7 days without a plan is readable and still exports whole.

Every rule is the same on every surface: the web app, the connector and the public API all ask the same questions of the same records.

