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." } ```
OfficialUse herdr-inbox to asynchronously ask or alert the operator from Claude Code without blocking, then check or withdraw items as needed.
File non-blocking questions with
ask_operator, receiving a receipt such asQ12immediately.Ask a single question or up to 4 related questions in one call, with headers, context,
asked_by, and a title.Offer up to 9 options, including labels, descriptions, and highlighted previews; support multi-select, free-text answers, and notes.
Raise non-blocking operator alerts with
alert_operatorusing info, warning, or urgent severity.Withdraw resolved alerts with
withdraw_alertand resolved questions withwithdraw_question.Retrieve unseen operator answers with
check_answers, especially after compaction or missed delivery.List this session’s questions, statuses, and answers with
list_my_questions.Operator answers arrive back in the conversation as
[inbox]messages naming the question IDs.
1. Click on "Deploy Server".
2. Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
3. In the chat, type `@` followed by the MCP server name and your instructions, e.g., "`@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:
{
"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."
}
```` ask the operator which database to use for this service, then continue"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a [step-by-step guide with screenshots](https://glama.ai/blog/2025-07-08-how-to-install-and-use-mcp-servers).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
❓Ncount 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-inboxThen 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.openRelated 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-uicards need 2.1.301+.uv on
PATHfor both herdr and Claude Code (it brings its own Python 3.11+); the hooks use the systempython3(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 |
| Move the |
| Jump to that row or option |
| Open the group; select the option (single-select) or toggle it (multi-select) |
| Toggle (multi-select) |
| Add a note to the option / clear the draft |
| Next / previous tab inside a group |
| Go to the asking agent's pane |
| Dismiss the group or question ( |
| 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-inboxThis 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-inboxThe 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 ( | the block, in place of the prompt row |
idle session woken by the | the block, in place of that row |
busy session, | one dim transcript line |
busy session, | Claude Code's own |
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-inboxConfiguration
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_qThe 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 |
| File a question (or |
| Answers not seen yet (after a missed delivery or compaction) |
| The session's questions, to recover after |
| The agent resolved it itself |
| "Please check X": no answer expected; shows as an alert until acknowledged |
| 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 groupRun 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 opencannot pass arguments to the popup. Soinbox openwrites a one-shot request (open-request.jsonnext 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 openexits with code 3 and the message "the inbox popup is already open", and writes nothing.--questiontakesQnornand--grouptakes 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.
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.
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-inboxThen 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-tokensThen 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-inboxFrom 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 promptcall 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 throughcheck_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
claudenested 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 toolsalert_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.
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | ||
| message | No | ||
| asked_by | No | ||
| severity | No | warning |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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 passquestions; optional for a single question (its header or text is used instead).questions: instead ofquestion, 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.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | ||
| header | No | ||
| context | No | ||
| options | No | ||
| asked_by | No | ||
| question | No | ||
| questions | No | ||
| multi_select | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| include_closed | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| reason | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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.
6 tool updates
v0.8.0- First observed
alert_operator - First observed
ask_operator - First observed
check_answers - First observed
list_my_questions - First observed
withdraw_alert - First observed
withdraw_question
TDQS
Scored across 6 tools
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.
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.
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.
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
Related MCP Connectors
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Shared memory and mail for your AI agents. Verified with Claude Code; other MCP clients in testing.
Shared memory MCP server for Claude Code, Codex, Gemini CLI and Cursor. Cited, editable.
MCP server for OnceAsk, the AI-native current-address layer for people and agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP server that enables Claude Code to communicate with other Claude Code agents over HTTP, allowing users to ask questions about remote codebases or delegate coding tasks.MIT
- AlicenseNot gradedqualityDmaintenanceA flexible MCP server enabling multiple Claude AI sessions to coordinate work across machines through shared state management.1MIT
- AlicenseAqualityDmaintenanceMCP 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.835 npmMIT
- AlicenseNot gradedqualityBmaintenanceMCP 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 npmMIT