8
n8n 中文网amn8n.com

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
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 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)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量16
分类3
节点类型11
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

作者
Dayong Huang

Dayong Huang

@dayonghuang

Developer of mcphub.com. Use mcp to automate LLM tool call!

外部链接
在 n8n.io 查看

分享此工作流