Skip to main content
Glama
If you're referring to the MCP server published by this repository, it's **herdr-inbox** (the README calls it “herdr inbox”).

**Description:** It lets Claude Code agents running in herdr ask a question once, get a receipt, and keep working instead of blocking, while the operator answers all open questions from a single popup and each answer is delivered back to the pane that asked.

A couple of notes on the constraints you gave:

- The name used is the repository's own project name, **herdr-inbox**, not a person or organization.
- The description deliberately avoids repeating the name and focuses on what the server enables: asynchronous agent questions, non-blocking work, centralized answering, and delivery back to the originating agent.
- If you want the answer as a strict JSON object only, it would be:

```json
{
  "name": "herdr-inbox",
  "description": "Enables Claude Code agents running in herdr to ask a question once, receive a receipt, and continue working instead of blocking, while the operator answers all open questions from one popup and each answer is delivered back to the pane that asked."
}
```

If you're referring to the MCP server published by this repository, it's **herdr-inbox** (the README calls it “herdr inbox”). **Description:** It lets Claude Code agents running in herdr ask a question once, get a receipt, and keep working instead of blocking, while the operator answers all open questions from a single popup and each answer is delivered back to the pane that asked. A couple of notes on the constraints you gave: - The name used is the repository's own project name, **herdr-inbox**, not a person or organization. - The description deliberately avoids repeating the name and focuses on what the server enables: asynchronous agent questions, non-blocking work, centralized answering, and delivery back to the originating agent. - If you want the answer as a strict JSON object only, it would be: ```json { "name": "herdr-inbox", "description": "Enables Claude Code agents running in herdr to ask a question once, receive a receipt, and continue working instead of blocking, while the operator answers all open questions from one popup and each answer is delivered back to the pane that asked." } ```

Official
by LeaveMyYard

herdr inbox

Ask once. Keep working. Answer when you're ready.

An asynchronous question inbox for Claude Code agents running in herdr: every agent's open questions in one popup, every answer delivered back to the pane that asked.

Click for the 36-second demo with herdr-panorama (MP4).

Ever had an agent stop dead to ask you a question, when it could have kept going with the rest of its work? Or one that asked in chat, carried on, and then asked the same thing again three turns later because it never knew you'd seen it?

herdr-inbox makes agent questions asynchronous. It works like Claude Code's own question prompt (same options, notes and multi-question groups), except the agent doesn't wait for you. It files the question once, gets a receipt (Q12) and keeps working on everything that doesn't depend on the answer. You answer whenever you're ready, from one popup that collects the open questions of every agent in your herdr session, and the answer lands back in the right agent's conversation.

  • Agents don't stall. No blocking dialog, no idle agent waiting for you to notice it.

  • Questions don't repeat. Asking the same thing twice just returns the existing receipt.

  • Nothing gets lost. Every open question from every pane is in one place, and tabs show a ❓N count while their agent is waiting on you.

  • Zero per-project setup. A session hook teaches every Claude Code session to use it.

claude plugin marketplace add LeaveMyYard/herdr-inbox
claude plugin install herdr-inbox@herdr-inbox
herdr plugin install LeaveMyYard/herdr-inbox

Then bind a key to the popup (Install has the snippet). The repo is two plugins at once: a Claude Code plugin (.claude-plugin/: MCP server, hooks, the herdr-inbox:operator-questions skill) and a herdr plugin (herdr-plugin.toml: popup, open and sync-tokens actions, startup hook), listed on the herdr plugin marketplace. You install both.

Works great with herdr-panorama

Running many Claude Code agents at once? herdr-panorama shows them all on one live screen: every orchestrator, the threads it drives and the subagents it spawned. The two plugins know about each other. An agent that asks through the inbox gets a ?N on its panorama card, a on that card opens the inbox right on its question, and your answer goes back to the agent, which carries on.

herdr plugin install LeaveMyYard/herdr-panorama   # then bind prefix+space to leavemyyard.herdr-panorama.open

Related MCP server: Claude Session Coordinator

Requirements

  • herdr ≥ 0.9.0 on Linux or macOS (herdr.dev).

  • Claude Code with plugin support. Hook delivery and idle wake-up were probed on 2.1.301; sessions whose hooks do not fire get their answers typed instead. The optional herdr-inbox-ui cards need 2.1.301+.

  • uv on PATH for both herdr and Claude Code (it brings its own Python 3.11+); the hooks use the system python3 (3.11+, else uv).

