Agents

Agents and MCP

Cotask exposes one endpoint that any AI assistant can use as a tool. It speaks MCP (the Model Context Protocol) and plain REST, at the same base, with the same permissions.

https://usecotask.com/mcp

Two ways to authorize, and the endpoint accepts either:

  • Sign in (OAuth 2.1) — for ChatGPT, Claude and any MCP client with a connector UI. Nothing to paste; you approve on Cotask's own consent screen.
  • An agent key — for terminals, scripts and Claude Code. A pl_… key you create in the app.

Whatever an agent creates lands in Drafts with the assistant's name and logo on it, until you accept it.

Connect ChatGPT or Claude (no key)#

  1. In the app: Settings → Agents → copy the MCP server URL.
  2. In ChatGPT or Claude: Settings → Connectors → Add custom connector (the wording differs a little per client) and paste the URL.
  3. The client discovers everything and sends you to Cotask's consent screen. Sign in with your Cotask account and approve.
  4. Ask for something: "look at my Cotask tasks and plan my week." Suggestions arrive in Drafts.

Access tokens last an hour and refresh tokens rotate on every use, so the connection keeps working without asking you again. Revoking is a matter of removing the connector in the client.

Connect Claude Code, a terminal or a script#

  1. Settings → Agents → New agent key, name it after the tool ("Claude Code"), and copy the key — pl_…, shown once and never again.
  2. Add the server:
claude mcp add --transport http cotask \
  https://usecotask.com/mcp \
  --header "Authorization: Bearer pl_your_key"

Any MCP client that takes a JSON config wants the same three things — an HTTP transport, the URL, and the header:

{
  "mcpServers": {
    "cotask": {
      "type": "http",
      "url": "https://usecotask.com/mcp",
      "headers": { "Authorization": "Bearer pl_your_key" }
    }
  }
}

Keys are stored hashed — Cotask cannot show you one again. Each key lists its prefix and when it was last used, so an unfamiliar one is easy to spot and swipe away. Deleting a key cuts that agent off immediately; nothing it created is touched.

The tools#

ToolDoesTakes
list_tasksLists tasks with their attachmentsstatus, project (id or name), priority, reminder (any · urgent · notify · none), query (title substring), limit (default 200, max 500)
get_taskOne task, with notes, reminder and attachmentsid
create_taskCreates a task — a draft by defaulttitle (required), notes, status, project, due_date, priority, recurrence, remind_at, remind_in, urgent, reminder_kind, time_zone, blocked_by, attachments
update_taskChanges only the fields passedid (required), plus any of title, notes, status, project, due_date, priority, recurrence, remind_at, remind_in, urgent, reminder_kind, time_zone, blocked_by — null clears the optional ones. Also completion_note, the note of completion
complete_taskMarks a task done, with an optional note of completion — notes are never touchedid (required), note (Markdown; left out, null or blank completes with no note)
set_reminderSets, moves or clears when a task rings — and how loudlytask_id (required), remind_at, remind_in, urgent, reminder_kind, time_zone
delete_taskRetracts a suggestion — drafts onlyid
add_attachmentAttaches a link; the title and favicon are resolved server-sidetask_id, url, title (optional)
attach_fileAttaches a file — bytes or a URL to fetchtask_id, one of data (base64, ≤ 8 MB) or source_url (≤ 25 MB), file_name, content_type, title
remove_attachmentRemoves a link or file (and deletes the stored file)id
list_projectsThe user's projects—
create_projectCreates a projectname, color (gray, red, orange, yellow, green, teal, blue, indigo, purple, pink)
list_delegate_routesYour Delegate to AI routes — never where a webhook posts—
delegate_taskDelegates a task through a route, like the button: it starts (Doing, due today); a Mac route answers with its dispatch_id and whether a Mac is listeningtask_id, route (id or name), message, params (add only), send_at / send_in
get_delegationHow a delegation is going: a run's status, stage, error and result, or a send still waitingid (dispatch_id or scheduled.id)

Every tool carries MCP annotations — readOnlyHint and openWorldHint on all of them, plus destructiveHint and idempotentHint on the ones that write — and a description on every property, so a model knows what is safe without being told in a prompt.

Delegating is there for when you ask for it — "send this to Claude Code on my Mac" — and only through the routes you set up, as you set them up. See Delegate to AI.

