@moor-sh/mcp 0.12.0 → 0.14.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/package.json +1 -1
- package/src/index.ts +56 -7
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -90,6 +90,17 @@ type Project = {
|
|
|
90
90
|
domain: string | null;
|
|
91
91
|
docker_image: string | null;
|
|
92
92
|
github_url: string | null;
|
|
93
|
+
// #71: live_* fields are written by the API's status reconciler.
|
|
94
|
+
// status above is moor's RECORDED state (only changes on explicit
|
|
95
|
+
// start/stop/build/cancel). live_status reflects Docker's view at
|
|
96
|
+
// last successful inspect. Differences mean moor missed an external
|
|
97
|
+
// change (or the reconciler hasn't run yet). live_error non-null
|
|
98
|
+
// means the most recent inspect failed; the live_status / exit_code
|
|
99
|
+
// shown is the last successful snapshot.
|
|
100
|
+
live_status?: "running" | "stopped" | "error" | "missing" | null;
|
|
101
|
+
live_exit_code?: number | null;
|
|
102
|
+
live_checked_at?: string | null;
|
|
103
|
+
live_error?: string | null;
|
|
93
104
|
};
|
|
94
105
|
|
|
95
106
|
async function resolveProject(name: string): Promise<Project> {
|
|
@@ -284,7 +295,8 @@ server.registerTool(
|
|
|
284
295
|
"moor_status",
|
|
285
296
|
{
|
|
286
297
|
title: "List Projects",
|
|
287
|
-
description:
|
|
298
|
+
description:
|
|
299
|
+
"List all projects managed by Moor. `status` is moor's recorded state (only changes on explicit start/stop/build/cancel). `live_status` is Docker's view at last successful inspect; differences (e.g. recorded='running' live='error') mean moor missed an external change like a host docker stop, crash, or OOM kill. `live_error` non-null means the most recent inspect failed and the live_* values are the last successful snapshot, not necessarily current.",
|
|
288
300
|
},
|
|
289
301
|
async () => {
|
|
290
302
|
const res = await apiGet("/api/projects");
|
|
@@ -293,6 +305,10 @@ server.registerTool(
|
|
|
293
305
|
const summary = projects.map((p) => ({
|
|
294
306
|
name: p.name,
|
|
295
307
|
status: p.status,
|
|
308
|
+
live_status: p.live_status ?? null,
|
|
309
|
+
live_exit_code: p.live_exit_code ?? null,
|
|
310
|
+
live_checked_at: p.live_checked_at ?? null,
|
|
311
|
+
live_error: p.live_error ?? null,
|
|
296
312
|
source: p.docker_image || p.github_url || null,
|
|
297
313
|
domain: p.domain,
|
|
298
314
|
}));
|
|
@@ -304,7 +320,8 @@ server.registerTool(
|
|
|
304
320
|
"moor_logs",
|
|
305
321
|
{
|
|
306
322
|
title: "Get Container Logs",
|
|
307
|
-
description:
|
|
323
|
+
description:
|
|
324
|
+
"Get recent logs from a project's container. Annotates output with state: ok (container running), exited (container is stopped but Docker still has logs), no_container (project never started), or missing (container_id is set but Docker doesn't have it). Throws only on docker_error (Docker daemon 5xx / unreachable) so an operator can distinguish infrastructure failure from app silence — pre-#74 the tool returned empty logs for all of these.",
|
|
308
325
|
inputSchema: z.object({
|
|
309
326
|
project: z.string().describe("Project name or ID"),
|
|
310
327
|
lines: z.number().optional().default(100).describe("Number of log lines to retrieve"),
|
|
@@ -313,11 +330,43 @@ server.registerTool(
|
|
|
313
330
|
async ({ project, lines }) => {
|
|
314
331
|
const p = await resolveProject(project);
|
|
315
332
|
const res = await apiGet(`/api/projects/${p.id}/logs?tail=${lines}`);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
333
|
+
// 502 = API surfaced a Docker daemon failure. Throw so the agent
|
|
334
|
+
// gets a tool error, not silent empty logs.
|
|
335
|
+
if (res.status === 502) {
|
|
336
|
+
const data = (await res.json().catch(() => ({}))) as { error?: string };
|
|
337
|
+
throw new Error(`Docker error: ${data.error ?? "unknown"}`);
|
|
338
|
+
}
|
|
339
|
+
if (!res.ok) throw new Error(`Failed: ${res.status} ${await res.text()}`);
|
|
340
|
+
const data = (await res.json()) as { logs: string; state?: string };
|
|
341
|
+
switch (data.state) {
|
|
342
|
+
case "no_container":
|
|
343
|
+
return {
|
|
344
|
+
content: [{ type: "text", text: "(project hasn't been started yet — no container)" }],
|
|
345
|
+
};
|
|
346
|
+
case "missing":
|
|
347
|
+
return {
|
|
348
|
+
content: [
|
|
349
|
+
{
|
|
350
|
+
type: "text",
|
|
351
|
+
text: "(container_id was recorded but Docker doesn't have it; moor may need to recreate the project)",
|
|
352
|
+
},
|
|
353
|
+
],
|
|
354
|
+
};
|
|
355
|
+
case "exited":
|
|
356
|
+
return {
|
|
357
|
+
content: [
|
|
358
|
+
{
|
|
359
|
+
type: "text",
|
|
360
|
+
text: `${data.logs || "(no logs captured)"}\n\n(container is exited; logs above are from before)`,
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
};
|
|
364
|
+
default:
|
|
365
|
+
// "ok" or undefined (older API) — render raw.
|
|
366
|
+
return {
|
|
367
|
+
content: [{ type: "text", text: data.logs || "(no logs)" }],
|
|
368
|
+
};
|
|
369
|
+
}
|
|
321
370
|
},
|
|
322
371
|
);
|
|
323
372
|
|