Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eleven-games-relate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"trigger.dev": patch
---

add wait_for_run_to_complete tool so agents don't spam the get_run_details call after triggering
3 changes: 1 addition & 2 deletions packages/cli-v3/src/commands/install-mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
} from "../utilities/fileSystem.js";
import { printStandloneInitialBanner } from "../utilities/initialBanner.js";
import { VERSION } from "../version.js";
import { spinner } from "../utilities/windows.js";

const cliVersion = VERSION as string;
const cliTag = cliVersion.includes("v4-beta") ? "v4-beta" : "latest";
Expand Down Expand Up @@ -113,7 +112,7 @@ type ResolvedClients = SupportedClients | "unsupported";

const InstallMcpCommandOptions = z.object({
projectRef: z.string().optional(),
tag: z.string().default(cliVersion),
tag: z.string().default(cliTag),
devOnly: z.boolean().optional(),
yolo: z.boolean().default(false),
scope: z.enum(scopes).optional(),
Expand Down
8 changes: 7 additions & 1 deletion packages/cli-v3/src/mcp/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,20 @@ export const toolsMetadata = {
name: "trigger_task",
title: "Trigger Task",
description:
"Trigger a task in the project. Use the get_tasks tool to get a list of tasks and ask the user to select one if it's not clear which one to use.",
"Trigger a task in the project. Use the get_tasks tool to get a list of tasks and ask the user to select one if it's not clear which one to use. Use the wait_for_run_to_complete tool to wait for the run to complete.",
},
get_run_details: {
name: "get_run_details",
title: "Get Run Details",
description:
"Get the details of a run. The run ID is the ID of the run that was triggered. It starts with run_",
},
wait_for_run_to_complete: {
name: "wait_for_run_to_complete",
title: "Wait for Run to Complete",
description:
"Wait for a run to complete. The run ID is the ID of the run that was triggered. It starts with run_",
},
cancel_run: {
name: "cancel_run",
title: "Cancel Run",
Expand Down
29 changes: 29 additions & 0 deletions packages/cli-v3/src/mcp/formatters.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AnyRunShape } from "@trigger.dev/core/v3";
import {
ListRunResponseItem,
RetrieveRunResponse,
Expand Down Expand Up @@ -100,6 +101,34 @@ export function formatRun(run: RetrieveRunResponse): string {
return lines.join("\n");
}

export function formatRunShape(run: AnyRunShape): string {
const lines: string[] = [];

lines.push(`Run ${run.id}`);
lines.push(`Task: ${run.taskIdentifier}`);
lines.push(`Status: ${formatStatus(run.status)}`);

if (run.output) {
lines.push(`Output: ${JSON.stringify(run.output, null, 2)}`);
}

if (run.error) {
lines.push(`Error: ${run.error.name || "Error"}: ${run.error.message}`);
}

if (run.metadata) {
lines.push(`Metadata: ${JSON.stringify(run.metadata, null, 2)}`);
}

lines.push(`Created at: ${formatDateTime(run.createdAt)}`);

if (run.finishedAt) {
lines.push(`Finished at: ${formatDateTime(run.finishedAt)}`);
}

return lines.join("\n");
}

function formatStatus(status: string): string {
return status.toLowerCase().replace(/_/g, " ");
}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli-v3/src/mcp/mintlifyClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export async function performSearch(query: string, signal: AbortSignal) {
const body = callToolBody("Search", { query });
const body = callToolBody("SearchTriggerDev", { query });

const response = await fetch("https://trigger.dev/docs/mcp", {
method: "POST",
Expand Down
8 changes: 7 additions & 1 deletion packages/cli-v3/src/mcp/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import {
listProjectsTool,
} from "./tools/orgs.js";
import { listPreviewBranchesTool } from "./tools/previewBranches.js";
import { cancelRunTool, getRunDetailsTool, listRunsTool } from "./tools/runs.js";
import {
cancelRunTool,
getRunDetailsTool,
listRunsTool,
waitForRunToCompleteTool,
} from "./tools/runs.js";
import { getCurrentWorker, triggerTaskTool } from "./tools/tasks.js";
import { respondWithError } from "./utils.js";

Expand All @@ -23,6 +28,7 @@ export function registerTools(context: McpContext) {
triggerTaskTool,
listRunsTool,
getRunDetailsTool,
waitForRunToCompleteTool,
cancelRunTool,
deployTool,
listDeploysTool,
Expand Down
56 changes: 55 additions & 1 deletion packages/cli-v3/src/mcp/tools/runs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AnyRunShape } from "@trigger.dev/core/v3";
import { toolsMetadata } from "../config.js";
import { formatRun, formatRunList, formatRunTrace } from "../formatters.js";
import { formatRun, formatRunList, formatRunShape, formatRunTrace } from "../formatters.js";
import { CommonRunsInput, GetRunDetailsInput, ListRunsInput } from "../schemas.js";
import { respondWithError, toolHandler } from "../utils.js";

Expand Down Expand Up @@ -60,6 +61,59 @@ export const getRunDetailsTool = {
}),
};

export const waitForRunToCompleteTool = {
name: toolsMetadata.wait_for_run_to_complete.name,
title: toolsMetadata.wait_for_run_to_complete.title,
description: toolsMetadata.wait_for_run_to_complete.description,
inputSchema: CommonRunsInput.shape,
handler: toolHandler(CommonRunsInput.shape, async (input, { ctx, signal }) => {
ctx.logger?.log("calling wait_for_run_to_complete", { input });

if (ctx.options.devOnly && input.environment !== "dev") {
return respondWithError(
`This MCP server is only available for the dev environment. You tried to access the ${input.environment} environment. Remove the --dev-only flag to access other environments.`
);
}

const projectRef = await ctx.getProjectRef({
projectRef: input.projectRef,
cwd: input.configPath,
});

const apiClient = await ctx.getApiClient({
projectRef,
environment: input.environment,
scopes: [`read:runs:${input.runId}`],
branch: input.branch,
});

const runSubscription = apiClient.subscribeToRun(input.runId, { signal });
const readableStream = runSubscription.getReader();

let run: AnyRunShape | null = null;

while (true) {
const { done, value } = await readableStream.read();
if (done) {
break;
}
run = value;

if (value.isCompleted) {
break;
}
}

if (!run) {
return respondWithError("Run not found");
}

return {
content: [{ type: "text", text: formatRunShape(run) }],
};
}),
};

export const cancelRunTool = {
name: toolsMetadata.cancel_run.name,
title: toolsMetadata.cancel_run.title,
Expand Down
2 changes: 1 addition & 1 deletion packages/cli-v3/src/mcp/tools/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export const triggerTaskTool = {
const contents = [
`Task ${input.taskId} triggered and run with ID created: ${result.id}.`,
`View the run in the dashboard: ${taskRunUrl}`,
`You can also use the get_run_details tool to get the details of the run.`,
`Use the ${toolsMetadata.wait_for_run_to_complete.name} tool to wait for the run to complete and the ${toolsMetadata.get_run_details.name} tool to get the details of the run.`,
];

if (input.environment === "dev") {
Expand Down