Skip to main content
Glama
README.md
# hitl-mcp

> Stay aware of what your agent is doing. Get pinged for tiny decisions. Go back to the chat when something bigger needs you.

HITL-MCP is an **ephemeral communication bridge** between an AI agent execution and a human channel you already use (Slack, …).

It is **not** a task manager, messaging platform, SaaS product, centralized gateway, or agent orchestration system.

The agent owns its own task state and context. HITL only delivers progress and short questions.

---

## Vision

```text
Agent starts work     → notify_human ("Started …")
Agent makes progress  → notify_human (milestones)
Small, quick choice   → ask_human   (brief channel reply)
Something important
  / long to read      → notify_human ("Open the agent chat to reply")
Agent finishes        → notify_human ("Done …")
```

| Situation | Tool | Where you respond |
|---|---|---|
| Progress from start → finish | `notify_human` | Nowhere (FYI only) |
| Tiny question (yes/no, A/B, one line) | `ask_human` | In the channel thread |
| Important / long / needs context | `notify_human` | In the **agent chat** |

HITL is awareness + triage — not a second inbox for deep conversations.

---

## Core idea

```text
AGENT
  ↓
MCP stdio
  ↓
HITL Core
  ↓
Channel Adapter
  ↓
Slack / WhatsApp / …
  ↓
Human
```

Nothing about the interaction is stored by HITL. Pending asks live in memory only and disappear when the process exits.

---

## Principles

| Principle | Meaning |
|---|---|
| Local-first | The MCP runs on your machine |
| stdio MVP | No HTTP server for event delivery |
| No central backend | No HITL cloud, no shared gateway |
| No HITL account | No email, password, or centralized identity |
| No task database | Agents keep their own state |
| Ephemeral pending requests | In memory only; gone when the process exits |
| User-owned providers | Your Slack app / your WhatsApp session |
| Persistent config only | Named targets + default + provider prefs locally; project `.hitl-mcp/config.json` overrides global |
| Credentials separated | Tokens/sessions stored apart from runtime state |
| Per-call / per-chat overrides | Explicit `target`, or `/hitl-channel.*` / `/hitl.off` for this chat only |

**Architectural rule:** if a feature requires HITL to remember something after the current agent execution ends, that feature probably does not belong here.

---

## MCP tools

Exactly three:

### `notify_human`

One-way update. Use for:

- start / progress / done
- “Something needs you in the agent chat — open it to reply”

Soft-skips when HITL is disabled for the chat (`/hitl.off`).

### `ask_human`

Short question; waits for a **brief** channel reply (confirm, pick an option, one line). Soft-skips when disabled.

### `configure_hitl`

Per-chat prefs. Call when the user types `/hitl.off`, `/hitl.on`, or `/hitl-channel.<channel>` (e.g. `/hitl-channel.slack`).

Optional `label` sets the channel thread title. On Slack, the first call opens a thread; later calls stay in it.

---

## Quick start

```bash
npm install
npm run build

# Configure Slack, WhatsApp, or Fake for local testing
npm run setup
# or: node dist/index.js setup

# Run the MCP server (stdio)
npm start
```

### Slack (Socket Mode)

1. Create a Slack App with Socket Mode enabled
2. Add bot scopes and `message.channels` / `message.groups` events
3. Install the app, copy `xoxb-` and `xapp-` tokens
4. Invite the bot to your HITL channel
5. Run `hitl-mcp setup` → choose Slack

Full walkthrough: [docs/slack.md](docs/slack.md)

### WhatsApp (local session)

1. Run `hitl-mcp setup` → choose WhatsApp
2. Link via QR (or pairing code) in WhatsApp → Linked Devices
3. Pick a default chat/group (or paste a JID)

Uses an unofficial client library — see warnings in [docs/whatsapp.md](docs/whatsapp.md).

### MCP client config

```json
{
  "mcpServers": {
    "hitl": {
      "command": "node",
      "args": ["/absolute/path/to/hitl-mcp/dist/index.js"],
      "env": {
        "HITL_PROJECT_ROOT": "${workspaceFolder}"
      }
    }
  }
}
```

---

## Status

| Channel | Status |
|---|---|
| Fake | Working (tests / local dev) |
| Slack (Socket Mode) | Working |
| WhatsApp (Baileys) | Working |

---

## Documentation

- [Architecture](docs/architecture.md)
- [Configuration](docs/configuration.md)
- [Channels](docs/channels.md)
- [Slack setup](docs/slack.md)
- [WhatsApp setup](docs/whatsapp.md)
- [Agent rules](docs/agent-rules.md)

Optional agent guidance: [`agent-rules/HITL.md`](agent-rules/HITL.md)

---

## Non-goals

No task management, databases, REST API, web dashboard, user accounts, or conversation history.

---

## License

MIT

TDQS

A4.2/5.0

Scored across 2 tools

Disambiguation5/5

ask_human and notify_human serve clearly distinct purposes: one requests a reply, the other sends a notification without waiting. There is no overlap or ambiguity in their intent.

Naming Consistency5/5

Both tool names follow the same verb_noun pattern, with the target 'human' consistently placed as the object. The naming is clear, predictable, and easy to pattern-match.

Tool Count4/5

Two tools is slightly below the typical 3-15 range, but the server's scope is narrow and both tools earn their place. The count feels slightly minimal but not inadequate for a basic HITL utility.

Completeness4/5

The tool surface covers the two core human-in-the-loop modes: interactive question-answering and one-way notification. Minor gaps like persistence or cancellation are absent, but they are not clearly implied by the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues