replicas-mcp 0.1.2 → 0.1.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/dist/index.js CHANGED
@@ -1,186 +1,616 @@
1
1
  #!/usr/bin/env node
2
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
- import { z } from 'zod';
5
- import { parseAgentEvents } from '@replicas/shared';
6
- const API_URL = process.env.REPLICAS_API_URL || 'https://api.replicas.dev';
7
- const API_KEY = process.env.REPLICAS_API_KEY;
2
+
3
+ // src/index.ts
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { z } from "zod";
7
+
8
+ // ../shared/src/display-message/parsers/codex-parser.ts
9
+ function safeJsonParse(str, fallback) {
10
+ try {
11
+ return JSON.parse(str);
12
+ } catch {
13
+ return fallback;
14
+ }
15
+ }
16
+ function getStatusFromExitCode(exitCode) {
17
+ return exitCode === 0 ? "completed" : "failed";
18
+ }
19
+ function findLastMessageByType(messages, type) {
20
+ return messages.findLast((m) => m.type === type);
21
+ }
22
+ function parsePatch(input) {
23
+ const operations = [];
24
+ const lines = input.split("\n");
25
+ let currentOp = null;
26
+ let diffLines = [];
27
+ for (let i = 0; i < lines.length; i++) {
28
+ const line = lines[i];
29
+ if (line.startsWith("*** Add File:")) {
30
+ if (currentOp) {
31
+ if (diffLines.length > 0) currentOp.diff = diffLines.join("\n");
32
+ operations.push(currentOp);
33
+ diffLines = [];
34
+ }
35
+ currentOp = {
36
+ action: "add",
37
+ path: line.replace("*** Add File:", "").trim()
38
+ };
39
+ } else if (line.startsWith("*** Update File:")) {
40
+ if (currentOp) {
41
+ if (diffLines.length > 0) currentOp.diff = diffLines.join("\n");
42
+ operations.push(currentOp);
43
+ diffLines = [];
44
+ }
45
+ currentOp = {
46
+ action: "update",
47
+ path: line.replace("*** Update File:", "").trim()
48
+ };
49
+ } else if (line.startsWith("*** Delete File:")) {
50
+ if (currentOp) {
51
+ if (diffLines.length > 0) currentOp.diff = diffLines.join("\n");
52
+ operations.push(currentOp);
53
+ diffLines = [];
54
+ }
55
+ currentOp = {
56
+ action: "delete",
57
+ path: line.replace("*** Delete File:", "").trim()
58
+ };
59
+ } else if (line.startsWith("*** Move to:")) {
60
+ if (currentOp) {
61
+ currentOp.moveTo = line.replace("*** Move to:", "").trim();
62
+ }
63
+ } else if (line.startsWith("*** Begin Patch") || line.startsWith("*** End Patch")) {
64
+ continue;
65
+ } else if (currentOp && (line.startsWith("+") || line.startsWith("-") || line.startsWith("@@") || line.trim() === "")) {
66
+ diffLines.push(line);
67
+ }
68
+ }
69
+ if (currentOp) {
70
+ if (diffLines.length > 0) currentOp.diff = diffLines.join("\n");
71
+ operations.push(currentOp);
72
+ }
73
+ return operations;
74
+ }
75
+ function parseCodexEvents(events) {
76
+ const messages = [];
77
+ const pendingPatches = /* @__PURE__ */ new Map();
78
+ events.forEach((event) => {
79
+ if (event.type === "event_msg" && event.payload?.type === "user_message") {
80
+ messages.push({
81
+ id: `user-${event.timestamp}`,
82
+ type: "user",
83
+ content: event.payload.message || "",
84
+ timestamp: event.timestamp
85
+ });
86
+ }
87
+ if (event.type === "event_msg" && event.payload?.type === "agent_reasoning") {
88
+ messages.push({
89
+ id: `reasoning-${event.timestamp}-${messages.length}`,
90
+ type: "reasoning",
91
+ content: event.payload.text || "",
92
+ status: "completed",
93
+ timestamp: event.timestamp
94
+ });
95
+ }
96
+ if (event.type === "response_item") {
97
+ const payloadType = event.payload?.type;
98
+ if (payloadType === "message" && event.payload?.role === "assistant") {
99
+ const content = event.payload.content || [];
100
+ const textContent = content.filter((c) => c.type === "output_text").map((c) => c.text || "").join("\n");
101
+ if (textContent) {
102
+ messages.push({
103
+ id: `agent-${event.timestamp}`,
104
+ type: "agent",
105
+ content: textContent,
106
+ timestamp: event.timestamp
107
+ });
108
+ }
109
+ }
110
+ if (payloadType === "function_call" && event.payload?.name === "shell") {
111
+ const args = safeJsonParse(event.payload.arguments || "{}", {});
112
+ const command = Array.isArray(args.command) ? args.command.join(" ") : args.command || "";
113
+ messages.push({
114
+ id: `command-${event.timestamp}`,
115
+ type: "command",
116
+ command,
117
+ output: "",
118
+ // Will be filled by function_call_output
119
+ status: "in_progress",
120
+ timestamp: event.timestamp
121
+ });
122
+ }
123
+ if (payloadType === "function_call_output") {
124
+ const output = safeJsonParse(
125
+ event.payload.output || "{}",
126
+ {}
127
+ );
128
+ if (output.output !== void 0 && output.metadata) {
129
+ const commandMsg = findLastMessageByType(messages, "command");
130
+ if (commandMsg) {
131
+ commandMsg.output = output.output || "";
132
+ commandMsg.exitCode = output.metadata?.exit_code;
133
+ commandMsg.status = getStatusFromExitCode(output.metadata?.exit_code);
134
+ }
135
+ }
136
+ }
137
+ if (payloadType === "custom_tool_call") {
138
+ const callId = event.payload.call_id;
139
+ const name = event.payload.name;
140
+ const input = event.payload.input || "";
141
+ const status = event.payload.status || "in_progress";
142
+ if (name === "apply_patch") {
143
+ const operations = parsePatch(input);
144
+ pendingPatches.set(callId, { input, status, timestamp: event.timestamp, operations });
145
+ } else {
146
+ messages.push({
147
+ id: `toolcall-${event.timestamp}`,
148
+ type: "tool_call",
149
+ server: "custom",
150
+ tool: name,
151
+ status,
152
+ timestamp: event.timestamp
153
+ });
154
+ }
155
+ }
156
+ if (payloadType === "custom_tool_call_output") {
157
+ const callId = event.payload.call_id;
158
+ const output = safeJsonParse(
159
+ event.payload.output || "{}",
160
+ {}
161
+ );
162
+ const pendingPatch = pendingPatches.get(callId);
163
+ if (pendingPatch) {
164
+ messages.push({
165
+ id: `patch-${pendingPatch.timestamp}`,
166
+ type: "patch",
167
+ operations: pendingPatch.operations,
168
+ output: output.output || "",
169
+ exitCode: output.metadata?.exit_code,
170
+ status: getStatusFromExitCode(output.metadata?.exit_code),
171
+ timestamp: pendingPatch.timestamp
172
+ });
173
+ pendingPatches.delete(callId);
174
+ } else {
175
+ const toolCallMsg = findLastMessageByType(messages, "tool_call");
176
+ if (toolCallMsg) {
177
+ toolCallMsg.status = getStatusFromExitCode(output.metadata?.exit_code);
178
+ }
179
+ }
180
+ }
181
+ if (payloadType === "function_call" && event.payload?.name === "update_plan") {
182
+ const args = safeJsonParse(
183
+ event.payload.arguments || "{}",
184
+ {}
185
+ );
186
+ if (args.plan && Array.isArray(args.plan)) {
187
+ const todoItems = args.plan.map((item) => ({
188
+ text: item.step,
189
+ completed: item.status === "completed"
190
+ }));
191
+ messages.push({
192
+ id: `todo-${event.timestamp}`,
193
+ type: "todo_list",
194
+ items: todoItems,
195
+ status: "completed",
196
+ timestamp: event.timestamp
197
+ });
198
+ }
199
+ }
200
+ }
201
+ });
202
+ return messages;
203
+ }
204
+
205
+ // ../shared/src/display-message/parsers/claude-parser.ts
206
+ function safeJsonParse2(str, fallback) {
207
+ try {
208
+ return JSON.parse(str);
209
+ } catch {
210
+ return fallback;
211
+ }
212
+ }
213
+ function extractToolResultContent(content) {
214
+ if (!content) return "";
215
+ if (typeof content === "string") return content;
216
+ if (Array.isArray(content)) {
217
+ return content.filter((item) => item.type === "text").map((item) => item.text || "").join("\n");
218
+ }
219
+ return "";
220
+ }
221
+ function parseClaudeEvents(events, parentToolUseId) {
222
+ const messages = [];
223
+ const filterValue = parentToolUseId !== void 0 ? parentToolUseId : null;
224
+ const filteredEvents = events.filter(
225
+ (e) => e.payload.parent_tool_use_id === filterValue
226
+ );
227
+ const toolCallMap = /* @__PURE__ */ new Map();
228
+ filteredEvents.forEach((event) => {
229
+ if (event.type === "claude-user") {
230
+ const content = event.payload.message?.content || [];
231
+ const toolResult = content.find((c) => c.type === "tool_result");
232
+ if (toolResult && toolResult.tool_use_id) {
233
+ return;
234
+ }
235
+ const textContent = content.filter((c) => c.type === "text").map((c) => c.text || "").join("\n");
236
+ const images = content.filter((c) => c.type === "image" && c.source).map((c) => {
237
+ const source = c.source;
238
+ return {
239
+ type: "image",
240
+ mediaType: source.media_type || "image/png",
241
+ data: source.data || ""
242
+ };
243
+ }).filter((img) => img.data);
244
+ if (textContent || images.length > 0) {
245
+ messages.push({
246
+ id: `user-${event.timestamp}`,
247
+ type: "user",
248
+ content: textContent || (images.length > 0 ? `[${images.length} image${images.length > 1 ? "s" : ""} attached]` : ""),
249
+ images: images.length > 0 ? images : void 0,
250
+ timestamp: event.timestamp
251
+ });
252
+ }
253
+ }
254
+ if (event.type === "claude-assistant") {
255
+ const contentBlocks = event.payload.message?.content || [];
256
+ contentBlocks.forEach((block) => {
257
+ if (block.type === "text" && block.text) {
258
+ messages.push({
259
+ id: `agent-${event.timestamp}-${messages.length}`,
260
+ type: "agent",
261
+ content: block.text,
262
+ timestamp: event.timestamp
263
+ });
264
+ }
265
+ if (block.type === "thinking" && block.text) {
266
+ messages.push({
267
+ id: `reasoning-${event.timestamp}-${messages.length}`,
268
+ type: "reasoning",
269
+ content: block.text,
270
+ status: "completed",
271
+ timestamp: event.timestamp
272
+ });
273
+ }
274
+ if (block.type === "tool_use" && block.id) {
275
+ const toolName = block.name || "unknown";
276
+ const toolInput = block.input || {};
277
+ const toolUseId = block.id;
278
+ toolCallMap.set(toolUseId, {
279
+ messageIndex: messages.length,
280
+ toolName,
281
+ input: toolInput
282
+ });
283
+ if (toolName === "Task") {
284
+ const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
285
+ const nestedEvents = events.filter((e) => e.payload.parent_tool_use_id === toolUseId).map((e) => ({
286
+ timestamp: e.timestamp,
287
+ type: e.type,
288
+ payload: e.payload
289
+ }));
290
+ messages.push({
291
+ id: `subagent-${event.timestamp}-${messages.length}`,
292
+ type: "subagent",
293
+ toolUseId,
294
+ description: inputObj.description || "Subagent Task",
295
+ prompt: inputObj.prompt || "",
296
+ subagentType: inputObj.subagent_type || "general",
297
+ model: inputObj.model,
298
+ status: "in_progress",
299
+ nestedEvents,
300
+ timestamp: event.timestamp
301
+ });
302
+ } else if (toolName === "Bash" || toolName === "bash" || toolName === "shell") {
303
+ const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
304
+ const command = inputObj.command || "";
305
+ messages.push({
306
+ id: `command-${event.timestamp}-${messages.length}`,
307
+ type: "command",
308
+ command,
309
+ output: "",
310
+ status: "in_progress",
311
+ timestamp: event.timestamp
312
+ });
313
+ } else if (toolName === "Write" || toolName === "Edit") {
314
+ const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
315
+ const filePath = inputObj.file_path || "";
316
+ const action = toolName === "Write" ? "add" : "update";
317
+ messages.push({
318
+ id: `file-${event.timestamp}-${messages.length}`,
319
+ type: "file_change",
320
+ changes: [{
321
+ path: filePath,
322
+ kind: action
323
+ }],
324
+ status: "in_progress",
325
+ timestamp: event.timestamp
326
+ });
327
+ } else if (toolName === "TodoWrite") {
328
+ const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
329
+ const todos = inputObj.todos || [];
330
+ const todoItems = todos.map((todo) => ({
331
+ text: todo.content,
332
+ completed: todo.status === "completed"
333
+ }));
334
+ if (todoItems.length > 0) {
335
+ messages.push({
336
+ id: `todo-${event.timestamp}-${messages.length}`,
337
+ type: "todo_list",
338
+ items: todoItems,
339
+ status: "completed",
340
+ timestamp: event.timestamp
341
+ });
342
+ }
343
+ } else if (toolName === "WebSearch") {
344
+ const inputObj = typeof toolInput === "string" ? safeJsonParse2(toolInput, {}) : toolInput;
345
+ const query = inputObj.query || "";
346
+ messages.push({
347
+ id: `search-${event.timestamp}-${messages.length}`,
348
+ type: "web_search",
349
+ query,
350
+ status: "in_progress",
351
+ timestamp: event.timestamp
352
+ });
353
+ } else {
354
+ messages.push({
355
+ id: `toolcall-${event.timestamp}-${messages.length}`,
356
+ type: "tool_call",
357
+ server: "claude",
358
+ tool: toolName,
359
+ input: toolInput,
360
+ status: "in_progress",
361
+ timestamp: event.timestamp
362
+ });
363
+ }
364
+ }
365
+ });
366
+ }
367
+ if (event.type === "claude-result") {
368
+ const payload = event.payload;
369
+ if (payload.is_error || payload.subtype !== "success") {
370
+ const errorList = payload.errors || [];
371
+ const errorMessage = errorList.length > 0 ? errorList.join("\n") : "Claude session encountered an unexpected error.";
372
+ messages.push({
373
+ id: `error-${event.timestamp}`,
374
+ type: "error",
375
+ message: errorMessage,
376
+ timestamp: event.timestamp
377
+ });
378
+ }
379
+ }
380
+ });
381
+ filteredEvents.forEach((event) => {
382
+ if (event.type === "claude-user") {
383
+ const content = event.payload.message?.content || [];
384
+ const toolResult = content.find((c) => c.type === "tool_result");
385
+ if (toolResult && toolResult.tool_use_id) {
386
+ const toolInfo = toolCallMap.get(toolResult.tool_use_id);
387
+ if (!toolInfo) return;
388
+ const resultContent = extractToolResultContent(toolResult.content);
389
+ const isError = toolResult.is_error || false;
390
+ const status = isError ? "failed" : "completed";
391
+ const message = messages[toolInfo.messageIndex];
392
+ if (!message) return;
393
+ if (message.type === "command") {
394
+ message.output = resultContent;
395
+ message.status = status;
396
+ const exitCodeMatch = resultContent.match(/exit code:?\s*(\d+)/i);
397
+ if (exitCodeMatch) {
398
+ message.exitCode = parseInt(exitCodeMatch[1], 10);
399
+ } else {
400
+ message.exitCode = isError ? 1 : 0;
401
+ }
402
+ } else if (message.type === "file_change") {
403
+ message.status = status;
404
+ } else if (message.type === "web_search") {
405
+ message.status = status;
406
+ } else if (message.type === "tool_call") {
407
+ message.output = resultContent;
408
+ message.status = status;
409
+ } else if (message.type === "subagent") {
410
+ message.output = resultContent;
411
+ message.status = status;
412
+ }
413
+ }
414
+ }
415
+ });
416
+ return messages;
417
+ }
418
+
419
+ // ../shared/src/display-message/parsers/index.ts
420
+ function parseAgentEvents(events, agentType) {
421
+ if (agentType === "codex") {
422
+ return parseCodexEvents(events);
423
+ } else if (agentType === "claude") {
424
+ return parseClaudeEvents(events);
425
+ }
426
+ return [];
427
+ }
428
+
429
+ // src/index.ts
430
+ var API_URL = process.env.REPLICAS_API_URL || "https://api.replicas.dev";
431
+ var API_KEY = process.env.REPLICAS_API_KEY;
8
432
  if (!API_KEY) {
9
- console.error('REPLICAS_API_KEY environment variable required');
10
- process.exit(1);
433
+ console.error("REPLICAS_API_KEY environment variable required");
434
+ process.exit(1);
11
435
  }
