mcp-agent-broker 1.0.1 → 1.0.2

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/app.js CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  "use strict";
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
package/dist/bin.js ADDED
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const sse_js_1 = require("@modelcontextprotocol/sdk/client/sse.js");
38
+ const readline = __importStar(require("readline"));
39
+ async function runProxy(url, apiKey) {
40
+ const transport = new sse_js_1.SSEClientTransport(new URL(url), {
41
+ eventSourceInit: {
42
+ headers: { Authorization: `Bearer ${apiKey}` }
43
+ },
44
+ requestInit: {
45
+ headers: { Authorization: `Bearer ${apiKey}` }
46
+ }
47
+ });
48
+ transport.onmessage = (message) => {
49
+ process.stdout.write(JSON.stringify(message) + "\n");
50
+ };
51
+ transport.onerror = (error) => {
52
+ console.error("Transport error:", error);
53
+ };
54
+ transport.onclose = () => {
55
+ process.exit(0);
56
+ };
57
+ await transport.start();
58
+ const rl = readline.createInterface({
59
+ input: process.stdin,
60
+ terminal: false
61
+ });
62
+ rl.on("line", async (line) => {
63
+ if (!line.trim())
64
+ return;
65
+ try {
66
+ const message = JSON.parse(line);
67
+ await transport.send(message);
68
+ }
69
+ catch (e) {
70
+ console.error("Error processing line:", e);
71
+ }
72
+ });
73
+ rl.on("close", () => {
74
+ transport.close().catch(() => { });
75
+ process.exit(0);
76
+ });
77
+ }
78
+ const args = process.argv.slice(2);
79
+ const command = args[0];
80
+ if (command === "connect") {
81
+ let url = "http://127.0.0.1:3000/mcp/sse";
82
+ let apiKey = "";
83
+ for (let i = 1; i < args.length; i++) {
84
+ if (args[i] === "--url" && args[i + 1]) {
85
+ url = args[i + 1];
86
+ i++;
87
+ }
88
+ else if (args[i] === "--token" && args[i + 1]) {
89
+ apiKey = args[i + 1];
90
+ i++;
91
+ }
92
+ }
93
+ if (!apiKey) {
94
+ console.error("Missing --token");
95
+ process.exit(1);
96
+ }
97
+ runProxy(url, apiKey).catch((e) => {
98
+ console.error("Proxy error:", e);
99
+ process.exit(1);
100
+ });
101
+ }
102
+ else {
103
+ // Start server
104
+ import("./app.js").catch(e => {
105
+ console.error("Failed to start server:", e);
106
+ process.exit(1);
107
+ });
108
+ }
@@ -4,6 +4,7 @@ exports.taskService = exports.TaskService = void 0;
4
4
  const index_js_1 = require("../../infrastructure/db/index.js");
5
5
  const schema_js_1 = require("../../infrastructure/db/schema.js");
6
6
  const crypto_1 = require("crypto");
7
+ const drizzle_orm_1 = require("drizzle-orm");
7
8
  const event_service_js_1 = require("../event/event.service.js");
8
9
  class TaskService {
9
10
  async createTask(params) {
@@ -35,6 +36,74 @@ class TaskService {
35
36
  return task;
36
37
  });
37
38
  }
39
+ async submitImplementation(params) {
40
+ return await index_js_1.db.transaction(async (tx) => {
41
+ const [task] = await tx.select().from(schema_js_1.tasks).where((0, drizzle_orm_1.eq)(schema_js_1.tasks.id, params.taskId)).for('update');
42
+ if (!task)
43
+ throw new Error('Task not found');
44
+ if (task.nextFencingToken !== params.fencingToken) {
45
+ throw new Error('Invalid fencing token. You no longer hold the active lease.');
46
+ }
47
+ const [updatedTask] = await tx.update(schema_js_1.tasks).set({
48
+ state: 'awaiting_review',
49
+ activeExecutionLeaseId: null,
50
+ version: task.version + 1,
51
+ updatedAt: new Date()
52
+ }).where((0, drizzle_orm_1.eq)(schema_js_1.tasks.id, params.taskId)).returning();
53
+ if (task.activeExecutionLeaseId) {
54
+ await tx.update(schema_js_1.leases).set({
55
+ status: 'released',
56
+ releasedAt: new Date()
57
+ }).where((0, drizzle_orm_1.eq)(schema_js_1.leases.id, task.activeExecutionLeaseId));
58
+ }
59
+ await event_service_js_1.eventService.appendEvent(tx, {
60
+ workspaceId: task.workspaceId,
61
+ eventType: 'ImplementationSubmitted',
62
+ aggregateType: 'Task',
63
+ aggregateId: task.id,
64
+ aggregateVersion: updatedTask.version,
65
+ actorType: 'Agent',
66
+ actorId: params.agentInstanceId,
67
+ payload: { pullRequestUrl: params.pullRequestUrl }
68
+ });
69
+ return updatedTask;
70
+ });
71
+ }
72
+ async submitReview(params) {
73
+ return await index_js_1.db.transaction(async (tx) => {
74
+ const [task] = await tx.select().from(schema_js_1.tasks).where((0, drizzle_orm_1.eq)(schema_js_1.tasks.id, params.taskId)).for('update');
75
+ if (!task)
76
+ throw new Error('Task not found');
77
+ if (task.nextFencingToken !== params.fencingToken) {
78
+ throw new Error('Invalid fencing token. You no longer hold the active lease.');
79
+ }
80
+ const newState = params.status === 'approved' ? 'completed' : 'changes_requested';
81
+ const [updatedTask] = await tx.update(schema_js_1.tasks).set({
82
+ state: newState,
83
+ activeReviewLeaseId: null,
84
+ version: task.version + 1,
85
+ completedAt: params.status === 'approved' ? new Date() : null,
86
+ updatedAt: new Date()
87
+ }).where((0, drizzle_orm_1.eq)(schema_js_1.tasks.id, params.taskId)).returning();
88
+ if (task.activeReviewLeaseId) {
89
+ await tx.update(schema_js_1.leases).set({
90
+ status: 'released',
91
+ releasedAt: new Date()
92
+ }).where((0, drizzle_orm_1.eq)(schema_js_1.leases.id, task.activeReviewLeaseId));
93
+ }
94
+ await event_service_js_1.eventService.appendEvent(tx, {
95
+ workspaceId: task.workspaceId,
96
+ eventType: 'ReviewSubmitted',
97
+ aggregateType: 'Task',
98
+ aggregateId: task.id,
99
+ aggregateVersion: updatedTask.version,
100
+ actorType: 'Agent',
101
+ actorId: params.agentInstanceId,
102
+ payload: { status: params.status, feedback: params.feedback }
103
+ });
104
+ return updatedTask;
105
+ });
106
+ }
38
107
  }
