Hanary MCP Server
Hanary MCP Server for Claude Code & OpenCode - task management that keeps new work outside the priority list until the user decides.
What Hanary MCP Is For
Hanary MCP is an operating layer for AI coding assistants. It lets agents read, start, update, and complete work from Hanary while preserving the user's priority decisions.
The key rule is: agents may capture and organize new work, but they should not silently insert it into the active priority order. New tasks default to needs_decision, staying outside top-task, start, and complete candidates until the user explicitly chooses to prioritize them or enables saved AI priority delegation for that scope.
Use Hanary MCP when you want Claude Code, OpenCode, or Codex to work from your confirmed Hanary task structure instead of inventing its own task order.
Mental model:
- Hanary owns the user's task hierarchy and priority order.
- The AI assistant follows that order.
- New work is captured safely as
needs_decision. - Explicit user intent, including a saved revocable priority policy, authorizes promotion into the active priority list.
executor_type: "ai"means user-approved execution delegation, not AI-owned priority judgment.planning_statusanswers when work belongs in priority;executor_typeanswers who can execute it.- Human-owned tasks are ownership and completion boundaries, not safe advisory work boundaries: guide mode and safe non-destructive advisory help are allowed when the user asks to start, asks for guidance, or asks what to do next.
- Users decide priority themselves or delegate priority decisions for new or existing unfinished tasks and can revoke that delegation. Completion judgment remains separate.
Independent AI Decision Delegation
Hanary web settings store two independent switches for each authenticated user's project or personal scope: delegate priority decisions and delegate task completion criteria decisions. Both default to OFF. The connected Codex or Claude AI reads live context, makes the permitted decision itself and saves it through MCP without asking for the same approval again:
| Priority delegation | Completion criteria delegation | Result |
|---|---|---|
| OFF | OFF | Capture work; the user decides priority and task completion criteria. |
| OFF | ON | AI defines or revises task completion criteria; new work stays needs_decision. |
| ON | OFF | AI defines the comparison rubric and decides priority for new or existing unfinished tasks; task completion criteria require separate user authority. |
| ON | ON | AI decides priority and task completion criteria independently. |
The assistant reads get_priority_delegation before capture or a delegated
decision, using priority_delegated and completion_criteria_delegated separately.
The deprecated criteria_delegated field concerned the priority comparison
rubric; it never grants task completion criteria permission. Only authenticated
web settings can enable or revoke either switch. Keep existing MCP connection
configuration; there is no local mode flag. Explicit record-only intent overrides
both grants for that request. A request only to defer priority leaves independent
completion criteria delegation intact. Personal consent never grants squad
changes; use the matching project-bound connection for squad tasks.
With priority delegation ON, the host AI reads prepare_priority_criteria and
uses save_priority_criteria when the comparison rubric is absent or changed
project goals/evidence warrant revision. The rubric answers which work comes
first; it is distinct from the standard for when a task is done. Then use
prepare_priority_placement(task_id) and finalize_priority_placement for new
or existing unfinished tasks, including already prioritized tasks. The AI chooses
a rank within the same parent while preserving all other siblings' relative
order, and records a concrete reason. Prepare placement afresh after a rubric
save changes the policy version. New tasks are first captured as needs_decision.
With completion criteria delegation ON, the host AI reads
prepare_task_completion_criteria(task_id) and judges a concrete, verifiable
completion standard from task purpose and live context. It directly saves or
revises that standard with save_task_completion_criteria, passing the task ID,
prepared policy version and snapshot, completion_criteria (at most 2000
characters), reason and retained idempotency key. The result sets
completion_criteria_source="explicit". Reuse suitable existing criteria; do
not weaken them just to claim completion. Missing essential intent still needs
clarification. Defining what counts as done does not grant authority to execute
or mark work done, change its executor or track time; existing completion evidence
and review requirements remain in force.
Creation, comparison-rubric saving, priority placement and task completion
criteria saving are separate outcomes. priority_workflow can report
pending_ai_criteria or pending_ai_priority; independent
completion_criteria_workflow can report pending_ai_completion_criteria.
Only criteria_saved=true, planning_status="prioritized" or
completion_criteria_saved=true, each with its receipt, confirms the relevant
save. Failed continuation remains resumable from the captured task ID.
The server checks live authority and context atomically at saving. A stale snapshot requires fresh preparation and a new decision/key. Revocation stops future decisions without undoing saved order or criteria. Never bypass refusal through ordinary update, completion or priority tools. After response loss, keep all original arguments and the key; retry only the identical request to retrieve its receipt, including after revocation while access remains valid. The bridge never retries automatically, invokes a model or continues after the host stops. Separate explicit one-off user instructions still use existing task tools.
API vs MCP
Hanary's REST API remains the canonical product API. Use it for first-party apps, mobile or desktop clients, custom integrations, and any workflow where you control the application code that calls Hanary.
MCP is the AI-assistant integration surface on top of that API. Use it when you want tools like Claude Code, OpenCode, or Codex to discover Hanary actions automatically through tools/list, call them through tools/call, and receive the priority-boundary guidance directly in tool schemas and server instructions.
In practice:
- REST API is for application integrations.
- MCP is for agent integrations.
hanary-mcpis the installable stdio bridge plus commands, skills, and agent guidance for local coding assistants.
MCP is not required to perform Hanary operations, but it avoids rebuilding the same tool wrapper for every AI host and keeps the assistant's behavior aligned with Hanary's user-owned priority model.
Features
- MCP Server: Direct tool integration with Claude Code and OpenCode
- Slash Commands:
/hanary-status,/hanary-start,/hanary-done - Skills: Task management workflow with estimation patterns
- Agents: Task planner that drafts complex work decomposition for user review
- Project Sync: Safe checks, diffs, and updates for generated assistant files
- Full Compatibility: Works with both Claude Code and OpenCode
Installation
# Using uvx (recommended)
uvx --from hanary-mcp hanary-mcp --squad my-project
# Or install globally
uv tool install hanary-mcp
Configuration
Project-Scoped Setup (Recommended)
Use project-scoped setup when different repositories should bind to different Hanary squads. Run this from the project root:
uvx --from hanary-mcp hanary-mcp init --squad your-squad-slug .
This creates project-local integration files:
.mcp.jsonfor Claude Codeopencode.jsonfor OpenCode.codex/config.tomlfor OpenAI Codex
Repeat the command in each project with that project's squad slug. This keeps AI assistants working inside the right Hanary squad without sharing one global --squad value across all projects.
The value after --squad is the squad slug, not the display name. For example,
if Hanary shows FutureGate (futuregate), use futuregate:
uvx --from hanary-mcp hanary-mcp init --squad futuregate .
After setup, verify the local binding:
uvx --from hanary-mcp hanary-mcp doctor --squad your-squad-slug
--squad can appear before or after doctor, init, or sync. For doctor,
the same applies to --api-url and --token: explicit CLI values take precedence
over environment defaults. If an option is explicitly given on both sides of
the command, the later value wins.
Doctor prints the requested scope and checks project files against that scope;
it does not infer the requested scope from those files. It reports project
configuration and remote diagnostics separately. A successful squad-list lookup
is not a membership check: Requested squad access check verifies access to the
named squad, or explicitly shows SKIPPED in personal mode. The tool contract
check compares the advertised tool catalog; it does not execute every tool or
verify the MCP process already running in your assistant.
The printed package version belongs to the newly launched CLI. Doctor compares
the configured API's /mcp catalog with that CLI's generated bridge catalog;
it does not inspect an external app/session's exposed tools or an existing host
process. --version has the same process boundary. A successful doctor result
does not establish that an external app exposes the execution tools.
An actual project scope mismatch still exits with status 1, even when remote
diagnostics succeed. Review the listed configuration arguments or rerun doctor
with the intended scope; doctor never rewrites project files. Missing project
files and a client without tools/list diagnostic support are reported as
skipped, not failed; a skipped catalog leaves the remote summary INCOMPLETE
rather than OK. A catalog request that fails still causes a failed result.
Inside an AI assistant, use get_current_scope when the active project or squad is unclear before creating, starting, completing, or reordering tasks.
In project-scoped squad mode, the MCP server exposes the squad as the working boundary: use get_top_task for "what should I do next" inside that project. get_overall_top_task is intentionally not exposed in squad mode; use a separate personal/global Hanary MCP only when the user explicitly asks to leave the project scope.
Keeping Project Files Synced
Use hanary-mcp sync after upgrading hanary-mcp when an existing project should
receive updated commands, skills, agents, or generated MCP config.
Start with a status check:
uvx --from hanary-mcp hanary-mcp sync --squad your-squad-slug .
Review diffs before writing:
uvx --from hanary-mcp hanary-mcp sync --squad your-squad-slug --dry-run .
Write only safe changes:
uvx --from hanary-mcp hanary-mcp sync --squad your-squad-slug --write .
sync --write creates missing files and updates files that still match the last
managed template hash. It does not overwrite user-modified files. Local config
files such as .mcp.json, opencode.json, and .codex/config.toml are marked
for review instead of being overwritten, because they may contain squad slugs,
tokens, uv cache settings, or other project-specific choices.
Use init --force only when you intentionally want to overwrite existing
generated files. It can replace local edits in .codex/config.toml,
.mcp.json, and opencode.json; after using it, re-check any OS-specific
command, token, and cache settings.
The sync manifest is stored in .hanary-mcp-sync.json. It records template
hashes for files managed by hanary-mcp, so future upgrades can distinguish
safe generated-file updates from user edits. AI guidance changes are listed
separately in sync output because they affect assistant judgment boundaries.
Claude Code Setup
- Set your API token as a system environment variable:
export HANARY_API_TOKEN='your-token-here'
On Windows PowerShell, set a persistent user environment variable:
[Environment]::SetEnvironmentVariable("HANARY_API_TOKEN", "your-token-here", "User")
Or set it only for the current PowerShell session:
$env:HANARY_API_TOKEN = "your-token-here"
Restart your AI coding assistant after changing environment variables. Existing
Codex, Claude Code, or OpenCode processes do not inherit newly saved user
environment variables; if they start the MCP server without the token, you may
see an initialize/handshake failure such as connection closed.
- Prefer
hanary-mcp initabove, or add this to your project's.mcp.jsonmanually:
{
"mcpServers": {
"hanary": {
"command": "uvx",
"args": ["--refresh-package", "hanary-mcp", "--from", "hanary-mcp", "hanary-mcp", "--squad", "your-squad-slug"]
}
}
}
Global CLI registration is useful only when one Hanary squad should be used everywhere:
claude mcp add hanary -- uvx --refresh-package hanary-mcp --from hanary-mcp hanary-mcp --squad your-squad-slug
Do not use global CLI registration with --squad when you need project-by-project squad separation. In that case, keep the --squad binding in each project's .mcp.json or .codex/config.toml instead.
OpenAI Codex Notes
hanary-mcp init generates .codex/config.toml for the current operating
system. On macOS/Linux it uses zsh -lc so shell profile environment variables
can load. On native Windows it runs uvx directly because zsh is not available
by default:
[mcp_servers.hanary]
command = "uvx"
args = ["--refresh-package", "hanary-mcp", "--from", "hanary-mcp", "hanary-mcp", "--squad", "your-squad-slug"]
[mcp_servers.hanary.env]
UV_CACHE_DIR = ".uv-cache"
Keep UV_CACHE_DIR in the project root, such as .uv-cache, so Codex sandboxed
runs can write to it. If you edit the Codex config manually on Windows, avoid
copying a macOS/Linux zsh -lc command into that file.
Environment Variables
Set these in your shell profile (.bashrc, .zshrc, etc.) or OS user
environment:
| Variable | Required | Description |
|---|---|---|
HANARY_API_TOKEN |
Yes | Your Hanary API token |
HANARY_API_URL |
No | API URL (default: https://hanary.org) |
Recovering a task write after a lost response
create_task and update_task accept an optional idempotency_key. Generate and
retain a nonsecret unique key before sending one intended write. If its response
is lost, call get_mutation_result(idempotency_key="the-original-key") in the
same scope, or resend the original tool with exactly the same key and arguments.
The bridge performs no automatic write retries.
An applied receipt confirms the write committed. A replay returns the same task
ID and its current state, preserving later edits. not_recorded does not prove
failure: the request might still be running. Different arguments with a used key
are rejected. Never generate a new key merely to retry. Deleted, moved, or
inaccessible tasks are not recreated or exposed by recovery.
The backend must advertise this contract before the bridge sends a keyed write. If no key was supplied, inspect the task and records after an uncertain response; legacy writes cannot be automatically retried safely. Receipt keys do not provide conflict detection for separate intentional edits with different keys.
Available Tools
Default Agent Workflow
Use Hanary MCP around one confirmed focus at a time:
get_top_task -> get_task/update_task for context and notes -> start_task
-> do the work -> stop_task/complete_task against the saved user-defined criterion
-> check completion/review state -> get_top_task and review current necessity
list_tasks, search_tasks, list_completed_tasks, list_work_activity, get_tasks_summary, and get_task_tree are context tools. They help inspect related work, historical completion or activity, duplicates, blockers, hierarchy, or review state, but they should not replace get_top_task as the source of current focus. Use list_completed_tasks for completed_at recall and list_work_activity with basis="activity" for work performed in an actual date range.
In get_tasks_summary, status_counts uses explicit status meanings: started/in-progress task context means started_at is set and completed_at is nil. highest_priority_started_task is the first started task in summary priority order, not the current AI focus. This is separate from active time tracking; use get_task with include_time_summary=true to inspect has_active_session and active_session_started_at.
When this server is started with --squad, get_top_task is the project focus boundary. Do not switch to overall/global focus unless the user explicitly asks to work outside the current project squad.
If get_top_task returns is_llm_boundary=true, treat it as an execution boundary, not as permission to pick from a list and not as an advisory stop signal. The response may include human_prioritized_candidates: these are user-prioritized tasks that are still marked executor_type: "human". Report that prioritized work exists but has not been delegated to AI for execution. Do not change executor_type, start execution work, or skip to a lower-priority AI task unless the user explicitly delegates AI execution or explicitly chooses that lower-priority work. If advisory_allowed=true and the user asks to start, asks for help, asks what to do next, or asks to work together, default to guide mode instead of only asking for AI delegation and stopping. Starting advisory time tracking for the current top-priority human-owned task is allowed in that flow; it is a collaboration record, not AI execution delegation.
That boundary does not block safe advisory support. Human-owned tasks create an
ownership and completion boundary, not a safe advisory work boundary. If
advisory_allowed=true and the user asks to start, asks for help with the
human-owned task, asks what to do next, or says completion/final approval
remains theirs, the assistant should continue in guide mode without asking for
extra permission for non-destructive support work. Guide mode begins by briefly
stating that the task remains human-owned, then reading the task context and
providing the first 1-3 concrete user actions.
Safe autonomous advisory work includes reading Hanary task details, completion
criteria, notes, and approach; reading related local documents; running
read-only inspection commands such as rg, ls, sed, and git status;
public research; summarizing findings; first-step guidance; checklists;
verification plans; evidence organization; draft communication; interpretations of user-provided results;
and creating new non-overwriting support artifacts such as Markdown reports
under docs/, guides/, reports/, or notes/. When creating such an
artifact, record its path and a short summary in Hanary notes and leave
completion approval to the user.
Advisory time tracking is allowed for the current top-priority human-owned task
when advisory_allowed=true and the user asks to start, asks for help, asks
what to do next, or asks to work together. start_task in this case records advisory work as a collaboration record; it does not change executor_type, grant completion authority,
or grant priority authority. Maintain an already active session; do not stop user-started sessions without confirmation, and do not stop any advisory session
unless the user asks to stop, wrap up, or says the work is here for now.
External Reply or Approval Wait
When an inquiry, order, or approval request is complete and progress depends on
an external reply, delivery, approval, or concrete event, inspect the task and
its children. If no independent work remains in the affected subtree and its
resume condition is known, call assess_task_hold with
external_wait_confirmed=true. The flag is a factual assertion and defaults to
false. The non-mutating assessment returns auto_hold_allowed=true only when the evidence is
confirmed and hold_recommended=true; then user_confirmation_required=false
and hold_task can proceed without an explicit stop or hold request, or another
dependency-impact confirmation. Inspect and report dependency impact. Hold only
the affected portion; keep executable preparation and siblings available. Use a
dependency for an actual Hanary predecessor, not a hold for the same reason.
Time tracking must be inactive on the task and descendants. Never stop an active session automatically to make a hold possible. A user stop/wrap-up request authorizes its own time-tracking action: verify that it succeeds, then reassess task state from context. A break or end-of-day stop alone does not establish external waiting. Timer-only requests change only tracking; assessment-only requests such as "should we hold this?", explicit read-only/status-only/planning-only requests, and a planning-only agent role leave task state and tracking unchanged even if the assessment says auto holding is allowed. If evidence is unclear, clarify the missing fact or use existing explicit hold intent.
hold_task requires a reason plus a resume condition or follow-up time;
automatic external-wait holds require a concrete resume condition. Record the
waiting party, start time, and follow-up time when known. It preserves rank, planning_status, dependencies, and time sessions and stores a durable hold
period without creating a judgment record. Report hold and timer results
separately, including partial failures. next_actionable_task is context, not
permission to start another task after a user stop. Use get_task_hold_history
to recover prior context. Call unhold_task only after explicit user intent;
it may add a short resume note and returns the task at its existing priority.
Prerequisites vs Hold
add_dependency represents a prerequisite relationship. Its legacy fields map
blocking_task_id to the prerequisite and blocked_task_id to the dependent
task. dependency_type defaults to blocks_start, which excludes the dependent
task and its descendants from top-task selection and prevents starting or
completion. Use blocks_completion when work and time tracking may proceed but
review submission and completion must wait; that gate does not propagate to
descendants. Use update_dependency_type to change the gate without deleting the
relationship. Every gate is derived: rank and planning_status do not change, and
completing the prerequisite clears the applicable gate automatically.
Use a dependency when a real Hanary task must finish first. Use hold_task when
progress depends on an external reply or condition that has no Hanary task.
Do not apply both mechanisms for the same waiting reason.
The assistant must ask first before modifying, deleting, or overwriting existing
files; changing source code, circuit designs, or config; completing tasks;
stopping user-started time sessions; stopping any time session without a user
stop/wrap-up request; changing executor_type; changing priority; committing,
pushing, or deploying; sending external messages; placing orders, payments, or
bookings; or define completion criteria for the user without active completion criteria delegation or explicit instruction; or making/replacing the
user's final judgment or completion approval.
Personal and Squad Mutation Boundary
Personal/global MCP keeps the normal tools for the user's personal tasks. An
accessible squad task does not become personally governed work: membership and
visibility provide context, not mutation authority. Only the directly assigned,
accepted assignee may start, complete, hold, or unhold that squad task, append
execution evidence through approach, notes, or retrospective, create an AI
judgment draft, record their own historical work, and stop or clean up their own
time session.
Squad priority, planning status, hierarchy, shared fields, dependencies, links,
deletion, completion reversal, relocation, and planning-session mutations
require the matching project-bound --squad context and server authorization.
Tools such as reorder_task remain available in personal mode for personal work;
their presence is not permission to apply them to a visible squad task.
Resuming saved work
Call get_task(task_id="123", include_resume_context=true) to add a read-only
resume_context containing saved purpose, completion criteria, notes, holds,
prerequisites, current judgments, an accepted next action when recorded, and AI
report freshness. Source IDs and timestamps accompany saved records; full note
text is preserved. Omit the option or use false to keep the existing response.
The option accepts only a boolean.
not_recorded means no applicable saved record was found; unavailable means it
could not be confirmed. A stale AI report means unknown liveness, not proof that
an external process stopped. Multiple accepted next actions remain visible as
conflicting candidates. Reading never generates or accepts a next action,
changes priorities or holds, or starts timers or execution. Use get_top_task
for the current priority and the existing history tools for older records.
Reviewing the next work after completion
After actual completion, assistant guidance connects what was resolved or newly
learned to the next task in the same scope's confirmed priority order. It reuses
fresh evidence and reads get_task(include_resume_context=true) only when the
completed task or next candidate needs more context; a parent's purpose is read
separately when relevant. The brief explanation identifies the next task and
why it still matters, or suggests a narrower scope or reconsideration based on
the new evidence. Missing context remains unconfirmed rather than an invented
reason to proceed.
This is a read-only assessment, not a new approval gate: it never starts timers
or AI execution, changes priority or delegation, writes a judgment, or skips to
lower-ranked work. Human-owned candidates remain visible without starting an
advisory timer. pending_review means submitted for review even when completion
flags are set; it is not final acceptance. If a later context read fails, the
known completion result is preserved and only the next-work review is reported
as unavailable. These are assistant instructions, not an automatic necessity
classifier or a guarantee that every agent will follow them.
Priority comparison scope
Execution candidates and comparison groups are separate choices. An explicit
comparison anchor or parent in the current request takes precedence, followed
by the conversation's confirmed scope and then a valid remembered selection.
next_actionable_task and current_ai_focus never choose the comparison parent.
Verify the project's connection with get_current_scope and briefly state the
anchor and comparison parent before assessment. Ask for a scope choice only
when the request remains ambiguous; a clear scope needs no repeated approval.
get_priority_comparison_scopereads the live comparison context. No arguments restore this user's remembered selection in the current project or personal scope.anchor_task_idalone selects its siblings, whileparent_idselects direct children and explicitparent_id: nullselects root. Supplying both verifies the relationship. Explicit arguments affect only that read.save_priority_comparison_scoperemembers one deliberately user-selectedanchor_task_idandparent_idfor future sessions. The scope choice can authorize saving it; incidental reads and "this time only" comparisons do not overwrite the remembered selection.clear_priority_comparison_scopeforgets only the current scope's selection when the user asks. Invalid selections are never automatically cleared.
Results include status, scope_source, the anchor and ancestor path, comparison
parent and ID, unfinished direct children, saved selection, invalid reason and
whether scope selection is required. Children include current ranks,
planning_status, holds and actionability; ranks on not-yet-prioritized tasks
do not represent a confirmed order. Restoration refreshes these states and
includes new siblings. A move, deletion or access change that breaks the stored
relationship or scope invalidates the selection instead of silently following
a new parent. Moving the parent within the same scope can remain valid when
the anchor is still its direct child.
Reads never change priority, execution or time sessions. Saving and clearing change only this authenticated user's selection. Remembering a scope grants no priority or execution authority. Existing parent assertions on prioritization and guards on reorder tools still apply, and applying an order requires user confirmation.
Task Management
get_current_scope- Show whether this MCP server is in personal mode or bound to a project squadget_top_task- Primary tool for ordinary top-priority and "what should I do next?" questions; returns the current AI focus without bypassing the user's confirmed priority orderget_priority_comparison_scope- Read or restore a comparison anchor, parent and live direct children without changing statesave_priority_comparison_scope/clear_priority_comparison_scope- Remember or forget only the user's deliberately chosen comparison scopeget_overall_top_task- Personal mode only and only for an explicit all-squad request. Returnspersonal_top,squad_tops, and selection metadata; it does not invent a cross-scope winner when no global order is confirmed. This tool is not exposed when the MCP server is bound to a project squad.get_task- Inspect a specific task with its purpose, attempts & decisions, references & results, children, ancestors, and time summarylist_judgment_records- Read the append-only problem → assessment → proposal → decision → outcome history attached to one taskcreate_judgment_record- Record a concise AI-authored problem/assessment/proposal draft. It never records user acceptance or rejection.withdraw_judgment_proposal- After explicit user confirmation of the exacttask_id,proposal_event_id, andreason, withdraw a pending AI proposal from review. Its effective status becomeswithdrawn, not rejected. Original content, actor, time, and reason remain in history; nothing is permanently deleted.supersede_judgment_proposal- With explicit user confirmation, provide the same fields plusreplacement_proposal_idto retain an already-existing pending AI proposal in the same task and dimension. The old proposal becomessuperseded; no third proposal is created and the target's content and acceptance state are unchanged. Human-authored or closed proposals cannot be cleaned up via MCP. Reportcleanup_applied, affected IDs and effective statuses, and the remainingdecision_targetswith exact links. Neither cleanup action is acceptance or authorization to change or execute a task. Re-list history after an uncertain response before retrying. Original events keep their historical status; followreplacement_proposal_idon cleanup events to see the connection.replace_judgment_proposal- Replace a pending AI proposal using its exacttask_idandproposal_event_id. Optionalproblem_raised,assessment, andproposalinherit omitted sections; at least one must change. The old thread becomessupersededand a full, unaccepted AI snapshot becomes the new review target. Human-authored, accepted, rejected, and already superseded proposals cannot be replaced through MCP. Independent alternative proposals are preserved. Text saying “replaces X” does not perform replacement. After a timeout or stale-target error, re-list history before retrying; never create another proposal as a fallback. Checkreplacement_applied, state whether the old proposal was superseded, and concisely present the currentdecision_targetwith its exact review link. Retainprevious_proposalandreplacement_proposalIDs for follow-up calls; show them when requested or needed to resolve an ambiguous target or recover from an error. This does not change task fields, priority, or execution authorization; final acceptance/rejection stays web-only.list_tasks- List tasks as supporting context; useget_tasks_summaryfor overviewssearch_tasks- Find related tasks, duplicates, or blockers without choosing focus automaticallylist_completed_tasks- List completed tasks bycompleted_atdate range for historical recall and retrospectiveslist_work_activity- List the authenticated user's actual activity by performed date with timer/manual provenance and exact/estimated accuracyget_task_tree- Inspect hierarchy and decomposition without treating the tree as a new priority ordercreate_task- Create a new task. In personal mode, pass asquad_slugselected fromlist_my_squadsto capture root squad work as aneeds_decisionproposal; omitparent_idandrank, and omit the slug for personal work. Adding a squad child or prioritized squad insertion requires the matching project-bound--squadcontext.update_task- Update task title, description, completion-criteria selection, executor, purpose/background/approach/notes/retrospective, or due date. Setdue_datewithYYYY-MM-DD, send explicitnullto clear it, or omit the field to keep the current value unchanged.complete_task- Mark task as completed against the user's saved completion-criteria selectionuncomplete_task- Mark task as incompletedelete_task- Soft delete a taskreorder_task/batch_reorder_tasks- Change priority order only after explicit user-confirmed placementprioritize_task/batch_prioritize_tasks- Atomically promote existing tasks into the priority chain using an explicit user-confirmed ordermove_task/batch_move_tasks- Clarify hierarchy inside the current personal or squad scope after user confirmation. They never expose personal work to a squad; userelocate_task_to_squadfrom the matching project-bound squad context for that visibility change.list_reference_child_violations- Read-only audit for legacy personal task roots hidden under squad-reference pointers or actual squad tasks without inherited squad scope. It never moves or shares tasks.relocate_task_to_squad- Project-bound squad mode only. After explicit user choice, move one repairable personal task subtree into the bound squad and pass aconfirmationsummarizing that choice. Personal/global mode reports the target squad but does not expose this mutation.assess_task_hold- Evaluate an external-wait hold candidate without changing task state or time trackinghold_task/unhold_task- Automatically hold confirmed external waits or follow explicit hold intent; resume only after explicit user intent, preserving existing priorityget_task_hold_history- Read newest hold periods without changing task staterecord_historical_completion- Record an explicitly confirmed past completion instant separately from the time it was entered; requires an existing saved completion standardadd_dependency- Add a typed prerequisite that defaults toblocks_startupdate_dependency_type- Change an existing prerequisite betweenblocks_startandblocks_completionwithout changing task priority or planning statusremove_dependency- Remove an existing prerequisite relationship
Historical Work Records
Do not start and stop today's timer to represent work performed on an earlier
date. First call assess_historical_work with the intended payload and present
the normalized performed date, duration, and any conflict. Call
record_historical_work only after the user confirms that assessment.
Use entry_mode="exact_interval" only when both real timestamps are known. If
the user remembers only the local date and duration, use
entry_mode="duration_only" with performed_on and duration_minutes. Mark an
approximate memory with accuracy="estimated" instead of inventing precise
timestamps. Reuse an idempotency_key only for an identical retry.
Historical activity and task completion are separate records.
record_historical_work never completes a task; use
record_historical_completion only after the user explicitly confirms the
actual completion instant and the task already has a saved user-confirmed
completion standard. Use list_work_activity for performed-date recall and
list_completed_tasks for completion-date recall.
Squad
list_my_squads- List squad display names and unique slugs. In personal mode, use it to resolve a user-named squad before passing its returned slug tocreate_task.get_squad- Get squad details and shared-problem contextlist_squad_members- List members who share the squad problem contextlist_squad_events- List events and deadlines for shared-problem coordinationget_online_members- Check current presence when coordination is neededstart_planning_session/stop_planning_session- Change squad planning-session state only from the matching project-bound--squadcontext
Messages
list_messages- List squad messages for recent decisions, blockers, and shared contextcreate_message- Send a squad message around the shared problem, decisions, or blockers
Task Creation Policy
create_task records new work without assuming it belongs in the priority list. By default, new tasks are created as needs_decision, so they stay outside top-task, start, or complete candidates until the user decides whether to break them down or place them into priority. Use planning_status: "prioritized" only when the user explicitly wants the task placed in the priority order now. rank is ignored unless planning_status: "prioritized" is explicit, and is required for prioritized creation except for the first executable child under a prioritized parent with no prioritized siblings. Use get_task on the parent first when unsure; its child_creation_policy reports the parent planning_status, direct incomplete child counts by planning status, prioritized child count, and whether rankless first executable child creation is allowed.
When a user in personal mode asks to add work to a named squad, call list_my_squads before creating. Prefer an exact returned slug; otherwise require one unique exact display-name match. If there is no exact match or multiple squads share the display name, ask the user to choose from the returned names and slugs instead of guessing. Call create_task with that returned squad_slug, omit parent_id and rank, and omit planning_status or use needs_decision. This captures a root proposal without changing the squad's shared hierarchy or agreed priority. In project-bound mode, task creation always stays in the configured --squad, a per-call squad_slug override is rejected, and adding a child or explicitly confirmed prioritized insertion is available.
A task with squad_ref_id is a personal dashboard reference to a squad, not an actual squad task parent. Never use that reference as parent_id. From personal/global mode, create only a squad root proposal with squad_slug and no parent. In the matching project-bound squad context, a child may use an actual squad task whose squad_id identifies that same squad.
Use list_reference_child_violations to detect legacy personal children that already exist under squad references or actual squad tasks without inherited squad scope. The audit is read-only: it returns each entry's violation_type, repairable flag, blocking_reasons, descendant_count, and target squad without moving or sharing anything. In personal/global mode, present the findings and tell the user which target --squad context to enter; the wrapper intentionally returns no executable relocation action. In that matching project-bound context, require an explicit user choice before calling relocate_task_to_squad, because relocation exposes the entire task subtree to squad members. Relocate only entries marked repairable, pass a non-empty confirmation, and do not pass a per-call squad override.
References & Results and child tasks have different jobs. record_update is only an update_task input. create_task accepts initial purpose/background/approach/notes without this object. Include record_update with every update_task record write; use it for all References & Results and Attempts & Decisions writes while keeping purpose/background/retrospective in their named update_task fields. Put links, research notes, command output, formulas, and deliverables in references_results (stored as notes), and put what was tried, blockers, and reasons for an already chosen direction change in attempts_decisions (stored as approach). Always include the required action_items array, even for evidence-only updates, and put uncertain placement in optional ambiguous_items. In update_task, do not send legacy top-level notes or approach; they remain compatibility-only during rollout. If action_items or ambiguous_items is non-empty, Hanary changes nothing and returns needs_decision child task candidates for user review. This is an explicit caller classification rather than an AI classifier, and Hanary never creates or prioritizes those candidates automatically. If a checklist item can be executed independently, have its result recorded separately, and be judged complete on its own, create it as a child task candidate with parent_id instead of burying it in a record. Measurements, tests, checks, and concrete actions often belong in child task candidates when they can be performed one by one. Creating child task candidates clarifies hierarchy only; it does not make them executable or prioritized unless the user explicitly asks for priority placement.
When a problem, assessment, or improvement proposal materially changes a task's purpose, approach, scope, completion criteria, priority, next action, or shared commitment, use create_judgment_record instead of flattening the turning point into a mutable note. Summarize the transition and keep only an opaque source reference; never copy raw conversations, prompts, credentials, or secrets. AI-created records remain proposals. list_judgment_records preserves adopted, rejected, and superseded history, but MCP intentionally exposes no decision tool: silence, an AI recommendation, and general execution delegation are not acceptance, and final acceptance or rejection must come from an authenticated user action in Hanary's web UI.
A proposal should contain one independently adoptable decision. Split decisions only when the user could accept one and reject another; multiple checks supporting the same completion judgment can stay together. Put detailed test results, logs, and supporting analysis in assessment or existing task results. Keep acceptance-defining conditions, thresholds, exceptions, and scope in the proposal, with references to supporting records where needed. Do not remove a condition merely to shorten the text or enforce a new fixed-length template.
For judgment tool results, inspect user_decision_required and decision_target or decision_targets. When a decision is required, the default chat response names the task and judgment dimension, briefly explains the core decision and what adoption would settle, and links directly to the returned decision_url. After replacement, also say whether the old proposal was superseded and identify the current review target. Preserve decisive conditions and uncertainty in the summary; use the necessary proposal text if a shorter summary would hide the decision scope.
proposal_summary remains the full stored proposal in the MCP response. Full text, history, identifiers and exact review links are preserved; only routine chat presentation is shorter. Show the full text or identifiers when requested or needed for disambiguation or recovery. Never invent or reconstruct a missing URL: say when no direct review link was returned and show the returned target identifiers. A required decision with a missing or inconsistent target must be reported without guessing. When user_decision_required=false, do not request a decision. Final acceptance or rejection remains the authenticated user's action in Hanary's web UI.
If the user explicitly asks to make a new child task executable now and there are no prioritized siblings under its prioritized parent, create it in one call with parent_id and planning_status: "prioritized"; Hanary places that first executable child at rank: 0 without a comparison. needs_decision and priority_pending siblings do not block this first executable child exception because they are not priority comparison targets. If prioritized siblings already exist, ask the user for sibling order and include a rank from the user's confirmed order. Otherwise, even the first child task under a parent remains a needs_decision candidate.
For existing tasks, plain reordering does not finalize execution readiness. After the user explicitly confirms or delegates priority, use prioritize_task for one existing task or batch_prioritize_tasks for a complete sibling order. For root-level work, explicitly pass expected_parent_id: null or parent_id: null; do not omit the field. A non-null parent must be the prioritized parent the user reviewed. These tools atomically update planning_status and sibling ranks. The batch tool rejects omitted existing prioritized siblings by default; use append_after only when the user explicitly keeps them after the listed tasks.
planning_status and executor_type are separate axes. planning_status answers when the task belongs in the priority chain; executor_type answers who can execute it. A clear coding task can be planning_status: "prioritized" and executor_type: "ai" when the user has placed it into priority and the cause, likely fix location, and verifiable completion criteria are known. A human task can also be prioritized when it requires hardware assembly, measurement, purchase, installation, field operation, external approval, or final human judgment.
When executor_type is omitted, Hanary assigns the safe human default without automatic executor classification or recommendation. Send executor_type: "ai" only after the user explicitly approves AI execution. Mixed work should usually be split: create the explicitly delegated AI implementation task separately from the human real-device or field validation task.
Priority placement and AI delegation are separate decisions. A task can be planning_status: "prioritized" and still remain a human task. In that case get_top_task should stop execution actions at the boundary and explain that the user must explicitly delegate AI execution or explicitly choose lower-priority AI work before the assistant changes executor_type, starts execution work, or moves down the priority list. If advisory_allowed=true, the assistant should default to guide mode when the user asks to start, asks for help, or asks what to do next. A completion follow-up or next-work necessity assessment remains read-only within guide mode; it does not authorize advisory time tracking or record writes.
For human tasks, guidance is still useful and allowed. The assistant can help the person perform the task through safe autonomous advisory work: read-only inspection, public research, summaries, checklists, verification plans, safety/risk notes, evidence organization, draft communication, draft measurement criteria for user confirmation, new non-overwriting support documents, and interpretations of results the user reports back. This is advisory support, not task execution or final judgment. The assistant should give the first 1-3 concrete user steps rather than stopping at an AI delegation prompt.
For the current top-priority human task, advisory time tracking is also allowed
as a collaboration record when the user asks to start, asks for help, asks what
to do next, or asks to work together.
This use of start_task does not delegate completion, change executor type, or
change priority. Stopping time tracking is intentionally stricter: do not stop a
user-started session without confirmation, and do not stop any advisory session
unless the user asks to stop, wrap up, or says the work is here for now.
When starting a child task while an ancestor task has an active session,
start_task defaults to ancestor_session_action: "ask" and returns a
confirmation payload instead of silently stopping the ancestor session. After the
user confirms, call start_task with ancestor_session_action: "switch" or use
switch_active_session(from_task_id, to_task_id) to stop the ancestor session
and start the child session.
Completion Policy
complete_task should be called against the user's saved completion-criteria selection. A saved completion_criteria_source: "title" means the user explicitly confirmed that the task title itself is the completion standard; do not repeat the title in completion_criteria. A saved completion_criteria_source: "explicit" means the task has a separate completion_criteria. Reuse either saved selection by calling complete_task with only task_id (and optional retrospective); do not prompt for or resend a criterion that is already saved.
With active completion_criteria_delegated consent, the host AI can define or revise the standard directly through prepare_task_completion_criteria and save_task_completion_criteria without repeated approval. Only when no completion-criteria source is saved and no active grant or separate explicit instruction covers the decision should the assistant ask the user to choose. If the user explicitly confirms that the title is sufficient, call complete_task with completion_criteria_source: "title". If the user defines a separate standard, send completion_criteria_source: "explicit" together with completion_criteria. Never infer that a title is sufficient, copy it into the separate field, or invent a criterion without the applicable permission. Criteria delegation never grants execution or completion authority. If the effective criteria are clear and verifiable, the agent may judge completion from evidence such as tests, deployment status, or document changes; if sufficiency is vague or depends on taste, values, social agreement, or priority judgment, ask the user to confirm it.
AI execution and human time
Autonomous AI work uses a separate execution record, not the user's timer:
- Read
get_top_task; only this scope's current hierarchical top task with explicitexecutor_type: "ai"delegation can start. - Call
start_delegated_executionwithtask_id, a stableexternal_session_id, and anidempotency_key. Retain the IDs and returned version; reuse the same key on retries. If the host has no conversation ID, generate and retain an opaque ID. The bridge's process run ID is not a conversation identifier. - Report
running,waiting, orblockedwithupdate_execution_status, supplying the execution ID, external session ID, andexpected_version. - Call
finish_delegated_executionwithsucceededorfailed. This does not complete or approve the task; existing completion criteria and user approval still apply tocomplete_taskseparately.
Use list_delegated_executions(task_id) for the active run and recent history.
get_task and get_top_task include execution_context. Different scopes can
run concurrently alongside a human timer. One task cannot have two active AI
claims. AI wall-clock duration includes waits; it is not human time or compute
usage and is not added to existing human time statistics.
A heartbeat missing for 15 minutes means liveness is unknown, not stopped.
Hanary does not automatically release stale claims or cancel external processes.
After confirming the host is stopped, the owner can use
cancel_delegated_execution with the execution ID, version, and reason, even if
the old conversation identity was lost. Priority changes do not cancel runs.
start_task remains for human work and intentional advisory collaboration.
Replacing any other active human timer requires user confirmation and the exact
expected_active_session_id from the prompt; a stale source is rejected.
Do not stop another timer as a workaround. If the execution tools are unavailable,
explain that this connection cannot provide Hanary AI execution tracking; do not
claim a registered execution or substitute start_task for AI work. Check the
current connection's actual start/update/finish/list tools before claiming a run.
For local stdio, refresh the package and restart the actual host/MCP process.
For an external app, verify its connector registration and tool catalog refresh
or reconnection separately. A local package refresh does not update that app's
schema, and an unknown server label alone does not identify the cause. Do not
invent a server name or switch connections/scopes automatically to bypass the
missing tools.
Development
# Clone and install
git clone https://github.com/hanary/hanary-mcp.git
cd hanary-mcp
uv sync
# Run locally
HANARY_API_TOKEN=your_token uv run hanary-mcp --squad test
# Run tests
uv run --with pytest python -m pytest
Enhanced Features
Beyond the MCP tools, this project includes commands, skills, and agents for better UX.
Slash Commands
| Command | Description |
|---|---|
/hanary-status |
Show current task status and squad overview |
/hanary-start |
Begin working on top priority task |
/hanary-done |
Complete current task against user-defined completion criteria and get next |
Skills
- hanary-workflow: Complete task management workflow with estimation patterns and best practices
Agents
- task-planner: Drafts structured subtasks and estimates for user review
Platform Setup
Claude Code
Files auto-discovered from .claude/ directory:
.claude/
├── commands/ # /hanary-status, /hanary-start, /hanary-done
├── skills/
│ └── hanary-workflow/
│ └── SKILL.md
└── agents/
└── task-planner.md
For project-specific squad separation, use the .mcp.json generated by hanary-mcp init --squad ... in each project. Global CLI registration binds hanary to one squad across projects, so use it only for a single shared default:
claude mcp add hanary -- uvx --refresh-package hanary-mcp --from hanary-mcp hanary-mcp
OpenCode
Files auto-discovered from .opencode/ directory:
.opencode/
├── commands/ # /hanary-status, /hanary-start, /hanary-done
└── agents/
└── task-planner.md
Skills are shared via .claude/skills/ (OpenCode reads both .opencode/skills/ and .claude/skills/).
Configuration in opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"mcpServers": {
"hanary": {
"command": "uvx",
"args": ["--refresh-package", "hanary-mcp", "--from", "hanary-mcp", "hanary-mcp"]
}
}
}
Note: HANARY_API_TOKEN must be set as a system environment variable.
Directory Structure
hanary-mcp/
├── .claude/ # Claude Code files
│ ├── commands/
│ │ ├── hanary-status.md
│ │ ├── hanary-start.md
│ │ └── hanary-done.md
│ ├── skills/
│ │ └── hanary-workflow/
│ │ ├── SKILL.md
│ │ └── references/
│ └── agents/
│ └── task-planner.md
├── .opencode/ # OpenCode files
│ ├── commands/
│ │ ├── hanary-status.md
│ │ ├── hanary-start.md
│ │ └── hanary-done.md
│ └── agents/
│ └── task-planner.md
├── .mcp.json # MCP server config
├── opencode.json # OpenCode config
└── src/hanary_mcp/ # MCP Server implementation
License
MIT
Decision context in read responses
detect_overloadchecks configured risk signals, not available capacity. Itsassessmentreports scope and per-rule candidate, evaluated, missing-data and matched counts. No signal does not mean the schedule has spare time. In a squad-bound connection the calculation is restricted to the user's work in that squad; personal/global mode retains the accessible user-work scope.list_work_activity.review_summaryreports total, pending-review and excluding-pending-review minutes for the returned page's activity slices.get_taskwithinclude_time_summaryprovides the same breakdown undertime_summary.review_summaryfor the task across all actors and all time, including corrections and active sessions. Pending session IDs allow review; approval and correction remain subject to session ownership.exactdescribes recorded interval boundaries, and excluding pending review does not establish that the user verified every remaining record.- Use
lifecycle_statusfor the task's own state. Child progress and active time tracking are separate. Legacystatusmeanings are documented intask_state_semantics, including compact task summaries. list_hold_reviewsacceptsdue,needs_context,undated, orall.needs_contextfinds missing reasons or return paths, not every undated wait.update_hold_reviewsupplements the current reason/condition or reschedulesfollow_up_at; omit a field to keep it, use null to clear an optional field. It preserves original hold history, hold state, priority and timers. Resume explicitly withunhold_taskwhen the user chooses to do so.
Connection capabilities can differ. doctor checks the advertised tool inventory,
executor default and structured update input against the bridge's contract; a
missing field is a connection mismatch, not an instruction to invent an input.
Criteria and verification reports
Use get_task(include_resume_context=true) to read saved criteria and reported
evidence together. record_verification_report appends a report against the
exact expected_criteria_source and expected_criteria_text you read, with a
retained idempotency_key, checked scope, optional limitations, and up to ten
items (criterion, outcome: met/unmet/unknown, optional checks, evidence,
and HTTP(S) result_url). A changed criterion rejects a stale submission.
list_verification_reports reads three reports per page; pass its
next_before_id as before_id for older reports. The web task resume panel shows
the same records and highlights changes to the original criterion. Corrections
are new reports; existing notes remain intact. After a lost write response, use
get_mutation_result or retry the identical request with its original key.
Reports are AI-reported evidence, not independently verified tests, complete
criterion coverage, user approval, or automatic task completion.
First-action drafts
Use get_task(task_id="…", include_planning_context=true) to reuse the saved
goal, current purpose and completion picture. The optional planning_context
contains original note IDs, explicit missing states and drafting guidance.
Present 1–3 small first-action candidates with reasons, asking only for missing
information that changes the first action. Let the user edit, select or cancel
before saving accepted candidates through create_task. Its default
needs_decision state keeps priority confirmation separate; reading context or
drafting candidates does not assign an executor, choose completion criteria,
or start a timer or execution. Existing executor inheritance still applies when
a user accepts a child task. Omitting the option preserves the existing response.
Metadata
Release files for hanary-mcp 0.40.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| hanary_mcp-0.40.0.tar.gz | 267.6 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hanary_mcp-0.40.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 401.0 kB
Release files / hanary_mcp-0.40.0.tar.gz
| Download URL | hanary_mcp-0.40.0.tar.gz |
|---|---|
| Size | 267.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d7466a761e2a9bb6487916ddbc919d84a5a1f6936a7ccc792dee6be28c6329da
|
|
BLAKE2b-256 checksum How to use checksums |
349f5e7e6447c79b0ea3b05c6a0475dfc2d2d4a743090c683414f05d3beac1f1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / hanary_mcp-0.40.0-py3-none-any.whl
| Download URL | hanary_mcp-0.40.0-py3-none-any.whl |
|---|---|
| Size | 133.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
85dfca6358ededaab7d02d2166667d7d3a86e888b1085fa7a412353fdc2c56ab
|
|
BLAKE2b-256 checksum How to use checksums |
76b37bc8c8196af5ee08b68e6a01426858afa143222affb775857eed981440d7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logSecurity for hanary-mcp 0.40.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for hanary_mcp-0.40.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.