feat(mcp): identity-via-arg + plugin ships .mcp.json

MCP tools (send/check_inbox/peek_inbox/list_mailboxes) now accept the
caller's mailbox name as an explicit argument (from/name), falling back
to the X-Mailbox header for legacy single-session HTTP setups. This
unblocks multi-session coordination through a shared .mcp.json — each
Claude session passes its own session-derived name on every call,
instead of relying on a single transport header that all sessions
would share.

The plugin now ships .mcp.json (no header), and the SessionStart
announcement spells out the exact args to pass to each mcp__mailbox__*
tool so Claude wires it up automatically.
This commit is contained in:
Mika Kuns
2026-05-19 11:50:58 +02:00
parent 462d6561e1
commit 9fd321043f
7 changed files with 179 additions and 51 deletions

View File

@@ -119,38 +119,50 @@ The doctor command auto-installs the daemon binary via npm (asks first), registe
- `/claude-mailbox:mailbox-status` — read-only health check
- `/claude-mailbox:mailbox-update` — pull the latest daemon version and restart
**Each Claude session gets its own mailbox identity** derived from the session's UUID — `claude-a8b3c1d2` by default, or `<base>-a8b3c1d2` if you set a prefix. Parallel sessions in the same project automatically get distinct names. The `SessionStart` hook announces the current session's name in context so Claude knows its own identity. Peers discover each other via `mcp__mailbox__list_mailboxes`.
**Each Claude session gets its own mailbox identity** derived from the session's UUID — `claude-a8b3c1d2` by default, or `<base>-a8b3c1d2` if you set a prefix. Parallel sessions in the same project automatically get distinct names. The `SessionStart` hook announces the current session's name in context so Claude knows its own identity and which args to pass to MCP tools.
The plugin auto-wires the MCP server too. Because two parallel sessions share one `.mcp.json`, the MCP tools take the caller's mailbox name as an **explicit argument** (`from` / `name`) instead of relying on a shared HTTP header — so multi-session coordination just works:
```
You: "I started a second session, work together on this."
Claude (session A): looks up peers via mcp__mailbox__list_mailboxes(name="<my-name>"),
sends via mcp__mailbox__send(from="<my-name>", to="<peer>", body="...")
Claude (session B): receives the message on the next prompt via the UserPromptSubmit hook.
```
If the daemon goes down later, the hook emits a one-line setup hint instead of staying silent.
See [`plugin/README.md`](./plugin/README.md) for the full walkthrough.
## Use from a Claude session
## Use from a Claude session (without the plugin)
Drop this into your project's `.mcp.json` (one per session, different `X-Mailbox` values):
If you're not using the Claude Code plugin, drop this into your project's `.mcp.json`:
```json
{
"mcpServers": {
"mailbox": {
"type": "http",
"url": "http://127.0.0.1:47822/mcp",
"headers": {
"X-Mailbox": "backend"
}
"url": "http://127.0.0.1:47822/mcp"
}
}
}
```
The MCP tools take the caller's identity as an argument. If you want the legacy single-session style where every call uses the same mailbox name without specifying it, add a header (Claude then doesn't need to pass `from` / `name`):
```json
"headers": { "X-Mailbox": "backend" }
```
Four MCP tools are exposed:
| Tool | Purpose |
|---|---|
| `mcp__mailbox__send(to, body)` | Send a message to another mailbox |
| `mcp__mailbox__check_inbox()` | Pull all pending messages for this mailbox (marks delivered) |
| `mcp__mailbox__peek_inbox()` | Non-consuming check — returns `{ pending, oldestAt }` |
| `mcp__mailbox__list_mailboxes()` | Discover known mailboxes and who has mail for you |
| `mcp__mailbox__send(from, to, body)` | Send a message. `from` is your mailbox; falls back to X-Mailbox header. |
| `mcp__mailbox__check_inbox(name)` | Pull all pending messages for `name` (marks delivered). Falls back to X-Mailbox header. |
| `mcp__mailbox__peek_inbox(name)` | Non-consuming check — returns `{ pending, oldestAt }`. Falls back to X-Mailbox header. |
| `mcp__mailbox__list_mailboxes(name)` | Discover known mailboxes; `name` is needed for accurate `pendingForYou`. Falls back to X-Mailbox header. |
### Suggested CLAUDE.md snippet for poll discipline