12
- /**
13
- * Makes an authenticated request to the Replicas API.
14
- */
15
436
  async function api(method, path, body) {
16
- const res = await fetch(`${API_URL}${path}`, {
17
- method,
18
- headers: {
19
- 'Authorization': `Bearer ${API_KEY}`,
20
- 'Content-Type': 'application/json',
21
- },
22
- body: body ? JSON.stringify(body) : undefined,
23
- });
24
- if (!res.ok) {
25
- const text = await res.text();
26
- throw new Error(`API error ${res.status}: ${text}`);
27
- }
28
- return res.json();
437
+ const res = await fetch(`${API_URL}${path}`, {
438
+ method,
439
+ headers: {
440
+ "Authorization": `Bearer ${API_KEY}`,
441
+ "Content-Type": "application/json"
442
+ },
443
+ body: body ? JSON.stringify(body) : void 0
444
+ });
445
+ if (!res.ok) {
446
+ const text = await res.text();
447
+ throw new Error(`API error ${res.status}: ${text}`);
448
+ }
449
+ return res.json();
29
450
  }
30
- /**
31
- * Creates a tool result with text content.
32
- */
33
451
  function result(data, isError = false) {
34
- return {
35
- content: [{
36
- type: 'text',
37
- text: typeof data === 'string' ? data : JSON.stringify(data, null, 2),
38
- }],
39
- ...(isError && { isError: true }),
40
- };
452
+ return {
453
+ content: [{
454
+ type: "text",
455
+ text: typeof data === "string" ? data : JSON.stringify(data, null, 2)
456
+ }],
457
+ ...isError && { isError: true }
458
+ };
41
459
  }
