Taskbead

Simple to-do lists for students and teams: let your AI assistant list, search, add, update and complete your tasks.

Hosted MCP Server

npx add-mcp 'https://taskbead.com/mcp'

Installs into Claude Code, Codex, Cursor and more

Documentation

What agents can do

Taskbead is a calm, simple to-do list for students and teams. An agent is any AI assistant or program you connect to your account: Claude, ChatGPT, Cursor, VS Code, an automation tool or your own script. It works as you, within the limits you choose:

  • See your workspaces and tasks, and search them by title or notes.
  • Add tasks (with a due date, notes, a workspace or a parent task), update them, mark them done or not done, and comment.
  • Work on tasks you hand to it, and report back as working, needs you or done.

An agent can't delete tasks, share them, invite people, change your settings, manage keys or make payments. Every change it makes shows in the activity log as " your name via app name " with a bot label.

Connecting agents and API keys works on every plan, including Free. Webhooks (instant notifications to an agent) are part of Plus and Team.

Quick start

  1. In your AI app, add a remote MCP server with this address: https://taskbead.com/mcp
  2. The app opens Taskbead. Sign in if you aren't already (Telegram, Google or an email link).
  3. On the approval screen, choose what it can see, then tap Allow.
  4. Ask something like "What's due this week in Taskbead?"

For scripts and automations, use an API key with the REST API or the same MCP address.

Connect an app

Server URLhttps://taskbead.com/mcp
TransportStreamable HTTP: JSON-RPC 2.0 over HTTPS POST, JSON responses (no event stream). Batches of up to 20 messages.
Protocol versions2025-06-18, 2025-03-26, 2024-11-05
Sign-inOAuth 2.1 with PKCE (S256) and dynamic client registration, or Authorization: Bearer tbk_… with an API key

The menus in each app change from time to time. If a step below looks different, look for "connectors", "MCP servers" or "tools" in the app's settings.

Claude

  1. Open Claude's settings and find Connectors.
  2. Choose Add custom connector, name it "Taskbead" and paste https://taskbead.com/mcp.
  3. Select Connect. Taskbead opens: sign in, choose what Claude can see, and tap Allow.
  4. In a chat, turn the Taskbead connector on from the tools menu and ask about your tasks.

Claude Code: claude mcp add --transport http taskbead https://taskbead.com/mcp, then run /mcp in Claude Code to sign in.

ChatGPT

Where your ChatGPT plan offers it, turn on developer mode in the apps or connectors settings, then create a connector with the URL https://taskbead.com/mcp and OAuth sign-in. ChatGPT opens Taskbead to sign in and approve. Taskbead isn't listed in the ChatGPT app directory yet.

Cursor

Add this to ~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project), then open the MCP settings and sign in when Cursor asks:

{
  "mcpServers": {
    "taskbead": { "url": "https://taskbead.com/mcp" }
  }
}

VS Code

Add this to .vscode/mcp.json (or run MCP: Add Server and choose HTTP), then start the server and sign in when asked:

{
  "servers": {
    "taskbead": { "type": "http", "url": "https://taskbead.com/mcp" }
  }
}

Other MCP clients

Any client that supports remote servers over Streamable HTTP with OAuth works: it discovers the sign-in from the 401 response (WWW-Authenticate: Bearer resource_metadata=…) and registers itself. If your client can't do OAuth but can send headers, create an API key and send Authorization: Bearer tbk_….

Discovery documents: /.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server, and a static server card at /.well-known/mcp/server-card.json.

The sign-in and approval screen

After you sign in, Taskbead shows "Connect app to Taskbead?" with what the app will be able to do, a choice of what it can see, and Allow / Cancel. Cancel sends the app an access_denied error and nothing is connected.

Connected apps get an access token that lasts 30 days and is renewed with a refresh token, so you don't have to sign in again. You can keep up to 10 connected apps; connecting an 11th removes the oldest. Disconnect any app in Settings > Agents and API keys.

Access and reach

Two separate choices control what an agent can do and see.

Access: read only or read and write

  • Read and write: can list and search, and also add, update, complete and comment.
  • Read only: can list and search only. Writes fail with 403 "This key is read-only."

You choose this when you create an API key. Connected apps (OAuth) always have read and write access; use the reach setting to limit them.

Reach: only tasks given to it, or all my tasks

  • Only tasks given to it (the default for new keys and apps): it sees only the tasks you hand to it. It can't add new tasks.
  • All my tasks: it sees every task you can see, and can add tasks and plan your whole list.

