- 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>
12 KiB
MCP Tools Implementation Strategy (Revised)
Executive Summary
After analyzing the actual n8n-mcp implementation, the core issue isn't data extraction or storage - you already have excellent property extraction with complete schemas stored as JSON. The real problem is information presentation - returning all 200+ properties at once overwhelms AI agents. This revised strategy focuses on intelligent filtering and presentation layers on top of your existing data.
Current System Strengths
- Comprehensive property extraction - All properties with types, options, displayOptions, etc.
- Efficient storage - JSON columns allow flexibility while maintaining query performance
- Complete metadata - Operations, credentials, documentation all properly extracted
- Version handling - Supports versioned nodes like HTTPRequest v1/v2/v3
Revised Implementation Approach
Core Principle: Filter, Don't Restructure
Instead of changing how data is stored, we'll add intelligent filtering layers:
// Your current data flow:
n8n source → PropertyExtractor → JSON properties → Database → get_node_info → 100KB response
// New data flow:
n8n source → PropertyExtractor → JSON properties → Database → PropertyFilter → Smart Tools → 5KB response
Phase 1: Intelligent Property Filtering (Week 1)
1.1 Enhanced get_node_essentials
Implementation - Add to src/mcp/server.ts:
case "get_node_essentials": {
const { nodeType } = request.params.arguments as { nodeType: string };
const node = await service.getNodeByType(nodeType);
if (!node) throw new Error(`Node type ${nodeType} not found`);
// Parse existing properties
const allProperties = JSON.parse(node.properties_schema || '[]');
// Filter to essentials using smart rules
const essentials = PropertyFilter.getEssentials(allProperties, nodeType);
return {
nodeType: node.node_type,
displayName: node.display_name,
description: node.description,
requiredProperties: essentials.required,
commonProperties: essentials.common,
examples: ExampleGenerator.getExamples(nodeType, essentials),
totalPropertiesAvailable: allProperties.length,
operations: JSON.parse(node.operations || '[]')
};
}
1.2 Create PropertyFilter Service
Create src/services/property-filter.ts:
export class PropertyFilter {
// Curated lists of essential properties per node type
private static ESSENTIAL_PROPERTIES: Record<string, EssentialConfig> = {
'nodes-base.httpRequest': {
required: ['url'],
common: ['method', 'authentication', 'sendBody', 'contentType', 'sendHeaders'],
categoryPriority: ['basic', 'authentication', 'request', 'response', 'advanced']
},
'nodes-base.webhook': {
required: [],
common: ['httpMethod', 'path', 'responseMode', 'responseData'],
categoryPriority: ['basic', 'response', 'advanced']
}
// Add more nodes...
};
static getEssentials(properties: any[], nodeType: string): FilteredProperties {
const config = this.ESSENTIAL_PROPERTIES[nodeType] || this.inferEssentials(properties);
const required = properties.filter(p =>
config.required.includes(p.name) || p.required === true
);
const common = properties.filter(p =>
config.common.includes(p.name) && !required.find(r => r.name === p.name)
);
// Simplify property structure for AI consumption
return {
required: required.map(p => this.simplifyProperty(p)),
common: common.map(p => this.simplifyProperty(p))
};
}
private static simplifyProperty(prop: any): SimplifiedProperty {
return {
name: prop.name,
displayName: prop.displayName,
type: prop.type,
description: prop.description || '',
required: prop.required || false,
default: prop.default,
options: prop.options?.map((opt: any) => ({
value: typeof opt === 'string' ? opt : opt.value,
label: typeof opt === 'string' ? opt : opt.name
})),
// Only include display conditions if simple
showWhen: this.simplifyDisplayConditions(prop.displayOptions?.show),
// Add usage hint
usageHint: this.getUsageHint(prop)
};
}
private static inferEssentials(properties: any[]): EssentialConfig {
// Fallback logic for nodes without curated lists
const required = properties.filter(p => p.required).map(p => p.name);
const common = properties
.filter(p => !p.displayOptions && !p.required)
.slice(0, 5)
.map(p => p.name);
return { required, common, categoryPriority: [] };
}
}
1.3 Smart Property Search
Enhance the existing structure with property search:
case "search_node_properties": {
const { nodeType, query, category } = request.params.arguments as {
nodeType: string;
query: string;
category?: string;
};
const node = await service.getNodeByType(nodeType);
if (!node) throw new Error(`Node type ${nodeType} not found`);
const allProperties = JSON.parse(node.properties_schema || '[]');
const matches = PropertySearch.search(allProperties, query, category);
return {
query,
category,
matches: matches.map(match => ({
...PropertyFilter.simplifyProperty(match.property),
path: match.path,
relevanceScore: match.score,
context: match.context
})),
totalMatches: matches.length
};
}
Phase 2: Configuration Intelligence (Week 2)
2.1 Task-Based Configuration
Create src/services/task-configurator.ts:
export class TaskConfigurator {
private static TASK_TEMPLATES: Record<string, TaskTemplate> = {
'post_json_request': {
nodeType: 'nodes-base.httpRequest',
description: 'Make a POST request with JSON data',
configuration: {
method: 'POST',
sendBody: true,
contentType: 'json',
specifyBody: 'json'
},
userMustProvide: ['url', 'jsonBody'],
conditionalProperties: {
'sendBody=true': ['contentType', 'specifyBody'],
'contentType=json': ['jsonBody']
}
}
// More templates...
};
static getTaskConfiguration(task: string): TaskConfiguration {
const template = this.TASK_TEMPLATES[task];
if (!template) throw new Error(`Unknown task: ${task}`);
// Resolve all properties needed for this configuration
const node = await service.getNodeByType(template.nodeType);
const allProperties = JSON.parse(node.properties_schema || '[]');
// Get properties mentioned in template
const relevantProperties = this.extractRelevantProperties(
allProperties,
template.configuration,
template.conditionalProperties
);
return {
task,
nodeType: template.nodeType,
description: template.description,
configuration: template.configuration,
properties: relevantProperties,
userMustProvide: template.userMustProvide,
propertyChain: this.buildPropertyChain(template.conditionalProperties)
};
}
}
2.2 Configuration Validator
export class ConfigurationValidator {
static async validate(nodeType: string, config: any): Promise<ValidationResult> {
const node = await service.getNodeByType(nodeType);
const properties = JSON.parse(node.properties_schema || '[]');
const errors: ValidationError[] = [];
const warnings: ValidationWarning[] = [];
const suggestions: string[] = [];
// Check required properties
const requiredProps = properties.filter(p => p.required);
for (const prop of requiredProps) {
if (!(prop.name in config)) {
errors.push({
type: 'missing_required',
property: prop.name,
message: `Required property '${prop.displayName}' is missing`
});
}
}
// Check property visibility
const visibleProps = this.getVisibleProperties(properties, config);
const configuredButHidden = Object.keys(config).filter(
key => !visibleProps.find(p => p.name === key)
);
if (configuredButHidden.length > 0) {
warnings.push({
type: 'hidden_properties',
message: `Properties ${configuredButHidden.join(', ')} won't be used with current configuration`,
properties: configuredButHidden
});
}
// Smart suggestions based on config
if (config.method === 'POST' && !config.sendBody) {
suggestions.push('POST requests typically send a body - consider setting sendBody=true');
}
return {
valid: errors.length === 0,
errors,
warnings,
suggestions,
visibleProperties: visibleProps.map(p => p.name),
hiddenProperties: properties
.filter(p => !visibleProps.includes(p))
.map(p => p.name)
};
}
private static getVisibleProperties(properties: any[], config: any): any[] {
return properties.filter(prop => {
if (!prop.displayOptions) return true;
// Check show conditions
if (prop.displayOptions.show) {
return this.evaluateConditions(prop.displayOptions.show, config);
}
// Check hide conditions
if (prop.displayOptions.hide) {
return !this.evaluateConditions(prop.displayOptions.hide, config);
}
return true;
});
}
}
Phase 3: Advanced Features (Week 3-4)
3.1 Property Resolution Helper
case "resolve_property_visibility": {
const { nodeType, currentConfig, targetProperty } = request.params.arguments;
const resolver = new PropertyResolver();
const path = resolver.getPathToProperty(nodeType, currentConfig, targetProperty);
return {
targetProperty,
currentlyVisible: path.isVisible,
requiredChanges: path.changes,
steps: path.steps,
alternatives: path.alternatives
};
}
3.2 Workflow Pattern Analyzer
export class WorkflowPatternAnalyzer {
// Analyze common patterns from existing workflows
static async suggestConfiguration(context: {
previousNode?: string;
nextNode?: string;
workflowObjective?: string;
}): Promise<ConfigurationSuggestion> {
// Use patterns to suggest optimal configuration
}
}
Implementation Priority & Timeline
Week 1: Core Filtering
- Implement PropertyFilter service
- Create get_node_essentials tool
- Add curated essential lists for top 20 nodes
- Implement property search within nodes
Week 2: Intelligence Layer
- Build TaskConfigurator with 10 common templates
- Implement ConfigurationValidator
- Add property visibility resolver
- Create example generator
Week 3: Testing & Refinement
- Test with all 525 nodes
- Refine essential property lists
- Add more task templates
- Performance optimization
Week 4: Advanced Features
- Workflow pattern analysis
- Context-aware suggestions
- Property dependency graphs
- Auto-completion support
Key Differences from Original Strategy
- No database schema changes needed - Work with existing JSON structure
- Focus on filtering, not restructuring - Properties are already well-structured
- Build intelligence layers - Add smart filtering and validation on top
- Leverage existing extraction - Don't duplicate the excellent work already done
- Progressive enhancement - Each tool adds value independently
Success Metrics
| Metric | Current | Target | How to Measure |
|---|---|---|---|
| Properties returned | 200+ | 10-20 | get_node_essentials response |
| Response size | 100KB+ | <5KB | JSON.stringify().length |
| Time to find property | 30+ seconds | <5 seconds | Property search tool |
| Configuration errors | 40% | <10% | Validation success rate |
| AI success rate | Low | >90% | Successful workflow creation |
Next Steps
- Implement PropertyFilter with hardcoded essentials for HTTP Request node
- Test size reduction with real AI agents
- Iterate on essential property lists based on usage
- Add task templates for common use cases
- Build validation layer to catch errors early
This revised strategy works WITH your existing architecture rather than against it, delivering immediate value while building toward a comprehensive solution.