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": "ssu8GdKQEJM3KbGx",
"name": "Adhoc Query",
"description": null,
"active": true,
"isArchived": false,
"nodes": [
{
"parameters": {
"path": "adhoc-query",
"httpMethod": "POST",
"authentication": "none",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook-1",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
240,
300
]
},
{
"parameters": {
"inputSource": "passthrough"
},
"id": "sub-workflow-trigger",
"name": "When Called by Another Workflow",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1.1,
"position": [
240,
480
]
},
{
"parameters": {
"jsCode": "// Support both webhook JSON and MCP chat input\nconst raw = $input.item.json;\n\n// Debug: log what we're receiving\nconsole.log('Raw input:', JSON.stringify(raw, null, 2));\n\n// Check for chatInput at various levels\nif (raw.chatInput) {\n console.log('Found chatInput:', raw.chatInput);\n // Extract query from natural language input\n const match = raw.chatInput.match(/select[\\s\\S]*$/i);\n if (!match) {\n throw new Error('Could not extract SQL query from chat input: ' + raw.chatInput);\n }\n return {\n json: {\n query: match[0].trim(),\n agent: 'mcp',\n description: 'MCP chat query',\n timestamp: new Date().toISOString()\n }\n };\n}\n\n// Check if chatInput is in body or other locations\nif (raw.body && raw.body.chatInput) {\n console.log('Found chatInput in body:', raw.body.chatInput);\n const match = raw.body.chatInput.match(/select[\\s\\S]*$/i);\n if (!match) {\n throw new Error('Could not extract SQL query from chat input: ' + raw.body.chatInput);\n }\n return {\n json: {\n query: match[0].trim(),\n agent: 'mcp',\n description: 'MCP chat query',\n timestamp: new Date().toISOString()\n }\n };\n}\n\n// Otherwise fall back to webhook JSON\nconst body = raw.body || raw;\nconst { query, params = {}, rawSqlParams = {}, agent = 'unknown', description = 'Adhoc query execution' } = body;\n\nif (!query) {\n throw new Error('Query is required. Received: ' + JSON.stringify(raw));\n}\n\n// Simple parameter substitution\nlet processedQuery = query;\nObject.keys(params).forEach(key => {\n const value = params[key];\n const paramPattern = new RegExp(`:${key}\\\\b`, 'g');\n \n if (rawSqlParams[key]) {\n processedQuery = processedQuery.replace(paramPattern, value.toString());\n } else if (typeof value === 'string') {\n processedQuery = processedQuery.replace(paramPattern, `'${value.replace(/'/g, \"''\")}'`);\n } else if (typeof value === 'number') {\n processedQuery = processedQuery.replace(paramPattern, value.toString());\n } else if (Array.isArray(value)) {\n const arrayValues = value.map(v => \n typeof v === 'string' ? `'${v.replace(/'/g, \"''\")}'` : v\n ).join(', ');\n processedQuery = processedQuery.replace(paramPattern, `(${arrayValues})`);\n }\n});\n\n// Basic safety check\nconst dangerousPatterns = [\n /DROP\\s+TABLE/i,\n /DROP\\s+DATABASE/i,\n /TRUNCATE/i\n];\n\nconst isDangerous = dangerousPatterns.some(pattern => pattern.test(processedQuery));\nif (isDangerous) {\n throw new Error('Query contains potentially dangerous operations');\n}\n\nreturn {\n json: {\n query: processedQuery,\n agent: agent,\n description: description,\n timestamp: new Date().toISOString()\n }\n};"
},
"id": "process-query",
"name": "Process Query",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "={{ $('Process Query').item.json.query }}; SHOW WARNINGS",
"options": {}
},
"id": "execute-query",
"name": "Execute Query",
"type": "n8n-nodes-base.mySql",
"typeVersion": 2.5,
"position": [
680,
300
],
"credentials": {
"mySql": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const queryInfo = $('Process Query').item.json;\nconst queryResults = $input.all();\n\n// Check if first result has error object\nif (queryResults.length > 0 && queryResults[0].json.error) {\n return [{\n json: {\n success: false,\n query: queryInfo.query,\n error: queryResults[0].json.message,\n errorCode: queryResults[0].json.error.description?.match(/code: (\\w+)/)?.[1],\n timestamp: new Date().toISOString()\n }\n }];\n}\n\n// Separate main results from warnings\n// Last N items might be warnings (they have Level, Code, Message fields)\nconst warnings = [];\nconst data = [];\n\nqueryResults.forEach(item => {\n if (item.json.Level && item.json.Message) {\n warnings.push(item.json);\n } else {\n data.push(item.json);\n }\n});\n\nreturn [{\n json: {\n success: true,\n query: queryInfo.query,\n agent: queryInfo.agent,\n description: queryInfo.description,\n results: {\n count: data.length,\n data: data\n },\n warnings: warnings.length > 0 ? warnings : undefined,\n timestamp: new Date().toISOString()\n }\n}];"
},
"id": "format-response",
"name": "Format Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
300
]
},
{
"parameters": {
"respondWith": "allIncomingItems",
"options": {}
},
"id": "webhook-response",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
1120,
300
]
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Process Query",
"type": "main",
"index": 0
}
]
]
},
"When Called by Another Workflow": {
"main": [
[
{
"node": "Process Query",
"type": "main",
"index": 0
}
]
]
},
"Process Query": {
"main": [
[
{
"node": "Execute Query",
"type": "main",
"index": 0
}
]
]
},
"Execute Query": {
"main": [
[
{
"node": "Format Response",
"type": "main",
"index": 0
}
]
]
},
"Format Response": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": true,
"timeSavedMode": "fixed",
"timezone": "America/Chicago"
},
"staticData": null,
"versionId": "b209db9f-1c17-438b-abef-74a8a7a9504b",
"createdAt": "2025-12-21 02:17:16.081",
"updatedAt": "2025-12-25 19:16:11.611"
}
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.
mySql
About this workflow
Adhoc Query. Uses executeWorkflowTrigger, mySql, respondToWebhook. Webhook trigger; 6 nodes.
Source: https://github.com/pchambless/wf-monorepo/blob/47cd16469735c59a12b7c76e2552861f899e335d/.n8n/workflows/adhoc-query.json — original creator credit. Request a take-down →