Choose it on the approval screen or when creating a key, and change it any time in Settings > Agents and API keys. API keys can also be limited to one workspace.

Assigning tasks to agents

Hand a task to an agent like you'd hand it to a coworker: open the task, use Assign to, and pick it under Your agents. Your API keys and connected apps are listed there. Agents don't take a seat on Team.

  • Only the person a task is with can hand it to an agent: the person it's assigned to, or the owner when nobody is. You can only pick your own agents.
  • Agents can't hand tasks to other agents.
  • Assigning the task to a person, taking it back, or revoking the agent takes the task back from the agent.

Status

The agent reports with set_agent_status (MCP) or POST /api/v1/tasks/:id/status (REST). The task shows a status chip:

StatusMeaningYou get a ping
workingIt has started. Clears quietly after a day without news.No
needs_youIt needs your input; the question is in the note or a comment.Yes, once
doneIts part is finished; the result is in a comment or the notes.Yes, once

Pings arrive in Telegram or as a push notification, once per task per status; handing the task over again resets that. done doesn't tick the task off: you mark it done yourself when you're happy with the result.

When does the agent find out?

Taskbead doesn't run AI itself. A chat app like Claude or ChatGPT picks up its tasks when you open it and ask (for example "do my Taskbead tasks"). A script or automation finds them when it next checks GET /api/v1/tasks?agent=me, or at once with a webhook on Plus and Team.

API keys

API keys are for scripts, automations and MCP clients that can send a header. Keys live in Settings > Agents and API keys, which shows in Pro mode: use Switch to Pro in the menu (Pro mode is free on every plan).

  1. Enter a name (for example "My script"). It's how the key's changes are labelled.
  2. Choose access (Read and write or Read only), reach (Only tasks given to it or All my tasks) and a workspace (or All workspaces).
  3. Select Create API key and copy the key (tbk_…). It's shown once; Taskbead stores only a hash.
PlanAPI keys
Free2
Plus and Team10

Connected apps (OAuth) don't count toward these limits.

Revoking: select Revoke next to the key (or Disconnect for a connected app). It stops working at once, any webhook deliveries waiting for it are dropped, and tasks handed to it come back to you.

REST API reference

Base URL https://taskbead.com/api/v1. Send Authorization: Bearer tbk_… on every request and JSON bodies with Content-Type: application/json. Responses are JSON. Dates are ISO 8601 (UTC in responses). IDs are integers.

Method and pathWhat it does
GET /workspacesYour workspaces
GET /tasksOpen tasks. Query: workspace_id, include_done=1, limit (1–200, default 50), q (search title and notes)
GET /tasks?agent=meTasks handed to this key, with notes and the latest comments (up to 20). Add include_done=1 for finished ones
POST /tasksAdd a task: title (required, up to 300 chars), workspace_id, due, notes, parent_id
POST /tasks/:idUpdate: title, notes, due (or null to clear), workspace_id
POST /tasks/:id/doneMark done; send {"done": false} to reopen
POST /tasks/:id/commentsComment: text (required, up to 2,000 chars)
POST /tasks/:id/statusAgent status on a task handed to this key: status (working, needs_you or done), optional note (posted as a comment)

Examples

export TB=tbk_your_key_here

curl -s https://taskbead.com/api/v1/workspaces -H "Authorization: Bearer $TB"
{"workspaces":[{"id":615,"name":"School","icon":null},{"id":616,"name":"Personal","icon":null}]}
curl -s "https://taskbead.com/api/v1/tasks?workspace_id=615&limit=2" -H "Authorization: Bearer $TB"
{"tasks":[{"id":4821,"title":"Biology lab report","workspace_id":615,"done":false,"due":"2026-10-28T09:00:00.000Z",
  "parent_id":null,"bucket_id":null,"comments":1}],"total":1}

A task handed to an agent also has agent (its name) and agent_status.

curl -s https://taskbead.com/api/v1/tasks -H "Authorization: Bearer $TB" -H "Content-Type: application/json" \
  -d '{"title":"Read chapter 4","workspace_id":615,"due":"2026-10-30T01:00:00Z","notes":"Pages 88-121"}'
{"id":4822,"ok":true}
curl -s https://taskbead.com/api/v1/tasks/4822 -H "Authorization: Bearer $TB" -H "Content-Type: application/json" -d '{"due":null}'
# {"ok":true,"id":4822}

