@dolusoft/claude-collab 1.10.3 → 1.10.4
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 +51 -50
- package/dist/cli.js +1 -124
- package/dist/cli.js.map +1 -1
- package/dist/mcp-main.js +1 -124
- package/dist/mcp-main.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,13 +7,12 @@ Real-time collaboration between Claude Code terminals via MCP (Model Context Pro
|
|
|
7
7
|
|
|
8
8
|
## Overview
|
|
9
9
|
|
|
10
|
-
Claude Collab lets multiple Claude Code terminals communicate
|
|
10
|
+
Claude Collab lets multiple Claude Code terminals communicate directly — no central server needed. Each peer runs its own node; peers discover each other automatically on the LAN via UDP multicast and connect directly over WebSocket.
|
|
11
11
|
|
|
12
12
|
```
|
|
13
|
-
alice
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
└─────────────────┘
|
|
13
|
+
alice ◄──────────────────► bob
|
|
14
|
+
direct WebSocket
|
|
15
|
+
(auto-discovered)
|
|
17
16
|
```
|
|
18
17
|
|
|
19
18
|
## Setup
|
|
@@ -28,55 +27,39 @@ claude mcp add claude-collab -- npx -y @dolusoft/claude-collab --name <your-name
|
|
|
28
27
|
|-------------|-------------|
|
|
29
28
|
| `<your-name>` | Your identifier on the network (e.g. `alice`, `backend`, `frontend`) |
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
### Step 2 — Connect to peers
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
In Claude Code, call the `start_hub` tool:
|
|
32
|
+
Call `peer_find` in Claude Code:
|
|
36
33
|
|
|
37
34
|
```
|
|
38
|
-
|
|
39
|
-
start_hub(port=8888) # custom port
|
|
35
|
+
peer_find()
|
|
40
36
|
```
|
|
41
37
|
|
|
42
38
|
This will:
|
|
43
|
-
1.
|
|
44
|
-
2.
|
|
45
|
-
3.
|
|
46
|
-
|
|
47
|
-
Everyone else will auto-connect within seconds. No IP address sharing needed.
|
|
39
|
+
1. Open a **Windows UAC prompt** — click **Yes** to open your firewall
|
|
40
|
+
2. Wait 30 seconds while peers are discovered and connected
|
|
41
|
+
3. Close the firewall (another UAC prompt) — existing connections persist
|
|
48
42
|
|
|
49
|
-
|
|
43
|
+
Everyone on the team should call `peer_find` at the same time when setting up.
|
|
50
44
|
|
|
51
|
-
|
|
52
|
-
stop_hub()
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
This stops the server and removes the firewall rule (UAC prompt shown once).
|
|
56
|
-
|
|
57
|
-
---
|
|
45
|
+
### Step 3 — Adding a new peer later
|
|
58
46
|
|
|
59
|
-
|
|
47
|
+
Only the **new peer** needs to call `peer_find`. Existing peers will connect to them automatically — no action needed from others.
|
|
60
48
|
|
|
61
|
-
|
|
49
|
+
### Step 4 — After a disconnect or restart
|
|
62
50
|
|
|
63
|
-
|
|
64
|
-
# Start hub manually in a terminal:
|
|
65
|
-
npx @dolusoft/claude-collab --hub --port 9999
|
|
51
|
+
The disconnecting peer calls `peer_find` again. Others reconnect automatically.
|
|
66
52
|
|
|
67
|
-
|
|
68
|
-
claude mcp add claude-collab -- npx -y @dolusoft/claude-collab --name <your-name> --server <hub-ip>:<hub-port>
|
|
69
|
-
```
|
|
53
|
+
---
|
|
70
54
|
|
|
71
55
|
## MCP Tools
|
|
72
56
|
|
|
73
57
|
| Tool | Description |
|
|
74
58
|
|------|-------------|
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `peers` | Show currently connected peers and your own name. |
|
|
59
|
+
| `peer_find` | Discover and connect to peers. Opens firewall, waits 30s, closes firewall. |
|
|
60
|
+
| `ask` | Ask a peer a question by name. Waits up to 5 minutes for a reply. |
|
|
61
|
+
| `reply` | Reply to an incoming question. |
|
|
62
|
+
| `peers` | Show connected peers and your own name/port. |
|
|
80
63
|
| `history` | Show past questions and answers from this session. |
|
|
81
64
|
|
|
82
65
|
## Example
|
|
@@ -85,10 +68,29 @@ claude mcp add claude-collab -- npx -y @dolusoft/claude-collab --name <your-name
|
|
|
85
68
|
# Alice asks Bob
|
|
86
69
|
ask("bob", "What's the response format for the /users endpoint?")
|
|
87
70
|
|
|
88
|
-
# Bob sees the question
|
|
89
|
-
reply("
|
|
71
|
+
# Bob sees the question injected into his terminal and replies
|
|
72
|
+
reply("<question-id>", "Returns JSON: { id, name, email }")
|
|
90
73
|
|
|
91
|
-
# Alice
|
|
74
|
+
# Alice receives the answer
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## How it works
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
Startup:
|
|
81
|
+
Each peer binds a WebSocket server on a random port (10000–19999)
|
|
82
|
+
Each peer broadcasts UDP multicast (239.255.42.42:11776) every 5s
|
|
83
|
+
|
|
84
|
+
Discovery:
|
|
85
|
+
Peer A hears Peer B's multicast → connects outbound to B's WS port
|
|
86
|
+
If multicast is one-way (e.g. VMware + WiFi), the receiving side
|
|
87
|
+
sends a unicast reply so both peers discover each other
|
|
88
|
+
|
|
89
|
+
peer_find:
|
|
90
|
+
Opens firewall (inbound TCP + UDP 11776) → wait → closes firewall
|
|
91
|
+
Established connections persist after firewall closes (stateful TCP)
|
|
92
|
+
New peers only need to open their own firewall — existing peers
|
|
93
|
+
connect outbound to them automatically
|
|
92
94
|
```
|
|
93
95
|
|
|
94
96
|
## Architecture
|
|
@@ -96,17 +98,16 @@ reply("q_abc123", "Returns JSON: { id, name, email }")
|
|
|
96
98
|
```
|
|
97
99
|
src/
|
|
98
100
|
├── infrastructure/
|
|
99
|
-
│ ├──
|
|
100
|
-
│ │
|
|
101
|
-
│
|
|
102
|
-
│ │
|
|
103
|
-
│
|
|
104
|
-
│ ├──
|
|
105
|
-
│ │
|
|
106
|
-
│
|
|
107
|
-
│ └── terminal-injector/ # Injects incoming questions into Claude Code
|
|
101
|
+
│ ├── discovery/
|
|
102
|
+
│ │ └── multicast-discovery.ts # UDP multicast + unicast reply
|
|
103
|
+
│ ├── firewall/
|
|
104
|
+
│ │ └── firewall.ts # Windows Firewall via UAC (netsh)
|
|
105
|
+
│ ├── p2p/
|
|
106
|
+
│ │ ├── p2p-node.ts # WS server + client + discovery
|
|
107
|
+
│ │ └── p2p-protocol.ts # Wire protocol (HELLO, ASK, ANSWER…)
|
|
108
|
+
│ └── terminal-injector/ # Injects incoming questions into Claude Code
|
|
108
109
|
└── presentation/
|
|
109
|
-
└── mcp/
|
|
110
|
+
└── mcp/ # MCP server + tools
|
|
110
111
|
```
|
|
111
112
|
|
|
112
113
|
## Development
|
package/dist/cli.js
CHANGED
|
@@ -1044,128 +1044,7 @@ async function removeFirewallRule(port) {
|
|
|
1044
1044
|
}
|
|
1045
1045
|
}
|
|
1046
1046
|
|
|
1047
|
-
// src/presentation/mcp/tools/
|
|
1048
|
-
var FIREWALL_OPEN_DESCRIPTION = `Open a Windows Firewall inbound rule so peers on the LAN can connect directly to you.
|
|
1049
|
-
|
|
1050
|
-
WHEN YOU NEED THIS:
|
|
1051
|
-
- Other peers cannot see you in their peers() list even though you are on the same LAN
|
|
1052
|
-
- You just started and want to make sure all peers can reach you
|
|
1053
|
-
- A peer explicitly says they cannot connect to you
|
|
1054
|
-
|
|
1055
|
-
WHEN YOU DO NOT NEED THIS:
|
|
1056
|
-
- You can already see peers in peers() \u2014 the connection is working
|
|
1057
|
-
- You are connecting outbound to others (outbound connections do not require firewall rules)
|
|
1058
|
-
|
|
1059
|
-
WHAT HAPPENS:
|
|
1060
|
-
- On most systems: the rule is applied immediately (terminal is already elevated)
|
|
1061
|
-
- On standard Windows: a UAC popup appears \u2014 the user must click Yes
|
|
1062
|
-
- On VMs or headless setups: applied directly if running as Administrator
|
|
1063
|
-
|
|
1064
|
-
The rule is named "claude-collab-{port}" and allows inbound TCP on your current listen port.
|
|
1065
|
-
Call firewall_close() when you are done to clean up the rule.`;
|
|
1066
|
-
function registerFirewallOpenTool(server, client) {
|
|
1067
|
-
server.tool(
|
|
1068
|
-
"firewall_open",
|
|
1069
|
-
FIREWALL_OPEN_DESCRIPTION,
|
|
1070
|
-
{
|
|
1071
|
-
port: z.number().min(1024).max(65535).optional().describe(
|
|
1072
|
-
"Port to open. Defaults to your current listen port \u2014 omit this unless you have a specific reason to override."
|
|
1073
|
-
)
|
|
1074
|
-
},
|
|
1075
|
-
async ({ port }) => {
|
|
1076
|
-
const targetPort = port ?? client.getInfo().port;
|
|
1077
|
-
if (!targetPort) {
|
|
1078
|
-
return {
|
|
1079
|
-
content: [{ type: "text", text: "P2P node is not running yet \u2014 port unknown. Try again in a moment." }],
|
|
1080
|
-
isError: true
|
|
1081
|
-
};
|
|
1082
|
-
}
|
|
1083
|
-
try {
|
|
1084
|
-
await addFirewallRule(targetPort);
|
|
1085
|
-
return {
|
|
1086
|
-
content: [{
|
|
1087
|
-
type: "text",
|
|
1088
|
-
text: [
|
|
1089
|
-
`Firewall rule opened for port ${targetPort} (claude-collab-${targetPort}).`,
|
|
1090
|
-
`Peers on the LAN can now connect to you inbound.`,
|
|
1091
|
-
`Call firewall_close() when you are done with this session.`
|
|
1092
|
-
].join("\n")
|
|
1093
|
-
}]
|
|
1094
|
-
};
|
|
1095
|
-
} catch (err) {
|
|
1096
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1097
|
-
return {
|
|
1098
|
-
content: [{
|
|
1099
|
-
type: "text",
|
|
1100
|
-
text: [
|
|
1101
|
-
`Failed to open firewall: ${msg}`,
|
|
1102
|
-
``,
|
|
1103
|
-
`Try running your terminal as Administrator and call firewall_open() again.`
|
|
1104
|
-
].join("\n")
|
|
1105
|
-
}],
|
|
1106
|
-
isError: true
|
|
1107
|
-
};
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
);
|
|
1111
|
-
}
|
|
1112
|
-
var FIREWALL_CLOSE_DESCRIPTION = `Remove the Windows Firewall inbound rule that was opened by firewall_open().
|
|
1113
|
-
|
|
1114
|
-
WHEN TO USE:
|
|
1115
|
-
- At the end of a collaboration session to clean up
|
|
1116
|
-
- When you no longer want to accept inbound peer connections
|
|
1117
|
-
- As general hygiene \u2014 open firewall rules should not be left indefinitely
|
|
1118
|
-
|
|
1119
|
-
WHAT HAPPENS:
|
|
1120
|
-
- The inbound TCP rule "claude-collab-{port}" is deleted from Windows Firewall
|
|
1121
|
-
- Existing active connections are not dropped \u2014 only new inbound connections are blocked
|
|
1122
|
-
- On standard Windows: a UAC popup appears \u2014 the user must click Yes
|
|
1123
|
-
- On VMs or admin terminals: applied directly without a popup
|
|
1124
|
-
|
|
1125
|
-
NOTE: Because ports are random each session, each startup creates a new rule name.
|
|
1126
|
-
Old rules from previous sessions can be removed by passing the port explicitly.`;
|
|
1127
|
-
function registerFirewallCloseTool(server, client) {
|
|
1128
|
-
server.tool(
|
|
1129
|
-
"firewall_close",
|
|
1130
|
-
FIREWALL_CLOSE_DESCRIPTION,
|
|
1131
|
-
{
|
|
1132
|
-
port: z.number().min(1024).max(65535).optional().describe(
|
|
1133
|
-
"Port whose rule to remove. Defaults to your current listen port. Pass a specific port to clean up a rule from a previous session."
|
|
1134
|
-
)
|
|
1135
|
-
},
|
|
1136
|
-
async ({ port }) => {
|
|
1137
|
-
const targetPort = port ?? client.getInfo().port;
|
|
1138
|
-
if (!targetPort) {
|
|
1139
|
-
return {
|
|
1140
|
-
content: [{ type: "text", text: "P2P node is not running yet \u2014 port unknown. Try again in a moment." }],
|
|
1141
|
-
isError: true
|
|
1142
|
-
};
|
|
1143
|
-
}
|
|
1144
|
-
try {
|
|
1145
|
-
await removeFirewallRule(targetPort);
|
|
1146
|
-
return {
|
|
1147
|
-
content: [{
|
|
1148
|
-
type: "text",
|
|
1149
|
-
text: `Firewall rule removed for port ${targetPort} (claude-collab-${targetPort}).`
|
|
1150
|
-
}]
|
|
1151
|
-
};
|
|
1152
|
-
} catch (err) {
|
|
1153
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1154
|
-
return {
|
|
1155
|
-
content: [{
|
|
1156
|
-
type: "text",
|
|
1157
|
-
text: [
|
|
1158
|
-
`Failed to remove firewall rule: ${msg}`,
|
|
1159
|
-
``,
|
|
1160
|
-
`The rule may not exist (if firewall_open was never called this session), or try running as Administrator.`
|
|
1161
|
-
].join("\n")
|
|
1162
|
-
}],
|
|
1163
|
-
isError: true
|
|
1164
|
-
};
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
);
|
|
1168
|
-
}
|
|
1047
|
+
// src/presentation/mcp/tools/peer-find.tool.ts
|
|
1169
1048
|
var PEER_FIND_DESCRIPTION = `Discover and connect to peers on the LAN automatically.
|
|
1170
1049
|
|
|
1171
1050
|
WHAT IT DOES:
|
|
@@ -1256,8 +1135,6 @@ function createMcpServer(options) {
|
|
|
1256
1135
|
registerReplyTool(server, client);
|
|
1257
1136
|
registerPeersTool(server, client);
|
|
1258
1137
|
registerHistoryTool(server, client);
|
|
1259
|
-
registerFirewallOpenTool(server, client);
|
|
1260
|
-
registerFirewallCloseTool(server, client);
|
|
1261
1138
|
registerPeerFindTool(server, client);
|
|
1262
1139
|
return server;
|
|
1263
1140
|
}
|