Tool reference
Twenty-seven tools over MCP. Names use underscores; the same capabilities are on the REST API with dotted names.
Reading
| Tool | Arguments | What it does |
|---|---|---|
project_list | {} | Every project in the workspace, with status, next step and public URL. |
project_resume | { project } | The whole document in one call — purpose, architecture, features, roadmap, tasks, activity, decisions, feedback, people, plus the page URL and an inbox of answered and open questions. Call this first. |
task_list | { project, state? } | The work list, with each task's key. |
feature_list | { project } | Every feature with the key feature_upsert takes. Call it before editing a feature on a project you did not create — guessing the key makes a duplicate. |
theme_get | { project } | Preset, overrides, the stored CSS verbatim, resolved token values, and every token you may override. Read this before theme_set. |
feedback_list | { project, state?, kind? } | What stakeholders asked for, highest-voted first, with a count of what is still unanswered. |
Writing
Every write requires a token with write scope, and is logged and revertable.
| Tool | Arguments | What it does |
|---|---|---|
project_ensure | { name, slug?, summary? } | Idempotent — returns the existing project if the slug is taken, and the page URL either way. |
project_import | { project, …state, purpose?, architecture?, roadmap?, features[]?, tasks[]?, updates[]?, theme?, visibility?, ifRevision? } | The whole document in one call. Use it for a first import instead of thirty separate writes, and for bulk corrections after. A bad row is reported in refused; the rest still lands. |
status_set | { project, status, note? } | Moves the standing. Pass a note; a status change with no reason is noise. |
next_set | { project, next, owner? } | Exactly one next step. |
update_create | { project, title, body?, tags?, kind?, statusChange?, happenedAt?, links? } | An update, or a decision with kind: "decision". Pass happenedAt (ISO 8601, past only) when writing up work that already happened, or a year of history all reads as minutes old. |
feature_upsert | { project, key, name, state?, area?, version?, owner?, summary?, detail?, shipped?, links?, question? } | A capability someone could have an opinion about. Keyed, so it edits rather than duplicates. |
task_upsert | { project, key, title, state?, detail?, area?, owner?, internal?, links?, question? } | A job on the list. No task appears on the published page, so internal is a marker for chores rather than a visibility control. |
task_delete | { project, key } | For a duplicate or one created in error. |
feature_delete | { project, key } | For a feature that should not exist. Mis-filed work should use feature_to_task instead. |
update_delete | { project, at?, title? } | For something posted in error. Identify it by at, the exact timestamp from project_resume; an ambiguous title is refused rather than guessed at. |
project_ask | { project, question } | A question about the project itself rather than any one piece of work — instead of inventing a task to hang it on. |
feedback_to_task | { project, id, title?, state? } | Turns feedback into work, keeping the trace back to who asked. Does not reply — follow it with feedback_reply. |
feature_to_task | { project, feature } | Reclassify build work that was filed as a feature. Nothing is lost. |
purpose_set | { project, why?, who?, success?, constraints?, ifRevision? } | Merges into the purpose section. |
architecture_set | { project, summary?, services?, entrypoints?, environments?, integrations?, conventions?, openQuestions?, ifRevision? } | Merges into architecture. Provenance is stamped from the token. |
roadmap_set | { project, doing?, planned?, considering?, ifRevision? } | Each bucket you pass replaces that bucket. |
theme_set | { project, preset?, css?, overrides?, fonts?, dryRun?, ifRevision? } | Styling. fonts is { display, body } from theme_get's fontsAvailable — self-hosted, so an arbitrary family is refused. css replaces the stored stylesheet rather than merging: read theme_get first. dryRun resolves without saving. |
logo_set | { project, url, alt? } | Copies an image to Ticulate and shows it above the project name. Copied rather than linked, so the page never fetches from another host and it survives the original moving. url: null removes it. |
publish_set | { project, visibility } | private, shared or public. Returns the URL. Ask first. |
feedback_reply | { project, id, text, state? } | Answers on the object the feedback was left on. |
review_open | { project, feature, ask } | Asks stakeholders a specific question about something you shipped. |
Values that are fixed
status | shipped ontrack atrisk blocked idle |
visibility | private shared public |
feature state | live building beta deprecated |
task state | open doing done |
feedback state | triaged planned review answered declined |
theme preset | ticulate terminal editorial blueprint |
ontrack and atrisk have no space and no underscore. An unknown value is refused with an error naming the legal ones.
Tuple shapes in architecture_set
Order matters.
services: [["name", "what it does", "language", "repo", "runs on"]]
entrypoints: [["label", "path", "why it matters"]]
environments: [["name", "url", "branch", "note"]]
openQuestions: [["the question", "what it is blocked on"]]
integrations: ["Stripe", "GitHub"]
conventions: ["Every agent write carries an actor and a revision"]Errors worth handling
| Message | What to do |
|---|---|
| No project "x" in this workspace | project_list, or project_ensure to create it |
| This token is read only | Stop, and ask for a write token rather than working around it |
| Token rejected | Revoked or wrong — a new one is needed |
| The project moved on while you were working | Resume again, merge into what is there now, retry — see several agents at once |
| This token is scoped to a single project | It was issued for one project and cannot reach others. project_list shows which |
| "x" is archived | Someone took the project down. It has to be restored before it accepts writes |