curl -s https://taskbead.com/api/v1/tasks/4822/done -H "Authorization: Bearer $TB" -H "Content-Type: application/json" -d '{}'
# {"ok":true,"id":4822,"done":true}

curl -s https://taskbead.com/api/v1/tasks/4822/comments -H "Authorization: Bearer $TB" -H "Content-Type: application/json" -d '{"text":"Started"}'
# {"ok":true,"id":991}
curl -s "https://taskbead.com/api/v1/tasks?agent=me" -H "Authorization: Bearer $TB"
{"tasks":[{"id":4821,"title":"Biology lab report","workspace_id":615,"done":false,"due":"2026-10-28T09:00:00.000Z",
  "parent_id":null,"bucket_id":null,"comments":1,"agent":"My script","agent_status":null,"notes":"Include the graph",
  "shared_by":null,"latest_comments":[{"by":"Alex","text":"Use last week's data","at":"2026-10-26T04:10:00.000Z"}]}],"total":1}
curl -s https://taskbead.com/api/v1/tasks/4821/status -H "Authorization: Bearer $TB" -H "Content-Type: application/json" \
  -d '{"status":"needs_you","note":"Which experiment should the graph show?"}'
# {"ok":true,"id":4821,"status":"needs_you"}

MCP tools reference

Every tool has a title and readOnlyHint, destructiveHint (always false) and openWorldHint (always false) annotations. Results come back as structuredContent and as JSON text; errors come back with isError: true and a plain message. Output shapes match the REST responses above.

ToolInputsReturns
list_workspaces readnone{workspaces: [{id, name, icon}]}
list_tasks readworkspace_id?, include_done?, limit? (1–200){tasks: [task], total}
search_tasks readquery, workspace_id?, include_done?{tasks: [task], total}
list_assigned readinclude_done?{tasks: [task + notes, shared_by, latest_comments], total}
add_tasktitle, workspace_id?, due? (ISO 8601), notes?, parent_id?{id, ok}
update_tasktask_id, title?, notes?, due? (or null), workspace_id?{ok, id}
complete_tasktask_id, done? (default true){ok, id, done}
add_commenttask_id, text{ok, id}
set_agent_statustask_id, status (working, needs_you, done), note?{ok, id, status}

task is {id, title, workspace_id, done, due, parent_id, bucket_id, comments}, plus agent and agent_status when it's handed to an agent.

The server's instructions tell the assistant the usual flow for handed-over work: list_assigned → set_agent_status working → post the result with add_comment → set_agent_status done (or needs_you with a question).

curl -s https://taskbead.com/mcp -H "Authorization: Bearer $TB" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_tasks","arguments":{"query":"lab report"}}}'

Webhooks (Plus and Team)

A webhook lets a script or automation start the moment you hand it a task, instead of checking on a schedule. Webhooks belong to API keys; connected chat apps like Claude and ChatGPT pick up work when you open them.

Set up

  1. In Settings > Agents and API keys, enter an address under the key's Webhook and select Save.
  2. Copy the signing secret (whsec_…). It's shown once.
  3. Use Send test to send a ping. New secret replaces the secret (the old one stops working at once); Remove deletes the webhook.

The address must be https:// on port 443, without a user name or password, up to 500 characters, and on a public server (private networks and local names are refused, and the name is checked in DNS when you save).

Events

Events are about tasks handed to that key. A change the key made itself isn't sent back to it.

EventWhen
task.assignedA task is handed to the key
task.unassignedThe task is taken back, given to another agent or assigned to a person
comment.addedSomeone comments on the task
task.updatedThe task's title, notes, due date or other details change
pingYou select Send test

Request

POST /your/path HTTP/1.1
Content-Type: application/json
User-Agent: Taskbead-Webhooks/1
X-Taskbead-Event: task.assigned
X-Taskbead-Delivery: dlv_1234
X-Taskbead-Timestamp: 1793000000
X-Taskbead-Signature: t=1793000000,v1=5f2b…

{"event":"task.assigned","created_at":"2026-10-26T05:40:00.000Z","task":{"id":4821,"title":"Biology lab report","due":"2026-10-28T09:00:00.000Z"}}

comment.added also has "comment":{"id":991}. ping has only event and created_at. Nothing else about you is sent: fetch details with your key through the API.

Verify the signature

