fix: remove faulty auto-generated examples from MCP tools

- Remove examples from get_node_essentials responses
- Remove examples from validate_node_operation when errors occur
- Update documentation to reflect removal of examples
- Keep helpful format hints in get_node_for_task (different purpose)

The auto-generated examples were misleading AI agents with incorrect
configurations (e.g., Slack "channel" vs "select" property). Tools
now focus on validation and error messages instead of examples.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
czlonkowski
2025-07-17 21:17:35 +02:00
parent 24d775960b
commit ba7f8f9ea6
6 changed files with 47 additions and 146 deletions

Binary file not shown.

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "n8n-mcp",
"version": "2.7.11",
"version": "2.7.17",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "n8n-mcp",
"version": "2.7.11",
"version": "2.7.17",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.13.2",

View File

@@ -1,6 +1,6 @@
{
"name": "n8n-mcp",
"version": "2.7.16",
"version": "2.7.17",
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
"main": "dist/index.js",
"bin": {

View File

@@ -13,7 +13,6 @@ import { logger } from '../utils/logger';
import { NodeRepository } from '../database/node-repository';
import { DatabaseAdapter, createDatabaseAdapter } from '../database/database-adapter';
import { PropertyFilter } from '../services/property-filter';
import { ExampleGenerator } from '../services/example-generator';
import { TaskTemplates } from '../services/task-templates';
import { ConfigValidator } from '../services/config-validator';
import { EnhancedConfigValidator, ValidationMode, ValidationProfile } from '../services/enhanced-config-validator';
@@ -1061,9 +1060,6 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
// Get essential properties
const essentials = PropertyFilter.getEssentials(allProperties, node.nodeType);
// Generate examples
const examples = ExampleGenerator.getExamples(node.nodeType, essentials);
// Get operations (already parsed by repository)
const operations = node.operations || [];
@@ -1082,7 +1078,7 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
action: op.action,
resource: op.resource
})),
examples,
// Examples removed - use validate_node_operation for working configurations
metadata: {
totalProperties: allProperties.length,
isAITool: node.isAITool,

View File

@@ -4,48 +4,54 @@ export const getNodeEssentialsDoc: ToolDocumentation = {
name: 'get_node_essentials',
category: 'configuration',
essentials: {
description: 'Returns only the most commonly-used properties for a node (10-20 fields) with working examples. Response is 95% smaller than get_node_info (5KB vs 100KB+). Essential properties include required fields, common options, and authentication settings.',
description: 'Returns only the most commonly-used properties for a node (10-20 fields). Response is 95% smaller than get_node_info (5KB vs 100KB+). Essential properties include required fields, common options, and authentication settings. Use validate_node_operation for working configurations.',
keyParameters: ['nodeType'],
example: 'get_node_essentials({nodeType: "nodes-base.slack"})',
performance: '<10ms, ~5KB response',
tips: [
'Always use this before get_node_info',
'Includes ready-to-use examples',
'Perfect for configuring nodes quickly'
'Use validate_node_operation for examples',
'Perfect for understanding node structure'
]
},
full: {
description: 'Returns a curated subset of node properties focusing on the most commonly-used fields. Essential properties are hand-picked for each node type and include: required fields, primary operations, authentication options, and the most frequent configuration patterns. Each response includes working examples you can copy and modify.',
description: 'Returns a curated subset of node properties focusing on the most commonly-used fields. Essential properties are hand-picked for each node type and include: required fields, primary operations, authentication options, and the most frequent configuration patterns. NOTE: Examples have been removed to avoid confusion - use validate_node_operation to get working configurations with proper validation.',
parameters: {
nodeType: { type: 'string', description: 'Full node type with prefix, e.g., "nodes-base.slack", "nodes-base.httpRequest"', required: true }
},
returns: `Object containing:
{
"nodeType": "nodes-base.slack",
"essentialProperties": {
"resource": ["channel", "message", "user"],
"operation": ["post", "update", "delete"],
"authentication": ["accessToken", "oAuth2"],
"channel": "Channel ID or name",
"text": "Message content",
"blocks": "Advanced formatting (optional)"
},
"examples": {
"postMessage": {
"resource": "message",
"operation": "post",
"channel": "#general",
"text": "Hello from n8n!"
"displayName": "Slack",
"description": "Consume Slack API",
"category": "output",
"version": "2.3",
"requiredProperties": [], // Most nodes have no strictly required fields
"commonProperties": [
{
"name": "resource",
"displayName": "Resource",
"type": "options",
"options": ["channel", "message", "user"],
"default": "message"
},
"withBlocks": {
"resource": "message",
"operation": "post",
"blocks": [{"type": "section", "text": {"type": "mrkdwn", "text": "Hello"}}]
}
},
"authentication": {
"required": true,
"options": ["accessToken", "oAuth2"]
{
"name": "operation",
"displayName": "Operation",
"type": "options",
"options": ["post", "update", "delete"],
"default": "post"
},
// ... 10-20 most common properties
],
"operations": [
{"name": "Post", "description": "Post a message"},
{"name": "Update", "description": "Update a message"}
],
"metadata": {
"totalProperties": 121,
"isAITool": false,
"hasCredentials": true
}
}`,
examples: [
@@ -55,18 +61,18 @@ export const getNodeEssentialsDoc: ToolDocumentation = {
'// Workflow: search → essentials → validate',
'const nodes = search_nodes({query: "database"});',
'const mysql = get_node_essentials({nodeType: "nodes-base.mySql"});',
'validate_node_minimal("nodes-base.mySql", mysql.examples.select);'
'validate_node_operation("nodes-base.mySql", {operation: "select"}, "minimal");'
],
useCases: [
'Quickly configure nodes without information overload',
'Get working examples for common operations',
'Quickly understand node structure without information overload',
'Identify which properties are most important',
'Learn node basics before diving into advanced features',
'Build workflows faster with curated property sets'
],
performance: '<10ms response time, ~5KB payload (vs 100KB+ for full schema)',
bestPractices: [
'Always start with essentials, only use get_node_info if needed',
'Copy examples as configuration starting points',
'Use validate_node_operation to get working configurations',
'Check authentication requirements first',
'Use search_node_properties if specific property not in essentials'
],

View File

@@ -7,7 +7,6 @@
import { ConfigValidator, ValidationResult, ValidationError, ValidationWarning } from './config-validator';
import { NodeSpecificValidators, NodeValidationContext } from './node-specific-validators';
import { ExampleGenerator } from './example-generator';
export type ValidationMode = 'full' | 'operation' | 'minimal';
export type ValidationProfile = 'strict' | 'runtime' | 'ai-friendly' | 'minimal';
@@ -78,10 +77,7 @@ export class EnhancedConfigValidator extends ConfigValidator {
// Deduplicate errors
enhancedResult.errors = this.deduplicateErrors(enhancedResult.errors);
// Add examples from ExampleGenerator if there are errors
if (enhancedResult.errors.length > 0) {
this.addExamplesFromGenerator(nodeType, enhancedResult);
}
// Examples removed - use validate_node_operation for configuration guidance
// Generate next steps based on errors
enhancedResult.nextSteps = this.generateNextSteps(enhancedResult);
@@ -253,16 +249,7 @@ export class EnhancedConfigValidator extends ConfigValidator {
const { resource, operation } = result.operation || {};
if (resource === 'message' && operation === 'send') {
// Add example for sending a message
result.examples?.push({
description: 'Send a simple text message to a channel',
config: {
resource: 'message',
operation: 'send',
channel: '#general',
text: 'Hello from n8n!'
}
});
// Examples removed - validation focuses on error detection
// Check for common issues
if (!config.channel && !config.channelId) {
@@ -274,15 +261,6 @@ export class EnhancedConfigValidator extends ConfigValidator {
channelError.fix = 'Add channel: "#general" or use a channel ID like "C1234567890"';
}
}
} else if (resource === 'user' && operation === 'get') {
result.examples?.push({
description: 'Get user information by email',
config: {
resource: 'user',
operation: 'get',
user: 'user@example.com'
}
});
}
}
@@ -296,17 +274,7 @@ export class EnhancedConfigValidator extends ConfigValidator {
const { operation } = result.operation || {};
if (operation === 'append') {
result.examples?.push({
description: 'Append data to a spreadsheet',
config: {
operation: 'append',
sheetId: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms',
range: 'Sheet1!A:B',
options: {
valueInputMode: 'USER_ENTERED'
}
}
});
// Examples removed - validation focuses on configuration correctness
// Validate range format
if (config.range && !config.range.includes('!')) {
@@ -327,33 +295,7 @@ export class EnhancedConfigValidator extends ConfigValidator {
config: Record<string, any>,
result: EnhancedValidationResult
): void {
// Add common examples based on method
if (config.method === 'GET') {
result.examples?.push({
description: 'GET request with query parameters',
config: {
method: 'GET',
url: 'https://api.example.com/users',
queryParameters: {
parameters: [
{ name: 'page', value: '1' },
{ name: 'limit', value: '10' }
]
}
}
});
} else if (config.method === 'POST') {
result.examples?.push({
description: 'POST request with JSON body',
config: {
method: 'POST',
url: 'https://api.example.com/users',
sendBody: true,
bodyContentType: 'json',
jsonBody: JSON.stringify({ name: 'John Doe', email: 'john@example.com' })
}
});
}
// Examples removed - validation provides error messages and fixes instead
}
/**
@@ -383,56 +325,13 @@ export class EnhancedConfigValidator extends ConfigValidator {
steps.push('Consider addressing warnings for better reliability');
}
if (result.examples && result.examples.length > 0 && result.errors.length > 0) {
steps.push('See examples above for working configurations');
if (result.errors.length > 0) {
steps.push('Fix the errors above following the provided suggestions');
}
return steps;
}
/**
* Add examples from ExampleGenerator to help fix validation errors
*/
private static addExamplesFromGenerator(
nodeType: string,
result: EnhancedValidationResult
): void {
const examples = ExampleGenerator.getExamples(nodeType);
if (!examples) {
return;
}
// Add minimal example if there are missing required fields
if (result.errors.some(e => e.type === 'missing_required')) {
result.examples?.push({
description: 'Minimal working configuration',
config: examples.minimal
});
}
// Add common example if available
if (examples.common) {
// Check if the common example matches the operation context
const { operation } = result.operation || {};
const commonOp = examples.common.operation || examples.common.action;
if (!operation || operation === commonOp) {
result.examples?.push({
description: 'Common configuration pattern',
config: examples.common
});
}
}
// Add advanced example for complex validation errors
if (examples.advanced && result.errors.length > 2) {
result.examples?.push({
description: 'Advanced configuration with all options',
config: examples.advanced
});
}
}
/**
* Deduplicate errors based on property and type