cross-agent-teams-mcp 0.3.3 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -224
- package/README.zh-CN.md +69 -234
- package/dist/channel-cli.js +43 -27
- package/dist/channel-cli.js.map +1 -1
- package/dist/cli.js +195 -170
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/src/daemon/server.ts +11 -1
- package/src/lib/agent-type.ts +1 -0
- package/src/mcp/agent-public-row.ts +4 -4
- package/src/mcp/bind-channel.ts +1 -1
- package/src/mcp/poke.ts +4 -4
- package/src/mcp/register-agent.ts +38 -8
- package/src/mcp/register-codex-self.ts +1 -1
- package/src/mcp/tools.ts +80 -157
- package/src/mcp/transport-dispatch.ts +7 -7
- package/src/mcp/transport.ts +69 -7
- package/src/storage/agents-repo.ts +24 -24
- package/src/storage/schema.ts +31 -10
- package/src/lib/client-kind.ts +0 -1
package/README.md
CHANGED
|
@@ -2,34 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
[中文说明](./README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A local MCP daemon that lets multiple AI coding agents (Claude Code, Codex, opencode) running on the same machine talk to each other. Agents register, send 1-to-1 messages, broadcast to a team or role, and wake each other up — all over a single daemon, no external services.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## What's in the npm package
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
`cross-agent-teams-mcp` ships two bins from the same package:
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- **`cross-agent-teams-mcp daemon`** — the long-running HTTP daemon. Stores agents, mailboxes, and the task list in a local SQLite file, exposes its tools at `http://127.0.0.1:9100/mcp`.
|
|
12
|
+
- **`cross-agent-teams-channel`** — a stdio MCP shim that lets Claude Code receive `notifications/channel_wake` from the daemon (Claude Code's experimental channel capability). Required for Claude Code wake-ups; not needed for Codex (which uses its own app-server transport) or opencode (which falls back to tmux-pane injection).
|
|
13
|
+
|
|
14
|
+
## 1. Start the daemon
|
|
15
|
+
|
|
16
|
+
Run this once on your machine and keep the process alive (dedicated terminal, `tmux`, `screen`, `launchd` — your call):
|
|
12
17
|
|
|
13
18
|
```bash
|
|
14
19
|
npx -y cross-agent-teams-mcp@latest daemon --port 9100
|
|
15
20
|
```
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
The daemon listens on `127.0.0.1:9100`. MCP endpoint is `http://127.0.0.1:9100/mcp`, health endpoint is `http://127.0.0.1:9100/health`.
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
Common flags:
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
- `--port <n>` (default `9100`)
|
|
27
|
+
- `--token <t>` (Bearer auth)
|
|
28
|
+
- `--db <path>` (default `~/.cross-agent-teams-mcp/data.db`)
|
|
29
|
+
- `--pid-file <path>` (default `~/.cross-agent-teams-mcp/daemon.pid`)
|
|
30
|
+
|
|
31
|
+
## 2. Configure your agent's MCP client
|
|
24
32
|
|
|
25
|
-
###
|
|
33
|
+
### Claude Code (needs both entries — HTTP for tools, stdio for channel wake)
|
|
26
34
|
|
|
27
|
-
|
|
35
|
+
`.mcp.json` (or `~/.claude.json`):
|
|
28
36
|
|
|
29
37
|
```json
|
|
30
38
|
{
|
|
31
39
|
"mcpServers": {
|
|
32
40
|
"cross-agent-teams": {
|
|
41
|
+
"type": "http",
|
|
42
|
+
"url": "http://127.0.0.1:9100/mcp"
|
|
43
|
+
},
|
|
44
|
+
"cross-agent-teams-channel": {
|
|
33
45
|
"command": "npx",
|
|
34
46
|
"args": [
|
|
35
47
|
"-y",
|
|
@@ -44,252 +56,85 @@ Add the channel proxy to `.mcp.json` (or `~/.claude.json`). The MCP server name
|
|
|
44
56
|
}
|
|
45
57
|
```
|
|
46
58
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
For Codex CLI, see [docs/configs/codex-cli.md](docs/configs/codex-cli.md) — Codex talks to the daemon directly over Streamable HTTP and does not need the channel proxy. For opencode see the "Using opencode with xats (tmux)" section below.
|
|
50
|
-
|
|
51
|
-
### 3. Start Claude Code with the channel loader
|
|
59
|
+
Then start Claude Code with the experimental channel loader so it subscribes to the proxy's wake notifications:
|
|
52
60
|
|
|
53
61
|
```bash
|
|
54
|
-
claude --dangerously-load-development-channels server:cross-agent-teams
|
|
62
|
+
claude --dangerously-load-development-channels server:cross-agent-teams-channel
|
|
55
63
|
```
|
|
56
64
|
|
|
57
|
-
The `server:<name>` suffix MUST equal the MCP server
|
|
58
|
-
|
|
59
|
-
### 4. Register from inside the agent
|
|
65
|
+
The `server:<name>` suffix MUST equal the MCP server key in `.mcp.json` (`cross-agent-teams-channel` above). If your daemon uses `--token <t>`, add `"headers": { "Authorization": "Bearer <t>" }` to the HTTP entry.
|
|
60
66
|
|
|
61
|
-
|
|
67
|
+
### Codex CLI
|
|
62
68
|
|
|
63
|
-
|
|
69
|
+
Codex talks to the daemon directly over Streamable HTTP. No channel proxy is needed — Codex has no `claude/channel` capability, and wake-ups are delivered via Codex's own app-server websocket transport (or tmux paste fallback).
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
`~/.codex/config.toml`:
|
|
66
72
|
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
# or, without a build step:
|
|
72
|
-
npx tsx src/cli.ts daemon --port 9100
|
|
73
|
+
```toml
|
|
74
|
+
[mcp_servers.cross-agent-teams]
|
|
75
|
+
type = "streamable-http"
|
|
76
|
+
url = "http://127.0.0.1:9100/mcp"
|
|
73
77
|
```
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
## Common Flags
|
|
78
|
-
|
|
79
|
-
- `--port <port>`: listening port, default `9100`
|
|
80
|
-
- `--token <token>`: enable Bearer token authentication
|
|
81
|
-
- `--db <path>`: SQLite database path
|
|
82
|
-
- `--pid-file <path>`: pid file path
|
|
83
|
-
|
|
84
|
-
The default data directory is `~/.cross-agent-teams-mcp/`. The default database file is `~/.cross-agent-teams-mcp/data.db`, and the default pid file is `~/.cross-agent-teams-mcp/daemon.pid`.
|
|
79
|
+
(daemon with `--token <t>`: add `[mcp_servers.cross-agent-teams.headers]` and `Authorization = "Bearer <t>"`.)
|
|
85
80
|
|
|
86
|
-
If
|
|
87
|
-
|
|
88
|
-
## Delivery Transports
|
|
89
|
-
|
|
90
|
-
The daemon currently supports these wake-up paths:
|
|
91
|
-
|
|
92
|
-
- `tmux_pane_id`: inject text directly into a target tmux pane
|
|
93
|
-
- `delivery.kind='codex-appserver'`: resume a Codex thread over websocket and start a turn
|
|
94
|
-
- `delivery.kind='claude-channel'`: bind a Claude channel session and deliver channel wake notifications
|
|
95
|
-
|
|
96
|
-
`register_agent(...)` now requires an explicit `client`. Use one of `codex`, `claude-code`, or `opencode` for first-class runtimes. For other agent harnesses, pass `client: "custom"` and optionally `client_name` for observability.
|
|
97
|
-
|
|
98
|
-
When you do not explicitly choose a `team`, pass `project_dir` as the caller's current working directory. The daemon derives the default team from that directory's basename, and still falls back to `"default"` when both fields are omitted.
|
|
99
|
-
|
|
100
|
-
## Codex App-Server Delivery
|
|
101
|
-
|
|
102
|
-
For daily Codex usage, the recommended entry point is `register_agent({ client: "codex", ... })`. It registers a caller-supplied `thread_id` as a `codex-appserver` delivery target through the unified registration API. It does not auto-bind a tmux pane. If you want tmux fallback delivery, call `bind_runtime_identity(...)` after registration.
|
|
103
|
-
|
|
104
|
-
`register_agent({ client: "codex", ... })` no longer guesses the caller's current thread from `thread/loaded/list`. The daemon cannot safely infer "which loaded thread is mine" from the MCP session alone. If `thread_id` is omitted, the tool returns `thread_id_required` with resumable thread ids for debugging instead of registering the wrong thread.
|
|
105
|
-
|
|
106
|
-
Minimal example:
|
|
107
|
-
|
|
108
|
-
```text
|
|
109
|
-
register_agent({
|
|
110
|
-
client: "codex",
|
|
111
|
-
model: "gpt-5",
|
|
112
|
-
name: "lead",
|
|
113
|
-
project_dir: "/Users/me/workspace/cross-agent-teams-mcp",
|
|
114
|
-
role: "worker",
|
|
115
|
-
thread_id: "11111111-1111-4111-8111-111111111111"
|
|
116
|
-
})
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
If you also want tmux fallback routing, bind runtime identity explicitly after registration:
|
|
120
|
-
|
|
121
|
-
```text
|
|
122
|
-
bind_runtime_identity({
|
|
123
|
-
agent: "codex",
|
|
124
|
-
ui_pid: 81979
|
|
125
|
-
})
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
If you do not have the UI pid, you can fall back to `ui_tty + tmux_pane_id`:
|
|
129
|
-
|
|
130
|
-
```text
|
|
131
|
-
bind_runtime_identity({
|
|
132
|
-
agent: "codex",
|
|
133
|
-
ui_tty: "/dev/ttys026",
|
|
134
|
-
tmux_pane_id: "%1902"
|
|
135
|
-
})
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
Override the websocket URL when needed:
|
|
139
|
-
|
|
140
|
-
```text
|
|
141
|
-
register_agent({
|
|
142
|
-
client: "codex",
|
|
143
|
-
model: "gpt-5",
|
|
144
|
-
name: "lead",
|
|
145
|
-
project_dir: "/Users/me/workspace/cross-agent-teams-mcp",
|
|
146
|
-
role: "worker",
|
|
147
|
-
thread_id: "11111111-1111-4111-8111-111111111111",
|
|
148
|
-
ws_url: "ws://127.0.0.1:8799"
|
|
149
|
-
})
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
If the app-server requires a Bearer token, pass `auth_token_ref` as an environment variable name visible to the daemon:
|
|
153
|
-
|
|
154
|
-
```text
|
|
155
|
-
register_agent({
|
|
156
|
-
client: "codex",
|
|
157
|
-
model: "gpt-5",
|
|
158
|
-
name: "lead",
|
|
159
|
-
project_dir: "/Users/me/workspace/cross-agent-teams-mcp",
|
|
160
|
-
role: "worker",
|
|
161
|
-
thread_id: "11111111-1111-4111-8111-111111111111",
|
|
162
|
-
auth_token_ref: "CODEX_REMOTE_TOKEN"
|
|
163
|
-
})
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Behavior notes:
|
|
167
|
-
|
|
168
|
-
- `register_agent({ client: "codex", ... })` is the recommended entry point
|
|
169
|
-
- Default `ws_url` is `ws://127.0.0.1:8799`
|
|
170
|
-
- `thread_id` is required for successful registration
|
|
171
|
-
- tmux pane binding is handled separately by `bind_runtime_identity`
|
|
172
|
-
- `detect_tmux_pane(...)` remains available for debugging, but does not write registry state
|
|
173
|
-
- No loaded thread returns `no_loaded_threads`
|
|
174
|
-
- Omitted `thread_id` returns `thread_id_required` with resumable thread ids for debugging
|
|
175
|
-
- Success returns `{ agent_id, team, thread_id, ws_url }`
|
|
176
|
-
|
|
177
|
-
Minimal Codex app-server startup:
|
|
81
|
+
If you want other agents to be able to **wake** this Codex thread (not only mail it), start Codex's app-server alongside Codex itself:
|
|
178
82
|
|
|
179
83
|
```bash
|
|
180
|
-
codex app-server --listen ws://127.0.0.1:8799
|
|
181
|
-
codex --remote ws://127.0.0.1:8799
|
|
84
|
+
codex app-server --listen ws://127.0.0.1:8799 # in one terminal
|
|
85
|
+
codex --remote ws://127.0.0.1:8799 # in another terminal (TUI)
|
|
182
86
|
```
|
|
183
87
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
```text
|
|
187
|
-
register_agent({
|
|
188
|
-
model: "...",
|
|
189
|
-
name: "...",
|
|
190
|
-
role: "...",
|
|
191
|
-
team: "...",
|
|
192
|
-
delivery: {
|
|
193
|
-
kind: "codex-appserver",
|
|
194
|
-
thread_id: "11111111-1111-4111-8111-111111111111",
|
|
195
|
-
ws_url: "ws://127.0.0.1:8799"
|
|
196
|
-
}
|
|
197
|
-
})
|
|
198
|
-
```
|
|
88
|
+
Without an app-server, `send_message` to this Codex still queues a mailbox row, but you have to call `get_inbox` yourself to read it — there is no push to wake the thread.
|
|
199
89
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
```text
|
|
203
|
-
register_agent({
|
|
204
|
-
model: "...",
|
|
205
|
-
name: "...",
|
|
206
|
-
role: "...",
|
|
207
|
-
team: "...",
|
|
208
|
-
delivery: {
|
|
209
|
-
kind: "codex-appserver",
|
|
210
|
-
thread_id: "11111111-1111-4111-8111-111111111111",
|
|
211
|
-
ws_url: "ws://127.0.0.1:8799",
|
|
212
|
-
auth_token_ref: "CODEX_REMOTE_TOKEN"
|
|
213
|
-
}
|
|
214
|
-
})
|
|
215
|
-
```
|
|
90
|
+
Detailed config (auth headers, tmux fallback, lower-level `register_agent` form): [docs/configs/codex-cli.md](docs/configs/codex-cli.md).
|
|
216
91
|
|
|
217
|
-
|
|
92
|
+
### Other coding agents (opencode, cursor, ...)
|
|
218
93
|
|
|
219
|
-
|
|
220
|
-
- `ws_url` must use `ws://` or `wss://`
|
|
221
|
-
- `auth_token_ref` is interpreted only as an environment variable name
|
|
222
|
-
- On success, `poke()` returns `{ ok: true, transport_used: 'codex-appserver', thread_id }`
|
|
223
|
-
- On failure, `poke()` returns machine-readable errors such as `codex_connect_failed`, `codex_initialize_failed`, `codex_resume_failed`, `codex_turn_start_failed`, or `missing_auth_token`
|
|
224
|
-
- When a target is explicitly registered as `codex-appserver`, the daemon does not fall back to tmux
|
|
94
|
+
Anything that is not Claude Code or Codex — opencode, cursor, an editor extension, your own harness — connects over plain Streamable HTTP and registers as `agent_type="custom"` (the agent figures this out for you). There is no dedicated wake-up transport for these; cross-agent pokes are delivered by injecting text into the agent's tmux pane, so run the agent inside a tmux window and the daemon will resolve `pid → tty → pane` automatically when you register.
|
|
225
95
|
|
|
226
|
-
|
|
96
|
+
Per-tool config snippets live in [docs/configs/opencode.md](docs/configs/opencode.md) (and `docs/configs/` for the rest).
|
|
227
97
|
|
|
228
|
-
##
|
|
98
|
+
## 3. Use it from your agent
|
|
229
99
|
|
|
230
|
-
|
|
100
|
+
Once your agent is connected to the daemon, you don't have to memorize tool names. Just talk to the agent in plain language and it will pick the right tool — the README below shows the *kinds of things you say*, not the underlying API.
|
|
231
101
|
|
|
232
|
-
|
|
233
|
-
register_claude_self({
|
|
234
|
-
name: "lead",
|
|
235
|
-
project_dir: "/Users/me/workspace/cross-agent-teams-mcp",
|
|
236
|
-
role: "worker",
|
|
237
|
-
channel_session_id: "csid-abc"
|
|
238
|
-
})
|
|
239
|
-
```
|
|
102
|
+
> Note: always run these from inside the agent session. Don't try to register or send messages with `curl` or any other external HTTP client — that opens a different MCP session and the messages won't reach you.
|
|
240
103
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
```text
|
|
244
|
-
register_agent({
|
|
245
|
-
client: "claude-code",
|
|
246
|
-
model: "opus-4-7",
|
|
247
|
-
name: "lead",
|
|
248
|
-
project_dir: "/Users/me/workspace/cross-agent-teams-mcp",
|
|
249
|
-
role: "worker",
|
|
250
|
-
channel_session_id: "csid-abc"
|
|
251
|
-
})
|
|
252
|
-
```
|
|
104
|
+
### Register the session
|
|
253
105
|
|
|
254
|
-
|
|
106
|
+
The first time an agent connects to xats it stays unregistered until you tell it to register. Just say:
|
|
255
107
|
|
|
256
|
-
|
|
108
|
+
> Register me to xats as alice.
|
|
257
109
|
|
|
258
|
-
|
|
110
|
+
Or with an explicit team:
|
|
259
111
|
|
|
260
|
-
|
|
112
|
+
> Register me to xats as alice on team backend.
|
|
261
113
|
|
|
262
|
-
|
|
263
|
-
tmux new-window opencode
|
|
264
|
-
```
|
|
114
|
+
If you don't give a team, the agent uses your current working directory's basename — so you typically don't need to think about it.
|
|
265
115
|
|
|
266
|
-
|
|
267
|
-
register_agent({
|
|
268
|
-
client: "opencode",
|
|
269
|
-
model: "opencode-default",
|
|
270
|
-
name: "my-opencode-agent",
|
|
271
|
-
project_dir: "/Users/me/workspace/cross-agent-teams-mcp",
|
|
272
|
-
role: "worker",
|
|
273
|
-
ui_pid: <opencode pid>
|
|
274
|
-
})
|
|
275
|
-
```
|
|
116
|
+
### Talk to other agents
|
|
276
117
|
|
|
277
|
-
|
|
118
|
+
Address by name, by team, or by role:
|
|
278
119
|
|
|
279
|
-
|
|
120
|
+
> Send a message to bob: how is the migration going?
|
|
121
|
+
>
|
|
122
|
+
> Tell my team I'm starting the deploy.
|
|
123
|
+
>
|
|
124
|
+
> Send the frontend role a heads-up that the API will change.
|
|
125
|
+
>
|
|
126
|
+
> What's in my inbox?
|
|
280
127
|
|
|
281
|
-
|
|
128
|
+
The agent picks the right tool (`send_message`, `broadcast`, `broadcast_to_role`, `get_inbox`). Outgoing messages also wake the recipient automatically — you don't need a separate poke.
|
|
282
129
|
|
|
283
|
-
|
|
284
|
-
- `client="opencode"`: `tmux-poke`
|
|
285
|
-
- `client="codex"`: `codex-appserver` first, then `tmux-poke`
|
|
130
|
+
### See who else is around
|
|
286
131
|
|
|
287
|
-
|
|
132
|
+
> Who else is registered on xats?
|
|
133
|
+
>
|
|
134
|
+
> List agents on team backend.
|
|
288
135
|
|
|
289
|
-
|
|
136
|
+
## More
|
|
290
137
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
4. Remove any shell alias that pointed at `launch-opencode.sh` (the script no longer exists).
|
|
295
|
-
5. Re-register opencode agents using the `register_agent({ client: "opencode", ui_pid, ... })` flow shown above.
|
|
138
|
+
- Full tool reference and schema: launch the daemon and call `tools/list` on the MCP endpoint.
|
|
139
|
+
- Per-agent config details: `docs/configs/`.
|
|
140
|
+
- Source: [github.com/jtianling/cross-agent-teams-mcp](https://github.com/jtianling/cross-agent-teams-mcp).
|