MCP task workflows
Read exact task history, post comments, save deliverables, and attach repository work.
Before changing a task, call list_tasks to find it and get_task_context to read its plan, checklist, relationships, and completion readiness. Move completed implementation to review; use done only when the user explicitly requests final completion.
Pencil injects workspace and caller identity. Do not supply workspaceId, orgId, or agentId. Reuse an idempotencyKey only when the tool schema accepts it, including post_comment, save_output, agent_update, ask_question, create_handoff, and create_handoff_action_item. Other writes, including create_task, are not guaranteed retry-safe.
Bounded task discovery
Use projection: "summary" with list_tasks or list_assignee_tasks when finding work. The default preview projection includes up to 500 description characters and a descriptionTruncated flag. Use get_task for full text. Titles and expanded related-object names are bounded to 240 characters; expanded assignee teams are capped at 10 and report teamsTruncated.
Both projections include historyCoverage (complete, partial, or unavailable). Pages have a 48 KiB JSON response budget and can contain fewer rows than limit. Continue using nextCursor until hasMore is false. Keep the same filters and caller; changing either invalidates the cursor. Cursors issued by the older format must be restarted. Results use current updated-time order, so concurrent edits can move rows between pages; they are not a snapshot.
Structured handoffs
Use create_handoff instead of a task for session handover. Supply teamId, completed, inProgress, blockers, and nextSteps; each body supports up to 4000 characters. The author is the authenticated human. Source and destination timezones default to team timezoneA and timezoneB; override them explicitly for the reverse shift. The default date is the current date in the source timezone.
{
"name": "create_handoff",
"arguments": {
"teamId": "your-team-id",
"completed": "Released and verified the API change.",
"inProgress": "Monitoring rollout.",
"blockers": "",
"nextSteps": "Review the next metrics window.",
"idempotencyKey": "api-rollout-session-2026-09-22"
}
}
list_handoffs supports team, author, recipient, and inclusive since/until date filters and returns metadata. get_handoff returns the bodies, accessible linked-task IDs, and the first action-item page. Use list_handoff_action_items with the same handoff ID to continue; use get_handoff_action_item for full action-item details. Action-item lists can also use a team ID and date.
One handoff exists per author/team/date. A separate create for that slot returns HANDOFF_ALREADY_EXISTS; amend it with update_handoff. Both update tools require expectedUpdatedAt from a fresh read. Omitted fields stay unchanged; null clears documented optional fields. Updates to entry bodies require the original author; action items follow team permissions.
Use the same retry key and identical arguments after an uncertain create result. A changed payload with an existing key returns IDEMPOTENCY_CONFLICT. Keys persist for the workspace lifetime. A late retry returns the original identity without overwriting later edits. Recipient emails and in-app notifications are opt-in through sendEmail and sendNotification; action-item assignee notifications follow normal team behavior.
These tools require OAuth or a paired gateway user. API-key and autonomous-agent callers receive HUMAN_IDENTITY_REQUIRED. Team access, enabled settings, and linked-task visibility still apply.
Task lifecycle history
list_task_events returns persisted source facts for human/agent assignment changes, workflow-status transitions, and blocker-count changes. Events are written in the same Convex transaction as the task mutation and returned oldest-first, with an immutable event id as the timestamp tie-breaker. occurredAt and the task's canonical createdAt are serialized as UTC ISO-8601 strings.
Every request must be bounded by taskId, humanAssigneeId, agentAssigneeId, or both since and until. since is inclusive, until is exclusive, limit is capped at 100, and cursor is an opaque value from the previous response. A response includes nextCursor, hasMore, and coverage.
{
"name": "list_task_events",
"arguments": {
"taskId": "T-123",
"eventTypes": ["assignment_changed", "status_changed", "blocker_changed"],
"since": "2026-08-01T00:00:00Z",
"until": "2026-09-01T00:00:00Z",
"limit": 50
}
}
get_task exposes only a bounded lifecycle summary: coverage, canonical creation time, latest event time, current status and assignees, and exact event count. Detailed events stay behind list_task_events.
Coverage is complete only for tasks created after exact tracking began. Pre-migration tasks expose their real createdAt and current state but report partial or unavailable history. Pencil never derives lifecycle events from updatedAt, current status or assignment, comments, activity-feed text, files, or polling snapshots.
Human owners and agents remain separate. Use humanAssigneeId in assign_task, create_task, or update_task; pass null through assign_task or update_task to clear the human owner. The REST POST /api/v1/tasks and PATCH /api/v1/tasks/{id} endpoints use the same humanAssigneeId field.
Examples
List in-progress tasks:
{
"name": "list_tasks",
"arguments": { "status": "in_progress" }
}
Post a task comment:
{
"name": "post_comment",
"arguments": {
"taskId": "task_123",
"content": "**Update**\n- Tests are passing."
}
}
Save a deliverable:
{
"name": "save_output",
"arguments": {
"taskId": "task_123",
"name": "audit.md",
"content": "# Audit\n\nFindings..."
}
}
Attach repository work immediately after pushing a branch. Include prUrl
when a pull request exists; calling the action again for the same task, repo,
agent, and branch updates the existing link instead of creating a duplicate.
Use list_task_repos when task context did not supply the internal repoId.
Neither report_repo_status nor a URL pasted into chat creates this link.
{
"name": "propose_repo_change",
"arguments": {
"repoId": "repo_123",
"taskId": "task_123",
"branch": "agent/orion/mc-123-fix-login",
"targetBranch": "main",
"title": "Fix login redirect",
"summary": "Updates the redirect guard and adds a regression test.",
"prUrl": "https://github.com/acme/app/pull/42"
}
}
What to try next
Review MCP tools and permissions before enabling more tools.