# io.github.Harflow-Dev/harflow-mcp (pypi · harflow-mcp)

Dispatch coding tasks to local headless agents with persistent history and workflows.

- Trust score: 78/100 (medium)
- Change this week: +18
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-11-05

## Components

- pypi · `harflow-mcp`: 78/100 (this document), [markdown](https://verifymcp.io/servers/harflow-dev-harflow-mcp/harflow-mcp.md), [page](https://verifymcp.io/servers/harflow-dev-harflow-mcp/harflow-mcp)

## Channel facts

- Registry: `pypi`
- Package: `harflow-mcp`
- Version: `0.0.10`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-11-05.

- **Supply Chain Security**: 100/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs hatchling.build at install time, a recognised build step with no custom scripting around it.
  - 1 of 29 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 97/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to Harflow-Dev/HarflowMCP).
  - Clear OSI-approved license (Apache-2.0).
  - Actively maintained (last published 0 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 45/100
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 18109 tokens (~329/item across 55 items; 55 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 47/100
  - Stability observed for 14 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 71/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Tool Safety**: 75/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 0 of 4 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "send_message" implies "send" and declares no destructiveHint at all, which the MCP spec reads as destructive by default.
  - An AI judge read all 56 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

## Install

### How do I install the io.github.Harflow-Dev/harflow-mcp server?

io.github.Harflow-Dev/harflow-mcp runs locally as a PyPI package, launched with uvx harflow-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add harflow-dev-harflow-mcp -- uvx harflow-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "harflow-dev-harflow-mcp": {
      "command": "uvx",
      "args": [
        "harflow-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "harflow-dev-harflow-mcp": {
      "command": "uvx",
      "args": [
        "harflow-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add harflow-dev-harflow-mcp -- uvx harflow-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "harflow-dev-harflow-mcp": {
      "type": "local",
      "command": [
        "uvx",
        "harflow-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add harflow-dev-harflow-mcp --command uvx --arg harflow-mcp
```

### Hermes

```yaml
mcp_servers:
  harflow-dev-harflow-mcp:
    command: "uvx"
    args: ["harflow-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "harflow-dev-harflow-mcp": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "harflow-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add harflow-dev-harflow-mcp -t stdio -c uvx -a harflow-mcp
```

### Other

```json
{
  "mcpServers": {
    "harflow-dev-harflow-mcp": {
      "command": "uvx",
      "args": [
        "harflow-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-11-05 (score 78, +44)

- [security improvement] Malware scan: unverified → pass
- [security improvement] Injection markers: unverified → pass
- [functional improvement] Tool coverage: unverified → 100
- [functional improvement] MCP protocol: unverified → pass
- [functional improvement] Stability: unverified → 0.47
- [functional] Package version: 0.0.9 → 0.0.10

### 2026-11-04 (score 34, −43)

- [security regression] Stability: 0.40 → unverified
- [security regression] Malware scan: pass → unverified
- [security regression] Tool safety: pass → unverified
- [functional regression] Capabilities: pass → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional] First check of Schema quality: unverified
- [functional] Package version: 0.0.7 → 0.0.9
- [functional] Package version: 0.0.7 → 0.0.8

### 2026-11-03 (score 77, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-11-02 (score 62, −14)

- [security regression] Malware scan: pass → unverified
- [functional] Package version: 0.0.6 → 0.0.7

### 2026-11-01 (score 76, 0)

- [security regression] Tool safety: pass → unverified
- [security regression] Stability: 0.30 → unverified
- [functional regression] Schema quality: 15162 → 18053
- [functional regression] Capabilities: pass → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional] First check of Schema quality: unverified
- [functional] Package version: 0.0.5 → 0.0.6

### 2026-10-31 (score 76, +1)

No change was recorded against any check on this day. Stability & Change Management went from 27 to 30. That category is still filling its 30-day observation window: 8 days of observed history at the previous scan, 9 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-30 (score 75, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-10-29 (score 60, 0)

- [functional] Package version: 0.0.4 → 0.0.5

## MCP tools (55)

### `list_backends` (~162 tokens)

Report the available agent backends, what is installed, and what each can actually do.

Worth calling before start_task if the choice is not already obvious. Each entry carries its
\`capabilities` (turn cap, cost reporting, OS sandbox, per-command deny, whether we can choose
the session id) and, for every `freedom` level, the enforcement it really delivers.
Ordinary script entrypoints retain version discovery and native eligibility checks.
Extra-path qualification separately rejects selected scripts before version execution.
capabilities.extra_writable_paths reports bounded support, certification and refusal reason;
capabilities.allowed_commands and caller_approval_support report their qualification gates.
At unrestricted freedom, extra_writable_paths is a validated, disclosed no-op, not a bounded grant.

Output parameters:

- `result` (array)

### `start_task` (~3615 tokens)

Dispatch a coding task to a headless agent and return immediately.

Args:
    prompt: Instructions for the agent. Be specific about the desired end state. Write it in
        plain prose: preserve spaces and word boundaries, and never concatenate words or strip
        whitespace to shrink the payload — harflow_mcp stores and delivers the text exactly as
        submitted, so compressed text reaches the agent exactly as garbled. Blank or
        all-whitespace prompts are rejected rather than trimmed into shape.
    repo_path: Absolute path to a git repository; the agent's working directory.
    backend: Which harness to use — "claude", "codex", "opencode", "vibe" or "antigravity". See
        list_backends.
    freedom: "read_only", "write_in_repo" (default), "publish", or "unrestricted". "publish"
        sits between "write_in_repo" and "unrestricted": it authorizes an attempt to
        remote publishing, including commit/push/PR creation/reviews, but that is not a promise the attempt succeeds — credentials,
        remote permissions, branch protection and hooks are all
        outside harflow_mcp's control. On Claude Code, write_in_repo denies a direct `git commit`
        and `git push`; `publish` authorizes committing; inherited harness rules can still restrict it. `enforcement.local_commit`
        reports that policy as denied, allowed, or not_enforced. How each level is enforced
        depends on the backend; the returned `enforcement` says what actually applies, via
        `local_commit`, `publish_attempts_allowed` and `network_access` among other fields.
    model: Model for this run, in the backend's own naming. Rejected outright, rather than
        silently ignored, when model selection is unsupported. Vibe accepts a configured
        model alias through its qualified ACP transport and verifies the selected alias;
        see list_backends' capabilities.supports_model_selection.
    background_idle_seconds: Optional finite positive live-input bac…

Input parameters:

- `allowed_commands`
- `auto_continue` (integer)
- `backend`
- `background_idle_seconds`
- `base`
- `branch`
- `caller_approvals` (boolean)
- `caller_write_approvals` (boolean)
- `extra_writable_paths`
- `fetch`
- `fetch_required` (boolean)
- `freedom`
- `git_https_rewrite`
- `group`
- `group_report_output`
- `interaction_owner` (string)
- `max_turns`
- `model`
- `network`
- `notify`
- `observe_repos`
- `prompt` (string, required)
- `reasoning_effort`
- `repo_path` (string, required)
- `resource_wait_seconds`
- `resources`
- `title`
- `workflow`
- `worktree`

### `list_approval_requests` (~109 tokens)

List bounded permission request metadata for exactly one task or root workflow tree.

Default page size 16, maximum 32. Raw actions appear only in get_approval_request.
Workers and orchestrators cannot inspect caller approval records. A pending request is
an interaction substate; underlying execution remains running. No approval is inferred
from agent prose, errors or already denied actions.

Input parameters:

- `cursor`
- `limit` (integer)
- `task_id`
- `workflow_run_id`

### `get_approval_request` (~66 tokens)

Read the complete exact action for an authorized direct caller.

Inspect this payload before approving; request IDs, digest and revision are comparison
fields, never authorization tokens. Payloads may contain sensitive command arguments.

Input parameters:

- `request_id` (string, required)
- `task_id` (string, required)

### `respond_approval_request` (~332 tokens)

Reserve approve/reject for one exact action, with stale/duplicate answer protection.

Only the authoritative root interaction owner can answer; workers/orchestrators cannot
self-approve. interaction_owner="monitor" is refused on this MCP caller channel: the Monitor
answers through harflow-ctl, and every MCP decision is recorded as a caller decision. Approval preserves exact original input and never
installs permission suggestions or reusable grants. Reservation, local pipe delivery and
observed tool outcome are separate states. No ambiguous decision is automatically resent.
A request unanswered after 1800 seconds, or at an earlier workflow attempt deadline, is
rejected by Harflow (approval_expired) and never approved; a stale or expired answer fails.
There is no approve-later path after a denial or expiry. Recovery is always a new resume_task
or continue_task execution of the finished task, and what to change follows the denied entry's
denial_remedy: allowed_commands covers only Bash approval_required and chained_command parts;
a denied or expired Read, Write or Edit needs a resumed run (caller_approvals and
caller_write_approvals are inherited) so the agent can raise a fresh request; path_safety and
outside_working_directory go through caller approvals, not grants; a deny_rule cannot be lifted
by grants. Messages and resume are never decisions.

Input parameters:

- `action_digest` (string, required)
- `decision` (string, required)
- `interaction_owner` (string)
- `owner_revision` (integer, required)
- `request_id` (string, required)
- `task_id` (string, required)

### `preview_task_permissions` (~448 tokens)

Preview standalone task permissions without launching an agent or allocating scratch.

With qualification_only, returns only the cached qualification requirement plan before
provider self-tests, path certification or owner checks; launch still validates those gates.
Empty required feature sets need no binary inspection.

Uses the same bounded extra_writable_paths validation, installed-version checks and detected
owner caps as start_task. Returns requested/effective typed paths, certification and truthful
enforcement. Writable scratch-aware launches disclose future task, chain and group scratch
symbolically in writable_roots without allocating them; read-only previews have no scratch root.
The preview is an observation, not a reservation: launch revalidates paths and
configuration. Extra grants never authorize publication. Workflow/native-adapter grants and
unverified harness configurations are unavailable. Known external backend execution configuration
is protected; unsupported existing inputs reject requests. Existing repository configuration
authority retains its baseline limits. Grants authorize output writes, not trust in that output
as a future repository, hook or executable. Startup inputs are checked, not atomically
pinned against independently authorized concurrent writers; see docs/extra-writable-paths.md.

group_report_output opts in to a qualified read_only run whose sole writable root is its
concrete canonical group folder (group is required or inherited). No folder is allocated.
This excludes caller approvals, native children and extra writable grants.

allowed_commands is validated exactly as in start_task (grammar, installed backend version,
nested-subset cap) and the returned enforcement lists it as extra_allowed_commands.
branch, base and fetch are validated the same way as start_task and shown as dispatch_git
without running Git.

Input parameters:

- `allowed_commands`
- `backend`
- `base`
- `branch`
- `caller_approvals` (boolean)
- `caller_write_approvals` (boolean)
- `extra_writable_paths`
- `fetch`
- `fetch_required` (boolean)
- `freedom`
- `git_https_rewrite`
- `group`
- `group_report_output`
- `network`
- `qualification_only` (boolean)
- `repo_path` (string, required)

### `subscribe` (~125 tokens)

Durably subscribe to one task's observed terminal settlement using a configured alias.

Direct callers only. The server administrator configures HARFLOW_NOTIFY_DESTINATIONS; caller URLs
and secrets are refused. Repeated task/alias subscriptions share a stable event ID. Delivery
retries at most six times and can duplicate after a crash: receivers must deduplicate IDs.
Pending delivery resumes while a configured server is active, not while every server is down.
Delivery failure never changes task execution. See docs/task-notifications.md.

Input parameters:

- `notify` (string, required)
- `task_id` (string, required)

### `get_task_notifications` (~29 tokens)

Read bounded subscription delivery states; this never establishes task success.

Input parameters:

- `task_id` (string, required)

Output parameters:

- `result` (array)

### `unsubscribe` (~39 tokens)

Stop future attempts for a task/alias (or all aliases); in-flight requests may finish.

Input parameters:

- `notify`
- `task_id` (string, required)

Output parameters:

- `result` (array)

### `get_task_status` (~1013 tokens)

Report a dispatched task's current state without blocking.

Args:
    task_id: Identifier returned by start_task or resume_task, or a unique prefix of at
        least 8 characters; a prefix reply carries resolved_from.
    include_tail: If True, include the full last_output_tail (20 lines × 2000 chars each);
        if False (default), the tail is omitted for running/completed tasks and shortened
        to 5 lines × 500 chars for failed tasks. The caller can request the full raw stream
        log path from `raw_stream_log` in full detail for complete output, or use get_task_events for
        normalized events.
    brief: Compatibility alias for detail="compact"; preserves the complete summary.
        include_tail=True still explicitly requests the full tail.
    detail: "compact" (default) omits static execution metadata and detailed outcome probes;
        "full" returns complete MCP status. Both retain the complete summary/report,
        approval attention, failure diagnostics and recovery uncertainty.
    include_successors: Fetch the first authorized page of successor IDs. Defaults false:
        ordinary polling includes a detail reference without scanning retained task history.

A task still waiting for its `resources` has no record yet: it reports `status: "running"`,
\`launch_state` (`waiting_for_resources`, `granted`, `uncertain`, or `not_started` once it
settled without starting, with `not_started_reason`) and `resources` (names, queue `position`,
\`blocked_by`, deadline). See docs/resources-and-worktrees.md.

Full detail returns the task's status, summary, enforcement, and `recent_activity` — a list of ≤ 5 one-line
strings describing the most recent meaningful events (tool calls, failed tool results, assistant
messages, notices). For running tasks this gives a live summary without the bulk of the
raw stream. These lines deliberately collapse whitespace and truncate to stay short — they are
a summary only; the stored event log (see get_task_events) an…

Input parameters:

- `brief` (boolean)
- `detail` (string)
- `include_successors` (boolean)
- `include_tail` (boolean)
- `task_id` (string, required)

### `wait_for_task` (~791 tokens)

Wait for a task to finish, giving up after a timeout without disturbing the run.

Args:
    task_id: Identifier of the task to await.
    timeout_seconds: How long to hold, 0..3600 (default 50; 0 observes once without
        sleeping). Honoured as asked, never silently clamped; out of range is INVALID_PARAMS.
        Breaking change: values above 3600 are now rejected (0 is newly accepted). Your MCP
        client applies its own request deadline, and exceeding it fails the *call* even though
        the task keeps running — see docs/multi-task-waiting.md before asking for long holds.
    include_tail: If True, include the full last_output_tail (20 lines × 2000 chars each);
        if False (default), the tail is omitted for running/completed tasks and shortened
        to 5 lines × 500 chars for failed tasks.
    detail: "compact" (default) omits static execution metadata and detailed outcome probes;
        "full" returns complete MCP status. Both preserve the complete summary/report,
        approval attention, failure diagnostics and wait fields. include_tail=True retains
        the full tail in either mode.
    until: "timeout" (default) returns when the task settles or timeout_seconds elapses.
        "terminal" holds until the task settles, bounded only by a 6 hour server ceiling;
        timeout_seconds must then be omitted (passing both is INVALID_PARAMS).
    ctx: Injected by the server; not a caller argument.

The result is the task status plus `requested_timeout_seconds`, `effective_timeout_seconds`,
\`until`, `timed_out`, `stop_reason` (terminal, attention, timeout, ceiling or observation_unavailable),
\`elapsed_seconds` and `polling_guidance`. If the task is still going when the wait ends, the
status is "running" with a `next_step` hint: call this again, or poll get_task_status. The
dispatched process is never signalled, written or resumed by a wait, so waiting is always safe
and repeating it costs nothing. For a task recovered from an earlier server…

Input parameters:

- `detail` (string)
- `include_tail` (boolean)
- `task_id` (string, required)
- `timeout_seconds`
- `until` (string)

### `wait_for_tasks` (~387 tokens)

Observe 1..32 unique task IDs, returning compact statuses in requested order.

mode any returns when at least one requested task is settled; all waits for every task.
timeout_seconds accepts 0..3600 (default 30) and is honoured as asked, never silently clamped;
out of range is INVALID_PARAMS. Zero polls immediately. until="terminal" holds until the mode
is satisfied, bounded by a 6 hour server ceiling, and requires timeout_seconds to be omitted.
Your MCP client's own request deadline still applies. Prefer holds <=50 seconds after
remote "device did not respond" or "connection closed" errors; see docs/multi-task-waiting.md.
All IDs must exist and pass caller read authorization before waiting.
Existence checks and initial metadata share a two-second I/O budget; undecidable existence
rejects the request. A final metadata observation can add up to two more seconds.
Returns terminal_task_ids, bounded summaries and get_task_status diagnostic references;
no output tails. A recovered task whose process is confirmed gone without an observed exit is
listed in undecidable_task_ids (status unknown) and counts as settled in both modes, as in
wait_for_task, after a short grace if its owning harflow_mcp server is still alive; an uncertain
identity keeps waiting. Under until="terminal", targets that stay unobservable for
3 rounds stop the wait with stop_reason observation_unavailable. Rows carry a bounded
failure_diagnostic (category, reason) when one exists. Also returns requested/effective
timeout, until, timed_out, stop_reason, elapsed_seconds and polling_guidance. Progress is sent
every 5 seconds. Timeout and caller cancellation never cancel or signal the observed tasks.

Input parameters:

- `mode` (string)
- `task_ids` (array, required)
- `timeout_seconds`
- `until` (string)

### `continue_task` (~470 tokens)

Start a fresh session from a conclusively settled standalone task.

This differs from resume_task: it reconstructs the original assignment, latest summary and
captured outcome, with optional UTF-8 notes and caller follow-up preserved verbatim. Oversized
evidence is referenced by path. Backend, model and access settings are retained. Process exit,
complete output drainage and a durable terminal record must be observed; old or inferred
records without settlement evidence are refused. Workflow-owned tasks use workflow recovery.
Concurrent identical retries share one successor; mismatched or unsettled reservations fail.
A source that had `resources` re-queues the same names; while they are busy the successor is
acknowledged with `launch_state: "waiting_for_resources"` (the reservation is `accepted`, and a
retry returns the same pending successor).
The returned continuation_of_task_id is separate from session resume/delegation ancestry.

Follow-ups queued on the source with send_message are consumed by this call: they appear
verbatim, in queue order, ahead of extra_prompt (or ahead of a fixed closing line when there is
none), and the new task's task_started event lists their message_ids. With nothing queued the
call behaves exactly as without the feature. Two manual calls with the same extra_prompt and
notes are the same request whatever is queued: the queue is read once, when the successor is
reserved, and a retry returns that successor. An automatic continuation never consumes.

group_report_output: omitted or null inherits the saved opt-in; false disables scoped output.
allowed_commands: omitted or null inherits the source task's saved command grants (an automatic
continuation always does); a list replaces them after the same validation and nested-subset check
as start_task. See start_task for the grammar and limits.
fetch refreshes remote-tracking refs before the fresh session, the same way as start_task.
Continuations reuse a branch prepared at the original dispatc…

Input parameters:

- `allowed_commands`
- `background_idle_seconds`
- `extra_prompt`
- `fetch`
- `fetch_required` (boolean)
- `git_https_rewrite`
- `group_report_output`
- `notes_path`
- `task_id` (string, required)

### `resume_task` (~767 tokens)

Continue a finished task's session with follow-up instructions.

Args:
    task_id: A task that has finished; its session is the one resumed.
    followup_prompt: What the agent should do next, with the prior context intact. Write it
        in plain prose, as with start_task's prompt: preserve spaces and word boundaries and
        never concatenate words to shrink the payload — the text is stored and delivered
        exactly as submitted. Blank or all-whitespace follow-ups are rejected rather than
        trimmed into shape. May be omitted only when the task has follow-ups queued with
        send_message (see below); otherwise it is required.
    max_turns: Cap on agent turns, where the backend supports one.
    network: Optional boolean overriding the parent run's network setting for this run only:
        None (the default) inherits what the parent was dispatched with — which is also the
        historical default for a record written before the field existed — True asks for no
        network barrier of harflow_mcp's own, False asks for one, honoured or refused exactly
        as on start_task for the parent's freedom.
    fetch: Optional refresh of remote-tracking refs before the resumed agent starts. true uses
        the default remote; a list names remotes. A prepared branch is reused and is not recreated.
        branch and base are not accepted on resume.
    fetch_required: When true, a fetch failure refuses the resume.
    group_report_output: None inherits the saved group-scoped output opt-in; false disables it.
    allowed_commands: None (the default) inherits the parent's saved command grants; a list replaces
        them for this run after the same validation and nested-subset check as start_task, which
        documents the grammar and limits.

Follow-ups queued on the task with send_message are consumed by this call, exactly once: the
prompt is each queued message as a block "Queued caller follow-up N of M (message <id>, queued
\<time>):" follow…

Input parameters:

- `allowed_commands`
- `background_idle_seconds`
- `fetch`
- `fetch_required` (boolean)
- `followup_prompt`
- `git_https_rewrite`
- `group_report_output`
- `max_turns`
- `network`
- `task_id` (string, required)

### `list_tasks` (~534 tokens)

List dispatched tasks, oldest first.

Args:
    status: Optional filter — running, completed, failed, timed_out or cancelled.
    backend: Optional filter by harness, e.g. "codex".
    waiting_for_resource: Optional resource name: only launches that have not started and are
        still queued for it (`launch_state: "waiting_for_resources"`). Uses the unpaged listing.

The unpaged listing also carries launches that are waiting for resources and have no task
record yet (`pending_launch: true`); the indexed page does not.

Includes tasks from earlier harflow_mcp server processes, marked `recovered: true`.
Supplying group/title_contains/repo/since/limit/fields/cursor selects a bounded newest-first
indexed page (default limit 50, maximum 100), rather than the legacy oldest-first list.
since is an inclusive ISO8601 timestamp with timezone. fields selects compact names. Accepted
fields, in sorted order: background_idle_seconds, backend, dispatch_origin, duration_seconds,
finished_at, group, input_channel, last_captured_output_at, needs_direct_lookup,
needs_reconciliation, note, observation_mode, observation_note, observed_exit, output_capture,
owner, parent_task_id, persisted_status, process_identity_state, recovered, repo_path,
responding_server, root_task_id, session_id, started_at, status, task_id, title. The repository
field is repo_path, not repo. Identity and status fields are always included: task_id, status,
needs_reconciliation, needs_direct_lookup, persisted_status, observed_exit, process_identity_state.
An unknown name, an empty list, a non-string entry and a list longer than the accepted set each
produce their own error, and the error names the bad entries and lists the accepted ones.
Accepted filters: group, title_contains, repo, status, backend, since, predecessor_task_id.
Filters run before pagination;
cursor binds filters. Status is the indexed observation: inspect needs_reconciliation and
observed_exit before interpreting it. See docs/compact-task-reads…

Input parameters:

- `backend`
- `cursor`
- `fields`
- `group`
- `limit`
- `repo`
- `since`
- `status`
- `title_contains`
- `waiting_for_resource`

Output parameters:

- `result`

### `list_task_page` (~138 tokens)

Stable newest-first persisted task headers; inspect a task for reconciled status/output.

bootstrap_pending indicates bounded indexing or requested-header refresh is preparing.
Preserve loaded headers and cursors while catalog_state reports preparing.
Active-only pages are a separate inventory and do not reorder history cursors.
predecessor_task_id selects direct resumes and continuations of that task, for following
successor links without scanning all retained history. Combine it with the returned cursor.

Input parameters:

- `active_only` (boolean)
- `cursor`
- `limit` (integer)
- `predecessor_task_id`
- `session_id`
- `task_ids`

### `recent_limit_hits` (~323 tokens)

Latest provider usage-limit hit per backend and requested model, from persisted task records; direct callers only.

Read-only: nothing is retried, switched or continued. Evidence is a persisted task
failure_diagnostic with category usage_limit (never provider_error or prose). There is no
pagination: a query sees only the newest 500 hits that match its since, backend and model
bounds, so filtering by backend (or backend and model) gives each its own newest-500 window,
while an unfiltered query sees only the newest 500 overall. repo and group filter inside that
window. model is the requested model; a task on the backend default has requested_model null.
since is an inclusive ISO8601 timestamp with timezone. At most 50 backend/model keys are returned.
scan.complete is false when older matching hits were left unexamined, the key cap was reached, or
the index is still preparing (index_state), so retry while it is preparing.
Each hit carries task_id, title, group, observed_at (when the task settled: finished_at, else
started_at, named by observed_at_source; not necessarily when the provider rejected the request), diagnostic and reset {raw, at, state}. A numeric reset is epoch seconds.
reset.state is future, elapsed or unknown; elapsed only says the stated time has passed and does
not say the provider is available again. See docs/usage-limits.md.

Input parameters:

- `backend`
- `group`
- `model`
- `repo`
- `since`

### `cancel_task` (~306 tokens)

Stop a running task, terminating the agent and any processes it spawned, and cascade the
same stop to any live descendants this bridge can find.

Args:
    task_id: Identifier of the task to stop.

A launch still waiting for resources is stopped before it starts: the request is recorded, its
owner honours it at the next poll, and pending descendants are asked to stop too
(`cascade.pending_cancel_requested`).

Already-finished tasks are returned unchanged. Work the agent had already written to disk is
left in place. Tasks started by an earlier harflow_mcp server process can be stopped too, via
their recorded process group.

The cascade reaches nested dispatches that task's own agent made through harflow_mcp —
\`spawned_by`/`root_task_id` lineage, best-effort, not a sandboxed guarantee — and the response
carries the result as `cascade`: `cancelled_descendants` (ids now cancelled),
\`sigkill_survivors` (ids that resisted even SIGKILL), `owner_still_settling` (ids belonging to
a still-alive bridge server that has not settled them yet), `not_signalled` (ids that
could not be signalled at all, with why), and `not_recorded` (ids that were signalled but
whose `cancelled` status could not be written, with why — their records are left untouched).

Input parameters:

- `task_id` (string, required)

### `get_task_events` (~559 tokens)

Fetch normalized events from a task's event log.

Args:
    task_id: Identifier of the task whose events to read.
    limit: Maximum number of events to return, capped at 200. Default is 50.
    before_seq: Exclusive upper bound — return events with seq < before_seq (older events).
        Cannot be used with after_seq.
    after_seq: Exclusive lower bound — return events with seq > after_seq (newer events).
        Cannot be used with before_seq.
    kinds: Optional filter by event kind. Must be a non-empty list of known kinds from
        `task_started`, `assistant_text`, `assistant_delta`, `tool_call`, `tool_result`,
        `user_message`, `usage`, `notice`, `task_finished`, `undelivered`.
        `assistant_delta` is excluded by default unless explicitly listed. Pass `null`
        to get all kinds except assistant_delta.

Returns events in oldest→newest order within the page, with:
\- `events`: list of event objects with their `seq`, `kind`, and data fields
\- `has_more`: true if there are more matching events in the requested direction
\- `next_before_seq`: the `seq` of the oldest event in this page (for paging older)
\- `next_after_seq`: the `seq` of the newest event in this page (for paging newer)
\- `skipped_oversized`: count of lines > 1 MiB that were skipped (not parsed, not counted as events)

For the complete final summary/report, use get_task_status in compact or full detail;
event pages are bounded and are not a lossless final report read.

Each returned event has its long string fields truncated to 2000 chars, lists to 50 items,
and dict nesting to depth 4, with `"truncated": true` added if anything was cut. An event still
over 16 KiB after that (a very wide dict) is replaced by a stub carrying only `seq`, `kind`,
\`observed_at`, `truncated: true`, `oversized: true` and its size in `bytes`. A page
stops early once its serialized size would pass 256 KiB (has_more remains true, cursors still
valid). A page is never empty while has_more is true.

Default (n…

Input parameters:

- `after_seq`
- `before_seq`
- `kinds`
- `limit` (integer)
- `recovery_cursor`
- `task_id` (string, required)

### `get_task_event_page` (~138 tokens)

Read one bounded recent or older activity page using an opaque stable cursor.

Defaults to 100 records; each call reads at most 1 MiB plus integrity anchors
and returns at most 256 KiB. Pass next_cursor for exactly one older page.
Append-only live growth preserves the historical snapshot. Replacement or
truncation requires reloading without a cursor. Filtering can return an empty
page with has_more true. An indexing response exposes no task events; retry
after the bounded legacy catalog bootstrap advances.

Input parameters:

- `cursor`
- `kinds`
- `limit` (integer)
- `task_id` (string, required)

### `send_message` (~248 tokens)

Queue exact caller prose for any task's next continuation or owning workflow dispatch.

\`delivery` is `queue` (default; never folds into the current turn) or `now`. Now starts a
safely settled standalone continuation; an unsafe interruption returns a stable `refusal`
alongside the queued message id, preserving the message for later. When `delivery` is `queue`
and resolve_status says the target has already finished, the reply keeps the queued message id
and adds `target_settled: true`, `target_status`, and a note that the message waits for
resume_task / continue_task (or delivery="now"). A running target, including a recovered task
that is still alive, returns the same reply as before, with no settled fields. Workflow/node
messages follow their owning workflow and never widen node authority; a completed non-builder
or cancelled run says no further dispatch will consume the message. Use `interaction_owner=monitor`
only from a verified human Monitor caller. Status exposes messages and queued_followups.

Input parameters:

- `delivery` (string)
- `interaction_owner` (string)
- `task_id` (string, required)
- `text` (string, required)

### `cancel_queued_message` (~50 tokens)

Withdraw a still-queued task or workflow-owned message; claimed messages are refused.

Input parameters:

- `interaction_owner` (string)
- `message_id` (string, required)
- `task_id` (string, required)

### `send_workflow_message` (~161 tokens)

Queue a workflow or node message for its next issued dispatch. Exact prose and order are
preserved. `now` refuses unsupported interruption or required checkpoints while keeping the
queued message and returning its id plus a stable refusal code. A queued message to a completed
non-builder or cancelled run adds `target_settled`, `target_status` and a note that no further
dispatch will consume it; a running run, a failed run and a completed builder omit those fields.
No permission, goal, decision or attempt budget is changed. Owner checks match other workflow interactions.

Input parameters:

- `delivery` (string)
- `interaction_owner` (string)
- `run_id` (string, required)
- `task_id`
- `text` (string, required)

### `cancel_workflow_message` (~49 tokens)

Cancel one queued workflow message. Delivering and delivered messages cannot be withdrawn.

Input parameters:

- `interaction_owner` (string)
- `message_id` (string, required)
- `run_id` (string, required)

### `list_workflows` (~65 tokens)

List name, description, revision and workflow_id without graphs/instructions by default.

Use get_workflow(name) for one complete definition, or detail="full" for all definitions.
Incompatible or unavailable sources refuse the whole list in either mode.

Input parameters:

- `detail` (string)

Output parameters:

- `result` (array)

### `get_workflow` (~24 tokens)

Read a saved workflow definition and revision.

Input parameters:

- `name` (string, required)

### `save_workflow` (~473 tokens)

Validate and save an explicit workflow; expected_revision protects concurrent edits.

The store creates persistence envelopes; supply only the authored graph payload.
Incompatible or unavailable saved sources refuse mutation and complete-store indexing.
expected_workflow_id optionally checks the loaded stable identity, rejecting a
deleted or replaced same-name definition even if its revision matches.
Every save normalizes context_delivery to optimized_v1, including omitted or legacy
values. Historical runs retain their pinned delivery policy. Bounded delivery uses
session-bound acknowledgements and assigned evidence retrieval,
with a 64 KiB target that never silently cuts required constraints.
orchestrator.instructions holds the workflow purpose; Start and End have no settings.
on_demand_nodes is separate from connected nodes, with id/title, required instructions,
optional call_condition (When to call guidance), agent/fallbacks, freedom/network,
session_mode agent_decides|fresh|resume and execution_mode headless|prefer_subagent.
Standalone IDs are unique across both lists; connections cannot reference them.
max_on_demand_calls defaults to 5, range 1–50, per routing/question checkpoint;
no per-node or per-run call cap exists. Legacy Start prompt migrates on saved reads.
Set routing_mode="explicit". Ordinary nodes choose exactly one outgoing path.
Parallel execution uses paired parallel_start/parallel_end nodes with shared
parallel_group_id. Every branch reaches its matching end; nesting is supported.
A Run workflow node (type "workflow") references a saved workflow by
workflow_ref.workflow_id with orchestrator_mode child or current.
Child mode supports child_session_policy agent_decides (default), fresh, or
resume. Resume inherits only the latest completed compatible child
conversation in this immediate parent run, with fresh workflow state; an
unavailable explicit Resume fails closed. Current mode retains its owner. The whole
dependency tree is resolved and pinned…

Input parameters:

- `definition` (object, required)
- `expected_revision`
- `expected_workflow_id`
- `name` (string, required)

### `delete_workflow` (~32 tokens)

Delete a qualified definition after scanning qualified referrers; historical snapshots remain available.

Input parameters:

- `name` (string, required)

### `workflow_builder` (~623 tokens)

Generate a workflow, or refine the current canvas into an unsaved validated proposal.

Orchestrator instructions belong in orchestrator.instructions; Start/End are structural.
Optional on_demand_nodes are a separate ordered list with globally unique local id, title,
required nonempty instructions, optional call_condition (When to call guidance), agent,
freedom, network, session_mode agent_decides|fresh|resume and execution_mode.
They have no position, role or connections. max_on_demand_calls defaults to 5 (1–50)
per routing/question checkpoint; no per-node or per-run call cap exists.

Write prompt in plain prose: preserve spaces and word boundaries rather than
concatenating words to save tokens. The caller's prompt is retained unchanged
before builder input assembly.

Keep node and connection instructions concise and task-specific. HarflowMCP owns
runtime retries, budget enforcement, configured fallback dispatch and user interaction;
use existing configuration fields for limits and fallback candidates, and orchestrator
needs_input for clarification or approval. End means intentional workflow termination,
not waiting for user input. Preserve legitimate task branches and revision loops.

Layout uses top-left logical point coordinates with x/y >= 0 and a 10-point dot grid.
Agent nodes are 200 x 92 points (reserve 20 x 10 grid cells); Start/End are 72 x 72
(reserve 8 x 8 cells). Leave at least 40 points (4 cells) between node edges and avoid
overlaps. Arrange forward steps left to right and parallel branches on separate rows.
Use routing_mode="explicit". Ordinary outgoing paths are exclusive alternatives.
Parallel execution requires paired parallel_start/parallel_end structural nodes with
a shared parallel_group_id; every branch must reach its matching end. Parallel start
defaults to `branch_selection: "all"`. With `branch_selection: "orchestrator"`, the
orchestrator selects applicable issued branch continuations, assigns each selected entry
through `branch_assignments…

Input parameters:

- `agent`
- `definition`
- `fallbacks`
- `name` (string, required)
- `prompt` (string, required)
- `repo_path`
- `source`

### `followup_workflow_builder` (~164 tokens)

Queue a message in the same workflow-builder conversation without saving its draft.

Keep node and connection instructions concise and task-specific. HarflowMCP owns
runtime retries, budget enforcement, configured fallback dispatch and user interaction;
use existing configuration fields for limits and fallback candidates, and orchestrator
needs_input for clarification or approval. End means intentional workflow termination,
not waiting for user input. Preserve legitimate task branches and revision loops.

Preserve spaces and word boundaries in prompt rather than compressing natural
prose; the caller's source text is retained unchanged before builder input assembly.
Restarting an idle or completed builder sets the run's resumed_at; feedback queued to a
running builder does not.

Input parameters:

- `prompt` (string, required)
- `run_id` (string, required)

### `apply_workflow_draft` (~293 tokens)

Publish a preview from the verified active builder task; never write a saved workflow.

Positions are top-left logical points, with finite x/y >= 0, on a 10-point dot grid.
Agent nodes are 200 x 92 points (reserve 20 x 10 grid cells); Start/End are 72 x 72
(reserve 8 x 8 cells). Leave at least 40 points (4 cells) between node edges; no overlaps.
Use routing_mode="explicit". Ordinary outgoing paths are exclusive alternatives.
Parallel execution requires paired parallel_start/parallel_end structural nodes with
a shared parallel_group_id; every branch must reach its matching end. Parallel start
defaults to `branch_selection: "all"`. With `branch_selection: "orchestrator"`, the
orchestrator selects applicable issued branch continuations, assigns each selected entry
through `branch_assignments`, and records a non-empty `selection_reason` explaining
selections and exclusions before dispatch. Optional `selection_guidance` advises that
choice. Selected branches may contain multiple steps and properly nested groups;
convergence uses the frozen selected membership, including singleton selections.
Preserve existing node positions exactly unless the user explicitly asks to move or rearrange them.
The canvas expands automatically; do not constrain nodes to a fixed viewport.

Input parameters:

- `definition` (object, required)
- `expected_draft_revision` (integer, required)

### `preview_workflow_run` (~93 tokens)

Preview resources, worktree plan, native ownership, permissions and fallback reasons without launching.

The orchestrator receives the permissions required by compatible native
children. Supply preview_hash as expected_preview_hash when starting to
refuse changed workflow, launch settings or compatibility evidence.

Input parameters:

- `name` (string, required)
- `network`
- `overrides`
- `repo_path` (string, required)
- `worktree`

### `start_workflow` (~374 tokens)

Start a durable workflow run; returns workflow_run_id rather than task_id.

Saved top-level resources are held through pauses and caller-input checkpoints;
agent-node resources are acquired before a harness slot. Resources grant no access.
Optional worktree {base_ref?, branch?, detach?} creates one shared checkout for
the root and every child run after the run-scope grant. Nested callers and
workflows whose agents are all read_only cannot request one. The default branch
is harflow/workflow-<run_id>. Removal is explicit through harflow-ctl.
Resources and the worktree plan are bound by expected_preview_hash.

Preserve spaces and word boundaries in prompt rather than compressing natural prose;
the caller's source text is stored unchanged before workflow input assembly.

The complete dependency tree of any Run workflow node is resolved and pinned
before the run is created, so later edits or deletes never reinterpret the
run. Children are linked runs that share the root's harness-turn budget;
public controls apply to the root run id only.

goal is optional nonblank text up to 64 KiB UTF-8, preserved verbatim. It complements the
saved purpose and request without expanding permissions. notify reserves configured root-run
settlement/attention webhooks before creation; notify_events selects terminal, attention,
or both (default). Direct callers only; see docs/task-notifications.md.
Completion requires an assessment
with evidence for the current goal revision; conflicts or unverifiable criteria need input.

Input parameters:

- `expected_preview_hash`
- `freedom`
- `goal`
- `name` (string, required)
- `network`
- `notify`
- `notify_events`
- `overrides`
- `prompt` (string, required)
- `repo_path` (string, required)
- `worktree`

### `subscribe_workflow` (~77 tokens)

Subscribe a root workflow to configured webhooks (terminal, attention, or both).

Direct callers only. Current and future points are delivered; historical points are not
replayed. Repeat calls update event selection. Delivery never changes workflow execution.

Input parameters:

- `events`
- `notify` (string, required)
- `workflow_run_id` (string, required)

### `unsubscribe_workflow` (~37 tokens)

Stop future workflow delivery attempts for one configured alias, or every alias.

Input parameters:

- `notify`
- `workflow_run_id` (string, required)

### `get_workflow_notifications` (~36 tokens)

Read root workflow subscriptions and at most 50 recent delivery states; direct callers only.

Input parameters:

- `workflow_run_id` (string, required)

### `revise_workflow_goal` (~168 tokens)

Revise a root run goal at a quiescent paused or awaiting-input checkpoint.

Only the run's interaction owner can revise it. Supply the current goal_revision (0 if no
goal exists). Stale revisions, terminal runs and active nested/parallel work are rejected.
The nonblank goal is preserved verbatim up to 64 KiB UTF-8. History and completed work remain;
previous assessments are invalidated and replanning is required before further dispatch.
Each run retains at most 64 goal revisions (including the initial goal) and 1 MiB UTF-8
of cumulative goal text. Edits exceeding either bound are rejected; start a new run.

Input parameters:

- `expected_revision` (integer, required)
- `goal` (string, required)
- `run_id` (string, required)

### `list_workflow_runs` (~40 tokens)

List recorded workflow runs. Each carries resumed_at once the caller has resumed it.

Input parameters:

- `limit` (integer)
- `offset` (integer)

### `list_workflow_run_page` (~434 tokens)

Stable newest-first run headers, with bounded ancestor/session-owner lookups.

Deferred explicit run_ids and ancestor reads report preparation; preserve loaded headers
and retry the read. Oversized or unsupported metadata reports blocked diagnostics with
incomplete counts, without publishing unknown placeholder outcomes. A header's optional
resumed_at (Unix seconds) is the caller's last continuation; it is absent if never resumed,
unlike updated_at, which changes on every write.

Optional filters narrow the page: workflow_id (stable workflow identity), repo (exact
recorded repo path), status (list of run statuses: pending, starting, building, running,
pausing, paused, needs_input, needs_attention, cancelling, completed, failed, cancelled; the
indexed status shown on each item), since (inclusive) and before (exclusive) ISO8601 created_at
bounds with timezone, title_contains (case-insensitive run name text) and scope (all, the
default; root; nested child runs). Runs have no group, so there is no group filter. Filters
cannot be combined with run_ids or related_run_id. A filtered page examines at most 2000
catalog rows after its cursor and never computes a filtered total (total_active_count is
null). When that window ends before the page fills, the reply has scan_incomplete true, any
matches so far, and a next_cursor after the last examined row: keep calling with it until
has_more is false. A cursor is bound to the filters that produced it. fields selects item
keys (workflow_run_id, status, created_at and updated_at are always included; while a run
needs_input its question fields stay); values equal the unprojected reply.

Input parameters:

- `active_only` (boolean)
- `before`
- `cursor`
- `fields`
- `limit` (integer)
- `related_run_id`
- `repo`
- `run_ids`
- `scope`
- `since`
- `status`
- `title_contains`
- `workflow_id`

### `workflow_limit_hits` (~458 tokens)

Provider usage-limit hits and blocking recoveries of workflow runs, from persisted run evidence.

Read-only: nothing is retried, switched or continued. Evidence is only an attempt's
failure_diagnostic with category usage_limit (headless and Codex-native attempts alike) and the
run's orchestrator or worker usage-limit recovery checkpoint; node results and prose are never
read. Direct callers read every run; a workflow orchestrator reads its own run and descendants
verified through persisted invocation links; workers and builders are refused.

current lists runs blocked on a usage-limit recovery (at most 100), reported on the owning run
even while its root is running. latest is the newest hit per (backend, requested_model,
observed_model) among the newest 500 hits matching the window bound: the first of
root_workflow_run_id (not supported for managed callers), workflow_id and repo that is set, plus the since (inclusive) and before
(exclusive) ISO8601 range with timezone; the other filters apply inside that window and there is no
pagination. At most 50 keys are returned. current_only reports only current. Each hit carries
root_workflow_run_id, workflow_run_id, node_id, execution_id, attempt, task_id, transport_task_id,
observed_at (when the attempt settled; observed_at_source names the field), diagnostic, reset
{raw, at, state} (a numeric reset is epoch seconds; elapsed does not say the provider is available
again), an accepted recovery {accepted, answer} when one answered it, and detail_ref, the
get_workflow_run_detail arguments for execution:<id>. Each attempt is its own hit: native children
that share a transport report it in transport_task_id. unavailable lists up to 20 runs whose
document could not be read. scan.complete is false when a cap was reached, runs are unavailable or
the index is still preparing (index_state), so retry while it is preparing.
See docs/usage-limits.md.

Input parameters:

- `before`
- `current_only` (boolean)
- `repo`
- `root_workflow_run_id`
- `since`
- `workflow_id`

### `get_workflow_status` (~228 tokens)

Read a workflow run's execution state and task associations.

Child runs of Run workflow nodes report their parent and root links,
orchestrator mode and session owner, input source, tree settling state and
per-execution child invocation status. Public controls on a child id are
refused with the root run id. Resolved attention reasons are omitted on active runs.
Workflow approval read failures appear as bounded approval_summary.read_errors,
separately from known pending or uncertain approvals. interaction_state reports qualified
caller liveness, advisory human Monitor availability and any persisted handover audit.
Unknown caller identity never authorizes handover; server death alone is insufficient.
resumed_at (Unix seconds) appears once the caller has resumed or answered the run.
fields selects reply keys (workflow_run_id, status, created_at and updated_at are always
included; while the run needs_input its question fields stay). Values equal the unprojected
reply, which is read first, so derived status and managed-caller summaries are unchanged.

Input parameters:

- `fields`
- `workflow_run_id` (string, required)

### `wait_for_workflow` (~361 tokens)

Wait for a workflow run to need attention or finish; read-only and resumable.

timeout_seconds accepts 0..3600 (default 30; 0 reads once). It is honoured as asked, never
silently clamped; out of range is INVALID_PARAMS. Breaking change: values above 300 used to
be rejected, and 46..300 were silently held for only 45 seconds. until="terminal" holds until the run stops
needing the wait, bounded by a 6 hour server ceiling, and requires timeout_seconds to be
omitted. Your MCP client's own request deadline still applies. Prefer holds <=50 seconds after
remote "device did not respond" or "connection closed" errors; see docs/multi-task-waiting.md.

Returns when the run is completed, failed or cancelled and has finished settling
(stop_reason terminal), or reaches needs_input, needs_attention or paused (stop_reason
attention), or the hold ends (timeout, ceiling). If reading the run keeps failing for 3
rounds the last good snapshot comes back with stop_reason observation_unavailable, as does an
until="terminal" wait on a terminal run that stays settling with its run file unchanged for
300 seconds. Also
returns requested/effective timeout, until, timed_out, elapsed_seconds and polling_guidance.
Approval read errors alone do not stop the wait for attention; inspect
approval_summary.read_errors for incomplete sources. Known unanswered requests and
uncertain approval ownership still stop for attention.
Progress is sent every 5 seconds, best effort. A wait never changes, resumes or cancels a run.

Input parameters:

- `timeout_seconds`
- `until` (string)
- `workflow_run_id` (string, required)

### `get_workflow_run_detail` (~166 tokens)

Losslessly read executions, decisions, checklist, technical_plan, definition, owner_contracts, builder_draft, generated_definition, question, reason or wait_reason.

owner_contracts contains the pinned per-owner permission plan. Concatenate chunk fields
then decode JSON. Cursors bind content, run and view; changed content requires restarting.
On-demand detail views: on_demand_nodes (configured owner-scope catalog),
on_demand_calls (chronological reservation/call records), on_demand_state.
Calls include source scope, checkpoint/origin, timing, result_ref and nullable task_id.
Managed orchestrators use settled node inspection for executions.

Input parameters:

- `cursor`
- `limit` (integer)
- `view` (string, required)
- `workflow_run_id` (string, required)

### `pause_workflow` (~25 tokens)

Stop scheduling while active steps settle.

Input parameters:

- `workflow_run_id` (string, required)

### `resume_workflow` (~499 tokens)

Resume a caller-owned run with instructions and optional explicit attempt grants.

Preserve spaces and word boundaries in instructions rather than compressing natural
prose; the caller's source text is retained unchanged before workflow input assembly.

For non-question continuation, pass the originally displayed attention_checkpoint_id.
A stale checkpoint refuses the answer and grants; refresh before submitting again.
Omission retains legacy caller behavior. Do not combine it with decision_id.

For needs_input, supply its current input_decision_id as decision_id and a nonempty answer
in instructions. Stale answers and live/uncertain dispatches are refused. When the root
run carries a forwarded question from a Run workflow descendant, the answer is applied to
the attention source run; additional_attempts go to that source and grant no fresh child.
For an orchestrator usage-limit checkpoint, instructions must exactly match an offered
recovery answer (fallback, fallback:2, and so on, or retry_current); this approves a Fresh
configured recovery candidate for the preserved decision. Other prose does not approve replacement dispatch.
Use pause_workflow to wait or cancel_workflow to stop. A paused quota checkpoint retains
its decision_id and still requires the exact offered recovery answer (fallback or retry_current) on resume.
An accepted resume or answer sets the run's resumed_at; an answer routed through the root stamps the root.
Worker usage-limit recovery is selected explicitly by the
orchestrator using an issued retry continuation and candidate_id, within attempt limits.
The orchestrator may instead ask the caller to pause, cancel, or choose a configured
worker fallback; after the answer it must explicitly select the candidate_id.
Answers alone never authorize skipping. Set allow_optional_review_skip=True only to
permit the orchestrator to skip a current settled optional review with recorded harness
permission denial, when optional_review_skip_available is true. Th…

Input parameters:

- `additional_attempts` (integer)
- `allow_optional_review_skip` (boolean)
- `attention_checkpoint_id`
- `decision_id`
- `instructions`
- `workflow_run_id` (string, required)

### `read_workflow_assigned_input` (~178 tokens)

Read an immutable input explicitly assigned to your active worker activation.

Only verified managed workers may use this tool. Inputs are authorized by the persisted
activation allowlist and content digest, including linked child inputs with a verified
parent chain. Live, uncertain, unrelated, revoked, or changed inputs are refused.
Concatenate lossless JSON chunk fields until next_cursor is null, then decode JSON.
Return next_cursor as cursor; limit counts characters (default 16000, maximum 32000).
workflow_run_id is your own run; source_run_id optionally names a linked child run.
This does not grant general workflow inspection authority.

Input parameters:

- `cursor`
- `execution_id` (string, required)
- `limit` (integer)
- `source_run_id`
- `task_id`
- `workflow_run_id` (string, required)

### `inspect_workflow_node` (~216 tokens)

Inspect any fully settled node execution in your workflow, including older executions.

Result view returns lossless JSON text chunks: concatenate chunk fields until next_cursor
is null, then decode JSON. Pass next_cursor back as cursor. Default payload contains the
normalized node_result, full raw_output, permission_denials, and optional_skip consent
metadata when present. Selecting task_id reads a specific fallback
attempt. Activity uses normalized events with before_seq/after_seq. Result limit is
characters (default 16000, max 32000); activity limit is events (default 50, max 200).
No live or uncertain execution can be inspected. Orchestrator inspect decisions may name
a linked child run through workflow_run_id, authorized only by a verified parent chain.

Input parameters:

- `after_seq`
- `before_seq`
- `cursor`
- `execution_id` (string, required)
- `limit`
- `task_id`
- `view` (string)
- `workflow_run_id` (string, required)

### `recover_workflow` (~156 tokens)

Explicitly recover a failed settled run or a root with a confirmed-dead scheduler.

Supply a reason and retain completed work. Interrupted scheduler recovery preserves
existing attempts and decision budgets; uncertain execution ownership blocks recovery.
Accepted recovery sets the run's resumed_at. Pass the originally displayed
attention_checkpoint_id to bind failed-run or scheduler recovery to its current
persisted identity. Stale requests refuse without applying the reason or grants.

Preserve spaces and word boundaries in reason rather than compressing natural
prose; the caller's source text is retained unchanged before workflow input assembly.

Input parameters:

- `additional_attempts` (integer)
- `attention_checkpoint_id`
- `reason` (string, required)
- `workflow_run_id` (string, required)

### `cancel_workflow` (~97 tokens)

Stop root scheduling and cascade cancellation to associated tasks and children.

A cancellation request returns ``cancelling`` until settlement is observed;
unresolved dispatches or cancellation transport errors return ``needs_attention``.
Child runs must be controlled through their root workflow run.
Human Monitor cancellation uses the local CLI verified-human boundary; it does
not transfer the original caller's answer, retry, or continuation ownership.

Input parameters:

- `workflow_run_id` (string, required)

### `register_artifact` (~236 tokens)

Register an existing regular-file metadata reference for the verified calling task.

No owner parameter is accepted. Relative paths use the recorded repository; only repository,
allocated own scratch (including a granted shared chain or group folder), and revalidated saved grants are accepted. A standalone task, or a
running workflow node, orchestrator turn or native-subagent controller, may register; its
reference is bound to that workflow execution. Builders and inherited descendants are refused.
A native subagent has no channel of its own: what it registers lands on its controller.
Notes are preserved verbatim. Kinds: screenshot, log, report, other. Paths and notes are
at most 4096 UTF-8 bytes; at most 100 references per task and a 1 MiB manifest.
A reference establishes no content validity, task success, access, copy, or publication
authority. No content is read, copied, hashed, previewed, or published.
Caller indexing is bounded; retry a catalog-preparation error to advance cold history.

Input parameters:

- `kind` (string, required)
- `note` (string)
- `path` (string, required)

### `get_task_artifacts` (~155 tokens)

Page at most 50 artifact references with current stat observations, not content verification.

Verified human callers can inspect a known standalone or workflow-bound task; task callers can
inspect only self. Workflow-bound items carry a `workflow` binding. Builders and inherited
descendants are refused (use get_workflow_artifacts for run-level reads). Cursors are task-bound and reject manifest
changes. Availability is available/deleted/changed/unavailable at observed_at; available does
not establish unchanged contents. Missing legacy manifests are empty; corrupt ones unavailable.
Caller indexing is bounded; retry a catalog-preparation error to advance cold history.

Input parameters:

- `cursor`
- `limit` (integer)
- `task_id` (string, required)

### `get_workflow_artifacts` (~280 tokens)

Page artifact references registered by the attempts of a workflow run and its linked child runs.

References are metadata only (path, kind, note, a stat observation); nothing is read, copied or
validated. Each item carries `workflow` (run, node, execution, role, attribution) and current
\`availability`. `execution_id` selects one node execution; a native subagent has no channel of
its own, so references its controller registered appear under that execution with
\`attribution: native_transport`. `owners` lists only owners whose references could not be read
(`unavailable`, `record_removed`, `run_unavailable`). `state: unavailable` with `reason`
\`catalog_preparing` or `catalog_stale` means retry; `tree_bound_exceeded` (over 64 runs) is final.
Page with `next_cursor` (positional, so owners appended behind it appear only on a new pass).
Authority: a verified human reads any run; a delegation orchestrator reads its own run and
linked descendants; workers, native transports, builders and standalone task callers are refused
(a worker reads its own task with get_task_artifacts).

Input parameters:

- `cursor`
- `execution_id`
- `limit` (integer)
- `task_id`
- `workflow_run_id` (string, required)

### `acquire_slot` (~115 tokens)

Acquire a task-owned phase lease around heavy commands. Returns queued immediately when
blocked; retry the same name every two seconds to observe a grant. Queue budget is 0..21600
seconds, never a held-lease timeout. Release lease_id on every exit, including queued exits.
Phase slots require human enable and a verified task caller; they never borrow ancestor holds.
Disabled layout returns error data.code phase_slots_not_enabled; other refusals remain distinct.

Input parameters:

- `name` (string, required)
- `wait_seconds` (integer)

### `release_slot` (~78 tokens)

Release this execution's lease or cancel its queued request. Cleanup remains capacity
consuming until successful; failed/uncertain cleanup requires human inspection and resolve.
Stop all owned heavy descendants before release. Client interruption alone never releases.
Disabled layout returns error data.code phase_slots_not_enabled; other refusals remain distinct.

Input parameters:

- `lease_id` (string, required)

### `slot_status` (~56 tokens)

Read bounded phase holders, queue positions, capacity, cleanup blockers and timestamp events.
This read never performs cleanup or changes the ledger.
Disabled layout returns error data.code phase_slots_not_enabled; other refusals remain distinct.

Input parameters:

- `name`

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/harflow-dev-harflow-mcp/harflow-mcp#diagnostics

## Score history

- 2026-11-05: 78
- 2026-11-04: 34
- 2026-11-03: 77
- 2026-11-02: 62
- 2026-11-01: 76
- 2026-10-31: 76
- 2026-10-30: 75
- 2026-10-29: 60
- 2026-10-28: 60
- 2026-10-27: 59
- 2026-10-26: 59
- 2026-10-25: 58
- 2026-10-24: 58
- 2026-10-23: 57
- 2026-10-22: 72

## Common questions

### What is the io.github.Harflow-Dev/harflow-mcp server?

io.github.Harflow-Dev/harflow-mcp is listed in the public MCP registry as io.github.Harflow-Dev/harflow-mcp. Dispatch coding tasks to local headless agents with persistent history and workflows. This page covers its PyPI package (harflow-mcp).

### Is the io.github.Harflow-Dev/harflow-mcp server safe to use?

io.github.Harflow-Dev/harflow-mcp scores 78 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 5 November 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the io.github.Harflow-Dev/harflow-mcp server expose?

io.github.Harflow-Dev/harflow-mcp exposes 55 tools: list_backends, start_task, list_approval_requests, get_approval_request, respond_approval_request, and 50 more. Their descriptions and schemas cost roughly 17,096 tokens of context every time the server is loaded.

### Is the io.github.Harflow-Dev/harflow-mcp server still maintained?

io.github.Harflow-Dev/harflow-mcp is still listed as active in the MCP registry. We last reached this channel on 5 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the io.github.Harflow-Dev/harflow-mcp server under?

io.github.Harflow-Dev/harflow-mcp declares the Apache-2.0 licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- PyPI project: https://pypi.org/project/harflow-mcp/
- Socket report: https://socket.dev/pypi/package/harflow-mcp
- Repository: https://github.com/Harflow-Dev/HarflowMCP
- Changelog RSS feed: https://verifymcp.io/servers/harflow-dev-harflow-mcp/harflow-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/harflow-dev-harflow-mcp/harflow-mcp.json
- HTML version of this page: https://verifymcp.io/servers/harflow-dev-harflow-mcp/harflow-mcp