39
108
  exports.TaskService = TaskService;
40
109
  exports.taskService = new TaskService();
@@ -84,6 +84,35 @@ async function setupMcpTransport(fastify) {
84
84
  },
85
85
  required: ["taskId", "workspaceId", "agentInstanceId", "leaseType"]
86
86
  }
87
+ },
88
+ {
89
+ name: "submit_task_implementation",
90
+ description: "Submit task implementation for review",
91
+ inputSchema: {
92
+ type: "object",
93
+ properties: {
94
+ taskId: { type: "string" },
95
+ agentInstanceId: { type: "string" },
96
+ fencingToken: { type: "number" },
97
+ pullRequestUrl: { type: "string" }
98
+ },
99
+ required: ["taskId", "agentInstanceId", "fencingToken"]
100
+ }
101
+ },
102
+ {
103
+ name: "submit_task_review",
104
+ description: "Submit a review (approve/reject) for an implemented task",
105
+ inputSchema: {
106
+ type: "object",
107
+ properties: {
108
+ taskId: { type: "string" },
109
+ agentInstanceId: { type: "string" },
110
+ fencingToken: { type: "number" },
111
+ status: { type: "string", enum: ["approved", "rejected"] },
112
+ feedback: { type: "string" }
113
+ },
114
+ required: ["taskId", "agentInstanceId", "fencingToken", "status"]
115
+ }
87
116
  }
88
117
  ]
89
118
  };
@@ -154,6 +183,47 @@ async function setupMcpTransport(fastify) {
154
183
  throw e;
155
184
  }
156
185
  }
186
+ else if (req.params.name === "submit_task_implementation") {
187
+ try {
188
+ const args = req.params.arguments;
189
+ const task = await task_service_js_1.taskService.submitImplementation({
190
+ taskId: args.taskId,
191
+ agentInstanceId: args.agentInstanceId,
192
+ fencingToken: args.fencingToken,
193
+ pullRequestUrl: args.pullRequestUrl
194
+ });
195
+ return {
196
+ content: [
197
+ { type: "text", text: `Implementation submitted successfully! Task state is now: ${task.state}` }
198
+ ]
199
+ };
200
+ }
201
+ catch (e) {
202
+ console.error("Error in submit_task_implementation:", e);
203
+ throw e;
204
+ }
205
+ }
206
+ else if (req.params.name === "submit_task_review") {
207
+ try {
208
+ const args = req.params.arguments;
209
+ const task = await task_service_js_1.taskService.submitReview({
210
+ taskId: args.taskId,
211
+ agentInstanceId: args.agentInstanceId,
212
+ fencingToken: args.fencingToken,
213
+ status: args.status,
214
+ feedback: args.feedback
215
+ });
216
+ return {
217
+ content: [
218
+ { type: "text", text: `Review submitted successfully! Task state is now: ${task.state}` }
219
+ ]
220
+ };
221
+ }
222
+ catch (e) {
223
+ console.error("Error in submit_task_review:", e);
224
+ throw e;
225
+ }
226
+ }
157
227
  throw new Error(`Tool not found: ${req.params.name}`);
158
228
  });
159
229
  await mcpServer.connect(transport);
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "mcp-agent-broker",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "main": "dist/app.js",
5
5
  "bin": {
6
- "mcp-agent-broker": "dist/app.js"
6
+ "mcp-agent-broker": "dist/bin.js"
7
7
  },
8
8
  "scripts": {
9
9
  "build": "tsc",