@spencerbeggs/claude-coordinator-mcp 0.1.0
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/433.js +403 -0
- package/LICENSE +21 -0
- package/README.md +138 -0
- package/bin/claude-coordinator-mcp.js +18 -0
- package/index.d.ts +126 -0
- package/index.js +1 -0
- package/package.json +54 -0
package/433.js
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { AnswerInputSchema, AskInputSchema, DEFAULT_URL, GetContextInputSchema, JoinInputSchema, ListContextInputSchema, LogDecisionInputSchema, ShareContextInputSchema } from "@spencerbeggs/claude-coordinator-core";
|
|
2
|
+
import { createTRPCClient, createWSClient, wsLink } from "@trpc/client";
|
|
3
|
+
import ws from "ws";
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
function createCoordinatorClient(options = {}) {
|
|
8
|
+
const url = options.url ?? DEFAULT_URL;
|
|
9
|
+
const wsClient = createWSClient({
|
|
10
|
+
url,
|
|
11
|
+
WebSocket: ws
|
|
12
|
+
});
|
|
13
|
+
const trpc = createTRPCClient({
|
|
14
|
+
links: [
|
|
15
|
+
wsLink({
|
|
16
|
+
client: wsClient
|
|
17
|
+
})
|
|
18
|
+
]
|
|
19
|
+
});
|
|
20
|
+
const close = ()=>{
|
|
21
|
+
wsClient.close();
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
trpc,
|
|
25
|
+
close
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function formatConnectionError(error, url) {
|
|
29
|
+
const errorStr = String(error);
|
|
30
|
+
if (errorStr.includes("ECONNREFUSED") || errorStr.includes("ENOTFOUND") || errorStr.includes("WebSocket") || errorStr.includes("connect")) return `Could not connect to coordinator server at ${url}. Please start the server with: npx @spencerbeggs/claude-coordinator-server`;
|
|
31
|
+
return errorStr;
|
|
32
|
+
}
|
|
33
|
+
async function createMcpServer(options = {}) {
|
|
34
|
+
const serverUrl = options.url ?? DEFAULT_URL;
|
|
35
|
+
let client = null;
|
|
36
|
+
let agentId = null;
|
|
37
|
+
const server = new McpServer({
|
|
38
|
+
name: "claude-coordinator",
|
|
39
|
+
version: "0.1.0"
|
|
40
|
+
});
|
|
41
|
+
const getClient = ()=>{
|
|
42
|
+
if (!client) client = createCoordinatorClient({
|
|
43
|
+
url: serverUrl
|
|
44
|
+
});
|
|
45
|
+
return client;
|
|
46
|
+
};
|
|
47
|
+
const formatError = (error)=>formatConnectionError(error, serverUrl);
|
|
48
|
+
const requireAgentId = ()=>{
|
|
49
|
+
if (!agentId) throw new Error("Not joined to session. Call coordinator_join first.");
|
|
50
|
+
return agentId;
|
|
51
|
+
};
|
|
52
|
+
server.tool("coordinator_join", "Join the coordination session as an agent", JoinInputSchema.shape, async (params)=>{
|
|
53
|
+
try {
|
|
54
|
+
const result = await getClient().trpc.session.join.mutate(params);
|
|
55
|
+
agentId = result.agent.id;
|
|
56
|
+
return {
|
|
57
|
+
content: [
|
|
58
|
+
{
|
|
59
|
+
type: "text",
|
|
60
|
+
text: JSON.stringify({
|
|
61
|
+
success: true,
|
|
62
|
+
agent: result.agent,
|
|
63
|
+
sessionId: result.sessionId
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
};
|
|
68
|
+
} catch (error) {
|
|
69
|
+
return {
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
72
|
+
type: "text",
|
|
73
|
+
text: JSON.stringify({
|
|
74
|
+
success: false,
|
|
75
|
+
error: formatError(error)
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
isError: true
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
server.tool("coordinator_leave", "Leave the coordination session", {}, async ()=>{
|
|
84
|
+
try {
|
|
85
|
+
const id = requireAgentId();
|
|
86
|
+
const result = await getClient().trpc.session.leave.mutate({
|
|
87
|
+
agentId: id
|
|
88
|
+
});
|
|
89
|
+
if (result.success) agentId = null;
|
|
90
|
+
return {
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: "text",
|
|
94
|
+
text: JSON.stringify({
|
|
95
|
+
success: result.success
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return {
|
|
102
|
+
content: [
|
|
103
|
+
{
|
|
104
|
+
type: "text",
|
|
105
|
+
text: JSON.stringify({
|
|
106
|
+
success: false,
|
|
107
|
+
error: formatError(error)
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
isError: true
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
server.tool("coordinator_list_agents", "List all connected agents in the session", {}, async ()=>{
|
|
116
|
+
try {
|
|
117
|
+
const agents = await getClient().trpc.session.list.query();
|
|
118
|
+
return {
|
|
119
|
+
content: [
|
|
120
|
+
{
|
|
121
|
+
type: "text",
|
|
122
|
+
text: JSON.stringify({
|
|
123
|
+
success: true,
|
|
124
|
+
agents
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
};
|
|
129
|
+
} catch (error) {
|
|
130
|
+
return {
|
|
131
|
+
content: [
|
|
132
|
+
{
|
|
133
|
+
type: "text",
|
|
134
|
+
text: JSON.stringify({
|
|
135
|
+
success: false,
|
|
136
|
+
error: formatError(error)
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
],
|
|
140
|
+
isError: true
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
server.tool("coordinator_share_context", "Share a context entry with other agents", ShareContextInputSchema.shape, async (params)=>{
|
|
145
|
+
try {
|
|
146
|
+
const id = requireAgentId();
|
|
147
|
+
const entry = await getClient().trpc.context.share.mutate({
|
|
148
|
+
...params,
|
|
149
|
+
agentId: id
|
|
150
|
+
});
|
|
151
|
+
return {
|
|
152
|
+
content: [
|
|
153
|
+
{
|
|
154
|
+
type: "text",
|
|
155
|
+
text: JSON.stringify({
|
|
156
|
+
success: true,
|
|
157
|
+
entry
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
};
|
|
162
|
+
} catch (error) {
|
|
163
|
+
return {
|
|
164
|
+
content: [
|
|
165
|
+
{
|
|
166
|
+
type: "text",
|
|
167
|
+
text: JSON.stringify({
|
|
168
|
+
success: false,
|
|
169
|
+
error: formatError(error)
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
],
|
|
173
|
+
isError: true
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
server.tool("coordinator_get_context", "Get a context entry by key", GetContextInputSchema.shape, async (params)=>{
|
|
178
|
+
try {
|
|
179
|
+
const entry = await getClient().trpc.context.get.query(params);
|
|
180
|
+
return {
|
|
181
|
+
content: [
|
|
182
|
+
{
|
|
183
|
+
type: "text",
|
|
184
|
+
text: JSON.stringify({
|
|
185
|
+
success: true,
|
|
186
|
+
entry
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
};
|
|
191
|
+
} catch (error) {
|
|
192
|
+
return {
|
|
193
|
+
content: [
|
|
194
|
+
{
|
|
195
|
+
type: "text",
|
|
196
|
+
text: JSON.stringify({
|
|
197
|
+
success: false,
|
|
198
|
+
error: formatError(error)
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
],
|
|
202
|
+
isError: true
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
server.tool("coordinator_list_context", "List context entries with optional filters", {
|
|
207
|
+
...ListContextInputSchema.shape
|
|
208
|
+
}, async (params)=>{
|
|
209
|
+
try {
|
|
210
|
+
const entries = await getClient().trpc.context.list.query(params);
|
|
211
|
+
return {
|
|
212
|
+
content: [
|
|
213
|
+
{
|
|
214
|
+
type: "text",
|
|
215
|
+
text: JSON.stringify({
|
|
216
|
+
success: true,
|
|
217
|
+
entries
|
|
218
|
+
})
|
|
219
|
+
}
|
|
220
|
+
]
|
|
221
|
+
};
|
|
222
|
+
} catch (error) {
|
|
223
|
+
return {
|
|
224
|
+
content: [
|
|
225
|
+
{
|
|
226
|
+
type: "text",
|
|
227
|
+
text: JSON.stringify({
|
|
228
|
+
success: false,
|
|
229
|
+
error: formatError(error)
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
],
|
|
233
|
+
isError: true
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
server.tool("coordinator_ask", "Ask a question to other agents", AskInputSchema.shape, async (params)=>{
|
|
238
|
+
try {
|
|
239
|
+
const id = requireAgentId();
|
|
240
|
+
const question = await getClient().trpc.questions.ask.mutate({
|
|
241
|
+
...params,
|
|
242
|
+
agentId: id
|
|
243
|
+
});
|
|
244
|
+
return {
|
|
245
|
+
content: [
|
|
246
|
+
{
|
|
247
|
+
type: "text",
|
|
248
|
+
text: JSON.stringify({
|
|
249
|
+
success: true,
|
|
250
|
+
question
|
|
251
|
+
})
|
|
252
|
+
}
|
|
253
|
+
]
|
|
254
|
+
};
|
|
255
|
+
} catch (error) {
|
|
256
|
+
return {
|
|
257
|
+
content: [
|
|
258
|
+
{
|
|
259
|
+
type: "text",
|
|
260
|
+
text: JSON.stringify({
|
|
261
|
+
success: false,
|
|
262
|
+
error: formatError(error)
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
],
|
|
266
|
+
isError: true
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
server.tool("coordinator_answer", "Answer a pending question", AnswerInputSchema.shape, async (params)=>{
|
|
271
|
+
try {
|
|
272
|
+
const id = requireAgentId();
|
|
273
|
+
const question = await getClient().trpc.questions.answer.mutate({
|
|
274
|
+
...params,
|
|
275
|
+
agentId: id
|
|
276
|
+
});
|
|
277
|
+
return {
|
|
278
|
+
content: [
|
|
279
|
+
{
|
|
280
|
+
type: "text",
|
|
281
|
+
text: JSON.stringify({
|
|
282
|
+
success: true,
|
|
283
|
+
question
|
|
284
|
+
})
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
};
|
|
288
|
+
} catch (error) {
|
|
289
|
+
return {
|
|
290
|
+
content: [
|
|
291
|
+
{
|
|
292
|
+
type: "text",
|
|
293
|
+
text: JSON.stringify({
|
|
294
|
+
success: false,
|
|
295
|
+
error: formatError(error)
|
|
296
|
+
})
|
|
297
|
+
}
|
|
298
|
+
],
|
|
299
|
+
isError: true
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
server.tool("coordinator_pending_questions", "List pending questions (optionally for a specific agent)", {
|
|
304
|
+
agentId: z.string().uuid().optional().describe("Filter questions directed to this agent")
|
|
305
|
+
}, async (params)=>{
|
|
306
|
+
try {
|
|
307
|
+
const questions = await getClient().trpc.questions.listPending.query(params);
|
|
308
|
+
return {
|
|
309
|
+
content: [
|
|
310
|
+
{
|
|
311
|
+
type: "text",
|
|
312
|
+
text: JSON.stringify({
|
|
313
|
+
success: true,
|
|
314
|
+
questions
|
|
315
|
+
})
|
|
316
|
+
}
|
|
317
|
+
]
|
|
318
|
+
};
|
|
319
|
+
} catch (error) {
|
|
320
|
+
return {
|
|
321
|
+
content: [
|
|
322
|
+
{
|
|
323
|
+
type: "text",
|
|
324
|
+
text: JSON.stringify({
|
|
325
|
+
success: false,
|
|
326
|
+
error: formatError(error)
|
|
327
|
+
})
|
|
328
|
+
}
|
|
329
|
+
],
|
|
330
|
+
isError: true
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
server.tool("coordinator_log_decision", "Log a decision made during the session", LogDecisionInputSchema.shape, async (params)=>{
|
|
335
|
+
try {
|
|
336
|
+
const id = requireAgentId();
|
|
337
|
+
const decision = await getClient().trpc.decisions.log.mutate({
|
|
338
|
+
...params,
|
|
339
|
+
agentId: id
|
|
340
|
+
});
|
|
341
|
+
return {
|
|
342
|
+
content: [
|
|
343
|
+
{
|
|
344
|
+
type: "text",
|
|
345
|
+
text: JSON.stringify({
|
|
346
|
+
success: true,
|
|
347
|
+
decision
|
|
348
|
+
})
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
};
|
|
352
|
+
} catch (error) {
|
|
353
|
+
return {
|
|
354
|
+
content: [
|
|
355
|
+
{
|
|
356
|
+
type: "text",
|
|
357
|
+
text: JSON.stringify({
|
|
358
|
+
success: false,
|
|
359
|
+
error: formatError(error)
|
|
360
|
+
})
|
|
361
|
+
}
|
|
362
|
+
],
|
|
363
|
+
isError: true
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
server.tool("coordinator_list_decisions", "List all decisions made during the session", {}, async ()=>{
|
|
368
|
+
try {
|
|
369
|
+
const decisions = await getClient().trpc.decisions.list.query();
|
|
370
|
+
return {
|
|
371
|
+
content: [
|
|
372
|
+
{
|
|
373
|
+
type: "text",
|
|
374
|
+
text: JSON.stringify({
|
|
375
|
+
success: true,
|
|
376
|
+
decisions
|
|
377
|
+
})
|
|
378
|
+
}
|
|
379
|
+
]
|
|
380
|
+
};
|
|
381
|
+
} catch (error) {
|
|
382
|
+
return {
|
|
383
|
+
content: [
|
|
384
|
+
{
|
|
385
|
+
type: "text",
|
|
386
|
+
text: JSON.stringify({
|
|
387
|
+
success: false,
|
|
388
|
+
error: formatError(error)
|
|
389
|
+
})
|
|
390
|
+
}
|
|
391
|
+
],
|
|
392
|
+
isError: true
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
const transport = new StdioServerTransport();
|
|
397
|
+
await server.connect(transport);
|
|
398
|
+
console.error("[coordinator-mcp] MCP server started");
|
|
399
|
+
process.on("exit", ()=>{
|
|
400
|
+
if (client) client.close();
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
export { DEFAULT_URL, createCoordinatorClient, createMcpServer };
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 C. Spencer Beggs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# @spencerbeggs/claude-coordinator-mcp
|
|
2
|
+
|
|
3
|
+
MCP stdio bridge that exposes coordination tools to Claude Code instances,
|
|
4
|
+
enabling them to communicate through the coordinator server.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- **MCP tool integration** - Expose coordination as Claude Code tools
|
|
9
|
+
- **stdio transport** - Standard MCP communication protocol
|
|
10
|
+
- **Lazy connection** - Connect to server only when needed
|
|
11
|
+
- **Consistent responses** - All tools return predictable JSON format
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @spencerbeggs/claude-coordinator-mcp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### Configure in Claude Code
|
|
22
|
+
|
|
23
|
+
Add to your Claude Code MCP settings:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"claude-coordinator": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["@spencerbeggs/claude-coordinator-mcp"]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
With a custom server URL:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"mcpServers": {
|
|
41
|
+
"claude-coordinator": {
|
|
42
|
+
"command": "npx",
|
|
43
|
+
"args": [
|
|
44
|
+
"@spencerbeggs/claude-coordinator-mcp",
|
|
45
|
+
"--url=ws://192.168.1.100:3030"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Run Standalone
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Default URL (ws://localhost:3030)
|
|
56
|
+
npx @spencerbeggs/claude-coordinator-mcp
|
|
57
|
+
|
|
58
|
+
# Custom URL
|
|
59
|
+
npx @spencerbeggs/claude-coordinator-mcp --url=ws://server:3030
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Available Tools
|
|
63
|
+
|
|
64
|
+
Once configured, Claude Code can use these tools:
|
|
65
|
+
|
|
66
|
+
### Session Tools
|
|
67
|
+
|
|
68
|
+
| Tool | Parameters | Description |
|
|
69
|
+
| ---- | ---------- | ----------- |
|
|
70
|
+
| `coordinator_join` | name, role, repoPath | Join session as agent |
|
|
71
|
+
| `coordinator_leave` | (none) | Leave current session |
|
|
72
|
+
| `coordinator_list_agents` | (none) | List connected agents |
|
|
73
|
+
|
|
74
|
+
### Context Tools
|
|
75
|
+
|
|
76
|
+
| Tool | Parameters | Description |
|
|
77
|
+
| ---- | ---------- | ----------- |
|
|
78
|
+
| `coordinator_share_context` | key, value, tags? | Share context entry |
|
|
79
|
+
| `coordinator_get_context` | key | Get context by key |
|
|
80
|
+
| `coordinator_list_context` | tags?, createdBy? | List context entries |
|
|
81
|
+
|
|
82
|
+
### Question Tools
|
|
83
|
+
|
|
84
|
+
| Tool | Parameters | Description |
|
|
85
|
+
| ---- | ---------- | ----------- |
|
|
86
|
+
| `coordinator_ask` | question, to? | Ask a question |
|
|
87
|
+
| `coordinator_answer` | questionId, answer | Answer a question |
|
|
88
|
+
| `coordinator_pending_questions` | agentId? | List pending questions |
|
|
89
|
+
|
|
90
|
+
### Decision Tools
|
|
91
|
+
|
|
92
|
+
| Tool | Parameters | Description |
|
|
93
|
+
| ---- | ---------- | ----------- |
|
|
94
|
+
| `coordinator_log_decision` | decision, rationale? | Log a decision |
|
|
95
|
+
| `coordinator_list_decisions` | (none) | List all decisions |
|
|
96
|
+
|
|
97
|
+
## Usage Example
|
|
98
|
+
|
|
99
|
+
Once configured, Claude Code can coordinate with other instances:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
User: "Join the coordinator as a source agent"
|
|
103
|
+
|
|
104
|
+
Claude: I'll join the coordination session.
|
|
105
|
+
[Uses coordinator_join tool with role="source"]
|
|
106
|
+
|
|
107
|
+
User: "Share that we're using React 18"
|
|
108
|
+
|
|
109
|
+
Claude: I'll share that context.
|
|
110
|
+
[Uses coordinator_share_context with key="framework" value="React 18"]
|
|
111
|
+
|
|
112
|
+
User: "Ask the other agent what testing framework they prefer"
|
|
113
|
+
|
|
114
|
+
Claude: I'll ask the question.
|
|
115
|
+
[Uses coordinator_ask with question="What testing framework do you prefer?"]
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Response Format
|
|
119
|
+
|
|
120
|
+
All tools return JSON with consistent structure:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
// Success
|
|
124
|
+
{ "success": true, "agent": {...}, "sessionId": "..." }
|
|
125
|
+
|
|
126
|
+
// Error
|
|
127
|
+
{ "success": false, "error": "Error description" }
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Documentation
|
|
131
|
+
|
|
132
|
+
- [Architecture Design Doc](../../.claude/design/claude-coordinator-mcp/architecture.md)
|
|
133
|
+
- [Core Schemas Package](../claude-coordinator-core/README.md)
|
|
134
|
+
- [Server Package](../claude-coordinator-server/README.md)
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { DEFAULT_URL, createMcpServer } from "../433.js";
|
|
3
|
+
const args = process.argv.slice(2);
|
|
4
|
+
let url = DEFAULT_URL;
|
|
5
|
+
for(let i = 0; i < args.length; i++){
|
|
6
|
+
const arg = args[i];
|
|
7
|
+
if ("--url" === arg && args[i + 1]) {
|
|
8
|
+
url = args[i + 1];
|
|
9
|
+
i++;
|
|
10
|
+
} else if (arg?.startsWith("--url=")) url = arg.slice(6);
|
|
11
|
+
}
|
|
12
|
+
console.error(`[coordinator-mcp] Connecting to coordinator at ${url}`);
|
|
13
|
+
createMcpServer({
|
|
14
|
+
url: url
|
|
15
|
+
}).catch((error)=>{
|
|
16
|
+
console.error("[coordinator-mcp] Failed to start:", error);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
});
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \@spencerbeggs/claude-coordinator-mcp
|
|
3
|
+
*
|
|
4
|
+
* MCP stdio bridge for the Claude Coordinator system.
|
|
5
|
+
* Provides MCP tools that Claude Code can use to communicate
|
|
6
|
+
* with other Claude Code instances through the coordinator server.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Agent } from '@spencerbeggs/claude-coordinator-core';
|
|
12
|
+
import type { ContextEntry } from '@spencerbeggs/claude-coordinator-core';
|
|
13
|
+
import type { Decision } from '@spencerbeggs/claude-coordinator-core';
|
|
14
|
+
import type { JoinInput } from '@spencerbeggs/claude-coordinator-core';
|
|
15
|
+
import type { JoinResult } from '@spencerbeggs/claude-coordinator-core';
|
|
16
|
+
import type { Question } from '@spencerbeggs/claude-coordinator-core';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Options for creating the coordinator client
|
|
20
|
+
*/
|
|
21
|
+
export declare interface ClientOptions {
|
|
22
|
+
url?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Coordinator client instance
|
|
27
|
+
*/
|
|
28
|
+
export declare interface CoordinatorClient {
|
|
29
|
+
trpc: TypedTRPCClient;
|
|
30
|
+
close: () => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create a tRPC client that connects to the coordinator server
|
|
35
|
+
*/
|
|
36
|
+
export declare function createCoordinatorClient(options?: ClientOptions): CoordinatorClient;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create and run the MCP server
|
|
40
|
+
*/
|
|
41
|
+
export declare function createMcpServer(options?: McpServerOptions): Promise<void>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* MCP server options
|
|
45
|
+
*/
|
|
46
|
+
export declare interface McpServerOptions {
|
|
47
|
+
url?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Typed tRPC client interface matching the coordinator server's router
|
|
52
|
+
* This provides type safety without requiring cross-package type inference
|
|
53
|
+
*/
|
|
54
|
+
declare interface TypedTRPCClient {
|
|
55
|
+
session: {
|
|
56
|
+
join: {
|
|
57
|
+
mutate: (input: JoinInput) => Promise<JoinResult>;
|
|
58
|
+
};
|
|
59
|
+
leave: {
|
|
60
|
+
mutate: (input: {
|
|
61
|
+
agentId: string;
|
|
62
|
+
}) => Promise<{
|
|
63
|
+
success: boolean;
|
|
64
|
+
}>;
|
|
65
|
+
};
|
|
66
|
+
list: {
|
|
67
|
+
query: () => Promise<Agent[]>;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
context: {
|
|
71
|
+
share: {
|
|
72
|
+
mutate: (input: {
|
|
73
|
+
key: string;
|
|
74
|
+
value: string;
|
|
75
|
+
tags?: string[];
|
|
76
|
+
agentId: string;
|
|
77
|
+
}) => Promise<ContextEntry>;
|
|
78
|
+
};
|
|
79
|
+
get: {
|
|
80
|
+
query: (input: {
|
|
81
|
+
key: string;
|
|
82
|
+
}) => Promise<ContextEntry | null>;
|
|
83
|
+
};
|
|
84
|
+
list: {
|
|
85
|
+
query: (input?: {
|
|
86
|
+
prefix?: string;
|
|
87
|
+
tags?: string[];
|
|
88
|
+
}) => Promise<ContextEntry[]>;
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
questions: {
|
|
92
|
+
ask: {
|
|
93
|
+
mutate: (input: {
|
|
94
|
+
question: string;
|
|
95
|
+
to?: string;
|
|
96
|
+
agentId: string;
|
|
97
|
+
}) => Promise<Question>;
|
|
98
|
+
};
|
|
99
|
+
answer: {
|
|
100
|
+
mutate: (input: {
|
|
101
|
+
questionId: string;
|
|
102
|
+
answer: string;
|
|
103
|
+
agentId: string;
|
|
104
|
+
}) => Promise<Question>;
|
|
105
|
+
};
|
|
106
|
+
listPending: {
|
|
107
|
+
query: (input?: {
|
|
108
|
+
agentId?: string;
|
|
109
|
+
}) => Promise<Question[]>;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
decisions: {
|
|
113
|
+
log: {
|
|
114
|
+
mutate: (input: {
|
|
115
|
+
decision: string;
|
|
116
|
+
rationale?: string;
|
|
117
|
+
agentId: string;
|
|
118
|
+
}) => Promise<Decision>;
|
|
119
|
+
};
|
|
120
|
+
list: {
|
|
121
|
+
query: () => Promise<Decision[]>;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export { }
|
package/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createCoordinatorClient, createMcpServer } from "./433.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@spencerbeggs/claude-coordinator-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "MCP stdio bridge for Claude Coordinator",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"claude",
|
|
8
|
+
"coordinator",
|
|
9
|
+
"mcp",
|
|
10
|
+
"model-context-protocol"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/spencerbeggs/claude-design-coordinator.git",
|
|
15
|
+
"directory": "pkgs/claude-coordinator-mcp"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": {
|
|
19
|
+
"name": "C. Spencer Beggs",
|
|
20
|
+
"email": "spencer@beggs.codes",
|
|
21
|
+
"url": "https://spencerbeg.gs"
|
|
22
|
+
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./index.d.ts",
|
|
27
|
+
"import": "./index.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"bin": {
|
|
31
|
+
"claude-coordinator-mcp": "./bin/claude-coordinator-mcp.js"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
35
|
+
"@spencerbeggs/claude-coordinator-core": "0.1.0",
|
|
36
|
+
"@spencerbeggs/claude-coordinator-server": "0.1.0",
|
|
37
|
+
"@trpc/client": "^11.8.1",
|
|
38
|
+
"@trpc/server": "^11.8.1",
|
|
39
|
+
"ws": "^8.19.0",
|
|
40
|
+
"zod": "^4.3.5"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=20.0.0"
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"433.js",
|
|
47
|
+
"LICENSE",
|
|
48
|
+
"README.md",
|
|
49
|
+
"bin/claude-coordinator-mcp.js",
|
|
50
|
+
"index.d.ts",
|
|
51
|
+
"index.js",
|
|
52
|
+
"package.json"
|
|
53
|
+
]
|
|
54
|
+
}
|