twitter-mcp / server.js
uhave's picture
server.js
4aac4d3 verified
import express from "express";
import puppeteer from "puppeteer";
import fs from "fs";
import path from "path";
const app = express();
app.use(express.json());
const cookiesPath = path.resolve("./cookies.json");
app.post("/tweet", async (req, res) => {
const { tweetText, imagePath, username, password } = req.body;
if (!tweetText || !imagePath) {
return res.status(400).json({ error: "Missing parameters" });
}
const browser = await puppeteer.launch({
headless: true,
args: ["--no-sandbox", "--disable-setuid-sandbox"],
});
try {
const page = await browser.newPage();
if (fs.existsSync(cookiesPath)) {
const cookiesString = fs.readFileSync(cookiesPath, "utf8");
const cookies = JSON.parse(cookiesString);
await page.setCookie(...cookies);
console.log("βœ… cookies loaded");
}
await page.goto("https://twitter.com/home", { waitUntil: "networkidle2" });
if (await page.$('input[name="text"]')) {
if (!username || !password) {
return res.status(403).json({ error: "cookies expired, please provide username/password" });
}
console.log("πŸ” need login");
await page.type('input[name="text"]', username, {delay: 100});
await page.keyboard.press('Enter');
await page.waitForTimeout(2000);
await page.waitForSelector('input[name="password"]', {timeout: 60000});
await page.type('input[name="password"]', password, {delay: 100});
await page.keyboard.press('Enter');
await page.waitForNavigation({waitUntil: 'networkidle2'});
const cookies = await page.cookies();
fs.writeFileSync(cookiesPath, JSON.stringify(cookies, null, 2));
console.log("βœ… cookies saved");
}
await page.waitForSelector('a[aria-label="Post"]', { timeout: 60000 });
await page.click('a[aria-label="Post"]');
await page.waitForSelector('div[aria-label="Tweet text"]');
await page.type('div[aria-label="Tweet text"]', tweetText);
const [fileChooser] = await Promise.all([
page.waitForFileChooser(),
page.click('div[aria-label="Add photos or video"]')
]);
await fileChooser.accept([imagePath]);
await page.waitForTimeout(3000);
await page.click('div[data-testid="tweetButtonInline"]');
await browser.close();
res.json({ success: true, message: "Tweet posted" });
} catch (err) {
console.error(err);
await browser.close();
res.status(500).json({ error: err.message });
}
});
app.get("/", (_, res) => {
res.send("βœ… MCP Puppeteer Twitter server is running");
});
app.listen(7860, () => {
console.log("βœ… MCP server on port 7860");
});