From a6b672a4ca4ea5b907bb393dad4c1f94b26224d4 Mon Sep 17 00:00:00 2001 From: Eric Allam Date: Wed, 27 Aug 2025 15:10:49 +0100 Subject: [PATCH 1/2] 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 --- .changeset/eleven-games-relate.md | 5 ++ packages/cli-v3/src/mcp/config.ts | 8 +++- packages/cli-v3/src/mcp/formatters.ts | 29 ++++++++++++ packages/cli-v3/src/mcp/mintlifyClient.ts | 2 +- packages/cli-v3/src/mcp/tools.ts | 8 +++- packages/cli-v3/src/mcp/tools/runs.ts | 56 ++++++++++++++++++++++- packages/cli-v3/src/mcp/tools/tasks.ts | 2 +- 7 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 .changeset/eleven-games-relate.md diff --git a/.changeset/eleven-games-relate.md b/.changeset/eleven-games-relate.md new file mode 100644 index 0000000000..20feff8f1e --- /dev/null +++ b/.changeset/eleven-games-relate.md @@ -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 diff --git a/packages/cli-v3/src/mcp/config.ts b/packages/cli-v3/src/mcp/config.ts index bfa16437ec..206b5910fa 100644 --- a/packages/cli-v3/src/mcp/config.ts +++ b/packages/cli-v3/src/mcp/config.ts @@ -56,7 +56,7 @@ 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", @@ -64,6 +64,12 @@ export const toolsMetadata = { 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", diff --git a/packages/cli-v3/src/mcp/formatters.ts b/packages/cli-v3/src/mcp/formatters.ts index 12b3cf05dd..a16f947a73 100644 --- a/packages/cli-v3/src/mcp/formatters.ts +++ b/packages/cli-v3/src/mcp/formatters.ts @@ -1,3 +1,4 @@ +import { AnyRunShape } from "@trigger.dev/core/v3"; import { ListRunResponseItem, RetrieveRunResponse, @@ -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, " "); } diff --git a/packages/cli-v3/src/mcp/mintlifyClient.ts b/packages/cli-v3/src/mcp/mintlifyClient.ts index 16fe41b411..d7bc98c7db 100644 --- a/packages/cli-v3/src/mcp/mintlifyClient.ts +++ b/packages/cli-v3/src/mcp/mintlifyClient.ts @@ -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", diff --git a/packages/cli-v3/src/mcp/tools.ts b/packages/cli-v3/src/mcp/tools.ts index 8bcb8280e0..5c69bb82fe 100644 --- a/packages/cli-v3/src/mcp/tools.ts +++ b/packages/cli-v3/src/mcp/tools.ts @@ -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"; @@ -23,6 +28,7 @@ export function registerTools(context: McpContext) { triggerTaskTool, listRunsTool, getRunDetailsTool, + waitForRunToCompleteTool, cancelRunTool, deployTool, listDeploysTool, diff --git a/packages/cli-v3/src/mcp/tools/runs.ts b/packages/cli-v3/src/mcp/tools/runs.ts index 8a13603a23..13fe601da0 100644 --- a/packages/cli-v3/src/mcp/tools/runs.ts +++ b/packages/cli-v3/src/mcp/tools/runs.ts @@ -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"; @@ -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, diff --git a/packages/cli-v3/src/mcp/tools/tasks.ts b/packages/cli-v3/src/mcp/tools/tasks.ts index 15e8d40295..41c988ce1a 100644 --- a/packages/cli-v3/src/mcp/tools/tasks.ts +++ b/packages/cli-v3/src/mcp/tools/tasks.ts @@ -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") { From ab59db8624fd80c2cac512cddcb7309c6112fac7 Mon Sep 17 00:00:00 2001 From: Eric Allam Date: Wed, 27 Aug 2025 15:11:58 +0100 Subject: [PATCH 2/2] Install mcp using the latest tag, not the specific version --- packages/cli-v3/src/commands/install-mcp.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/cli-v3/src/commands/install-mcp.ts b/packages/cli-v3/src/commands/install-mcp.ts index c1d36374f7..545014292d 100644 --- a/packages/cli-v3/src/commands/install-mcp.ts +++ b/packages/cli-v3/src/commands/install-mcp.ts @@ -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"; @@ -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(),