Twitter MCP发布调度器
高级
这是一个Miscellaneous, AI RAG, Multimodal AI领域的自动化工作流,包含 16 个节点。主要使用 Code, Wait, MySql, Slack, Twitter 等节点。 使用OpenAI GPT和MCP进行趋势分析,自动化Twitter内容发布
前置要求
- •MySQL 数据库连接信息
- •Slack Bot Token 或 Webhook URL
- •Twitter API 凭证
- •OpenAI API Key
使用的节点 (16)
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "8BcTtr8AdLgBa23S",
"meta": {
"instanceId": "9c51453afbec31d8209fd304a1a3e6af1fb4621ca939ac8364a6b6d4aeed48c1",
"templateCredsSetupCompleted": true
},
"name": "twitter_mcp_post_scheduler",
"tags": [],
"nodes": [
{
"id": "dd350044-eff4-40b7-bbe8-aaf95d17e019",
"name": "格式化结果1",
"type": "n8n-nodes-base.function",
"position": [
720,
-128
],
"parameters": {
"functionCode": "// Get the raw array of names from the AI Agent\nlet arr = items[0].json.output;\n\n// If it's a stringified array, parse it\nif (typeof arr === 'string') {\n arr = JSON.parse(arr);\n}\n\n// Ensure it's an array\nif (!Array.isArray(arr)) {\n return [];\n}\n\n// Return one item per trend name\nreturn arr.map(name => ({ json: { name } }));\n"
},
"typeVersion": 1
},
{
"id": "b60238c7-03b5-4a5b-84ca-c01e2cd3af93",
"name": "遍历项目",
"type": "n8n-nodes-base.splitInBatches",
"position": [
896,
144
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "deb12dad-4c08-4310-8dd2-46c1615eaaed",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1184,
-112
],
"parameters": {
"text": "=You are an AI agent with access to ONE MCP server:\n- Twitter Search → aigeon-ai-twitter154.search_tweets\n\nINPUT (from workflow)\nTrend name: {{ $json.name }}\n\nGoal\nSearch recent tweets for the given trend name and produce a concise, brand-safe “why it’s trending” summary. Do not generate or request any images.\n\nRules\n- Make at most ONE tool call.\n- Use the INPUT trend name verbatim as the query (no expansions).\n- Focus on “why now” (current event, game, release, announcement, controversy, etc.).\n- Keep it readable for a general audience; no hashtags, emojis, or @usernames.\n- Include concrete details if available; do NOT fabricate.\n- If the input is empty after trimming, skip the tool call and return the JSON with a brief “unknown reason” summary.\n\nSteps\n1) CALL `aigeon-ai-twitter154.search_tweets` with the trend name as the query (recent timeframe).\n2) Synthesize a 1–2 sentence summary (≈30–60 words) explaining why it’s trending.\n\nOutput (STRICT)\nReturn ONLY this JSON object (no prose, no extra keys, no markdown fences):\n\n{\n \"trend\": \"{{ $json.name }}\",\n \"summary\": \"<your concise explanation in 30–60 words>\",\n \"search_url\": \"https://x.com/search?q={{ encodeURIComponent($json.name) }}\",\n \"image_url\": null,\n \"image_prompt\": null,\n \"aspect_ratio\": \"16:9\"\n}\n",
"options": {},
"promptType": "define"
},
"typeVersion": 2.2
},
{
"id": "2dff454b-a58a-4303-9e5b-dafd635250a7",
"name": "MCP 客户端",
"type": "@n8n/n8n-nodes-langchain.mcpClientTool",
"position": [
1328,
304
],
"parameters": {
"endpointUrl": "https://amber.mcpreview.com/slug/aigeon-ai-twitter154",
"authentication": "headerAuth",
"serverTransport": "httpStreamable"
},
"credentials": {
"httpHeaderAuth": {
"id": "DNAG7Ji5OdnS7oBi",
"name": "Header Auth account"
}
},
"typeVersion": 1.1
},
{
"id": "862a8930-0f27-4e51-b662-c28b9240c5f7",
"name": "发送消息",
"type": "n8n-nodes-base.slack",
"position": [
1680,
-112
],
"webhookId": "ae669a44-f283-42b3-9cea-6f0b0febe4da",
"parameters": {
"text": "={{ $json.output }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "#mcp-hub-test"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"id": "CbAz3Qd1iNJhMuNj",
"name": "Slack account"
}
},
"typeVersion": 2.3
},
{
"id": "427bb5ba-2ba0-4444-89ab-4488b3e874ce",
"name": "等待",
"type": "n8n-nodes-base.wait",
"position": [
2640,
304
],
"webhookId": "adf20b2f-acdc-49b1-96c5-7c57a18ea1cd",
"parameters": {},
"typeVersion": 1.1
},
{
"id": "baa30922-1058-41d7-a394-cd1f1a9fb48a",
"name": "OpenAI 聊天模型",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1184,
288
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini",
"cachedResultName": "gpt-5-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "Kca9177CPSlzNiHg",
"name": "Cooper Openai"
}
},
"typeVersion": 1.2
},
{
"id": "bf43e456-b478-4038-a1b4-f2b05dddc5c6",
"name": "AI 智能体预处理",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
208,
-128
],
"parameters": {
"text": "=You are an AI agent with access to ONE MCP server:\n- Twitter trends → get-trends-near-location\n\nINPUT from workflow\nEXCLUDE (JSON array of normalized forms): {{ JSON.stringify($json.exclude || []) }}\n\nPrimary goal\nReturn the most conversation-worthy U.S. trend. Cross-run suppression is handled in MySQL, but you must also avoid any trend whose normalized form appears in EXCLUDE.\n\nTask\n1) CALL `get-trends-near-location` with WOEID 23424977 (United States). The tool may return an array of items like:\n { name, url, query, tweet_volume|null, ... }. Handle missing fields gracefully.\n\n2) Internally normalize names for comparison ONLY:\n • lowercase • strip leading “#” • trim • collapse spaces • remove surrounding punctuation/symbols\n\n3) Filter out any item whose normalized form is present in EXCLUDE.\n\n4) Score remaining items by ENGAGEMENT POTENTIAL (not just tweet volume). Treat tweet_volume=null as UNKNOWN (do NOT treat as 0). Prefer:\n • clear moments happening now (games, finals, premieres, elections, announcements, releases, controversies, breaking news)\n • specific & recognizable entities over generic tags\n • conversation-friendly, broad-interest communities\n • distinct items (avoid near-duplicates)\n • brand-safe topics (skip NSFW/harassment)\n\n Heuristics (guidance, not rules):\n • +3 specific event/entity signals (e.g., “Team A vs Team B”, “Finale”, “Kickoff”, “Trailer”, “Album”, “Box Office”)\n • +2 strong recognizability (proper-noun phrases, league/team/celebrity names)\n • +1 recency cues in top tweets (today/tonight/just announced) if visible via the search URL/metadata\n • TIE-BREAKERS ONLY: when two candidates are otherwise close, prefer the one with a non-null tweet_volume; if both have volume, prefer the higher.\n\n Exclude/penalize:\n • overly generic tags (#news, #breaking), single emojis, day-of-week only, spammy promos.\n\n5) Select exactly ONE trend name with the highest overall score.\n • If no viable item remains, return an empty list. Do NOT fabricate.\n\nOutput (STRICT)\nReturn ONLY a JSON array of strings with the final human-friendly name(s). No prose, counts, or extra fields.\nExample: [\"Cracker Barrel\"]\n",
"options": {},
"promptType": "define"
},
"typeVersion": 2.2
},
{
"id": "45a35c06-c201-40a4-a058-c864afc3e8fb",
"name": "OpenAI 聊天模型1",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
176,
128
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini",
"cachedResultName": "gpt-4.1-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "Kca9177CPSlzNiHg",
"name": "Cooper Openai"
}
},
"typeVersion": 1.2
},
{
"id": "5715d5af-7b63-4e92-99a8-b0a87a2b3dcf",
"name": "MCP 客户端1",
"type": "@n8n/n8n-nodes-langchain.mcpClientTool",
"position": [
352,
144
],
"parameters": {
"endpointUrl": "https://amber.mcpreview.com/slug/aigeon-ai-twitter154",
"authentication": "headerAuth",
"serverTransport": "httpStreamable"
},
"credentials": {
"httpHeaderAuth": {
"id": "DNAG7Ji5OdnS7oBi",
"name": "Header Auth account"
}
},
"typeVersion": 1.1
},
{
"id": "c40a0864-3376-43db-bc02-46e3069e33a2",
"name": "执行 SQL 查询",
"type": "n8n-nodes-base.mySql",
"position": [
2144,
-272
],
"parameters": {
"query": "INSERT INTO keyword_registry\n (platform, locale, raw_keyword, canon, status, published_at, publish_payload, next_eligible_at)\nVALUES (\n $1, -- platform\n $2, -- locale\n $3, -- raw_keyword (trend)\n $4, -- canon\n 'published',\n NOW(),\n JSON_OBJECT(\n 'trend', $3,\n 'summary', $5,\n 'search_url', $6,\n 'image_url', NULL,\n 'image_prompt', NULL,\n 'aspect_ratio', COALESCE($7, '16:9'),\n 'slack', JSON_OBJECT(\n 'channel', $8,\n 'ts', $9,\n 'message_timestamp', $10\n )\n ),\n DATE_ADD(NOW(), INTERVAL 3 DAY)\n)\nON DUPLICATE KEY UPDATE\n last_seen = CURRENT_TIMESTAMP,\n status = 'published',\n published_at = NOW(),\n publish_payload = VALUES(publish_payload),\n next_eligible_at = DATE_ADD(NOW(), INTERVAL 3 DAY);\n",
"options": {
"queryReplacement": "={{ [\n $json.platform || 'twitter', // $1\n $json.locale || 'US', // $2\n $json.trend,\n ($json.canon ??\n String($json.trend || '')\n .normalize('NFKC')\n .toLowerCase()\n .replace(/^#+/, '')\n .replace(/\\s+/g, ' ')\n .trim()\n ), // $4 (canon)\n $json.summary, // $5\n $json.search_url, // $6\n $json.aspect_ratio || '16:9', // $7\n ($json.channel ?? $json.message?.channel), // $8\n ($json.message?.ts ?? $json.ts ?? null), // $9\n ($json.message_timestamp ?? null) // $10\n] }}\n"
},
"operation": "executeQuery"
},
"credentials": {
"mySql": {
"id": "kqvrRLnX254pfQhm",
"name": "MySQL account"
}
},
"typeVersion": 2.5
},
{
"id": "9209ade7-5c70-452d-a832-9770a0691038",
"name": "执行 SQL 查询1",
"type": "n8n-nodes-base.mySql",
"position": [
-48,
-112
],
"parameters": {
"query": "SELECT\n CAST(CONCAT(\n '[',\n IFNULL(GROUP_CONCAT(JSON_QUOTE(canon)\n ORDER BY published_at DESC\n SEPARATOR ','), ''),\n ']'\n ) AS JSON) AS exclude\nFROM (\n SELECT canon, published_at\n FROM keyword_registry\n WHERE platform = $1\n AND locale = $2\n AND status = 'published'\n AND next_eligible_at > NOW() -- still in the 3-day window\n ORDER BY published_at DESC\n LIMIT 30\n) AS t;\n",
"options": {
"queryReplacement": "={{ [ 'twitter', 'US' ] }}"
},
"operation": "executeQuery"
},
"credentials": {
"mySql": {
"id": "kqvrRLnX254pfQhm",
"name": "MySQL account"
}
},
"typeVersion": 2.5
},
{
"id": "b891d9e0-1501-46b2-8a5f-17997b65eae6",
"name": "计划触发器",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-352,
-128
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 2,
"triggerAtMinute": 12
}
]
}
},
"typeVersion": 1.2
},
{
"id": "bd1341ee-dcd6-45cb-9b43-f986be70634f",
"name": "等待1",
"type": "n8n-nodes-base.wait",
"position": [
2080,
-736
],
"webhookId": "0c0a6cd3-b2cd-4ea7-85ba-3b38f901c572",
"parameters": {},
"typeVersion": 1.1
},
{
"id": "903b774d-3b3a-4a24-b3fb-ae1e5a668f13",
"name": "创建推文",
"type": "n8n-nodes-base.twitter",
"position": [
2864,
-192
],
"parameters": {
"text": "={{ $json.trend }}: {{ $json.summary }}",
"additionalFields": {}
},
"credentials": {
"twitterOAuth2Api": {
"id": "X7FXukmqV03ghtzN",
"name": "X account Ella.m@newsbreak.com"
}
},
"typeVersion": 2
},
{
"id": "d8411ea5-95c6-4c76-8af8-f35d279c84cb",
"name": "keyword_formatter",
"type": "n8n-nodes-base.code",
"position": [
1504,
-480
],
"parameters": {
"jsCode": "let o = $json.output;\nif (typeof o === 'string') {\n try { o = JSON.parse(o); } catch { o = {}; }\n}\nconst trend = o.trend ?? '';\nconst canon = trend\n .normalize('NFKC')\n .toLowerCase()\n .replace(/^#+/,'')\n .replace(/\\s+/g,' ')\n .trim();\n\nreturn [{\n json: {\n platform: 'twitter',\n locale: 'US',\n ...o, // trend, summary, search_url, etc.\n canon\n }\n}];\n"
},
"typeVersion": 2
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "f87d8268-70b1-4e5b-9111-c280b354b3b8",
"connections": {
"Wait": {
"main": [
[]
]
},
"Wait1": {
"main": [
[
{
"node": "Create Tweet",
"type": "main",
"index": 0
}
]
]
},
"AI Agent": {
"main": [
[
{
"node": "Send a message",
"type": "main",
"index": 0
},
{
"node": "keyword_formatter",
"type": "main",
"index": 0
}
]
]
},
"MCP Client": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"MCP Client1": {
"ai_tool": [
[
{
"node": "AI Agent Preprocess",
"type": "ai_tool",
"index": 0
}
]
]
},
"Create Tweet": {
"main": [
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
},
"Send a message": {
"main": [
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
},
"Format Results1": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Execute a SQL query1",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"keyword_formatter": {
"main": [
[
{
"node": "Wait1",
"type": "main",
"index": 0
},
{
"node": "Execute a SQL query",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model1": {
"ai_languageModel": [
[
{
"node": "AI Agent Preprocess",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AI Agent Preprocess": {
"main": [
[
{
"node": "Format Results1",
"type": "main",
"index": 0
}
]
]
},
"Execute a SQL query": {
"main": [
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
},
"Execute a SQL query1": {
"main": [
[
{
"node": "AI Agent Preprocess",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 杂项, AI RAG 检索增强, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
jekyll-autopost
Jekyll SEO 博客发布,集成 GPT-4、GitHub 和社交分享
Code
Wait
Github
+10
14 节点Antonio Trento
内容创作
使用GPT-4、Google搜索API和Slack自动化新闻发现与发布
使用GPT-4、Google搜索API和Slack自动化新闻发现与发布
Code
Slack
Http Request
+7
14 节点Kalyxi Ai
杂项
Wordpress 文章
基于Google Trends、GPT-4、Pexels和WordPress的自动化博客发布
Set
Xml
Code
+8
20 节点Cojocaru David
内容创作
每日 WhatsApp 群组智能分析:GPT-4.1 分析与语音消息转录
每日 WhatsApp 群组智能分析:GPT-4.1 分析与语音消息转录
If
Set
Code
+20
52 节点Daniel Lianes
杂项
在可视化参考库中探索n8n节点
在可视化参考库中探索n8n节点
If
Ftp
Set
+93
113 节点I versus AI
其他
💥 使用VEO 3生成AI病毒视频并上传到TikTok
使用VEO 3生成AI病毒视频并上传到TikTok
Set
Code
Wait
+9
24 节点Dr. Firas
内容创作