chore(cli): remove --mcp option from trigger dev (#4246)

This commit is contained in:
Chris Arderne
2026-07-13 16:23:05 +01:00
committed by GitHub
parent e0b42a88d6
commit 6e943f2421
6 changed files with 5 additions and 341 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"trigger.dev": patch
---
Remove the legacy `--mcp` and `--mcp-port` options from the `dev` command. Run the dedicated `trigger mcp` command to start the Trigger.dev MCP server.
-2
View File
@@ -56,7 +56,6 @@
"@types/gradient-string": "^1.1.2",
"@types/ini": "^4.1.1",
"@types/object-hash": "3.0.6",
"@types/polka": "^0.5.7",
"@types/react": "^18.2.48",
"@types/resolve": "^1.20.6",
"@types/rimraf": "^4.0.5",
@@ -133,7 +132,6 @@
"p-retry": "^6.1.0",
"partysocket": "^1.0.2",
"pkg-types": "^1.1.3",
"polka": "^0.5.2",
"resolve": "^1.22.8",
"semver": "^7.5.0",
"signal-exit": "^4.1.0",
-4
View File
@@ -59,8 +59,6 @@ const DevCommandOptions = CommonCommandOptions.extend({
envFile: z.string().optional(),
keepTmpFiles: z.boolean().default(false),
maxConcurrentRuns: z.coerce.number().optional(),
mcp: z.boolean().default(false),
mcpPort: z.coerce.number().optional().default(3333),
analyze: z.boolean().default(false),
disableWarnings: z.boolean().default(false),
skipMCPInstall: z.boolean().default(false),
@@ -101,8 +99,6 @@ export function configureDevCommand(program: Command) {
"--keep-tmp-files",
"Keep temporary files after the dev session ends, helpful for debugging"
)
.option("--mcp", "Start the MCP server")
.option("--mcp-port", "The port to run the MCP server on", "3333")
.addOption(
new CommandOption("--analyze", "Analyze the build output and import timings").hideHelp()
)
-13
View File
@@ -23,7 +23,6 @@ import type { EphemeralDirectory } from "../utilities/tempDirectories.js";
import { clearTmpDirs, getStoreDir, getTmpDir } from "../utilities/tempDirectories.js";
import { startDevOutput } from "./devOutput.js";
import { startWorkerRuntime } from "./devSupervisor.js";
import { startMcpServer, stopMcpServer } from "./mcpServer.js";
import { writeJSONFile } from "../utilities/fileSystem.js";
import { join } from "node:path";
@@ -67,17 +66,6 @@ export async function startDevSession({
dashboardUrl,
});
if (rawArgs.mcp) {
await startMcpServer({
port: rawArgs.mcpPort,
cliApiClient: client,
devSession: {
dashboardUrl,
projectRef: rawConfig.project,
},
});
}
const stopOutput = startDevOutput({
name,
branch,
@@ -237,7 +225,6 @@ export async function startDevSession({
stopBundling?.().catch((error) => {});
runtime.shutdown().catch((error) => {});
stopOutput();
stopMcpServer();
},
};
}
-266
View File
@@ -1,266 +0,0 @@
import polka from "polka";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { z } from "zod";
import { logger } from "../utilities/logger.js";
import type { CliApiClient } from "../apiClient.js";
import { ApiClient, RunStatus } from "@trigger.dev/core/v3";
import { eventBus } from "../utilities/eventBus.js";
let allTaskIds: string[] = [];
let projectRef: string;
let dashboardUrl: string;
// there is some overlap between `ApiClient` and `CliApiClient` which is not ideal
// we can address in this in the future, but for now we need keep using both
// as `ApiClient` exposes most of the methods needed for the MCP tools
let sdkApiClient: ApiClient;
let mcpTransport: SSEServerTransport | null = null;
const server = new McpServer({
name: "trigger.dev",
version: "1.0.0",
});
// The `list-all-tasks` tool primarily helps to enable fuzzy matching of task IDs (names).
// This way, one doesn't need to specify the full task ID and rather let the LLM figure it out.
// This could be a good fit for the `resource` entity in MCP.
// Also, a custom `prompt` entity could be useful to instruct the LLM to prompt the user
// for selecting a task from a list of matching tasks, when the confidence for an exact match is low.
server.tool("list-all-tasks", "List all available task IDs in the worker.", async () => {
return {
content: [
{
text: JSON.stringify(allTaskIds, null, 2),
type: "text",
},
],
};
});
server.tool(
"trigger-task",
"Trigger a task",
{
id: z.string().describe("The ID of the task to trigger"),
payload: z
.string()
.transform((val, ctx) => {
try {
return JSON.parse(val);
} catch {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "The payload must be a valid JSON string",
});
return z.NEVER;
}
})
.describe("The payload to pass to the task run, must be a valid JSON"),
// TODO: expose more parameteres from the trigger options
},
async ({ id, payload }) => {
const result = await sdkApiClient.triggerTask(id, {
payload,
});
const taskRunUrl = `${dashboardUrl}/projects/v3/${projectRef}/runs/${result.id}`;
return {
content: [
{
type: "text",
text: JSON.stringify({ ...result, taskRunUrl }, null, 2),
},
],
};
}
);
server.tool(
"list-runs",
"List task runs. This returns a paginated list which shows the details of the runs, e.g., status, attempts, cost, etc.",
{
filters: z
.object({
status: RunStatus.optional().describe(
"The status of the run. Can be WAITING_FOR_DEPLOY, QUEUED, EXECUTING, REATTEMPTING, or FROZEN"
),
taskIdentifier: z
.union([z.array(z.string()), z.string()])
.optional()
.describe("The identifier of the task that was run"),
version: z
.union([z.array(z.string()), z.string()])
.optional()
.describe("The version of the worker that executed the run"),
from: z
.union([z.date(), z.number()])
.optional()
.describe("Start date/time for filtering runs"),
to: z.union([z.date(), z.number()]).optional().describe("End date/time for filtering runs"),
period: z.string().optional().describe("Time period for filtering runs"),
bulkAction: z
.string()
.optional()
.describe("The bulk action ID to filter the runs by (e.g., bulk_1234)"),
tag: z
.union([z.array(z.string()), z.string()])
.optional()
.describe("The tags that are attached to the run"),
schedule: z
.string()
.optional()
.describe("The schedule ID to filter the runs by (e.g., schedule_1234)"),
isTest: z.boolean().optional().describe("Whether the run is a test run or not"),
batch: z.string().optional().describe("The batch identifier to filter runs by"),
})
.describe("Parameters for listing task runs"),
},
async ({ filters }) => {
const { data, pagination } = await sdkApiClient.listRuns(filters);
return {
content: [
{
type: "text",
text: JSON.stringify({ data, pagination }, null, 2),
},
],
};
}
);
server.tool(
"get-run",
"Retrieve the details of a task run, e.g., status, attempts, cost, etc.",
{
runId: z.string().describe("The ID of the task run to get"),
},
async ({ runId }) => {
const result = await sdkApiClient.retrieveRun(runId);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
);
server.tool(
"cancel-run",
"Cancel an in-progress run. Runs that have already completed cannot be cancelled.",
{
runId: z.string().describe("The ID of the task run to cancel"),
},
async ({ runId }) => {
const run = await sdkApiClient.retrieveRun(runId);
if (run?.status === "COMPLETED") {
return {
content: [
{
type: "text",
text: JSON.stringify(
{ message: "This run is already completed, no action taken.", run },
null,
2
),
},
],
};
}
await sdkApiClient.cancelRun(runId);
// we could also skip fetching the run again, but it provides more context to the LLM
// and one extra API call is no big deal
const updatedRun = await sdkApiClient.retrieveRun(runId);
return {
content: [
{
type: "text",
text: JSON.stringify(
{
message: "Task run was cancelled",
previousStatus: run.status,
currentStatus: updatedRun.status,
updatedTaskRun: updatedRun,
},
null,
2
),
},
],
};
}
);
server.tool(
"get-run-logs",
"Retrieve the logs output of a task run.",
{
runId: z.string().describe("The ID of the task run to get"),
},
async ({ runId }) => {
const result = await sdkApiClient.listRunEvents(runId);
return {
content: [
{
text: JSON.stringify(result, null, 2),
type: "text",
},
],
};
}
);
const app = polka();
app.get("/sse", (_req, res) => {
mcpTransport = new SSEServerTransport("/messages", res);
server.connect(mcpTransport);
});
app.post("/messages", (req, res) => {
if (mcpTransport) {
mcpTransport.handlePostMessage(req, res);
}
});
eventBus.on("backgroundWorkerInitialized", (worker) => {
allTaskIds = worker.manifest?.tasks.map((task) => task.id) ?? [];
});
export const startMcpServer = async (options: {
port: number;
cliApiClient: CliApiClient;
devSession: {
dashboardUrl: string;
projectRef: string;
};
}) => {
const { apiURL, accessToken } = options.cliApiClient;
if (!accessToken) {
logger.error("No access token found in the API client, failed to start the MCP server");
return;
}
sdkApiClient = new ApiClient(apiURL, accessToken);
projectRef = options.devSession.projectRef;
dashboardUrl = options.devSession.dashboardUrl;
app.listen(options.port, () => {
logger.info(`Trigger.dev MCP Server is now running on port ${options.port}`);
});
};
export const stopMcpServer = () => {
app.server?.close(() => {
logger.info(`Trigger.dev MCP Server is now stopped`);
});
};
-56
View File
@@ -1576,9 +1576,6 @@ importers:
pkg-types:
specifier: ^1.1.3
version: 1.1.3
polka:
specifier: ^0.5.2
version: 0.5.2
resolve:
specifier: ^1.22.8
version: 1.22.8
@@ -1643,9 +1640,6 @@ importers:
'@types/object-hash':
specifier: 3.0.6
version: 3.0.6
'@types/polka':
specifier: ^0.5.7
version: 0.5.7
'@types/react':
specifier: ^18.2.48
version: 18.2.48
@@ -2292,10 +2286,6 @@ packages:
'@ark/util@0.46.0':
resolution: {integrity: sha512-JPy/NGWn/lvf1WmGCPw2VGpBg5utZraE84I7wli18EDF3p3zc/e9WolT35tINeZO3l7C77SjqRJeAUoT0CvMRg==}
'@arr/every@1.0.1':
resolution: {integrity: sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==}
engines: {node: '>=4'}
'@aws-crypto/crc32@5.2.0':
resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==}
engines: {node: '>=16.0.0'}
@@ -5539,9 +5529,6 @@ packages:
engines: {node: '>=16'}
hasBin: true
'@polka/url@0.5.0':
resolution: {integrity: sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==}
'@popperjs/core@2.11.8':
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
@@ -7929,9 +7916,6 @@ packages:
'@types/pg@8.6.1':
resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==}
'@types/polka@0.5.7':
resolution: {integrity: sha512-TH8CDXM8zoskPCNmWabtK7ziGv9Q21s4hMZLVYK5HFEfqmGXBqq/Wgi7jNELWXftZK/1J/9CezYa06x1RKeQ+g==}
'@types/prismjs@1.26.0':
resolution: {integrity: sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==}
@@ -8031,9 +8015,6 @@ packages:
'@types/tinycolor2@1.4.3':
resolution: {integrity: sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ==}
'@types/trouter@3.1.4':
resolution: {integrity: sha512-4YIL/2AvvZqKBWenjvEpxpblT2KGO6793ipr5QS7/6DpQ3O3SwZGgNGWezxf3pzeYZc24a2pJIrR/+Jxh/wYNQ==}
'@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
@@ -11734,10 +11715,6 @@ packages:
match-sorter@6.3.4:
resolution: {integrity: sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==}
matchit@1.1.0:
resolution: {integrity: sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==}
engines: {node: '>=6'}
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
@@ -12966,9 +12943,6 @@ packages:
resolution: {integrity: sha512-OLS/0XeUAcE8a2fdwemNja+udKgXNnY6yKVIXqAD2zVRx1KvY6Ato/rZ2vdzbxqYwPW0u6SCNC/bAMPNzpzxbw==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
polka@0.5.2:
resolution: {integrity: sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==}
possible-typed-array-names@1.0.0:
resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
engines: {node: '>= 0.4'}
@@ -14657,10 +14631,6 @@ packages:
trough@2.1.0:
resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==}
trouter@2.0.1:
resolution: {integrity: sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==}
engines: {node: '>=6'}
ts-dedent@2.2.0:
resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==}
engines: {node: '>=6.10'}
@@ -15732,8 +15702,6 @@ snapshots:
'@ark/util@0.46.0': {}
'@arr/every@1.0.1': {}
'@aws-crypto/crc32@5.2.0':
dependencies:
'@aws-crypto/util': 5.2.0
@@ -19780,8 +19748,6 @@ snapshots:
optionalDependencies:
fsevents: 2.3.2
'@polka/url@0.5.0': {}
'@popperjs/core@2.11.8': {}
'@posthog/core@1.29.13':
@@ -22651,13 +22617,6 @@ snapshots:
pg-protocol: 1.10.3
pg-types: 2.2.0
'@types/polka@0.5.7':
dependencies:
'@types/express': 4.17.15
'@types/express-serve-static-core': 4.17.32
'@types/node': 22.20.0
'@types/trouter': 3.1.4
'@types/prismjs@1.26.0': {}
'@types/prop-types@15.7.5': {}
@@ -22773,8 +22732,6 @@ snapshots:
'@types/tinycolor2@1.4.3': {}
'@types/trouter@3.1.4': {}
'@types/trusted-types@2.0.7':
optional: true
@@ -26952,10 +26909,6 @@ snapshots:
'@babel/runtime': 7.24.5
remove-accents: 0.5.0
matchit@1.1.0:
dependencies:
'@arr/every': 1.0.1
math-intrinsics@1.1.0: {}
mdast-util-definitions@5.1.1:
@@ -28645,11 +28598,6 @@ snapshots:
polite-json@5.0.0: {}
polka@0.5.2:
dependencies:
'@polka/url': 0.5.0
trouter: 2.0.1
possible-typed-array-names@1.0.0: {}
postcss-discard-duplicates@5.1.0(postcss@8.5.10):
@@ -30655,10 +30603,6 @@ snapshots:
trough@2.1.0: {}
trouter@2.0.1:
dependencies:
matchit: 1.1.0
ts-dedent@2.2.0: {}
ts-easing@0.2.0: {}