run-background-task
Execute long-running shell commands in the background, enabling continued interaction with the process through compatible tools while it runs.
Instructions
Runs a long-running command (like 'npm run dev') in background. When the command is running, you can interact with it using other tools.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Unique name of the task | |
| shell | Yes | Shell command to run in background |
Implementation Reference
- src/index.ts:85-102 (handler)The main handler function for the 'run-background-task' tool. It checks if a task with the given name is already running, creates a new Child process with the provided shell command, stores it in the processes map, and returns a confirmation message with the PID.async ({ name, shell }) => { if (processes.has(name)) { throw new Error(`Task with name "${name}" is already running.`); } const child = new Child(shell); processes.set(name, child); return { content: [ { type: "text", text: `Task "${name}" started with PID ${child.getPid()}.`, }, ], }; }
- src/index.ts:80-83 (schema)Zod input schema defining the parameters for the tool: 'name' (unique task name) and 'shell' (command to run).inputSchema: { name: z.string().describe("Unique name of the task"), shell: z.string().describe("Shell command to run in background"), },
- src/index.ts:74-103 (registration)Registration of the 'run-background-task' tool on the MCP server, including name, metadata (title, description), input schema, and handler function.server.registerTool( "run-background-task", { title: "Run Background Task", description: "Runs a long-running command (like 'npm run dev') in background. When the command is running, you can interact with it using other tools.", inputSchema: { name: z.string().describe("Unique name of the task"), shell: z.string().describe("Shell command to run in background"), }, }, async ({ name, shell }) => { if (processes.has(name)) { throw new Error(`Task with name "${name}" is already running.`); } const child = new Child(shell); processes.set(name, child); return { content: [ { type: "text", text: `Task "${name}" started with PID ${child.getPid()}.`, }, ], }; } );
- src/index.ts:6-63 (helper)Child class that wraps a Node.js child process, capturing stdout/stderr, providing methods to interact with it (get output, state, PID, write to stdin, kill), used by the background task handler.class Child { process: childProcess.ChildProcess; state: "running" | "stopped" = "running"; stopCode: number | null = null; stdout: string = ""; stderr: string = ""; constructor(shell: string) { const child = childProcess.spawn(shell, { shell: true, }); child.stdout?.on("data", (data) => { this.stdout += data.toString(); }); child.stderr?.on("data", (data) => { this.stderr += data.toString(); }); child.on("exit", (code) => { this.state = "stopped"; this.stopCode = code; }); this.process = child; } public getStdout(): string { return this.stdout; } public getStderr(): string { return this.stderr; } public getState(): "running" | "stopped" { return this.state; } public getStopCode(): number | null { return this.stopCode; } public getPid(): number { return this.process.pid || -1; } public writeToStdin(data: string): void { if (this.process.stdin) { this.process.stdin.write(data); } else { throw new Error("Child process stdin is not available."); } } public kill(): void { if (this.process.killed) { return; } this.process.kill(); this.state = "stopped"; } }