Skip to content

Commit 6f6ca01

Browse files
authored
feat(mcp): add wait_for_run_to_complete tool so agents don't spam the get_run_details call after triggering (#2445)
* feat(mcp): add wait_for_run_to_complete tool so agents don't spam the get_run_details call after triggering This also fixes the search docs MCP tool * Install mcp using the latest tag, not the specific version
1 parent 11cbd1b commit 6f6ca01

File tree

8 files changed

+106
-7
lines changed

8 files changed

+106
-7
lines changed

.changeset/eleven-games-relate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"trigger.dev": patch
3+
---
4+
5+
add wait_for_run_to_complete tool so agents don't spam the get_run_details call after triggering

packages/cli-v3/src/commands/install-mcp.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
} from "../utilities/fileSystem.js";
1616
import { printStandloneInitialBanner } from "../utilities/initialBanner.js";
1717
import { VERSION } from "../version.js";
18-
import { spinner } from "../utilities/windows.js";
1918

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

114113
const InstallMcpCommandOptions = z.object({
115114
projectRef: z.string().optional(),
116-
tag: z.string().default(cliVersion),
115+
tag: z.string().default(cliTag),
117116
devOnly: z.boolean().optional(),
118117
yolo: z.boolean().default(false),
119118
scope: z.enum(scopes).optional(),

packages/cli-v3/src/mcp/config.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,20 @@ export const toolsMetadata = {
5656
name: "trigger_task",
5757
title: "Trigger Task",
5858
description:
59-
"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.",
59+
"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.",
6060
},
6161
get_run_details: {
6262
name: "get_run_details",
6363
title: "Get Run Details",
6464
description:
6565
"Get the details of a run. The run ID is the ID of the run that was triggered. It starts with run_",
6666
},
67+
wait_for_run_to_complete: {
68+
name: "wait_for_run_to_complete",
69+
title: "Wait for Run to Complete",
70+
description:
71+
"Wait for a run to complete. The run ID is the ID of the run that was triggered. It starts with run_",
72+
},
6773
cancel_run: {
6874
name: "cancel_run",
6975
title: "Cancel Run",

packages/cli-v3/src/mcp/formatters.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { AnyRunShape } from "@trigger.dev/core/v3";
12
import {
23
ListRunResponseItem,
34
RetrieveRunResponse,
@@ -100,6 +101,34 @@ export function formatRun(run: RetrieveRunResponse): string {
100101
return lines.join("\n");
101102
}
102103

104+
export function formatRunShape(run: AnyRunShape): string {
105+
const lines: string[] = [];
106+
107+
lines.push(`Run ${run.id}`);
108+
lines.push(`Task: ${run.taskIdentifier}`);
109+
lines.push(`Status: ${formatStatus(run.status)}`);
110+
111+
if (run.output) {
112+
lines.push(`Output: ${JSON.stringify(run.output, null, 2)}`);
113+
}
114+
115+
if (run.error) {
116+
lines.push(`Error: ${run.error.name || "Error"}: ${run.error.message}`);
117+
}
118+
119+
if (run.metadata) {
120+
lines.push(`Metadata: ${JSON.stringify(run.metadata, null, 2)}`);
121+
}
122+
123+
lines.push(`Created at: ${formatDateTime(run.createdAt)}`);
124+
125+
if (run.finishedAt) {
126+
lines.push(`Finished at: ${formatDateTime(run.finishedAt)}`);
127+
}
128+
129+
return lines.join("\n");
130+
}
131+
103132
function formatStatus(status: string): string {
104133
return status.toLowerCase().replace(/_/g, " ");
105134
}

packages/cli-v3/src/mcp/mintlifyClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export async function performSearch(query: string, signal: AbortSignal) {
2-
const body = callToolBody("Search", { query });
2+
const body = callToolBody("SearchTriggerDev", { query });
33

44
const response = await fetch("https://trigger.dev/docs/mcp", {
55
method: "POST",

packages/cli-v3/src/mcp/tools.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ import {
88
listProjectsTool,
99
} from "./tools/orgs.js";
1010
import { listPreviewBranchesTool } from "./tools/previewBranches.js";
11-
import { cancelRunTool, getRunDetailsTool, listRunsTool } from "./tools/runs.js";
11+
import {
12+
cancelRunTool,
13+
getRunDetailsTool,
14+
listRunsTool,
15+
waitForRunToCompleteTool,
16+
} from "./tools/runs.js";
1217
import { getCurrentWorker, triggerTaskTool } from "./tools/tasks.js";
1318
import { respondWithError } from "./utils.js";
1419

@@ -23,6 +28,7 @@ export function registerTools(context: McpContext) {
2328
triggerTaskTool,
2429
listRunsTool,
2530
getRunDetailsTool,
31+
waitForRunToCompleteTool,
2632
cancelRunTool,
2733
deployTool,
2834
listDeploysTool,

packages/cli-v3/src/mcp/tools/runs.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import { AnyRunShape } from "@trigger.dev/core/v3";
12
import { toolsMetadata } from "../config.js";
2-
import { formatRun, formatRunList, formatRunTrace } from "../formatters.js";
3+
import { formatRun, formatRunList, formatRunShape, formatRunTrace } from "../formatters.js";
34
import { CommonRunsInput, GetRunDetailsInput, ListRunsInput } from "../schemas.js";
45
import { respondWithError, toolHandler } from "../utils.js";
56

@@ -60,6 +61,59 @@ export const getRunDetailsTool = {
6061
}),
6162
};
6263

64+
export const waitForRunToCompleteTool = {
65+
name: toolsMetadata.wait_for_run_to_complete.name,
66+
title: toolsMetadata.wait_for_run_to_complete.title,
67+
description: toolsMetadata.wait_for_run_to_complete.description,
68+
inputSchema: CommonRunsInput.shape,
69+
handler: toolHandler(CommonRunsInput.shape, async (input, { ctx, signal }) => {
70+
ctx.logger?.log("calling wait_for_run_to_complete", { input });
71+
72+
if (ctx.options.devOnly && input.environment !== "dev") {
73+
return respondWithError(
74+
`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.`
75+
);
76+
}
77+
78+
const projectRef = await ctx.getProjectRef({
79+
projectRef: input.projectRef,
80+
cwd: input.configPath,
81+
});
82+
83+
const apiClient = await ctx.getApiClient({
84+
projectRef,
85+
environment: input.environment,
86+
scopes: [`read:runs:${input.runId}`],
87+
branch: input.branch,
88+
});
89+
90+
const runSubscription = apiClient.subscribeToRun(input.runId, { signal });
91+
const readableStream = runSubscription.getReader();
92+
93+
let run: AnyRunShape | null = null;
94+
95+
while (true) {
96+
const { done, value } = await readableStream.read();
97+
if (done) {
98+
break;
99+
}
100+
run = value;
101+
102+
if (value.isCompleted) {
103+
break;
104+
}
105+
}
106+
107+
if (!run) {
108+
return respondWithError("Run not found");
109+
}
110+
111+
return {
112+
content: [{ type: "text", text: formatRunShape(run) }],
113+
};
114+
}),
115+
};
116+
63117
export const cancelRunTool = {
64118
name: toolsMetadata.cancel_run.name,
65119
title: toolsMetadata.cancel_run.title,

packages/cli-v3/src/mcp/tools/tasks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export const triggerTaskTool = {
130130
const contents = [
131131
`Task ${input.taskId} triggered and run with ID created: ${result.id}.`,
132132
`View the run in the dashboard: ${taskRunUrl}`,
133-
`You can also use the get_run_details tool to get the details of the run.`,
133+
`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.`,
134134
];
135135

136136
if (input.environment === "dev") {

0 commit comments

Comments
 (0)