# MCP tools

> Every tool the Dockito MCP server offers, with its parameters.

This page is built from the MCP server's own tool list, so it always matches what your AI client sees.

A tool can never do more than the person who connected, and only what the connection's access allows in each workspace (View, Publish or Everything). History records changes made here as `mcp`.

## whoami

**Who am I** · Reads only

The user, how long this token lasts, and its access (View, Publish or Everything) in each workspace it can reach.

No parameters.

## tree

**Places** · Reads only

Every workspace, project and folder this token can use, each written as the "to" that publish takes, with doc counts and your role there (edit, comment or view; publishing needs edit). No docs; ls lists those.

No parameters.

## ls

**List docs** · Reads only

The docs (with their codes and links), projects and folders in one place: the workspace's Docs (no place), a project, or a folder. Each place has your role there (edit, comment or view; publishing needs edit).

| Parameter | Type | |
|---|---|---|
| `to` | string | "project" or "project/folder", as publish takes it. Empty: the workspace's Docs and its projects. |
| `workspace` | string | Workspace slug. Default: the only one, else the user's personal one. |

## get

**Read a doc** · Reads only

A doc's file: the current one, or a History entry. Returns its details, then the file's text. A file over 20,000 characters comes back as its outline (headings with line numbers) instead: read the part you need with "lines", or all of it with "full". A sheet comes back as its outline: each sheet's columns, what's in them, and the version to apply changes at; read gives its rows.

| Parameter | Type | |
|---|---|---|
| `doc` (required) | string | The doc's link or 12-character code. |
| `entry` | integer | A History entry number. Default: current. |
| `outline` | boolean | Only the details and the outline: each heading with the line it starts on. |
| `lines` | string | Only these lines of the file: "120-260", "120-" (to the end) or "120". |
| `text` | boolean | HTML as readable text: no tags, scripts or styles, headings and list items kept as # and -. Often a few times shorter. Markdown is already text. |
| `full` | boolean | The whole file, however long. |

## read

**Read a sheet** · Reads only

Rows of a sheet as a text table: row numbers, values as shown, and the version (v N) to apply changes at. A range, or a sheet's rows under its header row, filtered and sorted; with "group" or "totals", totals instead of rows. 200 rows unless "limit" says, at most 1,000; the answer says how to page on with "from". With "chart", a chart's points instead.

| Parameter | Type | |
|---|---|---|
| `doc` (required) | string | The doc's link or 12-character code. |
| `range` | string | "Tasks!A1:G40", "Tasks!B:B", "Tasks!3:5", a defined name, or "E17" when there's one sheet. |
| `sheet` | string | A sheet or table by name: its rows under its header row. Default: the only sheet. |
| `where` | string | A filter on headers: "Area = Kitchen and Status &lt;> Done or Hours > 4". With = &lt;> &lt; > &lt;= >= contains, "is empty" and "is not empty"; dates as yyyy-mm-dd. |
| `select` | array | Columns to show, by header or letter, in this order. |
| `orderBy` | string | "Due desc, ID". Empty cells go last. |
| `group` | array | Group the rows by these columns. |
| `totals` | array | Per group, or for all the rows: "count", "sum Hours", "avg Hours", "min Due", "max Due". |
| `from` | integer | The first of the matching rows to give, from 1. |
| `limit` | integer | How many rows. Default 200, at most 1,000. |
| `formulas` | boolean | Formulas with their results: =F2*50 → 50. |
| `styles` | boolean | Formatting in words: bold, fills, number formats, merges, sizes, frozen panes; a cell a conditional format colours shows it with the rule, as fill #f6d3d0 (format #3). |
| `csv` | boolean | As CSV instead of a table. |
| `chart` | integer | A chart's number (chart #2 in the outline): its points as a table, label column then each series, as drawn (a long range thinned, saying how many rows of how many). Alone, with doc. |

## apply

**Change a sheet** · Changes docs

