@notbnull/mcp-cursor-taskmaster
Version:
A project-scoped MCP server requiring explicit --project-dir configuration for task management, memory retrieval, and agentic workflows
154 lines • 5.62 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ApprovalUIServer = void 0;
exports.getApprovalUIServer = getApprovalUIServer;
const express_1 = __importDefault(require("express"));
const socket_io_1 = require("socket.io");
const http_1 = require("http");
const path_1 = __importDefault(require("path"));
const timers_1 = require("timers");
class ApprovalUIServer {
app;
server;
io;
port;
pendingApprovals = new Map();
isRunning = false;
constructor(port = 3456) {
this.port = port;
this.app = (0, express_1.default)();
this.server = (0, http_1.createServer)(this.app);
this.io = new socket_io_1.Server(this.server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
},
});
this.setupRoutes();
this.setupSocketHandlers();
}
setupRoutes() {
this.app.use(express_1.default.static(path_1.default.join(__dirname, "../public")));
this.app.use(express_1.default.json());
// Serve the approval UI
this.app.get("/", (req, res) => {
res.sendFile(path_1.default.join(__dirname, "../public/approval.html"));
});
// API endpoint to get pending approvals
this.app.get("/api/pending", (req, res) => {
const pending = Array.from(this.pendingApprovals.entries()).map(([id, data]) => ({
id,
request: data.request,
}));
res.json(pending);
});
}
setupSocketHandlers() {
this.io.on("connection", (socket) => {
console.error("Approval UI: Client connected");
// Send all pending approvals to newly connected client
const pending = Array.from(this.pendingApprovals.entries()).map(([id, data]) => ({
id,
request: data.request,
}));
socket.emit("pending-approvals", pending);
// Handle approval response
socket.on("approval-response", (response) => {
const pending = this.pendingApprovals.get(response.taskId);
if (pending) {
pending.resolve(response);
this.pendingApprovals.delete(response.taskId);
// Notify all clients that this approval is resolved
this.io.emit("approval-resolved", response.taskId);
}
});
socket.on("disconnect", () => {
console.error("Approval UI: Client disconnected");
});
});
}
async start() {
if (this.isRunning)
return;
return new Promise((resolve, reject) => {
this.server
.listen(this.port, () => {
this.isRunning = true;
console.error(`Approval UI server running at http://localhost:${this.port}`);
resolve();
})
.on("error", (err) => {
if (err.code === "EADDRINUSE") {
console.error(`Port ${this.port} is already in use, assuming UI is already running`);
this.isRunning = true;
resolve();
}
else {
reject(err);
}
});
});
}
async stop() {
if (!this.isRunning)
return;
return new Promise((resolve) => {
this.server.close(() => {
this.isRunning = false;
resolve();
});
});
}
async requestApproval(request) {
// Ensure server is running
await this.start();
return new Promise((resolve, reject) => {
// Store the pending approval
this.pendingApprovals.set(request.taskId, {
request,
resolve,
reject,
});
// Notify all connected clients
this.io.emit("new-approval", {
id: request.taskId,
request,
});
// Open the UI in browser if not already open
if (this.pendingApprovals.size === 1) {
import("open")
.then(({ default: open }) => {
open(`http://localhost:${this.port}`).catch(() => {
console.error("Failed to open browser automatically. Please open http://localhost:" +
this.port);
});
})
.catch(() => {
console.error("Failed to load open module. Please open http://localhost:" +
this.port +
" manually");
});
}
// Set a timeout for the approval (5 minutes)
(0, timers_1.setTimeout)(() => {
if (this.pendingApprovals.has(request.taskId)) {
this.pendingApprovals.delete(request.taskId);
reject(new Error("Approval timeout"));
}
}, 5 * 60 * 1000);
});
}
}
exports.ApprovalUIServer = ApprovalUIServer;
// Singleton instance
let approvalUIServer = null;
function getApprovalUIServer() {
if (!approvalUIServer) {
approvalUIServer = new ApprovalUIServer();
}
return approvalUIServer;
}
//# sourceMappingURL=approval-ui.js.map