v1 is the hex HMAC-SHA256 of t + "." + raw body with your signing secret. Use the raw body exactly as received, compare in constant time, and reject old timestamps (for example older than 5 minutes).

// Node.js (Express)
const crypto = require('crypto');
app.post('/taskbead', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.get('X-Taskbead-Signature') || '';
  const t = (sig.match(/t=(\d+)/) || [])[1], v1 = (sig.match(/v1=([0-9a-f]{64})/) || [])[1];
  const want = crypto.createHmac('sha256', process.env.TASKBEAD_WEBHOOK_SECRET).update(\`${t}.${req.body}\`).digest('hex');
  const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
  if (!t || !v1 || !fresh || !crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(want))) return res.sendStatus(401);
  const event = JSON.parse(req.body);
  res.sendStatus(200); // answer fast, then do the work
});
# Python (Flask)
import hmac, hashlib, os, re, time
from flask import Flask, request, abort
app = Flask(__name__)

@app.post("/taskbead")
def taskbead():
    sig = request.headers.get("X-Taskbead-Signature", "")
    t = re.search(r"t=(\d+)", sig); v1 = re.search(r"v1=([0-9a-f]{64})", sig)
    if not t or not v1 or abs(time.time() - int(t.group(1))) > 300:
        abort(401)
    body = request.get_data()  # raw bytes
    want = hmac.new(os.environ["TASKBEAD_WEBHOOK_SECRET"].encode(), t.group(1).encode() + b"." + body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(v1.group(1), want):
        abort(401)
    event = request.get_json()
    return "", 200

Delivery, retries and auto-disable

  • Any 2xx answer within 5 seconds counts as delivered. Redirects aren't followed.
  • A failed delivery is retried up to 5 tries in all, about 5, 10, 20 and 40 minutes apart. Undelivered events are dropped after 2 days.
  • After 10 failed attempts in a row, the webhook turns off. You get one notification, the activity log notes it, and Settings shows why; select Turn back on when your server is fixed.
  • Limits per key: 30 deliveries a minute (extra ones wait a minute) and 500 events a day.
  • Deliveries can repeat or arrive out of order; use X-Taskbead-Delivery to skip duplicates.

Rate limits and errors

LimitValue
Requests per key or connected app60 a minute
Requests per network (IP address)600 a minute
OAuth client registrations10 a minute per network
OAuth token requests30 a minute per network
Webhooks30 deliveries a minute and 500 events a day per key

Fair-use limits of your plan (tasks, uploads and so on) apply as in the app.

StatusMeaning
400Bad input, e.g. "A title is needed.", "due must be an ISO date-time."
401Missing, wrong, revoked or expired key: "Sign in with an API key or connect with OAuth."
403Not allowed, e.g. "This key is read-only.", adding a task with "Only tasks given to it", or a status on a task that isn't handed to you
404"Task not found." (also when it's outside the key's reach or workspace)
409The task has open subtasks; complete them first
429Too many requests; wait a minute (Retry-After: 60)

REST errors are {"error": "message"}. Over MCP, a failed tool call returns isError: true with the message; protocol errors use JSON-RPC codes (-32700, -32600, -32601, -32602).

Activity log and undo

Every change an agent makes is recorded on the task and in the Activity log (in Pro mode), labelled " your name via app name " with a bot badge. Comments by an agent carry the same label. Hand-offs, status reports and webhook changes show there too.

You can undo your own edits from the log: a rename, notes, a due date, a move to another workspace or bucket, and marking done or reopening. That includes changes your agents made for you.

Troubleshooting and FAQ

"Sign in with an API key or connect with OAuth."

The app isn't signed in, or its key was revoked or expired. Connect again, or create a new key.

The agent sees no tasks.

It's set to "Only tasks given to it". Hand it a task from Assign to, or switch it to "All my tasks" in Settings.

"This app only works on tasks given to it."

Agents with that reach can't add tasks. Switch it to "All my tasks" if you want it to.

I can't find Agents and API keys.

Switch to Pro mode from the menu; the section is in Settings.

The approval screen says the connection link isn't valid.

Start the connection again from your AI app. If it keeps happening, remove the connector in the app and add it again.

My webhook turned off.

Your server failed 10 times in a row. Settings shows the reason (for example "no answer within 5 seconds"). Fix it, then select Turn back on and Send test.

Does an agent cost a seat?

No. Agents act for you and don't count as people.

Can an agent delete my tasks?

No. No tool or endpoint deletes, shares or changes settings.