Changes a sheet, read at "base": the version (v N) your last get, read or changes showed. Addresses, rows and headers mean what they meant at that version, wherever they moved since; so do chart and format numbers (#N, by order in the outline; a chart an earlier op here makes takes the next number) and sheet names (after a rename by an earlier op, either works). Every op applies, or none: a cell someone changed since is refused, naming who, so read again and apply on the new version. Answers each cell old → new, results that changed, and the new version. "dryRun" answers the same without saving; "undo" takes back a change of yours.

| Parameter | Type | |
|---|---|---|
| `doc` (required) | string | The doc's link or 12-character code. |
| `base` | integer | The version you read: v N in the answer. |
| `ops` | array | Changes, applied in order; "sheet" can be left out when there's one. Each is one of:
&#123;"set": "Tasks!E17", "value": "Done"} · &#123;"set": "Tasks!B2:C3", "values": [["Tile grout", "Kitchen"], ["Vent cover", "Bathrooms"]]} (past the last row or column, the sheet grows)
&#123;"update": &#123;"sheet": "Tasks", "where": "ID = T-104", "set": &#123;"Status": "Done", "Owner": "Dana"}}} · &#123;"update": &#123;"sheet": "Tasks", "where": "Area = Kitchen and Status = Open", "set": &#123;"Status": "Done"}, "max": 50}} (rows matching at base, by header; max is 1 unless set, and more matches than max are refused, so set it when you mean several rows)
&#123;"append": &#123;"sheet": "Tasks", "rows": [&#123;"ID": "T-214", "Item": "Gutter downspout", "Status": "Open"}]}} (after the last filled row, by header; a table grows; a column's formula in the rows above carries into the new rows, as in Excel, unless you give a value)
&#123;"insertRows": &#123;"sheet": "Tasks", "after": 40, "count": 2}} (after 0: the top) · &#123;"deleteRows": &#123;"sheet": "Tasks", "rows": "41:42"}} (or a list: "9, 16, 41:42") · &#123;"moveRows": &#123;"sheet": "Tasks", "rows": "5:6", "after": 10}}
&#123;"insertCols": &#123;"sheet": "Tasks", "after": "C", "count": 1}} ("" for before A) · &#123;"deleteCols": &#123;"sheet": "Tasks", "cols": "D:E"}} · &#123;"moveCols": &#123;"sheet": "Tasks", "cols": "F", "after": "B"}}
&#123;"format": &#123;"range": "Tasks!1:1", "bold": true, "fill": "#fff2cc"}} (cells, rows "1:1" or columns "F:F"; null clears a field. bold italic underline strike wrap: true or false · size: points, 1 to 409 · font: a name, as "Inter" · color fill: "#rrggbb" · hAlign: left, center, right or justify · vAlign: top, middle or bottom · indent: 0 to 250 · borderTop borderRight borderBottom borderLeft: "thin #d0d5dd" or &#123;"line": "thin", "color": "#d0d5dd"}, lines thin, medium, thick, dashed, dotted or double · numFmt: Excel's, as "$#,##0.00")
&#123;"resize": &#123;"range": "Tasks!B:C", "size": 120}} (points or "auto"; "hidden": true hides) · &#123;"merge": "Tasks!A1:G1"} · &#123;"unmerge": "Tasks!A1:G1"}
&#123;"addSheet": &#123;"name": "Hours", "after": "Tasks"}} · &#123;"renameSheet": &#123;"sheet": "Hours", "name": "Time"}} · &#123;"moveSheet": &#123;"sheet": "Time", "first": true}} · &#123;"deleteSheet": "Old"} · &#123;"sheetProps": &#123;"frozenRows": 1, "frozenCols": 0, "hidden": false, "tabColor": "#4472c4"}}
&#123;"setName": &#123;"name": "Rate", "range": "Summary!B2"}} · &#123;"deleteName": "Rate"}
&#123;"addTable": &#123;"range": "Tasks!A1:G40", "name": "Tasks"}} (a header row and banded rows in one change; a cell's own fill shows over them) · &#123;"setTable": &#123;"table": "Tasks", "range": "Tasks!A1:G60", "totals": true}} · &#123;"deleteTable": "Tasks"} (its cells stay)
&#123;"validate": &#123;"range": "Tasks!E2:E", "list": ["Open", "In progress", "Done"], "reject": true, "help": "Pick a status"}} (E2:E: from row 2 down, rows added later too; reject: other values are refused, else taken and marked; the outline lists each rule) · one kind each: "list", "from": "Lists!A2:A20", "checkbox": true or ["Yes", "No"], "number": &#123;"between": [0, 100]} (or "equal to", "not equal to", "greater than", "at least", "less than", "at most", "not between"), "date": &#123;"after": "2026-01-01"} (or "before", "on or after", "on or before", "on", "not on", "between"; true: any date), "text": &#123;"contains": "x"} (or "not contains", "exactly"), "email": true, "url": true, "length": &#123;"at most": 50}, "formula": "=F2&lt;G2" (for the first cell) · &#123;"validate": &#123;"range": "Tasks!E2:E", "remove": true}}
&#123;"conditional": &#123;"range": "Tasks!E2:E", "text is": "Blocked", "format": &#123;"fill": "#f6d3d0", "bold": true}}} (the outline lists rules in order as format #N; on a cell the first that matches wins; new ones go last) · one condition each: "empty": true, "not empty": true, "text contains", "text not contains", "text starts with", "text ends with", "text is": "x", "date is", "date before", "date after": "today", "tomorrow", "yesterday", "past week", "past month", "past year" or "2026-01-01", "number": &#123;"greater than": 8} (validate's words), "formula": "=$F2&lt;TODAY()" (for the first cell), "scale": &#123;"min": "#ffffff", "mid": "#ffd666", "max": "#57bb8a"} (a point may be &#123;"color": "#57bb8a", "number": 10}, "percent" or "percentile"; no format), "duplicate": true, "unique": true, "top": 10 or "10%", "bottom", "above average": true, "below average": true · format: bold italic underline strike, color fill · "before": 2 or "first": true places it · &#123;"conditional": &#123;"rule": 3, "first": true}} moves rule 3; with range, a condition or format it changes them · &#123;"conditional": &#123;"rule": 3, "remove": true}} or &#123;"conditional": &#123;"range": "Tasks!E:E", "remove": true}} (rules inside it) · read with styles marks coloured cells: fill #f6d3d0 (format #3)
&#123;"replace": &#123;"find": "Lee", "with": "Priya", "in": "Owner"}} (find and replace, as one change: "in" is a column by header or letter, its rows under the header, or a range, "Tasks!C2:C"; left out, the whole sheet, "sheet" naming it when there's more than one; "with" may be "") · "case": true matches case · "whole": true the whole cell · "regex": true for a pattern (RE2), $1 in "with" its first group · "formulas": true changes formulas, searching their text (else a formula matches by its result and is left) · the answer says what was left and why: formulas, matched only as formatted, formulas that would break, values a rule refuses; over 100,000 cells changes nothing
&#123;"chart": &#123;"range": "Tasks!A1:C40", "type": "column", "title": "Costs by area"}} (the outline lists each as chart #N; the first row names the series and the first column labels the points, or is a scatter's x, guessed when left out: "header", "labels") · "type": "column", "bar", "line", "area", "pie", "donut" or "scatter" (first column: x), or "stacked column", "stacked bar", "stacked area", "doughnut", "horizontal bar"; "stacked": true for column, bar, area · "at": "E2" puts its top-left corner there, or "below", "beside", "below chart #2", "beside chart #2"; left out, beside the range on its first row, past whatever fills those rows (under a wide range when that's clear), never over filled cells or another chart (the sheet grows to fit; "below" far down says so) · "width", "height" in pixels, 40 to 4,000 (left out: fitted, 480 × 300, wider past 24 points; a pie 420 × 300) · "title" (left out: the series by the label column, "Kitchen and Bath by Month"), "x title", "y title" · "legend": "right", "bottom", "top" or "none" · "colors": ["#4285f4", null] per series (null: the default) · the answer says what it draws (points, labels, each series' range, a pie's shares) and warns about a total row or column, or a column with no numbers; read with "chart" gives its points · &#123;"chart": &#123;"chart": 2, "type": "line"}} changes chart 2 · &#123;"chart": &#123;"chart": 2, "remove": true}}
Values: a number, true or false, null (empty), a string ("=…" is a formula: "=SUM(F2:F40)", "=[@Hours]*85", "=Tasks[Hours]"), &#123;"text": "=shown as typed"} or &#123;"date": "2026-10-19"}. |
| `expect` | object | Cells that must hold these values before the ops, as at base, or nothing applies: &#123;"Tasks!E17": "Open"}. Not what the ops should make: the answer shows that. |
| `note` | string | Why, in a few words. Shown with the change in the sheet and in changes. |
| `dryRun` | boolean | Work it out and answer, saving nothing. |
| `undo` | integer | Undo your own change that made this version, as one change. Goes alone: no base, ops or expect. |
| `key` | string | A retry key, up to 64 characters. Default: one made from the request, so the same request on the same version applies once. |

## check

**Check a sheet** · Reads only

Problems in a sheet, by rules: formula errors, a formula that breaks its column's pattern, a value typed over a column's formulas or a cell left empty among them, numbers or dates typed as text, and totals that stop before their column does.

| Parameter | Type | |
|---|---|---|
| `doc` (required) | string | The doc's link or 12-character code. |
| `sheet` | string | One sheet by name. Default: every sheet. |

## changes

**What changed in a sheet** · Reads only

What changed after a version, or since a time, oldest first: who, when, through what, with each cell old → new, named where it is now. Ends at the current version, to apply changes at. 50 changes unless "max" says, at most 200.

| Parameter | Type | |
|---|---|---|
| `doc` (required) | string | The doc's link or 12-character code. |
| `since` (required) | integer,string | A version (412), or a time in UTC: "2026-10-13" or "2026-10-13 09:00". |
| `max` | integer | At most this many changes. Default 50. |

## publish

**Publish a doc** · Changes docs

Publishes Markdown or HTML. A file with the same name in that place updates its doc (same link, a new History entry); otherwise it becomes a new doc. Unchanged content is skipped. A .csv becomes a new live sheet, typed as Excel opens it; after that it changes with apply, never by a file. Docs are private: only people in the workspace can open them. Set public: true only when the user clearly asked for a public link; if they didn't say, keep it private. Only a new doc can be public; an existing private doc is made public from Share in the Dockito app.

| Parameter | Type | |
|---|---|---|
| `name` (required) | string | The file name, with .md, .html or .csv: "plan.md". It titles the doc and matches it next time. |
| `content` (required) | string | The whole file. |
| `title` | string | A new doc's title. Default: the file name without its extension. An existing doc keeps its title; rename changes it. |
| `to` | string | "project" or "project/folder". Default: the workspace's Docs. Ask the user when a doc belongs in a project; never guess. |
| `workspace` | string | Workspace slug. Default: the only one, else the user's personal one. |
| `message` | string | Keep this entry as a saved point, with this note. |
| `public` | boolean | Anyone with the link can open it, no sign-in. Only when the user asked. Only for a new doc. |
| `doc` | string | Update this doc (link or code) instead of matching by name. |
| `new` | boolean | A new doc even if one with this name is there. |

## mkdir

**Make a project or folders** · Changes docs

Makes whatever is missing of "project/folder/subfolder": the project, then up to 2 levels of folders. Only when the user wants them.

| Parameter | Type | |
|---|---|---|
| `path` (required) | string | "project", "project/folder" or "project/folder/subfolder". |
| `workspace` | string | Workspace slug. Default: the only one, else the user's personal one. |

## move

**Move a doc or folder** · Changes docs

Puts a doc (by "doc") anywhere in its workspace, or a folder (by "folder", "project/folder") elsewhere in its project. The link stays the same. Who can open it follows where it sits: a move that would let more people open it is refused, naming them, and the user does it in the Dockito app; a move that shuts people out says who. Only when the user asks.

| Parameter | Type | |
|---|---|---|
| `doc` | string | The doc's link or 12-character code. |
| `folder` | string | A folder, "project/folder" or "project/folder/subfolder", instead of a doc. |
| `to` | string | Where it goes: "project" or "project/folder". Empty: the workspace's Docs (docs only). |
| `workspace` | string | Workspace slug. Default: the only one, else the user's personal one. |

## rmdir

**Remove an empty folder** · Changes docs

Removes an empty folder ("project/folder"). A folder with docs or folders in it stays, and nothing is deleted with it. Only when the user asks.

| Parameter | Type | |
|---|---|---|
| `folder` (required) | string | "project/folder" or "project/folder/subfolder". |
| `workspace` | string | Workspace slug. Default: the only one, else the user's personal one. |

## history

**History** · Reads only

A doc's History, newest first: entry number, when, who, from where (upload, edit, cli, mcp), saved points with their notes, and the git commit. A sheet's entries are how each editing session left it (its version, and everyone who changed it then); the sheet now is newer than its first entry.

| Parameter | Type | |
|---|---|---|
| `doc` (required) | string | The doc's link or 12-character code. |

## restore

**Restore an entry** · Changes docs

Makes an older History entry the current one, as a new entry. Nothing is lost. A sheet is made as it was then in one change, which apply with undo takes back.

| Parameter | Type | |
|---|---|---|
| `doc` (required) | string | The doc's link or 12-character code. |
| `entry` (required) | integer | The entry number from history. |

## save

**Keep a saved point** · Changes docs

Keeps a History entry (default: the current one; a sheet: as it is now) as a saved point, so History never drops it, with an optional note. A doc keeps up to 10.

| Parameter | Type | |
|---|---|---|
| `doc` (required) | string | The doc's link or 12-character code. |
| `entry` | integer | Default: the current entry. |
| `message` | string | A note for the saved point. |

## share

**Who can open a doc** · Changes docs

Says whether a doc is private (only people in its workspace) or public (anyone with the link). "private": true takes a public link back at once. An existing doc is made public only from Share in the Dockito app; a new doc can be published public when the user asks.

| Parameter | Type | |
|---|---|---|
| `doc` (required) | string | The doc's link or 12-character code. |
| `private` | boolean | Make it private now. |

## rename

**Rename a doc** · Changes docs

Changes a doc's title. Its link stays the same.

| Parameter | Type | |
|---|---|---|
| `doc` (required) | string | The doc's link or 12-character code. |
| `title` (required) | string | The new title, 1 to 200 characters. |

## What the server tells your AI

Every client receives these instructions when it connects:

```text
Dockito hosts Markdown and HTML docs, and live sheets, at a short link, with History.

workspace: a person's or a team's space. project: docs grouped in a workspace, with folders up to 2 deep. Docs: a workspace's docs outside any project. doc: one file; publishing a file with the same name to the same place updates that doc and keeps its link. History: every publish is an entry; a message keeps one as a saved point. A token has View, Publish or Everything per workspace.

- Nothing is remembered between calls. Call tree to see where docs can go and ls for what's in a place.
- Just a link to share: publish with no "to"; it goes to the workspace's Docs. When a doc belongs in a project, ask the user where, never guess, and pass "to" every time.
- Docs are private: only people in the workspace can open them. Set public: true (anyone with the link, no sign-in) only when the user clearly asked for a public link. If they didn't say, keep it private. Only a new doc can be published public.
- A doc is named by its link or its 12-character code.
- move puts a doc or folder in another place; its link stays. Who can open it follows where it sits, so a move that would let more people in is refused: the user moves it in the Dockito app. rmdir removes an empty folder.
- Deleting docs and sharing with people happen in the Dockito app, not here.

Sheets: people and agents edit the same cells, live; publishing a .csv makes a new one.
- get gives a sheet's outline (its sheets, columns and what's in them) and its version (v N). read gives rows; check finds broken formulas and typed-over cells; changes lists what changed since a version.
- apply changes it, with "base" set to the version you last read. Addresses and rows mean what they meant then, wherever they moved since. If someone changed the same cells meanwhile, nothing applies and the answer says who: read again, then apply with the new version.
- Change rows by what's in them, not by row number: update with a filter ("ID = T-104"), and "max" when you mean several rows.
- Dates: write {"date": "yyyy-mm-dd"}; the outline says which order the sheet shows them in. Formulas start with =.
```
