This workflow corresponds to n8n.io template #8267 — we link there as the canonical source.
This workflow follows the Agent → OpenAI Chat recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "8BcTtr8AdLgBa23S",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "twitter_mcp_post_scheduler",
"tags": [],
"nodes": [
{
"id": "dd350044-eff4-40b7-bbe8-aaf95d17e019",
"name": "Format Results1",
"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": "Loop Over Items",
"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 \u2192 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 \u201cwhy it\u2019s trending\u201d 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 \u201cwhy now\u201d (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 \u201cunknown reason\u201d summary.\n\nSteps\n1) CALL `aigeon-ai-twitter154.search_tweets` with the trend name as the query (recent timeframe).\n2) Synthesize a 1\u20132 sentence summary (\u224830\u201360 words) explaining why it\u2019s 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\u201360 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 Client",
"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": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "862a8930-0f27-4e51-b662-c28b9240c5f7",
"name": "Send a message",
"type": "n8n-nodes-base.slack",
"position": [
1680,
-112
],
"parameters": {
"text": "={{ $json.output }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "#mcp-hub-test"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "427bb5ba-2ba0-4444-89ab-4488b3e874ce",
"name": "Wait",
"type": "n8n-nodes-base.wait",
"position": [
2640,
304
],
"parameters": {},
"typeVersion": 1.1
},
{
"id": "baa30922-1058-41d7-a394-cd1f1a9fb48a",
"name": "OpenAI Chat Model",
"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": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "bf43e456-b478-4038-a1b4-f2b05dddc5c6",
"name": "AI Agent Preprocess",
"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 \u2192 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 \u2022 lowercase \u2022 strip leading \u201c#\u201d \u2022 trim \u2022 collapse spaces \u2022 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 \u2022 clear moments happening now (games, finals, premieres, elections, announcements, releases, controversies, breaking news)\n \u2022 specific & recognizable entities over generic tags\n \u2022 conversation-friendly, broad-interest communities\n \u2022 distinct items (avoid near-duplicates)\n \u2022 brand-safe topics (skip NSFW/harassment)\n\n Heuristics (guidance, not rules):\n \u2022 +3 specific event/entity signals (e.g., \u201cTeam A vs Team B\u201d, \u201cFinale\u201d, \u201cKickoff\u201d, \u201cTrailer\u201d, \u201cAlbum\u201d, \u201cBox Office\u201d)\n \u2022 +2 strong recognizability (proper-noun phrases, league/team/celebrity names)\n \u2022 +1 recency cues in top tweets (today/tonight/just announced) if visible via the search URL/metadata\n \u2022 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 \u2022 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 \u2022 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 Chat Model1",
"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": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "5715d5af-7b63-4e92-99a8-b0a87a2b3dcf",
"name": "MCP Client1",
"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": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "c40a0864-3376-43db-bc02-46e3069e33a2",
"name": "Execute a SQL query",
"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": {
"name": "<your credential>"
}
},
"typeVersion": 2.5
},
{
"id": "9209ade7-5c70-452d-a832-9770a0691038",
"name": "Execute a SQL query1",
"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": {
"name": "<your credential>"
}
},
"typeVersion": 2.5
},
{
"id": "b891d9e0-1501-46b2-8a5f-17997b65eae6",
"name": "Schedule Trigger",
"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": "Wait1",
"type": "n8n-nodes-base.wait",
"position": [
2080,
-736
],
"parameters": {},
"typeVersion": 1.1
},
{
"id": "903b774d-3b3a-4a24-b3fb-ae1e5a668f13",
"name": "Create Tweet",
"type": "n8n-nodes-base.twitter",
"position": [
2864,
-192
],
"parameters": {
"text": "={{ $json.trend }}: {{ $json.summary }}",
"additionalFields": {}
},
"credentials": {
"twitterOAuth2Api": {
"name": "<your credential>"
}
},
"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,
"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
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
httpHeaderAuthmySqlopenAiApislackOAuth2ApitwitterOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This template creates a fully automated Twitter content system that discovers trending topics, analyzes why they're trending using AI, and posts intelligent commentary about them.
Source: https://n8n.io/workflows/8267/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow automates the entire lifecycle of social media management—from fetching draft content to AI-driven optimization and multi-platform publishing.
This workflow automatically monitors multiple websites using AI-powered analysis and MCP (Model Context Protocol) tools. The system runs scheduled checks, analyzes website performance and security usi
Stop spending hours manually pulling paid ads data. This workflow connects to Databox via MCP, auto-discovers every connected paid platform, fetches 6 key metrics, and delivers a consolidated weekly r
This workflow is for beauty salons who want consistent, high‑quality social media content without writing every post manually. It also suits agencies and automation builders who manage multiple beauty
Created by: Peyton Leveillee Last updated: October 2025