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 →
{
"meta": {
"templateCredsSetupCompleted": false,
"description": "Strategy Radar v0.3 \u2014 MCP Draft Writer\n\nExposes a single MCP tool 'write_draft_brief' that the analyst's Claude Code (using their Claude Max subscription, NO Anthropic API key) can call to write a generated draft sector brief to the Strategy Radar app.\n\nDifference from the 18-node analysis-automation workflow: the LLM analysis (PDF extraction, opener generation, observations + actions) happens entirely in Claude Code on the analyst's machine. n8n is just the persistence hop: receive structured fields via MCP \u2192 HMAC-sign \u2192 POST /api/admin/briefs/from-n8n.\n\nSETUP:\n1. Workflow \u2192 Settings \u2192 Static Data, add:\n - N8N_CALLBACK_SECRET: same HMAC value as N8N_CALLBACK_SECRET in src/.env.local\n - APP_CALLBACK_URL: full URL to your app's endpoint, e.g.\n https://<ngrok-id>.ngrok.app/api/admin/briefs/from-n8n\n (n8n Cloud cannot reach localhost \u2014 use ngrok or a deployed app URL.)\n2. Activate the workflow.\n3. Click the MCP Server Trigger node \u2192 copy the MCP server URL + auth token.\n4. In your terminal:\n claude mcp add strategy-radar <mcp-url> --header \"Authorization: Bearer <token>\"\n5. Verify: claude mcp list \u2192 'strategy-radar' should be listed.\n6. Test by attaching a publication PDF in a Claude Code session and asking for a draft brief.\n\nIF THE MCP SERVER TRIGGER NODE DOES NOT IMPORT CLEANLY:\nDelete the imported trigger and drag a fresh 'MCP Server Trigger' (under AI / LangChain category) onto the canvas. Configure the tool 'write_draft_brief' with the JSON schema documented below. Connect its main output to 'Compose Draft' and the rest of the chain stays intact.\n\nINPUT SCHEMA FOR write_draft_brief (Claude Code passes these):\n - naceDivision (string) e.g., '31' or '49'\n - openerMarkdown (string) 200\u2013400 word Czech opener\n - publicationBodyMarkdown (string, optional) full Markdown of the analysed text\n - observations (array) 3 items: {title, body}\n - closingActions (array) 3 items: {title, body, time_horizon: '1m'|'3m'|'6-12m'}\n - jobId (string, optional) generated if absent\n\nPRIVACY: this workflow does not persist any payload. Configure n8n Cloud retention policy to match."
},
"name": "Strategy Radar \u2014 MCP Draft Writer",
"nodes": [
{
"parameters": {
"path": "strategy-radar-draft",
"tools": [
{
"name": "write_draft_brief",
"description": "Write a draft sector brief to the Strategy Radar admin DB. Use this AFTER you have read the publication, generated a Czech-language opener (200\u2013400 words), 3 paired observations, and 3 paired actions with time-horizon tags. The draft will land at /admin in the app for analyst review and publish.",
"inputSchema": {
"type": "object",
"properties": {
"naceDivision": {
"type": "string",
"description": "Two-digit NACE division code, e.g. '31' (furniture) or '49' (freight)."
},
"openerMarkdown": {
"type": "string",
"description": "Lay-person sector summary in Czech, 200\u2013400 words. Goes into the brief's 'Sektorov\u00e1 anal\u00fdza' opener block."
},
"publicationBodyMarkdown": {
"type": "string",
"description": "Full Markdown of the source publication (optional). Stored as the brief's full_text_markdown."
},
"observations": {
"type": "array",
"minItems": 1,
"maxItems": 6,
"items": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"body": {
"type": "string"
}
},
"required": [
"title",
"body"
]
}
},
"closingActions": {
"type": "array",
"minItems": 1,
"maxItems": 6,
"items": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"body": {
"type": "string"
},
"time_horizon": {
"type": "string",
"enum": [
"1m",
"3m",
"6-12m"
]
}
},
"required": [
"title",
"body",
"time_horizon"
]
}
},
"jobId": {
"type": "string",
"description": "Optional correlation ID. If omitted, the workflow generates one."
}
},
"required": [
"naceDivision",
"openerMarkdown",
"observations",
"closingActions"
]
}
}
]
},
"id": "node-mcp-trigger",
"name": "MCP Server Trigger",
"type": "@n8n/n8n-nodes-langchain.mcpTrigger",
"typeVersion": 1,
"position": [
240,
300
]
},
{
"parameters": {
"jsCode": "// Compose the final draft payload per the n8n callback contract.\n// Same callback schema as the 18-node analysis-automation workflow's Compose Draft.\n// Difference: input fields come directly from the MCP tool call (Claude Code)\n// instead of being assembled from upstream HTTP/Code nodes.\n\nconst data = $input.first().json;\n\n// Generate a job_id if Claude Code didn't supply one.\nconst jobId = data.jobId || `mcp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n\n// Czech month-year string for title + publication.heading metadata\nconst now = new Date();\nconst czechMonths = ['Leden','\u00danor','B\u0159ezen','Duben','Kv\u011bten','\u010cerven','\u010cervenec','Srpen','Z\u00e1\u0159\u00ed','\u0158\u00edjen','Listopad','Prosinec'];\nconst publicationMonth = `${czechMonths[now.getMonth()]} ${now.getFullYear()}`;\nconst isoMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;\n\nconst draft = {\n title: `Sektorov\u00e1 anal\u00fdza \u2014 NACE ${data.naceDivision} \u2014 ${publicationMonth}`,\n publication_month: isoMonth,\n publication: {\n heading: 'Sektorov\u00e1 anal\u00fdza',\n opener_markdown: data.openerMarkdown,\n full_text_markdown: data.publicationBodyMarkdown || '',\n source: `Ekonomick\u00e9 a strategick\u00e9 anal\u00fdzy \u010cesk\u00e9 spo\u0159itelny \u2014 ${publicationMonth}`,\n },\n observations: data.observations,\n closing_actions: data.closingActions,\n};\n\nconst callbackPayload = {\n jobId,\n status: 'done',\n draft,\n};\n\n// Read callback URL from Static Data so Claude Code doesn't need to know it.\nconst workflowData = $getWorkflowStaticData('global');\nconst callbackUrl = workflowData.APP_CALLBACK_URL || '';\nif (!callbackUrl) {\n throw new Error('APP_CALLBACK_URL is not configured. Set it in workflow Static Data.');\n}\n\nreturn [{\n json: { callbackUrl, callbackPayload, jobId }\n}];"
},
"id": "node-compose-draft",
"name": "Compose Draft",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
]
},
{
"parameters": {
"jsCode": "// Sign the callback payload with HMAC-SHA256 using N8N_CALLBACK_SECRET.\n// Same logic as the 18-node workflow's Sign Callback node \u2014 produces the\n// X-Signature-256 header value the app's /api/admin/briefs/from-n8n route\n// validates before accepting the draft.\nconst crypto = require('crypto');\n\nconst workflowData = $getWorkflowStaticData('global');\nconst secret = workflowData.N8N_CALLBACK_SECRET || process.env.N8N_CALLBACK_SECRET || '';\n\nif (!secret) {\n throw new Error('N8N_CALLBACK_SECRET is not configured. Set it in workflow Static Data.');\n}\n\nconst data = $input.first().json;\nconst bodyStr = JSON.stringify(data.callbackPayload);\nconst sig = crypto.createHmac('sha256', secret).update(bodyStr, 'utf8').digest('hex');\n\nreturn [{\n json: {\n callbackUrl: data.callbackUrl,\n callbackBody: bodyStr,\n signatureHeader: `sha256=${sig}`,\n jobId: data.jobId,\n }\n}];"
},
"id": "node-sign-callback",
"name": "Sign Callback",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
300
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $json.callbackUrl }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "X-Signature-256",
"value": "={{ $json.signatureHeader }}"
}
]
},
"sendBody": true,
"specifyBody": "string",
"body": "={{ $json.callbackBody }}",
"options": {
"timeout": 30000,
"response": {
"response": {
"neverError": true,
"responseFormat": "json"
}
}
}
},
"id": "node-send-callback",
"name": "Send Callback",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
900,
300
]
},
{
"parameters": {
"jsCode": "// Format the MCP tool's return value for Claude Code.\n// Inspect the HTTP response from /api/admin/briefs/from-n8n and convert\n// to a structured success/failure payload that Claude Code can interpret.\n\nconst input = $input.first();\nconst data = input.json;\nconst statusCode = data.statusCode ?? data.statusCode2 ?? 200;\nconst jobId = $('Sign Callback').first().json.jobId;\n\nconst body = data.body || data;\n\nif (statusCode >= 200 && statusCode < 300) {\n return [{\n json: {\n success: true,\n jobId,\n message: `Draft brief written. Job ID: ${jobId}. Open /admin in the browser to review and publish.`,\n appResponse: body,\n }\n }];\n}\n\nreturn [{\n json: {\n success: false,\n jobId,\n statusCode,\n error: `Callback POST failed with status ${statusCode}.`,\n appResponse: body,\n }\n}];"
},
"id": "node-format-response",
"name": "Format Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1120,
300
]
}
],
"connections": {
"MCP Server Trigger": {
"main": [
[
{
"node": "Compose Draft",
"type": "main",
"index": 0
}
]
]
},
"Compose Draft": {
"main": [
[
{
"node": "Sign Callback",
"type": "main",
"index": 0
}
]
]
},
"Sign Callback": {
"main": [
[
{
"node": "Send Callback",
"type": "main",
"index": 0
}
]
]
},
"Send Callback": {
"main": [
[
{
"node": "Format Response",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"active": false,
"versionId": "1",
"id": "strategy-radar-mcp-draft-writer"
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Strategy Radar — MCP Draft Writer. Uses mcpTrigger, httpRequest. Event-driven trigger; 5 nodes.
Source: https://github.com/pdeaibootcamp-netizen/saap/blob/e77ec1fef11bfc08421a84b49e5ac73812a903c4/n8n-workflows/mcp-draft-writer.json — 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 n8n implementation, though not as fully featured as the official MCP server offered by Github, allows you to control precisely what access and/or functionality is granted to users which can make
3635. Uses executeWorkflowTrigger, mcpTrigger, toolWorkflow, httpRequest. Event-driven trigger; 19 nodes.
This workflow automates SEO analysis by comparing your website with a competitor’s site. It reads input URLs from Google Sheets, scrapes structured SEO data from both sites, and expands into important
Need help? Want access to this workflow + many more paid workflows + live Q&A sessions with a top verified n8n creator?
Spot Workplace Discrimination Patterns with AI. Uses manualTrigger, lmChatOpenAi, httpRequest, html. Event-driven trigger; 38 nodes.