MCP abilities

Add Note

lh-tasks/add-note

Adds a note to the progress log of a task without claiming it, so context can be added to a task you are not working on. Does not change status, claim or assignment, and works on any status, including finished tasks. The note shows in the progress_log returned by get-task as event "note" with the time and who added it. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
task_idintegerYesThe task to add the note to.
notestringYesPlain text, up to 4000 characters, stored exactly as written: line breaks and angle brackets are kept, and the note is escaped wherever it is shown.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Claim Next Task

lh-tasks/claim-next-task

Atomically claims the next eligible task for the calling account and returns it with a claim_token. It picks the highest priority first (urgent, high, normal, low), then the oldest, optionally narrowed to a queue and/or task type. Tasks still waiting on a blocked_by prerequisite are skipped. If task_id is given, atomically claims that specific task instead. A candidate is eligible if it is unassigned, or hard-assigned to the calling account – tasks assigned to someone else are skipped, not errored. Returns claimed:false with a reason when nothing was claimed – safe to poll repeatedly. Returns the task's title, description (also as Markdown) and payload, with a claim_token that must be passed to complete-task/fail-task/reassign-task/renew-claim for this task. Pass task_id and claim_token to the write abilities you call while working on it too: a call is then refused if the claim has been lost, and a successful one keeps the claim alive. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
queuestringNoQueue/lane slug to claim from. Omit to claim from any queue. Ignored if task_id is given.
task_typestringNoOnly claim tasks of this task type slug, e.g. "bug_fix". Omit for any type. Ignored if task_id is given.
task_idintegerNoClaim this specific task instead of the next eligible one. Still goes through the same atomic claim, assigned_to and blocked checks – returns claimed:false with a reason rather than an error if the task is not currently claimable.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Complete Assigned Task

lh-tasks/complete-assigned-task

Marks a task assigned to you done without a claim token, as the Mark as done button on the task page does. Use it only when the person the task is assigned to has confirmed in this conversation that the work is done: one task per call, never to clear a backlog. If someone else asked for the task it goes to Awaiting review for them to accept or send back; otherwise it is Resolved. A note saying what was done is required, and the progress log records that the task was closed through MCP. Fails unless the task is open, not waiting on a prerequisite or a review, and assigned to or claimed by you. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
task_idintegerYesThe task assigned to you that is done.
notestringYesWhat was done, in plain text up to 4000 characters. Logged with the completion and shown to the reviewer.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Complete Task

lh-tasks/complete-task

Marks a claimed task as Resolved and stores an optional result payload. Needs the claim_token returned by claim-next-task for this task – fails if the caller does not currently hold the claim. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
task_idintegerYesThe claimed task to mark Resolved.
claim_tokenstringYesThe claim_token returned by claim-next-task when you claimed this task.
resultobjectNoOptional structured result to store against the task.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Convert Task Descriptions to Blocks

lh-tasks/convert-descriptions-to-blocks Idempotent

