@mgsoftwarebv/mg-dashboard-mcp 2.2.1 → 2.2.3

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
@@ -16,11 +16,14 @@ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
16
16
  "INTERRUPTED",
17
17
  "EXPIRED"
18
18
  ]);
19
- var DEFAULT_TRIGGER_SERVER_ID = "03659d55-e194-400d-b82a-bf6457371ded";
19
+ var TRIGGER_SERVER_ID = "03659d55-e194-400d-b82a-bf6457371ded";
20
+ var COMPOSE_PROJECT = "mg-dashboard-supabase-trigger";
21
+ var PG_CONTAINER = `${COMPOSE_PROJECT}-postgres-1`;
22
+ var WA_CONTAINER = `${COMPOSE_PROJECT}-webapp-1`;
20
23
  var TRIGGER_TOOLS = [
21
24
  {
22
25
  name: "trigger-list",
23
- description: "List all Trigger.dev projects on the Trigger server. Returns the compose project name, webapp port, and status. Use the project name in other trigger-* tools.",
26
+ description: 'List all Trigger.dev projects. Returns the project slug and name. Use the slug as the "project" parameter in other trigger-* tools.',
24
27
  inputSchema: {
25
28
  type: "object",
26
29
  properties: {}
@@ -32,7 +35,7 @@ var TRIGGER_TOOLS = [
32
35
  inputSchema: {
33
36
  type: "object",
34
37
  properties: {
35
- project: { type: "string", description: "Compose project name (from trigger-list)" },
38
+ project: { type: "string", description: 'Project slug from trigger-list (e.g. "mg-dashboard-bHfS")' },
36
39
  status: {
37
40
  type: "string",
38
41
  description: "Comma-separated status filter: QUEUED,EXECUTING,COMPLETED,FAILED,CRASHED,CANCELED,SYSTEM_FAILURE"
@@ -49,7 +52,7 @@ var TRIGGER_TOOLS = [
49
52
  inputSchema: {
50
53
  type: "object",
51
54
  properties: {
52
- project: { type: "string", description: "Compose project name" },
55
+ project: { type: "string", description: "Project slug from trigger-list" },
53
56
  runId: { type: "string", description: "Run ID (e.g. run_xxxxx)" }
54
57
  },
55
58
  required: ["project", "runId"]
@@ -61,7 +64,7 @@ var TRIGGER_TOOLS = [
61
64
  inputSchema: {
62
65
  type: "object",
63
66
  properties: {
64
- project: { type: "string", description: "Compose project name" },
67
+ project: { type: "string", description: "Project slug from trigger-list" },
65
68
  taskId: { type: "string", description: 'Task identifier (e.g. "hello-world", "execute-pipeline")' },
66
69
  payload: { type: "string", description: "JSON payload string to pass to the task (optional)" },
67
70
  waitSeconds: { type: "number", description: "Max seconds to wait for completion (default 60, max 300)" }
@@ -75,7 +78,7 @@ var TRIGGER_TOOLS = [
75
78
  inputSchema: {
76
79
  type: "object",
77
80
  properties: {
78
- project: { type: "string", description: "Compose project name" },
81
+ project: { type: "string", description: "Project slug from trigger-list" },
79
82
  runId: { type: "string", description: "Run ID to cancel (e.g. run_xxxxx)" }
80
83
  },
81
84
  required: ["project", "runId"]
@@ -87,7 +90,7 @@ var TRIGGER_TOOLS = [
87
90
  inputSchema: {
88
91
  type: "object",
89
92
  properties: {
90
- project: { type: "string", description: "Compose project name" },
93
+ project: { type: "string", description: "Project slug from trigger-list" },
91
94
  runId: { type: "string", description: "Run ID to replay (e.g. run_xxxxx)" }
92
95
  },
93
96
  required: ["project", "runId"]
@@ -103,12 +106,11 @@ var TRIGGER_TOOL_MODULE_MAP = {
103
106
  "trigger-cancel-run": "ci_cd",
104
107
  "trigger-replay-run": "ci_cd"
105
108
  };
106
- async function discoverInstance(project, conn, proxy, sshExec2) {
107
- const pg = `${project}-postgres-1`;
108
- const wa = `${project}-webapp-1`;
109
+ async function discoverInstance(projectSlug, conn, proxy, sshExec2) {
110
+ const sql = `SELECT re.\\"apiKey\\" FROM \\"RuntimeEnvironment\\" re JOIN \\"Project\\" p ON re.\\"projectId\\" = p.id WHERE p.slug='${projectSlug}' AND re.slug='prod' LIMIT 1`;
109
111
  const cmd = [
110
- `PORT=$(docker port "${wa}" 3000/tcp 2>/dev/null | head -1 | sed 's/.*://')`,
111
- `KEY=$(docker exec "${pg}" psql -U postgres -d main -t -A -c "SELECT \\"apiKey\\" FROM \\"RuntimeEnvironment\\" WHERE slug='prod' LIMIT 1" 2>/dev/null | tr -d '[:space:]')`,
112
+ `PORT=$(docker port "${WA_CONTAINER}" 3000/tcp 2>/dev/null | head -1 | sed 's/.*://')`,
113
+ `KEY=$(docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql}" 2>/dev/null | tr -d '[:space:]')`,
112
114
  'echo "$PORT|$KEY"'
113
115
  ].join(" && ");
114
116
  const result = await sshExec2(conn, cmd, proxy);
@@ -118,18 +120,35 @@ async function discoverInstance(project, conn, proxy, sshExec2) {
118
120
  const apiKey2 = sepIdx > 0 ? output.substring(sepIdx + 1) : "";
119
121
  if (!port) {
120
122
  throw new Error(
121
- `Could not find webapp port for ${wa}. Is the container running? Use trigger-list to see available instances.`
123
+ `Could not find webapp port for ${WA_CONTAINER}. Is the container running?`
122
124
  );
123
125
  }
124
126
  if (!apiKey2) {
125
127
  throw new Error(
126
- `Could not get API key from ${pg}. Check if the Trigger.dev database is accessible and the RuntimeEnvironment table exists.`
128
+ `Could not get API key for project "${projectSlug}". Check if the project slug is correct (use trigger-list).`
127
129
  );
128
130
  }
129
131
  return { port, apiKey: apiKey2 };
130
132
  }
133
+ async function fetchRunLogs(runId, conn, proxy, sshExec2) {
134
+ const sql = `SELECT level, message, \\"isError\\", \\"createdAt\\" FROM \\"TaskEvent\\" WHERE \\"runId\\" = '${runId}' AND level IN ('INFO','WARN','ERROR','DEBUG','LOG','TRACE') ORDER BY \\"startTime\\" ASC LIMIT 200`;
135
+ const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql}" 2>/dev/null`;
136
+ const result = await sshExec2(conn, cmd, proxy);
137
+ const output = result.stdout.trim();
138
+ if (!output) return "";
139
+ return output.split("\n").map((line) => {
140
+ const parts = line.split("|");
141
+ const level = (parts[0] || "").padEnd(5);
142
+ const message = parts[1] || "";
143
+ const isError = parts[2] === "t";
144
+ const ts = parts[3] || "";
145
+ const time = ts ? ts.split(" ")[1]?.substring(0, 8) || "" : "";
146
+ const prefix = isError ? "!" : " ";
147
+ return `${prefix}${time} [${level}] ${message}`;
148
+ }).join("\n");
149
+ }
131
150
  async function triggerApi(conn, proxy, sshExec2, instance, method, path, body) {
132
- const parts = ["curl", "-s", "--max-time", "30"];
151
+ const parts = ["curl", "-s", "-g", "--max-time", "30"];
133
152
  if (method !== "GET") parts.push("-X", method);
134
153
  parts.push(`"http://localhost:${instance.port}${path}"`);
135
154
  parts.push(`-H "Authorization: Bearer ${instance.apiKey}"`);
@@ -191,35 +210,22 @@ function formatRunDetail(run) {
191
210
  }
192
211
  async function handleTriggerTool(name, args2, deps) {
193
212
  const { sshExec: sshExec2, getServerConnection: getServerConnection2 } = deps;
194
- const serverId = DEFAULT_TRIGGER_SERVER_ID;
213
+ const { conn, proxy } = await getServerConnection2(TRIGGER_SERVER_ID);
195
214
  switch (name) {
196
215
  // -----------------------------------------------------------------
197
216
  case "trigger-list": {
198
- const { conn, proxy } = await getServerConnection2(serverId);
199
- const script = [
200
- "FOUND=0",
201
- "for PG in $(docker ps --format '{{.Names}}' | grep -E 'trigger.*-postgres-[0-9]+$'); do",
202
- ` PROJECT=$(echo "$PG" | sed 's/-postgres-[0-9]*$//')`,
203
- ' WA="${PROJECT}-webapp-1"',
204
- ` PORT=$(docker port "$WA" 3000/tcp 2>/dev/null | head -1 | sed 's/.*://')`,
205
- ` STATUS=$(docker inspect -f '{{.State.Status}}' "$WA" 2>/dev/null || echo 'not_found')`,
206
- ` RUNNING=$(docker ps --filter "label=com.docker.compose.project=\${PROJECT}" --format '{{.Names}}' 2>/dev/null | wc -l)`,
207
- ` TOTAL=$(docker ps -a --filter "label=com.docker.compose.project=\${PROJECT}" --format '{{.Names}}' 2>/dev/null | wc -l)`,
208
- ' echo "${PROJECT}|${PORT:-?}|${STATUS}|${RUNNING}/${TOTAL}"',
209
- " FOUND=1",
210
- "done",
211
- '[ "$FOUND" = "0" ] && echo "NO_INSTANCES"'
212
- ].join("\n");
213
- const result = await sshExec2(conn, script, proxy);
217
+ const sql = 'SELECT slug, name FROM \\"Project\\" ORDER BY name';
218
+ const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql}" 2>/dev/null`;
219
+ const result = await sshExec2(conn, cmd, proxy);
214
220
  const output = result.stdout.trim();
215
- if (!output || output === "NO_INSTANCES") {
216
- return { content: [{ type: "text", text: "No Trigger.dev instances found on this server. Check if Docker containers are running." }] };
221
+ if (!output) {
222
+ return { content: [{ type: "text", text: "No Trigger.dev projects found." }] };
217
223
  }
218
- const header = `${"PROJECT".padEnd(45)} ${"PORT".padEnd(6)} ${"WEBAPP".padEnd(12)} CONTAINERS`;
219
- const sep = "-".repeat(85);
224
+ const header = `${"SLUG".padEnd(25)} NAME`;
225
+ const sep = "-".repeat(55);
220
226
  const lines = output.split("\n").map((line) => {
221
- const [project, port, status, containers] = line.split("|");
222
- return `${(project || "").padEnd(45)} ${(port || "?").padEnd(6)} ${(status || "?").padEnd(12)} ${containers || "?"}`;
227
+ const [slug, name2] = line.split("|");
228
+ return `${(slug || "").padEnd(25)} ${name2 || ""}`;
223
229
  });
224
230
  return { content: [{ type: "text", text: `${header}
225
231
  ${sep}
@@ -228,12 +234,11 @@ ${lines.join("\n")}` }] };
228
234
  // -----------------------------------------------------------------
229
235
  case "trigger-runs": {
230
236
  const project = String(args2.project);
231
- const { conn, proxy } = await getServerConnection2(serverId);
232
237
  const instance = await discoverInstance(project, conn, proxy, sshExec2);
233
238
  const limit = Math.min(Math.max(Number(args2.limit) || 20, 1), 100);
234
- const queryParts = [`page[size]=${limit}`];
235
- if (args2.status) queryParts.push(`filter[status]=${String(args2.status)}`);
236
- if (args2.taskIdentifier) queryParts.push(`filter[taskIdentifier]=${String(args2.taskIdentifier)}`);
239
+ const queryParts = [`page%5Bsize%5D=${limit}`];
240
+ if (args2.status) queryParts.push(`filter%5Bstatus%5D=${String(args2.status)}`);
241
+ if (args2.taskIdentifier) queryParts.push(`filter%5BtaskIdentifier%5D=${String(args2.taskIdentifier)}`);
237
242
  const rawJson = await triggerApi(
238
243
  conn,
239
244
  proxy,
@@ -256,7 +261,6 @@ ${rawJson.substring(0, 500)}` }] };
256
261
  case "trigger-run-detail": {
257
262
  const project = String(args2.project);
258
263
  const runId = String(args2.runId);
259
- const { conn, proxy } = await getServerConnection2(serverId);
260
264
  const instance = await discoverInstance(project, conn, proxy, sshExec2);
261
265
  const rawJson = await triggerApi(
262
266
  conn,
@@ -273,14 +277,18 @@ ${rawJson.substring(0, 500)}` }] };
273
277
  return { content: [{ type: "text", text: `Invalid API response:
274
278
  ${rawJson.substring(0, 500)}` }] };
275
279
  }
276
- return { content: [{ type: "text", text: formatRunDetail(run) }] };
280
+ const logs = await fetchRunLogs(runId, conn, proxy, sshExec2);
281
+ let text = formatRunDetail(run);
282
+ if (logs) {
283
+ text += "\n\n--- Logs ---\n" + logs;
284
+ }
285
+ return { content: [{ type: "text", text }] };
277
286
  }
278
287
  // -----------------------------------------------------------------
279
288
  case "trigger-test-task": {
280
289
  const project = String(args2.project);
281
290
  const taskId = String(args2.taskId);
282
291
  const waitSeconds = Math.min(Math.max(Number(args2.waitSeconds) || 60, 5), 300);
283
- const { conn, proxy } = await getServerConnection2(serverId);
284
292
  conn.timeout = (waitSeconds + 30) * 1e3;
285
293
  const instance = await discoverInstance(project, conn, proxy, sshExec2);
286
294
  let payload = "{}";
@@ -336,7 +344,10 @@ ${triggerJson.substring(0, 500)}` }] };
336
344
  continue;
337
345
  }
338
346
  if (TERMINAL_STATUSES.has(run.status)) {
339
- return { content: [{ type: "text", text: formatRunDetail(run) }] };
347
+ let text = formatRunDetail(run);
348
+ const logs = await fetchRunLogs(runId, conn, proxy, sshExec2);
349
+ if (logs) text += "\n\n--- Logs ---\n" + logs;
350
+ return { content: [{ type: "text", text }] };
340
351
  }
341
352
  }
342
353
  return {
@@ -350,7 +361,6 @@ ${triggerJson.substring(0, 500)}` }] };
350
361
  case "trigger-cancel-run": {
351
362
  const project = String(args2.project);
352
363
  const runId = String(args2.runId);
353
- const { conn, proxy } = await getServerConnection2(serverId);
354
364
  const instance = await discoverInstance(project, conn, proxy, sshExec2);
355
365
  const rawJson = await triggerApi(
356
366
  conn,
@@ -378,7 +388,6 @@ ${rawJson.substring(0, 500)}` }] };
378
388
  case "trigger-replay-run": {
379
389
  const project = String(args2.project);
380
390
  const runId = String(args2.runId);
381
- const { conn, proxy } = await getServerConnection2(serverId);
382
391
  const instance = await discoverInstance(project, conn, proxy, sshExec2);
383
392
  const rawJson = await triggerApi(
384
393
  conn,