mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-06 21:43:07 +00:00
feat: implement AI-optimized MCP tools with 95% size reduction
- Add get_node_essentials tool for 10-20 essential properties only - Add search_node_properties for targeted property search - Add get_node_for_task with 14 pre-configured templates - Add validate_node_config for comprehensive validation - Add get_property_dependencies for visibility analysis - Implement PropertyFilter service with curated essentials - Implement ExampleGenerator with working examples - Implement TaskTemplates for common workflows - Implement ConfigValidator with security checks - Implement PropertyDependencies for dependency analysis - Enhance property descriptions to 100% coverage - Add version information to essentials response - Update documentation with new tools Response sizes reduced from 100KB+ to <5KB for better AI agent usability. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
517
src/services/task-templates.ts
Normal file
517
src/services/task-templates.ts
Normal file
@@ -0,0 +1,517 @@
|
||||
/**
|
||||
* Task Templates Service
|
||||
*
|
||||
* Provides pre-configured node settings for common tasks.
|
||||
* This helps AI agents quickly configure nodes for specific use cases.
|
||||
*/
|
||||
|
||||
export interface TaskTemplate {
|
||||
task: string;
|
||||
description: string;
|
||||
nodeType: string;
|
||||
configuration: Record<string, any>;
|
||||
userMustProvide: Array<{
|
||||
property: string;
|
||||
description: string;
|
||||
example?: any;
|
||||
}>;
|
||||
optionalEnhancements?: Array<{
|
||||
property: string;
|
||||
description: string;
|
||||
when?: string;
|
||||
}>;
|
||||
notes?: string[];
|
||||
}
|
||||
|
||||
export class TaskTemplates {
|
||||
private static templates: Record<string, TaskTemplate> = {
|
||||
// HTTP Request Tasks
|
||||
'get_api_data': {
|
||||
task: 'get_api_data',
|
||||
description: 'Make a simple GET request to retrieve data from an API',
|
||||
nodeType: 'nodes-base.httpRequest',
|
||||
configuration: {
|
||||
method: 'GET',
|
||||
url: '',
|
||||
authentication: 'none'
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'url',
|
||||
description: 'The API endpoint URL',
|
||||
example: 'https://api.example.com/users'
|
||||
}
|
||||
],
|
||||
optionalEnhancements: [
|
||||
{
|
||||
property: 'authentication',
|
||||
description: 'Add authentication if the API requires it',
|
||||
when: 'API requires authentication'
|
||||
},
|
||||
{
|
||||
property: 'sendHeaders',
|
||||
description: 'Add custom headers if needed',
|
||||
when: 'API requires specific headers'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
'post_json_request': {
|
||||
task: 'post_json_request',
|
||||
description: 'Send JSON data to an API endpoint',
|
||||
nodeType: 'nodes-base.httpRequest',
|
||||
configuration: {
|
||||
method: 'POST',
|
||||
url: '',
|
||||
sendBody: true,
|
||||
contentType: 'json',
|
||||
specifyBody: 'json',
|
||||
jsonBody: ''
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'url',
|
||||
description: 'The API endpoint URL',
|
||||
example: 'https://api.example.com/users'
|
||||
},
|
||||
{
|
||||
property: 'jsonBody',
|
||||
description: 'The JSON data to send',
|
||||
example: '{\n "name": "John Doe",\n "email": "john@example.com"\n}'
|
||||
}
|
||||
],
|
||||
optionalEnhancements: [
|
||||
{
|
||||
property: 'authentication',
|
||||
description: 'Add authentication if required'
|
||||
}
|
||||
],
|
||||
notes: [
|
||||
'Make sure jsonBody contains valid JSON',
|
||||
'Content-Type header is automatically set to application/json'
|
||||
]
|
||||
},
|
||||
|
||||
'call_api_with_auth': {
|
||||
task: 'call_api_with_auth',
|
||||
description: 'Make an authenticated API request',
|
||||
nodeType: 'nodes-base.httpRequest',
|
||||
configuration: {
|
||||
method: 'GET',
|
||||
url: '',
|
||||
authentication: 'genericCredentialType',
|
||||
genericAuthType: 'headerAuth',
|
||||
sendHeaders: true,
|
||||
headerParameters: {
|
||||
parameters: [
|
||||
{
|
||||
name: '',
|
||||
value: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'url',
|
||||
description: 'The API endpoint URL'
|
||||
},
|
||||
{
|
||||
property: 'headerParameters.parameters[0].name',
|
||||
description: 'The header name for authentication',
|
||||
example: 'Authorization'
|
||||
},
|
||||
{
|
||||
property: 'headerParameters.parameters[0].value',
|
||||
description: 'The authentication value',
|
||||
example: 'Bearer YOUR_API_KEY'
|
||||
}
|
||||
],
|
||||
optionalEnhancements: [
|
||||
{
|
||||
property: 'method',
|
||||
description: 'Change to POST/PUT/DELETE as needed'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// Webhook Tasks
|
||||
'receive_webhook': {
|
||||
task: 'receive_webhook',
|
||||
description: 'Set up a webhook to receive data from external services',
|
||||
nodeType: 'nodes-base.webhook',
|
||||
configuration: {
|
||||
httpMethod: 'POST',
|
||||
path: 'webhook',
|
||||
responseMode: 'lastNode',
|
||||
responseData: 'allEntries'
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'path',
|
||||
description: 'The webhook path (will be appended to your n8n URL)',
|
||||
example: 'github-webhook'
|
||||
}
|
||||
],
|
||||
optionalEnhancements: [
|
||||
{
|
||||
property: 'httpMethod',
|
||||
description: 'Change if the service sends GET/PUT/etc'
|
||||
},
|
||||
{
|
||||
property: 'responseCode',
|
||||
description: 'Set custom response code (default 200)'
|
||||
}
|
||||
],
|
||||
notes: [
|
||||
'The full webhook URL will be: https://your-n8n.com/webhook/[path]',
|
||||
'Test URL will be different from production URL'
|
||||
]
|
||||
},
|
||||
|
||||
'webhook_with_response': {
|
||||
task: 'webhook_with_response',
|
||||
description: 'Receive webhook and send custom response',
|
||||
nodeType: 'nodes-base.webhook',
|
||||
configuration: {
|
||||
httpMethod: 'POST',
|
||||
path: 'webhook',
|
||||
responseMode: 'responseNode',
|
||||
responseData: 'firstEntryJson',
|
||||
responseCode: 200
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'path',
|
||||
description: 'The webhook path'
|
||||
}
|
||||
],
|
||||
notes: [
|
||||
'Use with a Respond to Webhook node to send custom response',
|
||||
'responseMode: responseNode requires a Respond to Webhook node'
|
||||
]
|
||||
},
|
||||
|
||||
// Database Tasks
|
||||
'query_postgres': {
|
||||
task: 'query_postgres',
|
||||
description: 'Query data from PostgreSQL database',
|
||||
nodeType: 'nodes-base.postgres',
|
||||
configuration: {
|
||||
operation: 'executeQuery',
|
||||
query: ''
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'query',
|
||||
description: 'The SQL query to execute',
|
||||
example: 'SELECT * FROM users WHERE active = true LIMIT 10'
|
||||
}
|
||||
],
|
||||
optionalEnhancements: [
|
||||
{
|
||||
property: 'additionalFields.queryParams',
|
||||
description: 'Use parameterized queries for security',
|
||||
when: 'Using dynamic values'
|
||||
}
|
||||
],
|
||||
notes: [
|
||||
'Always use parameterized queries to prevent SQL injection',
|
||||
'Configure PostgreSQL credentials in n8n'
|
||||
]
|
||||
},
|
||||
|
||||
'insert_postgres_data': {
|
||||
task: 'insert_postgres_data',
|
||||
description: 'Insert data into PostgreSQL table',
|
||||
nodeType: 'nodes-base.postgres',
|
||||
configuration: {
|
||||
operation: 'insert',
|
||||
table: '',
|
||||
columns: '',
|
||||
returnFields: '*'
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'table',
|
||||
description: 'The table name',
|
||||
example: 'users'
|
||||
},
|
||||
{
|
||||
property: 'columns',
|
||||
description: 'Comma-separated column names',
|
||||
example: 'name,email,created_at'
|
||||
}
|
||||
],
|
||||
notes: [
|
||||
'Input data should match the column structure',
|
||||
'Use expressions like {{ $json.fieldName }} to map data'
|
||||
]
|
||||
},
|
||||
|
||||
// AI/LangChain Tasks
|
||||
'chat_with_ai': {
|
||||
task: 'chat_with_ai',
|
||||
description: 'Send a message to an AI model and get response',
|
||||
nodeType: 'nodes-base.openAi',
|
||||
configuration: {
|
||||
resource: 'chat',
|
||||
operation: 'message',
|
||||
modelId: 'gpt-3.5-turbo',
|
||||
messages: {
|
||||
values: [
|
||||
{
|
||||
role: 'user',
|
||||
content: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'messages.values[0].content',
|
||||
description: 'The message to send to the AI',
|
||||
example: '{{ $json.userMessage }}'
|
||||
}
|
||||
],
|
||||
optionalEnhancements: [
|
||||
{
|
||||
property: 'modelId',
|
||||
description: 'Change to gpt-4 for better results'
|
||||
},
|
||||
{
|
||||
property: 'options.temperature',
|
||||
description: 'Adjust creativity (0-1)'
|
||||
},
|
||||
{
|
||||
property: 'options.maxTokens',
|
||||
description: 'Limit response length'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
'ai_agent_workflow': {
|
||||
task: 'ai_agent_workflow',
|
||||
description: 'Create an AI agent that can use tools',
|
||||
nodeType: 'nodes-langchain.agent',
|
||||
configuration: {
|
||||
text: '',
|
||||
outputType: 'output',
|
||||
systemMessage: 'You are a helpful assistant.'
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'text',
|
||||
description: 'The input prompt for the agent',
|
||||
example: '{{ $json.query }}'
|
||||
}
|
||||
],
|
||||
optionalEnhancements: [
|
||||
{
|
||||
property: 'systemMessage',
|
||||
description: 'Customize the agent\'s behavior'
|
||||
}
|
||||
],
|
||||
notes: [
|
||||
'Connect tool nodes to give the agent capabilities',
|
||||
'Configure the AI model credentials'
|
||||
]
|
||||
},
|
||||
|
||||
// Data Processing Tasks
|
||||
'transform_data': {
|
||||
task: 'transform_data',
|
||||
description: 'Transform data structure using JavaScript',
|
||||
nodeType: 'nodes-base.code',
|
||||
configuration: {
|
||||
language: 'javaScript',
|
||||
jsCode: `// Transform each item
|
||||
const results = [];
|
||||
|
||||
for (const item of items) {
|
||||
results.push({
|
||||
json: {
|
||||
// Transform your data here
|
||||
id: item.json.id,
|
||||
processedAt: new Date().toISOString()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return results;`
|
||||
},
|
||||
userMustProvide: [],
|
||||
notes: [
|
||||
'Access input data via items array',
|
||||
'Each item has a json property with the data',
|
||||
'Return array of objects with json property'
|
||||
]
|
||||
},
|
||||
|
||||
'filter_data': {
|
||||
task: 'filter_data',
|
||||
description: 'Filter items based on conditions',
|
||||
nodeType: 'nodes-base.if',
|
||||
configuration: {
|
||||
conditions: {
|
||||
conditions: [
|
||||
{
|
||||
leftValue: '',
|
||||
rightValue: '',
|
||||
operator: {
|
||||
type: 'string',
|
||||
operation: 'equals'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'conditions.conditions[0].leftValue',
|
||||
description: 'The value to check',
|
||||
example: '{{ $json.status }}'
|
||||
},
|
||||
{
|
||||
property: 'conditions.conditions[0].rightValue',
|
||||
description: 'The value to compare against',
|
||||
example: 'active'
|
||||
}
|
||||
],
|
||||
notes: [
|
||||
'True output contains matching items',
|
||||
'False output contains non-matching items'
|
||||
]
|
||||
},
|
||||
|
||||
// Communication Tasks
|
||||
'send_slack_message': {
|
||||
task: 'send_slack_message',
|
||||
description: 'Send a message to Slack channel',
|
||||
nodeType: 'nodes-base.slack',
|
||||
configuration: {
|
||||
resource: 'message',
|
||||
operation: 'post',
|
||||
channel: '',
|
||||
text: ''
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'channel',
|
||||
description: 'The Slack channel',
|
||||
example: '#general'
|
||||
},
|
||||
{
|
||||
property: 'text',
|
||||
description: 'The message text',
|
||||
example: 'New order received: {{ $json.orderId }}'
|
||||
}
|
||||
],
|
||||
optionalEnhancements: [
|
||||
{
|
||||
property: 'attachments',
|
||||
description: 'Add rich message attachments'
|
||||
},
|
||||
{
|
||||
property: 'blocks',
|
||||
description: 'Use Block Kit for advanced formatting'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
'send_email': {
|
||||
task: 'send_email',
|
||||
description: 'Send an email notification',
|
||||
nodeType: 'nodes-base.emailSend',
|
||||
configuration: {
|
||||
fromEmail: '',
|
||||
toEmail: '',
|
||||
subject: '',
|
||||
text: ''
|
||||
},
|
||||
userMustProvide: [
|
||||
{
|
||||
property: 'fromEmail',
|
||||
description: 'Sender email address',
|
||||
example: 'notifications@company.com'
|
||||
},
|
||||
{
|
||||
property: 'toEmail',
|
||||
description: 'Recipient email address',
|
||||
example: '{{ $json.customerEmail }}'
|
||||
},
|
||||
{
|
||||
property: 'subject',
|
||||
description: 'Email subject',
|
||||
example: 'Order Confirmation #{{ $json.orderId }}'
|
||||
},
|
||||
{
|
||||
property: 'text',
|
||||
description: 'Email body (plain text)',
|
||||
example: 'Thank you for your order!'
|
||||
}
|
||||
],
|
||||
optionalEnhancements: [
|
||||
{
|
||||
property: 'html',
|
||||
description: 'Use HTML for rich formatting'
|
||||
},
|
||||
{
|
||||
property: 'attachments',
|
||||
description: 'Attach files to the email'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all available tasks
|
||||
*/
|
||||
static getAllTasks(): string[] {
|
||||
return Object.keys(this.templates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tasks for a specific node type
|
||||
*/
|
||||
static getTasksForNode(nodeType: string): string[] {
|
||||
return Object.entries(this.templates)
|
||||
.filter(([_, template]) => template.nodeType === nodeType)
|
||||
.map(([task, _]) => task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific task template
|
||||
*/
|
||||
static getTaskTemplate(task: string): TaskTemplate | undefined {
|
||||
return this.templates[task];
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for tasks by keyword
|
||||
*/
|
||||
static searchTasks(keyword: string): string[] {
|
||||
const lower = keyword.toLowerCase();
|
||||
return Object.entries(this.templates)
|
||||
.filter(([task, template]) =>
|
||||
task.toLowerCase().includes(lower) ||
|
||||
template.description.toLowerCase().includes(lower) ||
|
||||
template.nodeType.toLowerCase().includes(lower)
|
||||
)
|
||||
.map(([task, _]) => task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get task categories
|
||||
*/
|
||||
static getTaskCategories(): Record<string, string[]> {
|
||||
return {
|
||||
'HTTP/API': ['get_api_data', 'post_json_request', 'call_api_with_auth'],
|
||||
'Webhooks': ['receive_webhook', 'webhook_with_response'],
|
||||
'Database': ['query_postgres', 'insert_postgres_data'],
|
||||
'AI/LangChain': ['chat_with_ai', 'ai_agent_workflow'],
|
||||
'Data Processing': ['transform_data', 'filter_data'],
|
||||
'Communication': ['send_slack_message', 'send_email']
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user