Reminders, for agents#

An agent asked to remind you of something has no clock of yours and no idea where you are, so it is met more than half way. set_reminder is the direct way in — the same fields also live on create_task and update_task.

FieldWhat it takes
remind_at2026-09-01T09:00:00-03:00, or 2026-09-01T09:00 read on your own clock, or 2026-09-01 for 09:00 that morning, or a delay: 45m, 2h, 1h30m, 3d. null clears the reminder
remind_inJust the delay: 45m, 2h. For "in an hour" — needs no clock and no time zone. Wins over remind_at
urgenttrue for the alarm that rings through silent mode and Focus; false (the default) for an ordinary notification
reminder_kindThe long form of urgent: notify or alarm
time_zoneAn IANA name, to read a zone-less remind_at somewhere else — "9am in Tokyo" is Asia/Tokyo

Your iPhone records its own time zone to your account, which is what a timestamp with no zone is read on; until a phone has signed in, that is UTC. Two things are refused rather than written and never rung: a kind with no moment to ring at, and a moment that has already gone by — and the refusal says what time it is where you are, which is usually what the agent was missing.

Every task comes back with a reminder object as well as the raw columns:

"reminder": {
  "at": "2026-09-01T12:00:00.000Z",
  "kind": "alarm",
  "urgent": true,
  "local_time": "Tue, 1 Sep 2026, 09:00 (America/Sao_Paulo)",
  "relative": "in 2 days",
  "has_passed": false
}

Tasks with no reminder have "reminder": null. An agent should only reach for urgent when you asked for something urgent; see Reminders.

What agents may not do: delete a task you accepted, remove an attachment you added to a task you accepted, delegate a task — to any route, now or later — create a Mac route or change how one runs, see or change a route's token or secret, or delete your account. Those are yours, and need you signed in to the app: holding an agent key yourself does not count.

Pro, for agents. An agent works inside your plan. Setting a reminder, a blocker or a note of completion, or uploading past your storage, on a Free account answers 402 — "… requires Cotask Pro. Upgrade in the app to continue." Everything already there stays readable, and clearing a value is always allowed.

Notes formatting#

Notes are plain text with light Markdown. The apps render:

  • line breaks, exactly as written
  • - bullets and 1. numbered lists
  • [text](https://…) links, and bare https://… URLs
  • inline **bold**, *italic* and code in backticks

They do not render headings, block quotes, code fences, tables or images. This spec is repeated in the MCP server's instructions and on the notes property of create_task and update_task, so an agent finds it wherever it looks.

For sources, attach the page instead of pasting a long URL into the notes: an attachment shows the page title and favicon and is fetchable later. For things an agent produced — a report, a chart, a CSV — use attach_file.

Note of completion#

An agent that finishes a task can say what it did and where the result is. complete_task is the direct way — it marks the task done and leaves the note in one call:

{ "id": "…", "note": "Completed, appended to doc: [Q3 plan](https://…)" }

update_task does the same with status and completion_note:

{ "id": "…", "status": "done", "completion_note": "Completed, appended to doc: [Q3 plan](https://…)" }
  • It is a field of its own, completion_note — separate from notes, which stay your brief and are never touched by it. Every task comes back with it (null when there is none).
  • It is Markdown, stored exactly as written — nothing is trimmed, shortened or rewritten.
  • Agents can always leave one. Completion notes — iPhone → Settings → Delegate to AI, Mac → Settings → Agents; off by default — only decides whether the apps show it: both tools offer the field whatever it says, and a note written while it is off is kept and appears once it is turned on. Writing one is part of Pro.
  • You can leave one too, with it on: on the Mac, ⇧⏎ completes the selected task and asks for its note (esc skips, ⌘⏎ saves; on a task that is already done it opens the note to edit); on the iPhone, press and hold a task's circle.
  • It belongs to the completion: update_task accepts it together with status: "done" or on a task that is already done, and refuses it on any other. Reopening the task clears it, whoever reopens it and from wherever — that is done in the database.
  • Each complete_task call is a completion of its own: with no note, a note left by an earlier completion is cleared; null or a blank string clears it explicitly.
  • On a done task update_task changes it on its own: pass a new completion_note to replace it, null (or a blank string) to clear it, or leave it out to keep it.

The same field is accepted by PATCH /tasks/:id on the REST API.