chore(cli): remove --mcp option from trigger dev (#4246)
This commit is contained in:
@@ -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.
|
||||
@@ -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",
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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`);
|
||||
});
|
||||
};
|
||||
Generated
-56
@@ -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: {}
|
||||
|
||||
Reference in New Issue
Block a user