42
- const server = new McpServer({
43
- name: 'replicas-mcp',
44
- version: '0.1.1',
460
+ var server = new McpServer({
461
+ name: "replicas-mcp",
462
+ version: "0.1.1"
45
463
  });
46
- const registerTool = server.registerTool.bind(server);
47
- registerTool('create_replica', {
48
- description: 'Create a new replica workspace and send initial message',
464
+ var registerTool = server.registerTool.bind(server);
465
+ registerTool(
466
+ "create_replica",
467
+ {
468
+ description: "Create a new replica workspace and send initial message",
49
469
  inputSchema: {
50
- name: z.string(),
51
- message: z.string(),
52
- repository: z.string(),
53
- instance_type: z.enum(['standard', 'large', 'power']).optional(),
54
- coding_agent: z.enum(['claude', 'codex']).optional(),
55
- },
56
- }, async (args) => {
57
- try {
58
- const body = {
59
- name: args.name,
60
- message: args.message,
61
- repository: args.repository,
62
- };
63
- if (args.instance_type)
64
- body.instance_type = args.instance_type;
65
- if (args.coding_agent)
66
- body.coding_agent = args.coding_agent;
67
- return result(await api('POST', '/v1/replica', body));
470
+ name: z.string(),
471
+ message: z.string(),
472
+ repository: z.string(),
473
+ instance_type: z.enum(["standard", "large", "power"]).optional(),
474
+ coding_agent: z.enum(["claude", "codex"]).optional()
68
475
  }
69
- catch (e) {
70
- return result(e instanceof Error ? e.message : String(e), true);
71
- }
72
- });
73
- registerTool('list_replicas', {
74
- description: 'List all replicas',
75
- inputSchema: {
76
- page: z.number().optional(),
77
- limit: z.number().optional(),
78
- },
79
- }, async (args) => {
476
+ },
477
+ async (args) => {
80
478
  try {
81
- const params = new URLSearchParams();
82
- if (args.page)
83
- params.set('page', String(args.page));
84
- if (args.limit)
85
- params.set('limit', String(args.limit));
86
- const q = params.toString();
87
- return result(await api('GET', `/v1/replica${q ? '?' + q : ''}`));
479
+ const body = {
480
+ name: args.name,
481
+ message: args.message,
482
+ repository: args.repository
483
+ };
484
+ if (args.instance_type) body.instance_type = args.instance_type;
485
+ if (args.coding_agent) body.coding_agent = args.coding_agent;
486
+ return result(await api("POST", "/v1/replica", body));
487
+ } catch (e) {
488
+ return result(e instanceof Error ? e.message : String(e), true);
88
489
  }
89
- catch (e) {
90
- return result(e instanceof Error ? e.message : String(e), true);
91
- }
92
- });
93
- registerTool('get_replica', {
94
- description: 'Get replica by ID',
490
+ }
491
+ );
492
+ registerTool(
493
+ "list_replicas",
494
+ {
495
+ description: "List all replicas",
95
496
  inputSchema: {
96
- id: z.string(),
97
- },
98
- }, async (args) => {
99
- try {
100
- return result(await api('GET', `/v1/replica/${args.id}`));
497
+ page: z.number().optional(),
498
+ limit: z.number().optional()
101
499
  }
102
- catch (e) {
103
- return result(e instanceof Error ? e.message : String(e), true);
500
+ },
501
+ async (args) => {
502
+ try {
503
+ const params = new URLSearchParams();
504
+ if (args.page) params.set("page", String(args.page));
505
+ if (args.limit) params.set("limit", String(args.limit));
506
+ const q = params.toString();
507
+ return result(await api("GET", `/v1/replica${q ? "?" + q : ""}`));
508
+ } catch (e) {
509
+ return result(e instanceof Error ? e.message : String(e), true);
104
510
  }
105
- });
106
- registerTool('send_replica_message', {
107
- description: 'Send message to a replica',
511
+ }
512
+ );
513
+ registerTool(
514
+ "get_replica",
515
+ {
516
+ description: "Get replica by ID",
108
517
  inputSchema: {
109
- id: z.string(),
110
- message: z.string(),
111
- coding_agent: z.enum(['claude', 'codex']).optional(),
112
- },
113
- }, async (args) => {
114
- try {
115
- const body = { message: args.message };
116
- if (args.coding_agent)
117
- body.coding_agent = args.coding_agent;
118
- return result(await api('POST', `/v1/replica/${args.id}/send`, body));
518
+ id: z.string()
119
519
  }
120
- catch (e) {
121
- return result(e instanceof Error ? e.message : String(e), true);
520
+ },
521
+ async (args) => {
522
+ try {
523
+ return result(await api("GET", `/v1/replica/${args.id}`));
524
+ } catch (e) {
525
+ return result(e instanceof Error ? e.message : String(e), true);
122
526
  }
123
- });
124
- registerTool('delete_replica', {
125
- description: 'Delete a replica',
527
+ }
528
+ );
529
+ registerTool(
530
+ "send_replica_message",
531
+ {
532
+ description: "Send message to a replica",
126
533
  inputSchema: {
127
- id: z.string(),
128
- },
129
- }, async (args) => {
534
+ id: z.string(),
535
+ message: z.string(),
536
+ coding_agent: z.enum(["claude", "codex"]).optional()
537
+ }
538
+ },
539
+ async (args) => {
130
540
  try {
131
- return result(await api('DELETE', `/v1/replica/${args.id}`));
541
+ const body = { message: args.message };
542
+ if (args.coding_agent) body.coding_agent = args.coding_agent;
543
+ return result(await api("POST", `/v1/replica/${args.id}/send`, body));
544
+ } catch (e) {
545
+ return result(e instanceof Error ? e.message : String(e), true);
132
546
  }
133
- catch (e) {
134
- return result(e instanceof Error ? e.message : String(e), true);
547
+ }
548
+ );
549
+ registerTool(
550
+ "delete_replica",
551
+ {
552
+ description: "Delete a replica",
553
+ inputSchema: {
554
+ id: z.string()
135
555
  }
136
- });
137
- registerTool('list_repositories', {
138
- description: 'List available repositories',
139
- }, async () => {
556
+ },
557
+ async (args) => {
140
558
  try {
141
- return result(await api('GET', '/v1/repositories'));
559
+ return result(await api("DELETE", `/v1/replica/${args.id}`));
560
+ } catch (e) {
561
+ return result(e instanceof Error ? e.message : String(e), true);
142
562
  }
143
- catch (e) {
144
- return result(e instanceof Error ? e.message : String(e), true);
563
+ }
564
+ );
565
+ registerTool(
566
+ "list_repositories",
567
+ {
568
+ description: "List available repositories"
569
+ },
570
+ async () => {
571
+ try {
572
+ return result(await api("GET", "/v1/repositories"));
573
+ } catch (e) {
574
+ return result(e instanceof Error ? e.message : String(e), true);
145
575
  }
146
- });
147
- registerTool('read_replica_history', {
148
- description: 'Read conversation history of a replica. Returns parsed DisplayMessage objects (user messages, agent responses, commands, file changes, tool calls, etc). If the workspace is sleeping, it will be woken and you should retry in 30-90 seconds.',
576
+ }
577
+ );
578
+ registerTool(
579
+ "read_replica_history",
580
+ {
581
+ description: "Read conversation history of a replica. Returns parsed DisplayMessage objects (user messages, agent responses, commands, file changes, tool calls, etc). If the workspace is sleeping, it will be woken and you should retry in 30-90 seconds.",
149
582
  inputSchema: {
150
- id: z.string(),
151
- limit: z.number().optional().describe('Maximum number of events to return'),
152
- offset: z.number().optional().describe('Number of events to skip from the end'),
153
- },
154
- }, async (args) => {
583
+ id: z.string(),
584
+ limit: z.number().optional().describe("Maximum number of events to return"),
585
+ offset: z.number().optional().describe("Number of events to skip from the end")
586
+ }
587
+ },
588
+ async (args) => {
155
589
  try {
156
- const params = new URLSearchParams();
157
- if (args.limit)
158
- params.set('limit', String(args.limit));
159
- if (args.offset)
160
- params.set('offset', String(args.offset));
161
- const q = params.toString();
162
- const response = await api('GET', `/v1/replica/${args.id}/read${q ? '?' + q : ''}`);
163
- if (response.waking) {
164
- return result({
165
- status: 'waking',
166
- message: 'Workspace is waking from sleep. Retry in 30-90 seconds.',
167
- });
168
- }
169
- // Parse raw events into DisplayMessage format
170
- const agentType = (response.coding_agent || 'claude');
171
- const messages = parseAgentEvents(response.events, agentType);
590
+ const params = new URLSearchParams();
591
+ if (args.limit) params.set("limit", String(args.limit));
592
+ if (args.offset) params.set("offset", String(args.offset));
593
+ const q = params.toString();
594
+ const response = await api("GET", `/v1/replica/${args.id}/read${q ? "?" + q : ""}`);
595
+ if (response.waking) {
172
596
  return result({
173
- thread_id: response.thread_id,
174
- coding_agent: response.coding_agent,
175
- total: response.total,
176
- hasMore: response.hasMore,
177
- messages,
597
+ status: "waking",
598
+ message: "Workspace is waking from sleep. Retry in 30-90 seconds."
178
599
  });
600
+ }
601
+ const agentType = response.coding_agent || "claude";
602
+ const messages = parseAgentEvents(response.events, agentType);
603
+ return result({
604
+ thread_id: response.thread_id,
605
+ coding_agent: response.coding_agent,
606
+ total: response.total,
607
+ hasMore: response.hasMore,
608
+ messages
609
+ });
610
+ } catch (e) {
611
+ return result(e instanceof Error ? e.message : String(e), true);
179
612
  }
180
- catch (e) {
181
- return result(e instanceof Error ? e.message : String(e), true);
182
- }
183
- });
184
- const transport = new StdioServerTransport();
613
+ }
614
+ );
615
+ var transport = new StdioServerTransport();
185
616
  await server.connect(transport);
186
- //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-mcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,16 +8,17 @@
8
8
  "replicas-mcp": "dist/index.js"
9
9
  },
10
10
  "scripts": {
11
- "build": "tsc",
11
+ "build": "tsup",
12
12
  "start": "node dist/index.js"
13
13
  },
14
14
  "dependencies": {
15
15
  "@modelcontextprotocol/sdk": "^1.25.0",
16
- "@replicas/shared": "*",
17
16
  "zod": "^3.25.0"
18
17
  },
19
18
  "devDependencies": {
19
+ "@replicas/shared": "*",
20
20
  "@types/node": "^20.11.17",
21
+ "tsup": "^8.5.0",
21
22
  "typescript": "^5.9.3"
22
23
  }
23
24
  }
package/src/index.ts CHANGED
@@ -1,5 +1,3 @@
1
- #!/usr/bin/env node
2
-
3
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
3
  import { z } from 'zod';
package/tsup.config.ts ADDED
@@ -0,0 +1,24 @@
1
+ const config = {
2
+ entry: ['src/index.ts'],
3
+ format: ['esm'],
4
+ bundle: true,
5
+ noExternal: ['@replicas/shared'],
6
+ dts: false,
7
+ clean: true,
8
+ outDir: 'dist',
9
+ banner: {
10
+ js: '#!/usr/bin/env node',
11
+ },
12
+ outExtension() {
13
+ return {
14
+ js: '.js',
15
+ };
16
+ },
17
+ esbuildOptions(options: { alias?: Record<string, string> }) {
18
+ options.alias = {
19
+ '@replicas/shared': '../shared/src',
20
+ };
21
+ },
22
+ };
23
+
24
+ export default config;
package/dist/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}