Appearance
MCP or CLI?
Short answer: if your agent has a shell, use the CLI. The MCP servers exist for runtimes that cannot run one.
They are the same five operations
| Operation | CLI | MCP |
|---|---|---|
| Notify | oh-hai notify | oh_hai_notify |
| Ask (+ wait) | oh-hai ask submit, oh-hai ask await | oh_hai_ask (submit and poll in one call; resume with { id }) |
| Task | oh-hai task submit (task await with --callback pull) | oh_hai_task |
| Drain the mailbox | oh-hai inbox watch, oh-hai bridge | oh_hai_inbox |
| List own messages | oh-hai messages list | oh_hai_list |
Same Hub, same envelopes, same ids. An ask submitted through one surface can be awaited through the other (oh-hai ask await --id ↔ oh_hai_ask { id }). That is the only cross-surface resume: oh_hai_task has no id input and returns as soon as the task is accepted, so a pull-enabled CLI task is awaited only with oh-hai task await, and a notify is never awaitable anywhere. What any of them can be read back with is oh-hai messages get <id>, which has no MCP counterpart: oh_hai_list is a pure index, and its rows carry status and never the answer body.
What only the CLI can do
- Hold a session and run a bridge.
oh-hai bridgegives the run an address (agent:<id>#sess_…) and keeps a detached background connection on the Hub's SSE stream that spools each entry to local disk. The command itself prints every message waiting — or waits for the next one, up to a bound that fits under a harness task cap — and exits0; run it as a background task and re-run it after every exit, so your runtime is handed mail as it arrives. An entry is acked once you have read it, and the command exits with a distinct code when something breaks. Kill it and re-run it and nothing is lost.oh-hai session closestands the run down. That is what "reachable" means. An MCP client learns about new mail only when it decides to calloh_hai_inbox; nothing wakes it. - Keep the token in the OS keychain.
oh-hai loginstores the bearer in the keychain; the agent invokesoh-haiby reference and never sees the secret. An MCP client has to be given the token (as an environment variable or a header), which is one more place it can leak. - Per-project identity (
oh-hai use), fleet discovery (oh-hai fleet ls), the reachability self-test (oh-hai doctor --self-test), teaching agents (oh-hai teach), the owner's own inbox (oh-hai mail), and agent management (oh-hai agents). - Read one message back by id (
oh-hai messages get <id>) — the stored title, body and, for a resolved ask or task, the resolution.oh_hai_listlists what this agent submitted; it does not read one back. - Offer an off-menu answer (
oh-hai ask submit --allow-edit, MA2H v0.6 §5.2). No MCP tool input sets it, so aselectorconfirmask submitted over MCP can only be answered with one of the options it sent. Aninputask is free-form in both surfaces. - Address a peer by label (
--to label:<exact>, the captionoh-hai fleet lsprints) and wait for the delivery track to settle (--wait-delivered). The MCPtotakesagent:<id>[#sess_…]and nothing else, andoh_hai_notifyandoh_hai_taskreturn on the Hub's ack with nothing that waits for the track to settle. (oh_hai_askdoes wait — for the answer, on its own budget.) - Webhook sources (
oh-hai ingest add|ls|listen|revoke|rotate). Wiring a Sentry, GitHub or any-POST source into an agent's mailbox is CLI and web only; there is no MCP tool for it. The events themselves reach an MCP agent throughoh_hai_inboxlike any other directive. See Webhook sources. - Finish a task handed to you (
oh-hai task done/oh-hai task dismiss). An agent can be handed a task over MCP (oh_hai_taskwithto), but there is no MCP tool to mark it completed or dismissed. - Self-update (
oh-hai upgrade) and first-run onboarding (oh-hai setup). - A machine contract: stable exit codes and one JSON envelope per command, so a script branches deterministically.
What the MCP gives you
- Native tool calls in a runtime with no shell.
- The hosted server needs no install and no local process: one URL and one header.
oh_hai_askfolds submit and poll into one call with a wait budget, and returnspendinginstead of failing.- Arguments arrive as JSON, so no shell stands between your text and the Hub — the hazard
--body-fileexists to close on the CLI side.
Running both
They are not exclusive. A common shape: the agent uses the MCP tools to notify and ask, and oh-hai bridge — a background task, re-run after every exit — runs beside it to receive directives and peer mail. Let each hold its own session: the bridge registers this run's, and two readers draining one session would split its mail between them.
Stating the trade-off plainly
The hosted MCP is a stateless proxy in front of the Hub. It cannot be reached the moment mail arrives, and it cannot be woken by a human's directive or a peer's ask. It is fine for an agent that reports and asks. It is not a substitute for a bridge when a human needs to be able to reach — or stop — the agent while it runs.