TEMPORARY, for the one-off conversion of task descriptions stored as raw markdown into block markup (#148851). Pass task_ids, or after_id and limit to work through every task in ID order (next_after_id continues). dry_run defaults to true: nothing is saved and each task reports what would happen. Tasks already holding blocks, or empty, are skipped. HTML entities in the stored markdown are decoded before conversion. A task is held, not saved, when the conversion was degraded or any word of the source is missing from the result. Saving changes post_content only: the previous content is kept as a revision, post_modified is kept so follow-up reminder timing is unchanged, and status, claims, taxonomies, meta and the progress log are not touched. Requires install_plugins. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
task_idsarray of integerNoSpecific tasks to convert. When given, after_id and limit are ignored.
after_idintegerNo0Work through tasks with an ID greater than this, in ID order. Pass the previous next_after_id to continue.
limitintegerNo20How many tasks to look at in an after_id run.
dry_runbooleanNotrueWhen true (the default) nothing is saved.
include_outputbooleanNofalseAlso return each converted result as block markup, for spot checks.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Create Task

lh-tasks/create-task

Creates a new task in the queue with status New. Accepts an optional machine-readable payload for agent-executable tasks, a queue/lane slug for routing, priority, due date, blocking task IDs, and an optional hard assignment. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
titlestringYesTask title.
descriptionstringNoHuman-readable description, written as markdown by default (see description_format). Stored as canonical HTML in post_content either way.
description_formatstringNo"markdown"How description is written: markdown (default) or html. It is stored as HTML either way. One of: markdown, html.
payloadobjectNoMachine-actionable spec for agent tasks, e.g. {"ability": "lh-email/send-broadcast", "params": {…}}.
queuestringNoQueue/lane slug for routing, e.g. "email-triage".
task_typestringNoTask type slug classifying what kind of work this is, e.g. "github_triage". Distinct from queue – queue is about routing, task_type is about classification.
post_statusstringNo"active"Visibility. active (default) is immediately visible/claimable. Use draft or pending for a task that should not be visible or claimable yet – e.g. an AI-drafted task awaiting human review before it is surfaced. One of: draft, pending, active.
assigned_tointegerNoWP user ID this task must be actioned by. Omit to leave the task open, claimable by anyone polling the queue.
prioritystringNourgent, high, normal or low; claim-next-task takes higher priorities first. Defaults to normal. One of: low, normal, high, urgent.
due_datestringNoMySQL datetime, e.g. 2026-07-10 09:00:00.
scheduled_forstringNoMySQL datetime (site local time). If in the future, the task stays hidden from claim-next-task until this time, then automatically activates to New. Omit to make the task claimable immediately.
blocked_byarray of integerNoTask IDs that must be finished (Resolved, Closed or Cancelled) before this task can be claimed. Each must be an existing, untrashed task; otherwise nothing is created and the error names the bad IDs. If a prerequisite is later cancelled, trashed or deleted, this task moves to Pending for a human to check.
max_retriesintegerNoHow many times to auto-requeue on failure before leaving the task Failed for triage.
requires_reviewbooleanNotrueOnly matters when someone other than the author does the task. true (default): their "done" goes to Awaiting review for the author to accept or send back. false: their "done" resolves it straight away, for trivial jobs.
source_pluginstringNoSlug of the plugin that created this task, e.g. lh-crm.
source_post_idintegerNoID of the originating post in the source plugin.
parent_idintegerNoMaster task this is a subtask of. The master must be an existing, untrashed task that is not itself a subtask: one level deep. When every subtask is finished (Resolved, Closed or Cancelled) the master resolves automatically; a Failed subtask moves the master to Pending.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Edit Task

lh-tasks/edit-task Destructive

Staff override that changes a task's assignment, workflow status or queue, or releases a stuck claim, without holding the claim. Returns success. It works unconditionally. Distinct from reassign-task, which is a self-service action for whoever currently holds the claim; use this for cleanup (stuck claims, wrong assignment) rather than routine handoffs. To requeue a Failed task with its full retries, set status to New with reset_retries true. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
task_idintegerYesThe task to change.
assigned_tointegerNoNew hard assignment. Pass 0 to explicitly clear assignment (open to anyone). Omit this field entirely to leave assignment unchanged.
release_claimbooleanNoRelease the current claim (if any) without changing assignment or status.
reset_retriesbooleanNoSet retry_count back to 0, so the task gets its full max_retries again. Logged with the previous count.
statusstringNoNew workflow status key. Omit to leave unchanged. One of: lh_tasks-new_task (New), lh_tasks-claim_task (Claimed), lh_tasks-prog_task (In Progress), lh_tasks-pend_task (Pending), lh_tasks-revw_task (Awaiting review), lh_tasks-fail_task (Failed), lh_tasks-res_task (Resolved), lh_tasks-clos_task (Closed), lh_tasks-cncl_task (Cancelled), lh_tasks-defr_task (Deferred). One of: lh_tasks-new_task, lh_tasks-claim_task, lh_tasks-prog_task, lh_tasks-pend_task, lh_tasks-revw_task, lh_tasks-fail_task, lh_tasks-res_task, lh_tasks-clos_task, lh_tasks-cncl_task, lh_tasks-defr_task.
queuestringNoNew queue/lane slug. Omit to leave unchanged.
notestringNoLogged alongside the change for audit purposes.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Fail Task

lh-tasks/fail-task

Marks a claimed task as failed. Needs the claim_token returned by claim-next-task for this task. reason_type "retryable" (default) requeues to New if retries remain, else sets it Failed and releases the claim, for a person to triage (edit-task with status New and reset_retries requeues it). reason_type "needs_human" skips retries entirely and hands the task off via reassignment instead – use this when the work itself is fine but something outside your authority/ability is needed to finish it. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
task_idintegerYesThe claimed task that failed.
claim_tokenstringYesThe claim_token returned by claim-next-task when you claimed this task.
error_messagestringNoWhat went wrong, or what is still needed. Stored as the task result and, for needs_human, as the handoff note.
reason_typestringNo"retryable"retryable (default): requeue to New while retries remain, then Failed. needs_human: skip retries and hand the task off (see new_assigned_to and new_queue). One of: retryable, needs_human.
new_assigned_tointegerNoneeds_human only. WP user ID of the specific person this should go to, if known. Omit to return it to the open queue.
new_queuestringNoneeds_human only. Move to a different queue/lane, e.g. a human-review lane.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Get Task

lh-tasks/get-task Read-only Idempotent

Retrieves a single task by ID with every field, including its Markdown description, progress log and blocked_by prerequisites. The fields: title, description (as stored and as Markdown), workflow and native status, queue, task type, priority, due date, claim holder and hard assignment, progress log, payload, result, retry counts, source, its blocked_by prerequisites with whether any are still holding it back, its master task (parent_id) and its subtasks (children). list-tasks returns the same shape with fewer fields by default. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
task_idintegerYesThe task to retrieve.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

List Tasks

lh-tasks/list-tasks Read-only Idempotent

Returns a page of tasks, filtered and sorted in the database. By default it lists open tasks (see status_group) in claim order: highest priority first, then oldest. Filters combine with AND: workflow status or status_group, queue, task type, claim holder (assignee), hard assignment (assigned_to), priority, source_plugin and source_post_id, due_before, overdue, created_after, updated_after, is_blocked (an unfinished prerequisite is holding the task back) and search (text in the title or description). Sort with orderby (priority, created, updated or due_date) and order. Dates are site-local, as Y-m-d H:i:s or Y-m-d. An unknown status or priority, both status and status_group, or a malformed date is refused with an error. Each task is compact by default: task_id, title, status, queue, task_type, priority, due_date, assignee, assigned_to, is_blocked, waiting_on, source_plugin and source_post_id. Name fields to choose others, such as description_markdown, payload or progress_log; task_id is always included and only the fields asked for are worked out. get-task returns every field of one task. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
statusstring|arrayNoOne workflow status key, or an array of them: lh_tasks-new_task (New), lh_tasks-claim_task (Claimed), lh_tasks-prog_task (In Progress), lh_tasks-pend_task (Pending), lh_tasks-revw_task (Awaiting review), lh_tasks-fail_task (Failed), lh_tasks-res_task (Resolved), lh_tasks-clos_task (Closed), lh_tasks-cncl_task (Cancelled), lh_tasks-defr_task (Deferred). Cannot be combined with status_group.
status_groupstringNoopen, the default when status is not given: New, Claimed, In Progress, Pending, Awaiting review, Failed. terminal: Resolved, Closed, Cancelled. all: every status, including Deferred, which is in neither group. One of: open, terminal, all.
queuestringNoQueue (lane) slug.
task_typestringNoTask type slug.
assigneeintegerNoOnly tasks whose claim is currently held by this WP user ID.
assigned_tointegerNoOnly tasks hard-assigned to this WP user ID.
prioritystring|arrayNoOne priority, or an array of them: low, normal, high, urgent. A task with no priority counts as normal.
source_pluginstringNoOnly tasks whose source_plugin is this plugin slug.
source_post_idintegerNoOnly tasks whose source_post_id is this ID.
parent_idintegerNoOnly the subtasks of this master task.
due_beforestringNoOnly tasks due before this site-local date or datetime. Tasks with no due date are left out.
overduebooleanNotrue: only tasks whose due date has passed. false or omitted: no overdue filter.
created_afterstringNoOnly tasks created after this site-local date or datetime.
updated_afterstringNoOnly tasks whose content or workflow status changed after this site-local date or datetime.
is_blockedbooleanNotrue: only tasks an unfinished prerequisite is holding back. false: only tasks nothing is holding back. Omit for both.
searchstringNoText to find in the title or description.
orderbystringNo"priority"priority (default): highest first, then oldest, the order claim-next-task uses. created and updated: newest first. due_date: soonest first, tasks with no due date last. One of: priority, created, updated, due_date.
orderstringNoReverses or confirms the direction of orderby. Defaults to desc for priority, created and updated, and asc for due_date. One of: asc, desc.
fieldsarray of stringNoThe fields to return for each task; task_id is always included. Defaults to task_id, title, status, queue, task_type, priority, due_date, assignee, assigned_to, is_blocked, waiting_on, source_plugin, source_post_id, parent_id. Name description_markdown, description, payload, result, progress_log or any other task field to get it.
include_progress_logbooleanNofalseKept for older callers: true adds progress_log to the fields returned, the same as naming it in fields.
pageintegerNo1Page number, from 1.
per_pageintegerNo20Tasks per page, up to 100. Defaults to 20.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Reassign Task

lh-tasks/reassign-task

Hands a claimed task off: releases the claim, optionally hard-assigns it to an account, and logs a handoff note. Returns success. Once hard-assigned, only that account (or edit-task) can claim or act on it next. The note describes what is done and what is left. Needs the claim_token returned by claim-next-task for this task – reassigning is an action available to whoever currently holds the claim. Use this for partial-completion handoffs; use fail-task for something that went wrong. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
task_idintegerYesThe claimed task to hand off.
claim_tokenstringYesThe claim_token returned by claim-next-task when you claimed this task.
new_assigned_tointegerNoWP user ID this task must be actioned by next. Omit to just return it to the open queue for anyone to claim.
new_queuestringNoMove the task to a different queue/lane.
new_statusstringNoDefaults to New (immediately claimable). Use Pending for a handoff to a human who is not actively polling. One of: lh_tasks-new_task (New), lh_tasks-claim_task (Claimed), lh_tasks-prog_task (In Progress), lh_tasks-pend_task (Pending), lh_tasks-revw_task (Awaiting review), lh_tasks-fail_task (Failed), lh_tasks-res_task (Resolved), lh_tasks-clos_task (Closed), lh_tasks-cncl_task (Cancelled), lh_tasks-defr_task (Deferred). One of: lh_tasks-new_task, lh_tasks-claim_task, lh_tasks-prog_task, lh_tasks-pend_task, lh_tasks-revw_task, lh_tasks-fail_task, lh_tasks-res_task, lh_tasks-clos_task, lh_tasks-cncl_task, lh_tasks-defr_task.
notestringYesWhat has been done so far and what is left – the next assignee will see this.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Renew Claim

lh-tasks/renew-claim

Extends a held claim by moving claimed_at to now, so a long-running task is not auto-released mid-work. Returns success. The automatic stale-claim sweep releases claims older than the configured cutoff (default 10 minutes). Does not change status or assignee. Needs the claim_token returned by claim-next-task for this task – fails if the caller does not currently hold the claim. Call periodically from a long-running task. Optionally logs a progress note alongside the heartbeat, the same way reassign-task logs its note. Write abilities called with this task's task_id and claim_token renew the claim automatically, but only up to a maximum lease (4 hours from the claim by default); renew-claim itself is not capped, so use it for work that runs longer or makes no writes. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
task_idintegerYesThe claimed task whose claim to extend.
claim_tokenstringYesThe claim_token returned by claim-next-task when you claimed this task.
notestringNoOptional progress note, logged alongside the heartbeat – lets a renewal double as a lightweight progress trail. Omit for a bare heartbeat with no side effects beyond extending the claim.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Review Task

lh-tasks/review-task

Accepts or sends back a task that is Awaiting review, the step after the person it was assigned to marks it done. accept resolves it. send_back returns it to New, still assigned to the same person, who is notified with your note. Only the task's author (the person who asked for it) or staff may review. A note is required to send a task back and optional to accept it. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
task_idintegerYesThe task that is Awaiting review.
decisionstringYesaccept (Resolved) or send_back (New, back to the same person). One of: accept, send_back.
notestringNoPlain text up to 4000 characters. Required for send_back: what still needs doing.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.

Update Task

lh-tasks/update-task

Changes the content of a task after it was created: title, description, payload, priority, due date, schedule, task type, max retries, blocked_by and parent_id (the master task). Only the fields you pass change; an empty value clears payload, due_date, task_type or blocked_by. Everything is checked before anything is written, so an invalid blocked_by (missing, trashed, the task itself, or a loop) changes nothing. Works on claimed tasks too, and every call adds an "updated" entry to the progress log listing the fields changed. Status, queue, assignment and the claim are not changed here: use edit-task or the claim-token abilities. Requires edit_others_posts. Pass site_id to act on another site you belong to.

ParameterTypeRequiredDefaultDescription
task_idintegerYesThe task to change.
titlestringNoNew title. Cannot be empty.
descriptionstringNoReplaces the description. Written as markdown by default (see description_format).
description_formatstringNo"markdown"How description is written: markdown (default) or html. It is stored as HTML either way. One of: markdown, html.
payloadobjectNoReplaces the whole payload. An empty object clears it.
prioritystringNoNew priority: urgent, high, normal or low. One of: low, normal, high, urgent.
due_datestringNoMySQL datetime, e.g. 2026-07-10 09:00:00. Empty string clears it.
scheduled_forstringNoNew activation time (site local MySQL datetime, in the future). Only for a task that is still scheduled.
task_typestringNoTask type slug. Empty string clears it.
max_retriesintegerNoHow many times to auto-requeue on failure before leaving the task Failed for triage.
blocked_byarray of integerNoReplaces the whole list of prerequisite task IDs. Empty array clears it.
parent_idintegerNoMakes this a subtask of that master task, or 0 to make it standalone again. One level deep: the master cannot be a subtask, and a task with subtasks cannot become one.
notestringNoWhy it changed; logged with the update.
site_idintegerNoOptional. ID of another site in the network to act on; list-my-sites gives the sites you belong to. Permissions are checked on that site. Omit for this site.