Answering

Press prefix+i. A group is one ask_operator call: a single question, or up to four related ones that the agent names with a short title.

The group list

With several open groups the popup opens on a list styled like Claude Code's option list: one row per group, named by its title (❯ 1. Invoice storage and caching · 2 questions · 4m), with the tab label, asked_by and the question headers on a dim second line. Groups from the pane you were in come first, then the rest oldest first; answers that could not be delivered are their own ⚠ rows. Enter opens a group, g jumps to its agent, d dismisses the whole group (y confirms). With exactly one open group the popup skips the list and opens straight into it.

Inside a group: tabs and Submit

A group's questions are tabs under its title, followed by its own Submit tab. Answering drafts the question and moves to the next tab. Submit reviews everything ("You have not answered all questions" when some are blank) and sends the group's answered questions in one message; blank ones stay open. Drafts are stored, so closing the popup loses nothing. Esc goes back to the list.

One question, with previews

A group of one question sends as soon as you select an answer. Options can be plain strings or {label, description, preview}; a preview (plain monospace text such as a config snippet or a git graph) is shown beside the list while that option is highlighted. There is always Type something. (a free answer; in multi-select it is added to the picks) and Chat about this (jumps to the asking agent's pane and leaves the question open). n adds a note to the highlighted option, e.g. Postgres (note: keep the old schema).

While you answer

Nothing that happens in the background changes what your next key does. New groups are appended to the list without moving your cursor, and a row that just arrived ignores Enter and digits for 1 s. Every view ignores Enter, digits and Space for 0.4 s after it appears. A group or question closed meanwhile (withdrawn, answered elsewhere) stays as an inert placeholder ("Q12 was closed") until you move. With no open questions the popup shows "No open questions" and closes on any key; groups arriving then are announced, and Tab or → shows them. An undelivered answer's ⚠ row offers Retry delivery and Stop showing it here (the agent can still fetch it with check_answers).

Keys

Key

Action

↑ ↓ / j k

Move the ❯ cursor

1–9

Jump to that row or option

Enter

Open the group; select the option (single-select) or toggle it (multi-select)

Space

Toggle (multi-select)

n / x

Add a note to the option / clear the draft

Tab → / Shift-Tab ←

Next / previous tab inside a group

g

Go to the asking agent's pane

d

Dismiss the group or question (y confirms); on an alert, acknowledge it

Esc

Back to the list; on the list, close without sending

Delivery

An answer arrives in the agent's conversation as [inbox] Q12 answered — <question>: Postgres (note: keep the old schema), or for several [inbox] answered — Q12 <q>: A · Q13 <q>: B, only while that pane still holds the conversation that asked.

How it gets there depends on the agent.

  • An idle Claude Code session (0.10.0) is woken with the answer without any typing. A background hook waits for answers after each turn and starts a new turn with the answer. It wakes the agent even while you are looking at its pane, without touching what you type. Each idle session keeps one small background process (about 12 MB of its own memory).

  • A Claude Code session that is working gets the answer without any typing. The inbox's own hooks hand it over as context at its next tool batch, or when its turn ends; then the turn continues with the answer.

  • Other agents (Codex etc.), Claude sessions started before the update, sessions whose hooks stopped firing, and Send now get it typed into the pane.

Note on consent. Claude Code marks an answer that arrives through its hooks as an automated notification, not as something the user typed. Agents act on such answers as information. But an agent may refuse to treat one as your approval for something risky, like "deploy? yes". Ask for such confirmations in chat, as the inbox rules already say.

Either way the inbox counts an answer as seen only once the conversation transcript shows it.

If an answer can't be delivered right away, one background delivery worker retries every few seconds. This covers an agent at a dialog, an agent busy, Claude Code's background-agents panel having focus, or a typed answer that never showed up in the conversation. The worker serves every pane, whichever inbox version each session runs. It starts with herdr and on demand (inbox worker --ensure). It stays up while herdr reports agents, and stops after 10 idle minutes without any.

The popup shows why an answer is waiting. If an answer is still undelivered after 5 minutes, or runs out of tries, herdr shows a notification. The agent can always fetch it itself with check_answers.

Tab marker and sidebar count

herdr has no per-tab tokens, so while a tab has open questions its label gets a ❓N prefix (herdr tab rename), updated as the count changes and removed at 0. Your own label is never stored: it is recovered by stripping the prefix each time, so renaming a prefixed tab is respected. Tabs without a custom name (herdr shows their position, e.g. 6) are left alone by default, because a rename cannot give them back automatic naming.

Optionally, every pane with open questions carries the pane token inbox_q = "?N", cleared when the last one closes. Add $inbox_q to a row of the agent sidebar:

[ui.sidebar.agents]
rows = [["state_icon", "tab", { token = "$inbox_q", fg = "#c04a4a", bold = true }], ["agent"]]

With herdr-radar, which replaces the agent rows with its own and has no slot for other plugins' tokens yet (hhdebb/herdr-radar#57 proposes an extra_tokens setting), run the action Inbox: show ?N in herdr-radar's sidebar (herdr plugin action invoke leavemyyard.herdr-inbox.radar-sidebar, or inbox radar-sidebar). It adds the $inbox_q cell to each of radar's agent rows, inside radar's managed block only, and reloads herdr's config. It runs only when you ask: radar rewrites its block on its configure action, and the popup then shows a one-line hint to run it again (radar_sidebar_hint = false turns the hint off). It leaves the file alone if it does not parse, if a row would exceed herdr's 16-token limit, or once radar's config carries $inbox_q in extra_tokens itself; a backup of the previous file is kept as config.toml.inbox-bak.

Install

See Requirements first.

Claude Code:

claude plugin marketplace add LeaveMyYard/herdr-inbox
claude plugin install herdr-inbox@herdr-inbox

This registers the MCP server (tools appear as mcp__plugin_herdr-inbox_herdr-inbox__ask_operator etc.) and the hooks. Restart running Claude sessions (or /reload-plugins). Claude Code installs plugins as a copy, so the MCP server keeps its Python environment in ${CLAUDE_PLUGIN_DATA}/venv-<version> (created by uv on first use, about 0.5 s from a warm cache; older versions' venvs are removed automatically once no server uses them; after restarting sessions that predate 0.5.3, inbox clean-venvs removes their older venvs too). The hooks need only the system python3 (3.11+; older falls back to uv) and always exit 0. MCP server only, without hooks: run claude mcp add --scope user herdr-inbox -- uv run --project /path/to/herdr-inbox inbox mcp from a checkout and add docs/agent-instructions.md to your CLAUDE.md; use one route, not both.

herdr:

herdr plugin install LeaveMyYard/herdr-inbox

The plugin is also on the herdr plugin marketplace (through the herdr-plugin GitHub topic); installing from there is the same command. herdr runs the manifest's [[build]] step (uv sync --frozen --no-dev) during install, after showing you what it will run. Add --ref <tag> to pin a revision. Then bind a key in ~/.config/herdr/config.toml and run herdr server reload-config:

[[keys.command]]
key = "prefix+i"
type = "plugin_action"
command = "leavemyyard.herdr-inbox.open"
description = "question inbox"

Transcript cards (optional)

herdr-inbox-ui is a separate plugin in the same marketplace that draws herdr-inbox in the Claude Code transcript: ask_operator as a card with the title, questions, options, asked_by and the filed Q ids; alert_operator as a card coloured by severity (info cyan, warning yellow, urgent red); check_answers, list_my_questions and the withdraw tools as one dim line (a folded run of inbox calls is unfolded when it asks or alerts, so the cards show). Operator answers show as a quiet block with no [inbox] prefix, ✓ Operator answered Q12 — <question> in green with the answer under it, plus a toast, on every delivery path Claude Code lets a mod draw:

Delivery

Drawn as

typed or pasted (Send now, sessions before 0.9)

the block, in place of the prompt row

idle session woken by the asyncRewake watcher (its row reads "Stop hook feedback")

the block, in place of that row

busy session, PostToolBatch hook context (Claude Code draws nothing for it)

one dim transcript line ✓ Operator answered Q12 — …: <answer>

busy session, Stop hook context

Claude Code's own Stop hook feedback: [inbox] … line, which no mod can redraw; the toast only

ctrl+o shows the raw message. A wake row from before the mod loaded (a resumed session) stays plain. It changes only what is drawn, never what the model reads. It uses Claude Code's early-access mods API (2.1.301+; terminal and desktop draw it, other surfaces keep the plain rows), which is why it is not part of herdr-inbox:

claude plugin install herdr-inbox-ui@herdr-inbox

Configuration

Settings live in config.toml in the plugin's config directory (herdr plugin config-dir leavemyyard.herdr-inbox):

tab_prefix = "❓"            # "" turns the tab prefix off
prefix_unnamed_tabs = false  # true: also prefix tabs named by position (they keep the number)
radar_sidebar_hint = true    # false: no popup hint when herdr-radar's rows lack $inbox_q

The popup and every Claude session read this file, and edits apply without a restart. The database is ${XDG_STATE_HOME:-~/.local/state}/herdr-inbox/inbox.db; HERDR_INBOX_DB overrides it.

Agent tools

Tool

Purpose

ask_operator(question, options?, header?, multi_select?, context?, asked_by?, title?)

File a question (or questions=[...], up to 4, named by title); returns a receipt immediately

check_answers

Answers not seen yet (after a missed delivery or compaction)

list_my_questions(include_closed=false)

The session's questions, to recover after /compact or /clear

withdraw_question(id, reason)

The agent resolved it itself

alert_operator(title, message?, severity?, asked_by?)

"Please check X": no answer expected; shows as an alert until acknowledged

withdraw_alert(id)

The issue resolved itself

Alerts

An alert (A7) is something the operator should check, with no answer expected. It heads the popup list (⚑, most severe first, unnumbered: digits and Enter keep acting on your questions exactly as before), raises a notification and counts in the ❓N badge until acknowledged with d (↑/↓ to reach it). The agent learns of the acknowledgement through check_answers; nothing is typed into its pane.

The delivery worker also raises an alert by itself (⏸ <tab> is waiting for you) for an agent herdr reports as blocked for 15 s — stuck at a permission, AskUserQuestion or plan prompt, where it cannot call any tool. A deliberate g (a pause after your last key) goes to it, never Enter or a digit; the alert clears when the prompt is answered. The inbox never types into that pane.

A SessionStart hook teaches every Claude Code session to use them, so no CLAUDE.md edit is needed. Outside herdr the hooks stay silent and ask_operator tells the agent to ask in chat.

From a shell (from a checkout, as uv run inbox ...):

inbox list [--all]
inbox answer Q12 "squash it"
inbox dismiss 12
inbox sync-tokens
inbox radar-sidebar [--remove]   # $inbox_q in herdr-radar's sidebar rows (on demand)

Opening the inbox from another plugin

Another plugin (or a script) can open the popup straight on one question or group:

root=$(herdr plugin list --json | jq -r '.result.plugins[] | select(.plugin_id == "leavemyyard.herdr-inbox") | .plugin_root')
uv run --quiet --frozen --no-dev --project "$root" inbox open --question Q12   # or:
#   inbox open --group 7            the group (one ask_operator call)
#   inbox open --pane w9:p5         that pane's oldest open group
#   inbox open --session <id>       that Claude session's oldest open group

Run it only on an explicit operator action (a key binding, a click), never from an event or a timer. A popup takes all keyboard input, so one that appears under the operator's typing would swallow their keys.

A caller whose open always comes from an explicit operator key or click (herdr-panorama's a, say) can pass --no-hold. The popup then opens like a normal one: its views arm for 0.4 s, then Enter works. Pass --no-hold only in that case.

Without it, as a second guard, a deep-linked popup sends nothing until the operator presses Tab or →, at least half a second after it appeared. ↑/↓ don't count, since they are what shell history under the popup would send. Until then it shows "Opened from another plugin — press Tab or → to start answering", and Enter and digits do nothing.

How it works:

  • herdr plugin pane open cannot pass arguments to the popup. So inbox open writes a one-shot request (open-request.json next to the database: target, time and nonce, written atomically, newest wins).

  • It then opens the inbox's own popup. The plugin id and root are fixed to the inbox's own, never the calling plugin's.

  • It hands the request's nonce to that popup. Only that popup takes the request, and only within 5 s; a popup opened by hand ignores it.

  • The popup opens the target group on the target question, with the list behind it (Esc goes back to the list). If the target is no longer open, it shows the list with a one-line notice.

  • If the popup is already open, inbox open exits with code 3 and the message "the inbox popup is already open", and writes nothing.

  • --question takes Qn or n and --group takes a number; anything else is a usage error (exit 2).

Remote machines

Agents on a saved herdr SSH machine (herdr machine list) can ask you too.

  1. Install the inbox there once, from this machine:

    inbox remote install <machine>     # later: inbox remote upgrade <machine>

    This needs key-based ssh; it never prompts for a password.

  2. Restart the Claude sessions on that machine.

Their questions then show up in this popup as <machine>:Q12. Answers are queued here and sent by the delivery worker, and the remote's own inbox types them into its agent. Settings in the inbox config.toml: remote_sync_seconds = 5 and remote_answer_expiry_hours = 12. Details: docs/REMOTE.md.

Updating

herdr plugin update                       # herdr side (or: herdr plugin update LeaveMyYard/herdr-inbox)
claude plugin marketplace update herdr-inbox
claude plugin update herdr-inbox@herdr-inbox

Then restart Claude sessions: a session started before the update keeps its old MCP server. While 0.2.x and 0.3 sessions overlap, an answer sent at the same moment as an old session's retry tick can (rarely) be delivered twice; the window closes once every session has restarted.

Uninstall

Remove the tab prefixes first (pane tokens vanish with herdr's next restart). Set tab_prefix = "" in the config file above, then reconcile every tab:

herdr plugin action invoke leavemyyard.herdr-inbox.sync-tokens

Then remove the plugins:

herdr plugin uninstall leavemyyard.herdr-inbox       # or: herdr plugin unlink ... if you linked it
claude plugin uninstall herdr-inbox@herdr-inbox
claude plugin marketplace remove herdr-inbox

From a checkout, uv run inbox sync-tokens --remove-prefixes does the first step in one command. If you added $inbox_q to herdr-radar's rows, take it out first with inbox radar-sidebar --remove. Remove the prefix+i binding yourself. The database stays in ~/.local/state/herdr-inbox/ until you delete it.

How it works

The MCP server (spawned per Claude session, so it inherits the pane's HERDR_PANE_ID) writes questions to a shared SQLite database. The popup reads it, and answering calls herdr agent prompt <pane>. Markers use herdr tab rename and herdr pane report-metadata. A SessionStart hook injects a short usage block into each session. Details, data model and design decisions: docs/DESIGN.md.

FAQ and troubleshooting

prefix+i does nothing. The key is yours to bind (see Install); after editing config.toml run herdr server reload-config. herdr plugin list should show leavemyyard.herdr-inbox enabled, and herdr plugin log shows its action and startup logs, including a missing uv on herdr's PATH.

My agents still ask in chat. Restart the Claude Code sessions (or /reload-plugins) after installing: the MCP server and the session hook load at session start. Outside herdr, or in a claude nested inside an agent's pane, the tool tells the agent to ask in chat on purpose.

An answer did not arrive. The popup shows it as a ⚠ Q12 not delivered row with Retry delivery; inbox list --all from a checkout shows every question's state. The agent can always fetch its answers itself with check_answers.

Tabs still show ❓N after I uninstalled. Run the sync-tokens step from Uninstall before removing the plugin, or rename the tabs back by hand.

Does anything leave my machine? The plugin sends your questions and answers nowhere: they live in a local SQLite database (~/.local/state/herdr-inbox/inbox.db), and the plugin talks only to your herdr session. The one exception is remote machines, if you set them up: then they travel over your own SSH to those machines. An answer is delivered into the asking agent's conversation, which Claude Code sends to its model as it does with everything you type. Installing and updating download the plugin from GitHub and its Python dependencies from PyPI (through uv).

Codex, pi or other agents? Not yet: the MCP tool and the hooks target Claude Code.

Limitations and known issues

  • Proof of concept. Interfaces may change. Claude Code only; other agents are not supported.

  • Answers are typed into the pane, so one that arrives while you are typing in that pane can merge with your input. Retries are skipped while the pane is focused or the agent is blocked, but the first delivery from the popup has no such guard.

  • A delivery whose agent prompt call times out after herdr already submitted it is retried, so the agent can receive that answer twice.

  • After /clear, a restart or another agent taking over the pane, an answer is not typed anywhere (conversation changed); the agent gets it through check_answers.

  • herdr has no compare-and-set rename, so a tab rename of yours landing in the few milliseconds between our read and our rename is overwritten.

  • If a pane moves to another tab, the old tab's prefix is refreshed at the next sync-tokens.

  • Subagents are not identified (use asked_by), and answers go to the main session's pane.

  • Outside herdr, or from a claude nested inside an agent's pane, nothing is filed and the agent is told to ask in chat.

  • No blocking questions, remote or mobile answering, or multi-machine sync.

Development

uv sync
uv run pytest
claude plugin validate --strict plugins/herdr-inbox-ui
claude plugin test plugins/herdr-inbox-ui   # the transcript-cards mod (terminal + desktop)

Tests never touch a real herdr: they point HERDR_BIN_PATH at a fake that records its argv and HERDR_INBOX_DB at a temp file. CI runs them on Linux and macOS, and validates the plugin manifests with claude plugin validate. Keep the version identical in pyproject.toml, herdr-plugin.toml, .claude-plugin/plugin.json and .claude-plugin/marketplace.json (a test checks this); bump it for every release, since Claude Code keys its plugin cache by version.

The README images are captures of a real herdr, made by uv run --with pyte --with pillow python docs/screenshots/herdr_demo.py (needs herdr ≥ 0.9, rsvg-convert and ffmpeg). It starts an isolated herdr (its own HOME, config, socket and inbox database under the git-ignored .scratch/), links this checkout as the plugin, runs a scripted stand-in agent in each tab (docs/screenshots/fake_agent.py, no API calls), files the demo questions through the plugin's own code and drives the popup with real keys; frame.py adds the backdrop. Popup-only renders: uv run pytest tests/make_screenshots.py (needs rsvg-convert).

Contributing

Contributions are welcome. Start with CONTRIBUTING.md (how to build, test and send a PR; the Python code is on a bug-fix-only freeze while the Rust port is in progress). Please follow the Code of Conduct; report security problems as described in SECURITY.md.

Available Tools

6 tools
alert_operatorA

Alert the human operator WITHOUT blocking and without expecting an answer: "please check X", "the deploy needs your eyes", "I hit something you should know about".

Use it instead of writing the warning into chat (the operator may not be looking at this pane) and instead of stopping to wait. It shows in the operator's inbox popup and as a herdr notification, and counts in this tab's ❓ badge, until the operator acknowledges it. Nothing is typed back; check_answers reports acknowledged alerts. Use ask_operator instead when you need a decision or information. severity: info | warning | urgent. Raise one alert per issue; call withdraw_alert if it resolves itself.

NameRequiredDescriptionDefault
titleYes
messageNo
asked_byNo
severityNowarning

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations supplied, the description carries the full burden and does so: it discloses non-blocking behavior, that no reply is typed back, where the alert surfaces (operator inbox popup, herdr notification), that it persists and counts in the tab's ❓ badge until acknowledged, and the one-alert-per-issue convention. This is a genuinely rich behavioral contract for a mutation-like tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core verb and its non-blocking constraint, then routing, then lifecycle. Every sentence carries information, though the quoted example phrasings and the multi-clause sentences make it denser than strictly necessary.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described. Combined with the lifecycle coverage (create, surface, acknowledge, withdraw), alternatives, and severity levels, an agent has nearly everything needed; only asked_by semantics and any dedup/expiry rules are absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It supplies the allowed severity values (info | warning | urgent) and implicitly the content of title/message via the quoted examples, but asked_by is never explained and the title-vs-message split is left to inference, so compensation is only partial.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific action (alert the human operator) with its defining constraint front-loaded: WITHOUT blocking and without expecting an answer. It clearly separates itself from ask_operator by name and by semantics, so an agent can pick between them without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use it ('instead of writing the warning into chat', 'instead of stopping to wait') and when not to ('Use ask_operator instead when you need a decision or information'), plus the follow-up actions (withdraw_alert if resolved, check_answers to see acknowledgements). Guidance and routing are complete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ask_operatorA

Ask the human operator a question WITHOUT blocking. Returns immediately with a receipt.

Use this instead of asking in chat whenever work can continue without the answer. The operator answers asynchronously; the answer will arrive in this conversation as a message starting with [inbox] that names the question id (Q). After calling it, continue with work that does not depend on the answer. Do not repeat the question in chat and do not call ask_operator for it again: a repeat is detected and only returns the existing receipt.

Keep the question self-contained: the operator reads it without your chat history, so name the repo/PR/file and what you need decided. The operator answers in a picker like AskUserQuestion's:

  • options: up to 9 choices, each a plain string or {"label", "description"} (label short, description says what picking it means). The operator can always type a free answer instead and attach a note to a choice.

  • header: a short chip shown above the question (max 12 chars), e.g. "DB choice".

  • multi_select: true when several options may be picked together.

  • preview (per option, optional): text shown beside the options while that option is highlighted (a code snippet, a config diff, an ASCII mock); monospace, no markup.

  • title: a short name for the whole call (≤60 chars), e.g. "Worker rollout settings". The operator's inbox lists calls by this name, so ALWAYS set it when you pass questions; optional for a single question (its header or text is used instead).

  • questions: instead of question, up to 4 related questions in one call, each {"question", "header"?, "options"?, "multi_select"?}. The operator answers them together; each gets its own Q id.

  • context: supporting detail; asked_by: who is asking (e.g. "reviewer PR 42") when you are a subagent or one of several roles. Each answer is one line: the picked label(s), notes in parentheses, or the free text. Answers the operator submits together arrive in one [inbox] message.

NameRequiredDescriptionDefault
titleNo
headerNo
contextNo
optionsNo
asked_byNo
questionNo
questionsNo
multi_selectNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden, and it delivers: non-blocking contract, immediate receipt return, async arrival format ('[inbox]' message naming Q<n>), duplicate detection behavior, and answer format. The only omitted bit is auth/permissions, which is not relevant here.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core contract and scoping in the first two sentences, then structured bullets per parameter. It is long, but the length is justified by the zero-coverage schema; only the duplicated chat-vs-inbox explanation could be trimmed slightly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers behavior, param semantics, and follow-up handling for an 8-param, zero-schema-description tool. Output schema exists so return-value detail is legitimately omitted, but the description could note the receipt fields or clarify how single `question` vs `questions` interacts with max-count limits.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must supply param meaning, and it does: it documents options (up to 9, string or {label, description}), header (≤12 chars), multi_select, per-option preview, title (≤60 chars, emphasized for `questions`), questions (up to 4, shape given), context, and asked_by. This is a rare case where prose fully compensates for an empty schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Ask the human operator a question') and immediately distinguishes itself from siblings by naming the key behavioral constraint ('WITHOUT blocking'). The contrast with 'asking in chat' and the routing comment to check_answers/ask_operator-again makes it unmistakable which tool handles async questions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use ('Use this instead of asking in chat whenever work can continue without the answer') and when-not ('Do not repeat the question in chat and do not call ask_operator for it again'). It also tells the agent the follow-up action (continue with independent work) and that duplicate calls are deduped — full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_answersA

Return operator answers to your questions that you have not seen yet, and mark them seen.

Answers are normally delivered as [inbox] messages naming the Q ids; use this as a fallback (e.g. after compaction or if a delivery was missed).

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does disclose the key trait that this mutates state by marking answers seen, plus the unread-only scope. It does not say whether 'seen' is global or per-consumer, nor anything about idempotency, but the core behavioral disclosure is present.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no waste, with the action and its side effect front-loaded before the fallback guidance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need no explanation, and with no parameters the definition is nearly self-sufficient. The only residual gap is the scope/permanence of the 'seen' marking, which an agent might wonder about but is not essential to calling it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters are accepted, so there is nothing for the description to clarify; the baseline for a no-parameter tool is 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('return operator answers... not seen yet') plus the side effect ('mark them seen'). It is clearly distinguished from question-oriented siblings such as list_my_questions by dealing with answers rather than questions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames itself as a fallback and names the primary delivery mechanism ('normally delivered as [inbox] messages'), with concrete triggering conditions: after compaction or a missed delivery. Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_my_questionsA

List the questions this session has asked the operator, with their status and answers.

Call this after compaction or resume BEFORE asking anything, so you do not re-ask a question that is already open or answered.

NameRequiredDescriptionDefault
include_closedNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full disclosure burden. It adds real value by explaining the session scope and the deduplication purpose, but it does not state that the operation is read-only, whether it is paginated, or any authorization requirements. Adequate but not rich for a tool with zero annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences: the first states what is returned, the second states the triggering situation and the reason. No filler and the most decision-relevant information (what it returns) comes first.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so the return shape need not be explained. The description covers the purpose, the session scope, and the dedup workflow; the only real gap is the undocumented include_closed default, which matters for predicting whether answered questions appear.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single parameter include_closed is never mentioned in the description. Since the default is false, the tool silently hides closed questions, and the description's claim of returning questions 'with their status and answers' does not clarify this filtering behavior. With only one parameter, the description needed to compensate and does not.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: listing the questions this session has asked the operator, including status and answers. The session-scoped framing ('this session has asked') is a meaningful qualifier, though it does not explicitly distinguish itself from the similarly named sibling check_answers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger condition and timing: call it after compaction or resume, before asking anything, to avoid re-asking. This is clear when-to-use guidance, but it never names an alternative tool or states when a sibling such as check_answers would be preferred.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

withdraw_alertC

Withdraw one of your open alerts because the issue resolved itself.

NameRequiredDescriptionDefault
idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It implies scope ('your open alerts') but says nothing about permissions, reversibility, whether the alert is deleted or archived, what happens to a non-open alert, or whether the operator is notified. For a mutation tool with zero annotation coverage this is a meaningful gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with the verb and resource first. Efficient and readable, though the trailing causal clause is arguably decorative rather than informative.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema relieves the description of explaining return values, but a mutation tool with no annotations and an undocumented parameter still needs disclosure of side effects, permissions, and reversibility. The description does not provide these, leaving the agent under-informed before calling it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for the single required 'id' parameter. The description only loosely implies the id refers to 'one of your open alerts'; it never states the id's format or how to obtain it, so the schema gap is not compensated.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (withdraw) and resource (open alerts), which is enough to distinguish it from sibling withdraw_question by resource type. It does not explicitly name that sibling, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an implicit condition for use ('because the issue resolved itself'), which gives the agent useful context. However, it names no alternatives or when-not conditions, and does not clarify the relationship to withdraw_question or alert_operator.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

withdraw_questionB

Withdraw one of your open questions because you resolved it yourself.

It is removed from the operator's inbox.

NameRequiredDescriptionDefault
idYes
reasonYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does contribute one real effect: the question is removed from the operator's inbox. However, it leaves open whether the withdrawal is reversible, whether the required reason is surfaced to the operator, and whether any permission or state prerequisite applies.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the action and the condition, with no filler. The second sentence is a distinct fact (inbox effect) rather than padding, though it is terse enough that it borders on under-specification.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, and the ownership constraint is covered. Still, for a two-required-parameter mutation with zero annotation and zero schema-description coverage, the description should say more about id provenance and reason handling than it does.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so both parameters are undocumented in structured data and the description must compensate — but it does not mention 'id' (whose id, how to obtain it) or 'reason' (what it is used for, who sees it). Only the colloquial "your open questions" hints at valid id values.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (withdraw) and resource (question) plus the ownership/state constraint (one of your open questions), so the agent knows exactly what is being acted on. It does not differentiate itself from the close sibling withdraw_alert, which the agent must infer from the noun alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"because you resolved it yourself" gives a usage motivation, implying this is for self-resolved questions rather than questions still needing an answer. It never names alternatives (e.g., that list_my_questions supplies the id, or when to prefer check_answers), so routing is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.8.0
    • First observedalert_operator
    • First observedask_operator
    • First observedcheck_answers
    • First observedlist_my_questions
    • First observedwithdraw_alert
    • First observedwithdraw_question

TDQS

A3.9/5.0

Scored across 6 tools

Disambiguation4/5

Most tools have clearly distinct purposes: ask_operator vs alert_operator (answer expected vs no answer), and withdraw_question vs withdraw_alert. check_answers and list_my_questions both retrieve question data, which could cause occasional misselection, but descriptions clarify their different scopes.

Naming Consistency5/5

All tool names use consistent snake_case with a verb_noun pattern (withdraw_alert, check_answers, ask_operator, alert_operator, list_my_questions, withdraw_question). The only minor variation is the possessive 'my' in list_my_questions, but it still fits the pattern.

Tool Count5/5

Six tools is well-scoped for the domain of asynchronous agent-operator communication. Each tool earns its place, covering asking, alerting, checking, listing, and withdrawing without redundancy.

Completeness5/5

The surface covers the full lifecycle: ask_operator/alert_operator to initiate, check_answers/list_my_questions to retrieve, and withdraw_question/withdraw_alert to cancel. Alerts are also tracked via check_answers for acknowledgments, leaving no obvious gaps.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    MCP server for inter-agent communication. Gives multiple Claude Code sessions a shared message board, agent registry, and orchestration layer — backed by a cloud relay so agents can coordinate across machines, repos, and teams.
    8
    35 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server that provides cross-session awareness for Claude Code, tracking active sessions, file conflicts, and shared todos to enable agent coordination without blocking tool calls.
    860 npm
    MIT