chore: remove outdated documentation and add diagnostic tools
This commit is contained in:
0
database.db
Normal file
0
database.db
Normal file
136
diagnose-claude-desktop.sh
Executable file
136
diagnose-claude-desktop.sh
Executable file
@@ -0,0 +1,136 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "n8n-MCP Claude Desktop Diagnostic"
|
||||
echo "================================="
|
||||
echo ""
|
||||
|
||||
# Check current directory
|
||||
echo "1. Current directory:"
|
||||
pwd
|
||||
echo ""
|
||||
|
||||
# Check git status
|
||||
echo "2. Git status:"
|
||||
git log -1 --oneline
|
||||
git status --short
|
||||
echo ""
|
||||
|
||||
# Check if built
|
||||
echo "3. Build status:"
|
||||
if [ -f "dist/mcp/index.js" ]; then
|
||||
echo "✅ dist/mcp/index.js exists"
|
||||
echo " Last modified: $(stat -f "%Sm" dist/mcp/index.js 2>/dev/null || stat -c "%y" dist/mcp/index.js 2>/dev/null)"
|
||||
else
|
||||
echo "❌ dist/mcp/index.js not found - run 'npm run build'"
|
||||
fi
|
||||
|
||||
if [ -f "dist/mcp/server-update.js" ]; then
|
||||
echo "✅ dist/mcp/server-update.js exists"
|
||||
echo " Last modified: $(stat -f "%Sm" dist/mcp/server-update.js 2>/dev/null || stat -c "%y" dist/mcp/server-update.js 2>/dev/null)"
|
||||
else
|
||||
echo "❌ dist/mcp/server-update.js not found"
|
||||
fi
|
||||
|
||||
if [ -f "dist/mcp/tools-update.js" ]; then
|
||||
echo "✅ dist/mcp/tools-update.js exists"
|
||||
echo " Last modified: $(stat -f "%Sm" dist/mcp/tools-update.js 2>/dev/null || stat -c "%y" dist/mcp/tools-update.js 2>/dev/null)"
|
||||
else
|
||||
echo "❌ dist/mcp/tools-update.js not found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check database
|
||||
echo "4. Database status:"
|
||||
if [ -f "data/nodes.db" ]; then
|
||||
echo "✅ data/nodes.db exists"
|
||||
echo " Size: $(du -h data/nodes.db | cut -f1)"
|
||||
echo " Last modified: $(stat -f "%Sm" data/nodes.db 2>/dev/null || stat -c "%y" data/nodes.db 2>/dev/null)"
|
||||
else
|
||||
echo "❌ data/nodes.db not found - run 'npm run rebuild'"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check tools in compiled code
|
||||
echo "5. Compiled tools check:"
|
||||
if [ -f "dist/mcp/tools-update.js" ]; then
|
||||
TOOL_COUNT=$(grep "name: '" dist/mcp/tools-update.js | wc -l | tr -d ' ')
|
||||
echo " Total tools found: $TOOL_COUNT"
|
||||
echo " New tools present:"
|
||||
for tool in "get_node_for_task" "validate_node_config" "get_property_dependencies" "list_tasks" "search_node_properties" "get_node_essentials"; do
|
||||
if grep -q "name: '$tool'" dist/mcp/tools-update.js; then
|
||||
echo " ✅ $tool"
|
||||
else
|
||||
echo " ❌ $tool"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "❌ Cannot check - file not found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test MCP server
|
||||
echo "6. MCP server test:"
|
||||
if [ -f "dist/mcp/index.js" ] && [ -f "data/nodes.db" ]; then
|
||||
echo " Running quick MCP server test..."
|
||||
if node test-mcp-tools.js 2>/dev/null | grep -q "get_node_for_task: ✅ Found"; then
|
||||
echo "✅ MCP server correctly exposes all new tools"
|
||||
else
|
||||
echo "❌ MCP server issue detected"
|
||||
fi
|
||||
else
|
||||
echo "❌ Cannot test - missing required files"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check Node.js version
|
||||
echo "7. Node.js version:"
|
||||
node --version
|
||||
echo ""
|
||||
|
||||
# Claude Desktop config location
|
||||
echo "8. Claude Desktop config location:"
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
CONFIG_PATH="$HOME/Library/Application Support/Claude/claude_desktop_config.json"
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
CONFIG_PATH="$HOME/.config/Claude/claude_desktop_config.json"
|
||||
elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
|
||||
CONFIG_PATH="$APPDATA/Claude/claude_desktop_config.json"
|
||||
fi
|
||||
|
||||
if [ -f "$CONFIG_PATH" ]; then
|
||||
echo "✅ Config file found at: $CONFIG_PATH"
|
||||
echo " Checking n8n-mcp entry..."
|
||||
if grep -q "n8n-mcp" "$CONFIG_PATH" 2>/dev/null; then
|
||||
echo "✅ n8n-mcp server configured"
|
||||
# Extract the path
|
||||
NODE_PATH=$(grep -A5 "n8n-mcp" "$CONFIG_PATH" | grep -o '"args".*\[.*".*"' | sed 's/.*\[\s*"\(.*\)".*/\1/')
|
||||
if [ ! -z "$NODE_PATH" ]; then
|
||||
echo " Configured path: $NODE_PATH"
|
||||
if [ -f "$NODE_PATH" ]; then
|
||||
echo "✅ Path exists"
|
||||
else
|
||||
echo "❌ Path does not exist!"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "❌ n8n-mcp not found in config"
|
||||
fi
|
||||
else
|
||||
echo "❌ Config file not found at expected location: $CONFIG_PATH"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Recommended actions
|
||||
echo "9. Recommended actions:"
|
||||
echo " If any ❌ items above:"
|
||||
echo " 1. git pull # Get latest code"
|
||||
echo " 2. npm install # Install dependencies"
|
||||
echo " 3. npm run build # Build TypeScript"
|
||||
echo " 4. npm run rebuild # Rebuild database"
|
||||
echo " 5. Update Claude Desktop config with absolute path to $(pwd)/dist/mcp/index.js"
|
||||
echo " 6. Completely quit and restart Claude Desktop"
|
||||
echo ""
|
||||
echo " If all ✅ but tools still missing in Claude:"
|
||||
echo " - Try removing and re-adding the n8n-mcp server in Claude Desktop config"
|
||||
echo " - Check Claude Desktop logs: View > Developer > Logs"
|
||||
echo ""
|
||||
@@ -1,188 +0,0 @@
|
||||
# Docker Optimization Guide
|
||||
|
||||
This guide explains the optimized Docker build that reduces image size from 2.61GB to ~200MB.
|
||||
|
||||
## What's Different?
|
||||
|
||||
### Original Build
|
||||
- **Size**: 2.61GB
|
||||
- **Database**: Built at container startup
|
||||
- **Dependencies**: Full n8n ecosystem included
|
||||
- **Startup**: Slower (builds database)
|
||||
- **Memory**: Higher usage
|
||||
|
||||
### Optimized Build
|
||||
- **Size**: ~200MB (90% reduction!)
|
||||
- **Database**: Pre-built at Docker build time
|
||||
- **Dependencies**: Minimal runtime only
|
||||
- **Startup**: Fast (database ready)
|
||||
- **Memory**: Lower usage
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Build Time**: Extracts all node information and source code
|
||||
2. **Database**: Complete SQLite database with embedded source code
|
||||
3. **Runtime**: Only needs MCP server and SQLite libraries
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Using Docker Compose
|
||||
|
||||
```bash
|
||||
# Create .env file
|
||||
echo "AUTH_TOKEN=$(openssl rand -base64 32)" > .env
|
||||
|
||||
# Build and run optimized version
|
||||
docker compose -f docker-compose.optimized.yml up -d
|
||||
|
||||
# Check health
|
||||
curl http://localhost:3000/health
|
||||
```
|
||||
|
||||
### Using Docker Directly
|
||||
|
||||
```bash
|
||||
# Build optimized image
|
||||
docker build -f Dockerfile.optimized -t n8n-mcp:optimized .
|
||||
|
||||
# Run it
|
||||
docker run -d \
|
||||
--name n8n-mcp-slim \
|
||||
-e MCP_MODE=http \
|
||||
-e AUTH_TOKEN=your-token \
|
||||
-p 3000:3000 \
|
||||
n8n-mcp:optimized
|
||||
```
|
||||
|
||||
## Feature Comparison
|
||||
|
||||
| Feature | Original | Optimized |
|
||||
|---------|----------|-----------|
|
||||
| List nodes | ✅ | ✅ |
|
||||
| Search nodes | ✅ | ✅ |
|
||||
| Get node info | ✅ | ✅ |
|
||||
| Get source code | ✅ | ✅ |
|
||||
| Extract new nodes | ✅ | ❌ |
|
||||
| Rebuild database | ✅ | ❌ |
|
||||
| HTTP mode | ✅ | ✅ |
|
||||
| Stdio mode | ✅ | ✅ |
|
||||
|
||||
## Limitations
|
||||
|
||||
### No Runtime Extraction
|
||||
The optimized build cannot:
|
||||
- Extract source from new nodes at runtime
|
||||
- Rebuild the database inside the container
|
||||
- Scan for custom nodes
|
||||
|
||||
### Static Database
|
||||
- Database is built at Docker image build time
|
||||
- To update nodes, rebuild the Docker image
|
||||
- Custom nodes must be present during build
|
||||
|
||||
## Benefits of Optimization
|
||||
|
||||
The optimized Docker image is now the default and only version, providing:
|
||||
- **Production-ready**: Pre-built database with all nodes
|
||||
- **Resource-efficient**: Only ~283MB vs 2.6GB
|
||||
- **Fast startup**: No database building required
|
||||
- **Minimal attack surface**: No unnecessary dependencies
|
||||
|
||||
## Testing the Optimized Build
|
||||
|
||||
Run the test script:
|
||||
```bash
|
||||
./scripts/test-optimized-docker.sh
|
||||
```
|
||||
|
||||
This will:
|
||||
- Build the optimized image
|
||||
- Check image size
|
||||
- Test stdio mode
|
||||
- Test HTTP mode
|
||||
- Compare with original
|
||||
|
||||
## Building for Production
|
||||
|
||||
### Multi-architecture Build
|
||||
```bash
|
||||
# Build for multiple platforms
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
-f Dockerfile.optimized \
|
||||
-t ghcr.io/yourusername/n8n-mcp:optimized \
|
||||
--push \
|
||||
.
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
- name: Build optimized image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.optimized
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
ghcr.io/${{ github.repository }}:optimized
|
||||
ghcr.io/${{ github.repository }}:slim
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Database Not Found
|
||||
```
|
||||
ERROR: Pre-built database not found at /app/data/nodes.db
|
||||
```
|
||||
**Solution**: The database must be built during Docker build. Ensure build completes successfully.
|
||||
|
||||
### Missing Source Code
|
||||
If `get_node_source` returns empty:
|
||||
- Check build logs for extraction errors
|
||||
- Verify n8n packages were available during build
|
||||
- Rebuild image with verbose logging
|
||||
|
||||
### Tool Not Working
|
||||
Some tools are disabled in optimized build:
|
||||
- `rebuild_documentation_database` - Not available
|
||||
- `list_available_nodes` - Uses database, not filesystem
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
### Startup Time
|
||||
- Original: ~10-30 seconds (builds database)
|
||||
- Optimized: ~1-2 seconds (database ready)
|
||||
|
||||
### Memory Usage
|
||||
- Original: ~150-200MB
|
||||
- Optimized: ~50-80MB
|
||||
|
||||
### Image Size
|
||||
- Original: 2.61GB
|
||||
- Optimized: ~200MB
|
||||
|
||||
## Future Improvements
|
||||
|
||||
1. **Compression**: Compress source code in database
|
||||
2. **Lazy Loading**: Load source code on demand
|
||||
3. **Incremental Updates**: Support partial database updates
|
||||
4. **Cache Layer**: Better Docker layer caching
|
||||
|
||||
## Migration Path
|
||||
|
||||
1. **Test**: Run optimized version alongside original
|
||||
2. **Validate**: Ensure all required features work
|
||||
3. **Deploy**: Gradually roll out to production
|
||||
4. **Monitor**: Track performance improvements
|
||||
|
||||
## Summary
|
||||
|
||||
The optimized Docker build is now the standard n8n-MCP Docker image, providing:
|
||||
- Dramatically reduced image size (283MB vs 2.6GB)
|
||||
- Fast startup with pre-built database
|
||||
- Minimal resource usage
|
||||
- All 525+ nodes included and ready to use
|
||||
|
||||
This optimization makes n8n-MCP suitable for any deployment scenario while maintaining full functionality.
|
||||
@@ -1,146 +0,0 @@
|
||||
# Immediate Deployment Action Plan
|
||||
|
||||
## 🚀 Quick Fix: Test if Tools are Actually Working
|
||||
|
||||
Based on the analysis, your implemented tools ARE working but the Docker image is outdated. Here's how to verify and fix:
|
||||
|
||||
## Option 1: Local Testing (Fastest)
|
||||
|
||||
```bash
|
||||
# 1. Stop current Docker container
|
||||
docker compose down
|
||||
|
||||
# 2. Run locally with npm
|
||||
cd /Users/romualdczlonkowski/Pliki/n8n-mcp/n8n-mcp
|
||||
npm run build
|
||||
npm run start:http
|
||||
|
||||
# 3. Test with curl
|
||||
curl -X POST http://localhost:3000/mcp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "tools/list",
|
||||
"id": 1
|
||||
}'
|
||||
```
|
||||
|
||||
You should see all 12 tools including:
|
||||
- get_node_essentials
|
||||
- search_node_properties
|
||||
- get_node_for_task
|
||||
- list_tasks
|
||||
- validate_node_config
|
||||
- get_property_dependencies
|
||||
|
||||
## Option 2: Update Docker Image
|
||||
|
||||
```bash
|
||||
# 1. Build new image with latest code
|
||||
docker build -t ghcr.io/czlonkowski/n8n-mcp:v2.4.0 .
|
||||
docker build -t ghcr.io/czlonkowski/n8n-mcp:latest .
|
||||
|
||||
# 2. Test locally
|
||||
docker run -p 3000:3000 -e USE_FIXED_HTTP=true ghcr.io/czlonkowski/n8n-mcp:latest
|
||||
|
||||
# 3. Push to registry (if you have access)
|
||||
docker push ghcr.io/czlonkowski/n8n-mcp:v2.4.0
|
||||
docker push ghcr.io/czlonkowski/n8n-mcp:latest
|
||||
```
|
||||
|
||||
## Option 3: Quick Local Docker Test
|
||||
|
||||
```bash
|
||||
# 1. Update docker-compose.yml to build locally
|
||||
cat > docker-compose.override.yml << 'EOF'
|
||||
services:
|
||||
n8n-mcp:
|
||||
build: .
|
||||
image: n8n-mcp:local
|
||||
EOF
|
||||
|
||||
# 2. Rebuild and start
|
||||
docker compose build
|
||||
docker compose up -d
|
||||
|
||||
# 3. Check health
|
||||
curl http://localhost:3000/health
|
||||
```
|
||||
|
||||
## Claude Desktop Testing
|
||||
|
||||
After updating:
|
||||
|
||||
1. **Completely quit Claude Desktop** (not just close window)
|
||||
2. **Clear any cache**:
|
||||
```bash
|
||||
# macOS
|
||||
rm -rf ~/Library/Caches/com.anthropic.claude*
|
||||
```
|
||||
3. **Restart Claude Desktop**
|
||||
4. **Test the new tools**:
|
||||
- "List all available MCP tools"
|
||||
- "Use get_node_essentials for HTTP Request"
|
||||
- "Use get_node_for_task to configure a post_json_request"
|
||||
|
||||
## Diagnostic Script
|
||||
|
||||
```bash
|
||||
# Save this as test-mcp-tools.sh
|
||||
#!/bin/bash
|
||||
|
||||
echo "Testing MCP Tools Availability..."
|
||||
|
||||
# Test tool list
|
||||
curl -s -X POST http://localhost:3000/mcp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}' | \
|
||||
jq '.result.tools[].name' | sort
|
||||
|
||||
echo -e "\nTesting get_node_essentials..."
|
||||
curl -s -X POST http://localhost:3000/mcp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"jsonrpc":"2.0",
|
||||
"method":"tools/call",
|
||||
"params":{
|
||||
"name":"get_node_essentials",
|
||||
"arguments":{"nodeType":"nodes-base.httpRequest"}
|
||||
},
|
||||
"id":2
|
||||
}' | jq '.result.content[0].text' -r | jq '.requiredProperties, .commonProperties' | head -20
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
If everything is working, you should see:
|
||||
1. **12 tools** in the tool list
|
||||
2. **get_node_essentials** returns ~6 properties (not 200+)
|
||||
3. **No errors** about missing tools
|
||||
|
||||
## If Tools Still Don't Appear
|
||||
|
||||
1. **Check which server file is being used**:
|
||||
```bash
|
||||
grep -n "from './server" dist/mcp/index.js
|
||||
```
|
||||
Should show: `from './server-update'`
|
||||
|
||||
2. **Verify the tools are in the compiled code**:
|
||||
```bash
|
||||
grep -c "get_node_essentials" dist/mcp/tools-update.js
|
||||
```
|
||||
Should show: 3 or more
|
||||
|
||||
3. **Check if there's a caching issue**:
|
||||
- Add `?v=2` to your MCP URL in Claude Desktop config
|
||||
- Or change the server name temporarily
|
||||
|
||||
## Next Steps
|
||||
|
||||
Once you confirm the tools are working:
|
||||
1. Document the deployment process that worked
|
||||
2. Update CI/CD to automate image builds
|
||||
3. Proceed with V2 improvements (deduplication, etc.)
|
||||
|
||||
The tools ARE implemented - we just need to get the latest code deployed!
|
||||
@@ -1,198 +0,0 @@
|
||||
# MCP Implementation Action Plan
|
||||
|
||||
## Key Insights from Analysis
|
||||
|
||||
### ✅ What You Already Have (Working Well)
|
||||
1. **Excellent property extraction** - All properties with complete schemas
|
||||
2. **Proper data structure** - Properties include types, options, displayOptions
|
||||
3. **Efficient storage** - JSON in SQLite is perfect for this use case
|
||||
4. **Complete metadata** - Operations, credentials, documentation all captured
|
||||
|
||||
### ❌ The Real Problem
|
||||
- **Information overload**: Returning 200+ properties when AI needs 10-20
|
||||
- **No filtering**: All properties returned regardless of relevance
|
||||
- **Poor organization**: Essential mixed with advanced properties
|
||||
- **No examples**: AI agents need concrete examples to work from
|
||||
|
||||
### 💡 The Solution
|
||||
**Don't restructure - add intelligent filtering layers on top**
|
||||
|
||||
## Immediate Action Plan (This Week)
|
||||
|
||||
### Day 1-2: Implement get_node_essentials
|
||||
|
||||
1. **Create services**:
|
||||
```bash
|
||||
touch src/services/property-filter.ts
|
||||
touch src/services/example-generator.ts
|
||||
```
|
||||
|
||||
2. **Copy code from implementation guide**:
|
||||
- PropertyFilter class with essential lists
|
||||
- ExampleGenerator with concrete examples
|
||||
- Tool implementation in server.ts
|
||||
|
||||
3. **Test with top 5 nodes**:
|
||||
- nodes-base.httpRequest
|
||||
- nodes-base.webhook
|
||||
- nodes-base.code
|
||||
- nodes-base.set
|
||||
- nodes-base.postgres
|
||||
|
||||
4. **Measure improvement**:
|
||||
```bash
|
||||
npm run build
|
||||
node scripts/test-essentials.js
|
||||
```
|
||||
|
||||
### Day 3: Expand Coverage
|
||||
|
||||
1. **Add 15 more nodes** to ESSENTIAL_PROPERTIES:
|
||||
- nodes-base.if
|
||||
- nodes-base.merge
|
||||
- nodes-base.splitInBatches
|
||||
- nodes-base.function
|
||||
- nodes-base.email
|
||||
- nodes-base.slack
|
||||
- nodes-base.github
|
||||
- nodes-base.googleSheets
|
||||
- nodes-base.openAi
|
||||
- nodes-base.redis
|
||||
- nodes-base.mongodb
|
||||
- nodes-base.mysql
|
||||
- nodes-base.ftp
|
||||
- nodes-base.ssh
|
||||
- nodes-base.executeCommand
|
||||
|
||||
2. **Create examples** for each node
|
||||
|
||||
3. **Test with AI agents**
|
||||
|
||||
### Day 4-5: Implement search_node_properties
|
||||
|
||||
1. **Create property flattener**:
|
||||
```typescript
|
||||
// Converts nested properties to flat list with paths
|
||||
class PropertyFlattener {
|
||||
static flatten(properties: any[], path = ''): FlatProperty[]
|
||||
}
|
||||
```
|
||||
|
||||
2. **Add search functionality**:
|
||||
- Search by name
|
||||
- Search by description
|
||||
- Search by type
|
||||
|
||||
3. **Test search accuracy**
|
||||
|
||||
### Week 2: Validation & Task Templates
|
||||
|
||||
1. **Implement validate_node_config**:
|
||||
- Check required properties
|
||||
- Validate against displayOptions
|
||||
- Provide helpful error messages
|
||||
|
||||
2. **Create task templates**:
|
||||
- Common API patterns
|
||||
- Database operations
|
||||
- File handling
|
||||
- Webhook patterns
|
||||
|
||||
## Essential Property Lists (Starting Point)
|
||||
|
||||
```typescript
|
||||
// Top 20 nodes to optimize first (80% of usage)
|
||||
const PRIORITY_NODES = {
|
||||
'nodes-base.httpRequest': {
|
||||
required: ['url'],
|
||||
common: ['method', 'authentication', 'sendBody', 'contentType', 'sendHeaders']
|
||||
},
|
||||
'nodes-base.webhook': {
|
||||
required: [],
|
||||
common: ['httpMethod', 'path', 'responseMode', 'responseData']
|
||||
},
|
||||
'nodes-base.code': {
|
||||
required: [],
|
||||
common: ['language', 'jsCode', 'pythonCode']
|
||||
},
|
||||
'nodes-base.set': {
|
||||
required: [],
|
||||
common: ['mode', 'assignments', 'options']
|
||||
},
|
||||
'nodes-base.if': {
|
||||
required: [],
|
||||
common: ['conditions', 'combineOperation']
|
||||
},
|
||||
'nodes-base.postgres': {
|
||||
required: [],
|
||||
common: ['operation', 'table', 'query', 'additionalFields']
|
||||
},
|
||||
'nodes-base.openAi': {
|
||||
required: [],
|
||||
common: ['resource', 'operation', 'modelId', 'prompt', 'messages']
|
||||
},
|
||||
'nodes-base.googleSheets': {
|
||||
required: [],
|
||||
common: ['operation', 'sheetId', 'range', 'dataStartRow']
|
||||
},
|
||||
'nodes-base.slack': {
|
||||
required: [],
|
||||
common: ['resource', 'operation', 'channel', 'text', 'attachments']
|
||||
},
|
||||
'nodes-base.email': {
|
||||
required: [],
|
||||
common: ['fromEmail', 'toEmail', 'subject', 'text', 'html']
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
### Week 1
|
||||
- [ ] get_node_essentials working for 20 nodes
|
||||
- [ ] 90%+ size reduction achieved
|
||||
- [ ] Examples provided for common use cases
|
||||
- [ ] Property search implemented
|
||||
|
||||
### Week 2
|
||||
- [ ] Configuration validation working
|
||||
- [ ] 10+ task templates created
|
||||
- [ ] Error messages are helpful
|
||||
- [ ] AI agents successfully creating workflows
|
||||
|
||||
### Month 1
|
||||
- [ ] 50+ nodes optimized
|
||||
- [ ] Advanced features implemented
|
||||
- [ ] Documentation updated
|
||||
- [ ] Migration guide created
|
||||
|
||||
## Quick Test Commands
|
||||
|
||||
```bash
|
||||
# Test essentials tool
|
||||
echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"get_node_essentials","arguments":{"nodeType":"nodes-base.httpRequest"}},"id":1}' | npm start
|
||||
|
||||
# Compare with original
|
||||
echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"get_node_info","arguments":{"nodeType":"nodes-base.httpRequest"}},"id":1}' | npm start
|
||||
|
||||
# Test property search
|
||||
echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"search_node_properties","arguments":{"nodeType":"nodes-base.httpRequest","query":"auth"}},"id":1}' | npm start
|
||||
```
|
||||
|
||||
## Remember
|
||||
|
||||
1. **Start small** - Get one tool working perfectly before moving on
|
||||
2. **Test with real AI** - Use Claude/GPT to validate improvements
|
||||
3. **Iterate quickly** - Refine based on what works
|
||||
4. **Keep compatibility** - Don't break existing tools
|
||||
5. **Measure everything** - Track size reduction and success rates
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Review this plan with your team
|
||||
2. Start with Day 1 implementation
|
||||
3. Test with HTTP Request node
|
||||
4. Get feedback from AI agents
|
||||
5. Iterate and improve
|
||||
|
||||
The key is to **deliver value incrementally** while building toward the complete solution.
|
||||
@@ -1,408 +0,0 @@
|
||||
# MCP Implementation Guide - Practical Steps
|
||||
|
||||
## Understanding the Current Architecture
|
||||
|
||||
Your current system already does the hard work:
|
||||
```
|
||||
n8n packages → PropertyExtractor → Complete Property Schema (JSON) → SQLite → MCP Tools
|
||||
```
|
||||
|
||||
The properties are well-structured with:
|
||||
- Complete type information
|
||||
- Display options (conditional visibility)
|
||||
- Default values and descriptions
|
||||
- Options for select fields
|
||||
|
||||
The issue is that `get_node_info` returns ALL of this (200+ properties) when AI agents only need 10-20.
|
||||
|
||||
## Step 1: Create Property Filter Service
|
||||
|
||||
Create `src/services/property-filter.ts`:
|
||||
|
||||
```typescript
|
||||
interface SimplifiedProperty {
|
||||
name: string;
|
||||
displayName: string;
|
||||
type: string;
|
||||
description: string;
|
||||
default?: any;
|
||||
options?: Array<{ value: string; label: string }>;
|
||||
required?: boolean;
|
||||
showWhen?: Record<string, any>;
|
||||
}
|
||||
|
||||
interface EssentialConfig {
|
||||
required: string[];
|
||||
common: string[];
|
||||
}
|
||||
|
||||
export class PropertyFilter {
|
||||
// Start with manual curation for most-used nodes
|
||||
private static ESSENTIAL_PROPERTIES: Record<string, EssentialConfig> = {
|
||||
'nodes-base.httpRequest': {
|
||||
required: ['url'],
|
||||
common: ['method', 'authentication', 'sendBody', 'contentType', 'sendHeaders']
|
||||
},
|
||||
'nodes-base.webhook': {
|
||||
required: [],
|
||||
common: ['httpMethod', 'path', 'responseMode', 'responseData', 'responseCode']
|
||||
},
|
||||
'nodes-base.set': {
|
||||
required: [],
|
||||
common: ['mode', 'assignments']
|
||||
},
|
||||
'nodes-base.if': {
|
||||
required: [],
|
||||
common: ['conditions']
|
||||
},
|
||||
'nodes-base.code': {
|
||||
required: [],
|
||||
common: ['language', 'jsCode', 'pythonCode']
|
||||
},
|
||||
'nodes-base.postgres': {
|
||||
required: [],
|
||||
common: ['operation', 'query', 'table', 'columns']
|
||||
},
|
||||
'nodes-base.openAi': {
|
||||
required: [],
|
||||
common: ['resource', 'operation', 'modelId', 'prompt']
|
||||
}
|
||||
};
|
||||
|
||||
static getEssentials(allProperties: any[], nodeType: string): {
|
||||
required: SimplifiedProperty[];
|
||||
common: SimplifiedProperty[];
|
||||
} {
|
||||
const config = this.ESSENTIAL_PROPERTIES[nodeType];
|
||||
|
||||
if (!config) {
|
||||
// Fallback: Take required + first 5 non-conditional properties
|
||||
return this.inferEssentials(allProperties);
|
||||
}
|
||||
|
||||
// Extract specified properties
|
||||
const required = config.required
|
||||
.map(name => allProperties.find(p => p.name === name))
|
||||
.filter(Boolean)
|
||||
.map(p => this.simplifyProperty(p));
|
||||
|
||||
const common = config.common
|
||||
.map(name => allProperties.find(p => p.name === name))
|
||||
.filter(Boolean)
|
||||
.map(p => this.simplifyProperty(p));
|
||||
|
||||
return { required, common };
|
||||
}
|
||||
|
||||
private static simplifyProperty(prop: any): SimplifiedProperty {
|
||||
const simplified: SimplifiedProperty = {
|
||||
name: prop.name,
|
||||
displayName: prop.displayName || prop.name,
|
||||
type: prop.type,
|
||||
description: prop.description || '',
|
||||
required: prop.required || false
|
||||
};
|
||||
|
||||
// Include default if it's simple
|
||||
if (prop.default !== undefined && typeof prop.default !== 'object') {
|
||||
simplified.default = prop.default;
|
||||
}
|
||||
|
||||
// Simplify options
|
||||
if (prop.options && Array.isArray(prop.options)) {
|
||||
simplified.options = prop.options.map((opt: any) => ({
|
||||
value: typeof opt === 'string' ? opt : (opt.value || opt.name),
|
||||
label: typeof opt === 'string' ? opt : (opt.name || opt.value)
|
||||
}));
|
||||
}
|
||||
|
||||
// Include simple display conditions
|
||||
if (prop.displayOptions?.show && Object.keys(prop.displayOptions.show).length <= 2) {
|
||||
simplified.showWhen = prop.displayOptions.show;
|
||||
}
|
||||
|
||||
return simplified;
|
||||
}
|
||||
|
||||
private static inferEssentials(properties: any[]) {
|
||||
// For unknown nodes, use heuristics
|
||||
const required = properties
|
||||
.filter(p => p.required)
|
||||
.map(p => this.simplifyProperty(p));
|
||||
|
||||
const common = properties
|
||||
.filter(p => !p.required && !p.displayOptions) // Simple, always-visible properties
|
||||
.slice(0, 5)
|
||||
.map(p => this.simplifyProperty(p));
|
||||
|
||||
return { required, common };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Step 2: Create Example Generator
|
||||
|
||||
Create `src/services/example-generator.ts`:
|
||||
|
||||
```typescript
|
||||
export class ExampleGenerator {
|
||||
private static EXAMPLES: Record<string, Record<string, any>> = {
|
||||
'nodes-base.httpRequest': {
|
||||
minimal: {
|
||||
url: 'https://api.example.com/data'
|
||||
},
|
||||
getWithAuth: {
|
||||
method: 'GET',
|
||||
url: 'https://api.example.com/protected',
|
||||
authentication: 'genericCredentialType',
|
||||
genericAuthType: 'headerAuth'
|
||||
},
|
||||
postJson: {
|
||||
method: 'POST',
|
||||
url: 'https://api.example.com/create',
|
||||
sendBody: true,
|
||||
contentType: 'json',
|
||||
specifyBody: 'json',
|
||||
jsonBody: '{ "name": "Example User", "email": "user@example.com" }'
|
||||
}
|
||||
},
|
||||
'nodes-base.webhook': {
|
||||
minimal: {
|
||||
path: 'my-webhook',
|
||||
httpMethod: 'POST'
|
||||
},
|
||||
withResponse: {
|
||||
path: 'webhook-endpoint',
|
||||
httpMethod: 'POST',
|
||||
responseMode: 'lastNode',
|
||||
responseData: 'allEntries'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static getExamples(nodeType: string, essentials: any): Record<string, any> {
|
||||
// Return curated examples if available
|
||||
if (this.EXAMPLES[nodeType]) {
|
||||
return this.EXAMPLES[nodeType];
|
||||
}
|
||||
|
||||
// Otherwise, generate minimal example
|
||||
const minimal: Record<string, any> = {};
|
||||
|
||||
// Add required fields
|
||||
for (const prop of essentials.required) {
|
||||
minimal[prop.name] = this.getDefaultValue(prop);
|
||||
}
|
||||
|
||||
// Add first common field with a default
|
||||
const firstCommon = essentials.common.find((p: any) => p.default !== undefined);
|
||||
if (firstCommon) {
|
||||
minimal[firstCommon.name] = firstCommon.default;
|
||||
}
|
||||
|
||||
return { minimal };
|
||||
}
|
||||
|
||||
private static getDefaultValue(prop: any): any {
|
||||
if (prop.default !== undefined) return prop.default;
|
||||
|
||||
switch (prop.type) {
|
||||
case 'string':
|
||||
return prop.name === 'url' ? 'https://api.example.com' : '';
|
||||
case 'number':
|
||||
return 0;
|
||||
case 'boolean':
|
||||
return false;
|
||||
case 'options':
|
||||
return prop.options?.[0]?.value || '';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Step 3: Implement get_node_essentials Tool
|
||||
|
||||
Add to `src/mcp/server.ts` in the tool handler switch:
|
||||
|
||||
```typescript
|
||||
case "get_node_essentials": {
|
||||
const { nodeType } = request.params.arguments as { nodeType: string };
|
||||
|
||||
// Get node from database
|
||||
const node = await service.getNodeByType(nodeType);
|
||||
if (!node) {
|
||||
throw new Error(`Node type ${nodeType} not found`);
|
||||
}
|
||||
|
||||
// Parse properties
|
||||
const allProperties = JSON.parse(node.properties_schema || '[]');
|
||||
|
||||
// Get essentials
|
||||
const essentials = PropertyFilter.getEssentials(allProperties, nodeType);
|
||||
|
||||
// Generate examples
|
||||
const examples = ExampleGenerator.getExamples(nodeType, essentials);
|
||||
|
||||
// Parse operations
|
||||
const operations = JSON.parse(node.operations || '[]');
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: JSON.stringify({
|
||||
nodeType: node.node_type,
|
||||
displayName: node.display_name,
|
||||
description: node.description,
|
||||
category: node.category,
|
||||
requiredProperties: essentials.required,
|
||||
commonProperties: essentials.common,
|
||||
operations: operations.map((op: any) => ({
|
||||
name: op.name || op.operation,
|
||||
description: op.description
|
||||
})),
|
||||
examples,
|
||||
metadata: {
|
||||
totalProperties: allProperties.length,
|
||||
isAITool: node.is_ai_tool,
|
||||
isTrigger: node.is_trigger,
|
||||
hasCredentials: node.credentials_required ? true : false
|
||||
}
|
||||
}, null, 2)
|
||||
}]
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Step 4: Add Tool Definition
|
||||
|
||||
In `src/mcp/server.ts`, add to the tools array:
|
||||
|
||||
```typescript
|
||||
{
|
||||
name: "get_node_essentials",
|
||||
description: "Get only essential properties for a node (10-20 most important properties instead of 200+). Perfect for quick configuration.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
nodeType: {
|
||||
type: "string",
|
||||
description: "The node type (e.g., 'nodes-base.httpRequest')"
|
||||
}
|
||||
},
|
||||
required: ["nodeType"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Step 5: Test Implementation
|
||||
|
||||
Create `scripts/test-essentials.ts`:
|
||||
|
||||
```typescript
|
||||
#!/usr/bin/env node
|
||||
import { NodeDocumentationService } from '../src/services/node-documentation-service';
|
||||
import { PropertyFilter } from '../src/services/property-filter';
|
||||
import { ExampleGenerator } from '../src/services/example-generator';
|
||||
|
||||
async function testEssentials() {
|
||||
const service = new NodeDocumentationService();
|
||||
await service.initialize();
|
||||
|
||||
const nodeTypes = [
|
||||
'nodes-base.httpRequest',
|
||||
'nodes-base.webhook',
|
||||
'nodes-base.set',
|
||||
'nodes-base.code'
|
||||
];
|
||||
|
||||
for (const nodeType of nodeTypes) {
|
||||
console.log(`\n=== Testing ${nodeType} ===`);
|
||||
|
||||
const node = await service.getNodeByType(nodeType);
|
||||
if (!node) continue;
|
||||
|
||||
const allProperties = JSON.parse(node.properties_schema || '[]');
|
||||
const essentials = PropertyFilter.getEssentials(allProperties, nodeType);
|
||||
const examples = ExampleGenerator.getExamples(nodeType, essentials);
|
||||
|
||||
console.log(`Total properties: ${allProperties.length}`);
|
||||
console.log(`Essential properties: ${essentials.required.length + essentials.common.length}`);
|
||||
console.log(`Size reduction: ${Math.round((1 - (essentials.required.length + essentials.common.length) / allProperties.length) * 100)}%`);
|
||||
|
||||
console.log('\nRequired:', essentials.required.map(p => p.name).join(', ') || 'None');
|
||||
console.log('Common:', essentials.common.map(p => p.name).join(', '));
|
||||
console.log('Examples:', Object.keys(examples).join(', '));
|
||||
|
||||
// Compare response sizes
|
||||
const fullSize = JSON.stringify(allProperties).length;
|
||||
const essentialSize = JSON.stringify({ ...essentials, examples }).length;
|
||||
console.log(`\nResponse size: ${(fullSize / 1024).toFixed(1)}KB → ${(essentialSize / 1024).toFixed(1)}KB`);
|
||||
}
|
||||
|
||||
await service.close();
|
||||
}
|
||||
|
||||
testEssentials().catch(console.error);
|
||||
```
|
||||
|
||||
## Step 6: Iterate Based on Testing
|
||||
|
||||
After testing, refine the essential property lists by:
|
||||
|
||||
1. **Analyzing actual usage**: Which properties do users set most often?
|
||||
2. **AI agent feedback**: Which properties cause confusion?
|
||||
3. **Workflow analysis**: What are common patterns?
|
||||
|
||||
## Next Tools to Implement
|
||||
|
||||
### search_node_properties (Week 1)
|
||||
```typescript
|
||||
case "search_node_properties": {
|
||||
const { nodeType, query } = request.params.arguments;
|
||||
const allProperties = JSON.parse(node.properties_schema || '[]');
|
||||
|
||||
// Flatten nested properties and search
|
||||
const flattened = PropertyFlattener.flatten(allProperties);
|
||||
const matches = flattened.filter(p =>
|
||||
p.name.toLowerCase().includes(query.toLowerCase()) ||
|
||||
p.displayName?.toLowerCase().includes(query.toLowerCase()) ||
|
||||
p.description?.toLowerCase().includes(query.toLowerCase())
|
||||
);
|
||||
|
||||
return { matches: matches.slice(0, 20) };
|
||||
}
|
||||
```
|
||||
|
||||
### validate_node_config (Week 2)
|
||||
```typescript
|
||||
case "validate_node_config": {
|
||||
const { nodeType, config } = request.params.arguments;
|
||||
// Use existing properties and displayOptions to validate
|
||||
}
|
||||
```
|
||||
|
||||
### get_node_for_task (Week 2)
|
||||
```typescript
|
||||
case "get_node_for_task": {
|
||||
const { task } = request.params.arguments;
|
||||
// Return pre-configured templates
|
||||
}
|
||||
```
|
||||
|
||||
## Measuring Success
|
||||
|
||||
Track these metrics:
|
||||
1. Response size reduction (target: >90%)
|
||||
2. Time to configure a node (target: <1 minute)
|
||||
3. AI agent success rate (target: >90%)
|
||||
4. Number of tool calls needed (target: 2-3)
|
||||
|
||||
## Key Insight
|
||||
|
||||
Your existing system is already excellent at extracting properties. The solution isn't to rebuild it, but to add intelligent filtering on top. This approach:
|
||||
- Delivers immediate value
|
||||
- Requires minimal changes
|
||||
- Preserves all existing functionality
|
||||
- Can be iteratively improved
|
||||
@@ -1,489 +0,0 @@
|
||||
# MCP Tools Implementation Strategy
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document outlines a comprehensive strategy to transform the n8n MCP from a documentation server into an AI-optimized workflow configuration assistant. The core issue is that `get_node_info` returns 100KB+ of unstructured JSON, making it nearly impossible for AI agents to efficiently build n8n workflows. Our strategy introduces new tools and restructures data to reduce complexity by 95% while maintaining full functionality.
|
||||
|
||||
## Current State Analysis
|
||||
|
||||
### Problems
|
||||
1. **Data Overload**: HTTP Request node returns 200+ properties when only 5-10 are needed
|
||||
2. **Poor Structure**: Properties stored as monolithic JSON blobs, not queryable
|
||||
3. **Duplicate Properties**: Same property appears 3-4 times with different conditions
|
||||
4. **Complex Nesting**: Properties buried in collections within collections
|
||||
5. **No Prioritization**: Essential properties mixed with rarely-used advanced options
|
||||
|
||||
### Impact
|
||||
- AI agents waste 90% of tokens parsing irrelevant data
|
||||
- High error rates due to confusion with duplicate properties
|
||||
- 5-10 minutes to configure a simple node (should be <1 minute)
|
||||
- Poor developer experience leads to workflow building failures
|
||||
|
||||
## Implementation Strategy Overview
|
||||
|
||||
### Design Principles
|
||||
1. **Progressive Disclosure**: Start with essentials, add complexity only when needed
|
||||
2. **Task-Oriented**: Focus on what users want to do, not technical details
|
||||
3. **Backward Compatible**: Keep existing tools, add new optimized ones
|
||||
4. **Incremental Deployment**: Each phase delivers value independently
|
||||
5. **AI-First Design**: Optimize for token efficiency and clarity
|
||||
|
||||
### Three-Phase Approach
|
||||
|
||||
**Phase 1: Quick Wins (Week 1-2)**
|
||||
- Implement without database changes
|
||||
- Filter existing data for essentials
|
||||
- Add common examples
|
||||
|
||||
**Phase 2: Enhanced Capabilities (Week 3-4)**
|
||||
- Parse property structures
|
||||
- Build search and validation
|
||||
- Create task templates
|
||||
|
||||
**Phase 3: Full Optimization (Month 2)**
|
||||
- Database schema migration
|
||||
- Property deduplication
|
||||
- Dependency tracking
|
||||
|
||||
## Phase 1: Quick Wins Implementation
|
||||
|
||||
### 1.1 get_node_essentials Tool
|
||||
|
||||
**Purpose**: Return only the 10-20 properties needed for 90% of use cases
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
interface GetNodeEssentialsInput {
|
||||
nodeType: string;
|
||||
}
|
||||
|
||||
interface GetNodeEssentialsOutput {
|
||||
nodeType: string;
|
||||
displayName: string;
|
||||
description: string;
|
||||
requiredProperties: PropertyInfo[];
|
||||
commonProperties: PropertyInfo[];
|
||||
examples: {
|
||||
minimal: object;
|
||||
common: object;
|
||||
};
|
||||
}
|
||||
|
||||
interface PropertyInfo {
|
||||
name: string;
|
||||
type: string;
|
||||
description: string;
|
||||
default?: any;
|
||||
options?: string[];
|
||||
placeholder?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Technical Approach**:
|
||||
1. Create curated lists of essential properties for top 20 nodes
|
||||
2. Parse existing property schema to extract required fields
|
||||
3. Filter properties based on usage frequency
|
||||
4. Return simplified structure without nested collections
|
||||
|
||||
**Example Output**:
|
||||
```json
|
||||
{
|
||||
"nodeType": "nodes-base.httpRequest",
|
||||
"displayName": "HTTP Request",
|
||||
"requiredProperties": [{
|
||||
"name": "url",
|
||||
"type": "string",
|
||||
"description": "The URL to make the request to",
|
||||
"placeholder": "https://api.example.com/endpoint"
|
||||
}],
|
||||
"commonProperties": [
|
||||
{
|
||||
"name": "method",
|
||||
"type": "options",
|
||||
"options": ["GET", "POST", "PUT", "DELETE"],
|
||||
"default": "GET"
|
||||
},
|
||||
{
|
||||
"name": "authentication",
|
||||
"type": "options",
|
||||
"options": ["none", "basicAuth", "bearerToken"],
|
||||
"default": "none"
|
||||
}
|
||||
],
|
||||
"examples": {
|
||||
"minimal": { "url": "https://api.example.com/data" },
|
||||
"common": {
|
||||
"method": "POST",
|
||||
"url": "https://api.example.com/create",
|
||||
"sendBody": true,
|
||||
"contentType": "json",
|
||||
"jsonBody": "{ \"name\": \"example\" }"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 Enhanced Tool Descriptions
|
||||
|
||||
Update all existing tool descriptions based on testing feedback to be more concise and action-oriented.
|
||||
|
||||
### 1.3 Common Examples Database
|
||||
|
||||
Create JSON configuration examples for the top 20 most-used nodes, stored in `src/data/node-examples.json`.
|
||||
|
||||
## Phase 2: Enhanced Capabilities
|
||||
|
||||
### 2.1 search_node_properties Tool
|
||||
|
||||
**Purpose**: Find specific properties within a node without parsing everything
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
interface SearchNodePropertiesInput {
|
||||
nodeType: string;
|
||||
query: string; // Keyword to search for
|
||||
category?: 'authentication' | 'request' | 'response' | 'advanced';
|
||||
}
|
||||
|
||||
interface SearchNodePropertiesOutput {
|
||||
query: string;
|
||||
matches: PropertyMatch[];
|
||||
totalMatches: number;
|
||||
}
|
||||
|
||||
interface PropertyMatch {
|
||||
name: string;
|
||||
type: string;
|
||||
path: string; // Dot notation path
|
||||
description: string;
|
||||
visibleWhen?: Record<string, any>;
|
||||
category: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Technical Approach**:
|
||||
1. Parse property schema recursively
|
||||
2. Build searchable index of all properties
|
||||
3. Include visibility conditions
|
||||
4. Return flattened results with paths
|
||||
|
||||
### 2.2 get_node_for_task Tool
|
||||
|
||||
**Purpose**: Return pre-configured property sets for common tasks
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
interface GetNodeForTaskInput {
|
||||
task: string; // e.g., "post_json_request", "call_api_with_auth"
|
||||
nodeType?: string; // Optional, can infer from task
|
||||
}
|
||||
|
||||
interface GetNodeForTaskOutput {
|
||||
task: string;
|
||||
description: string;
|
||||
nodeType: string;
|
||||
configuration: object;
|
||||
userMustProvide: Array<{
|
||||
property: string;
|
||||
description: string;
|
||||
}>;
|
||||
optionalEnhancements: Array<{
|
||||
property: string;
|
||||
description: string;
|
||||
}>;
|
||||
}
|
||||
```
|
||||
|
||||
**Task Templates** (stored in `src/data/task-templates.json`):
|
||||
- `get_api_data` - Simple GET request
|
||||
- `post_json_request` - POST with JSON body
|
||||
- `call_api_with_auth` - Authenticated API call
|
||||
- `webhook_receiver` - Accept incoming webhooks
|
||||
- `database_query` - Query a database
|
||||
- `send_email` - Send an email
|
||||
- `process_file` - Read and process files
|
||||
|
||||
### 2.3 validate_node_config Tool
|
||||
|
||||
**Purpose**: Validate configurations before use, catch errors early
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
interface ValidateNodeConfigInput {
|
||||
nodeType: string;
|
||||
config: object;
|
||||
}
|
||||
|
||||
interface ValidateNodeConfigOutput {
|
||||
valid: boolean;
|
||||
errors: ValidationError[];
|
||||
warnings: ValidationWarning[];
|
||||
suggestions: string[];
|
||||
hiddenProperties: string[]; // Properties not visible with current config
|
||||
autofix?: object; // Suggested fixes
|
||||
}
|
||||
```
|
||||
|
||||
**Validation Rules**:
|
||||
1. Check required properties
|
||||
2. Validate property types
|
||||
3. Check property dependencies
|
||||
4. Suggest common missing configurations
|
||||
5. Warn about potential issues
|
||||
|
||||
### 2.4 Property Parsing Service
|
||||
|
||||
Create `src/services/property-parser.ts` to:
|
||||
1. Parse nested property structures
|
||||
2. Flatten collections to dot notation
|
||||
3. Extract visibility conditions
|
||||
4. Categorize properties (essential/common/advanced)
|
||||
5. Build property dependency graph
|
||||
|
||||
## Phase 3: Full Optimization
|
||||
|
||||
### 3.1 Database Schema Migration
|
||||
|
||||
**New Tables**:
|
||||
```sql
|
||||
-- Property-level storage
|
||||
CREATE TABLE node_properties_v2 (
|
||||
id INTEGER PRIMARY KEY,
|
||||
node_type TEXT NOT NULL,
|
||||
property_name TEXT NOT NULL,
|
||||
property_path TEXT NOT NULL, -- Dot notation path
|
||||
property_type TEXT NOT NULL,
|
||||
is_required BOOLEAN DEFAULT 0,
|
||||
is_essential BOOLEAN DEFAULT 0,
|
||||
is_common BOOLEAN DEFAULT 0,
|
||||
category TEXT, -- authentication, request, response, advanced
|
||||
parent_property TEXT,
|
||||
display_conditions TEXT, -- JSON conditions
|
||||
description TEXT,
|
||||
default_value TEXT,
|
||||
options TEXT, -- JSON array for select fields
|
||||
placeholder TEXT,
|
||||
usage_frequency INTEGER DEFAULT 0,
|
||||
UNIQUE(node_type, property_path)
|
||||
);
|
||||
|
||||
-- Task templates
|
||||
CREATE TABLE task_templates (
|
||||
id INTEGER PRIMARY KEY,
|
||||
task_name TEXT UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
node_type TEXT NOT NULL,
|
||||
configuration TEXT NOT NULL, -- JSON
|
||||
user_must_provide TEXT, -- JSON array
|
||||
optional_enhancements TEXT -- JSON array
|
||||
);
|
||||
|
||||
-- Property dependencies
|
||||
CREATE TABLE property_dependencies (
|
||||
id INTEGER PRIMARY KEY,
|
||||
node_type TEXT NOT NULL,
|
||||
property_name TEXT NOT NULL,
|
||||
depends_on_property TEXT NOT NULL,
|
||||
depends_on_value TEXT,
|
||||
dependency_type TEXT -- enables, requires, conflicts
|
||||
);
|
||||
|
||||
-- Common examples
|
||||
CREATE TABLE node_examples (
|
||||
id INTEGER PRIMARY KEY,
|
||||
node_type TEXT NOT NULL,
|
||||
example_name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
configuration TEXT NOT NULL, -- JSON
|
||||
category TEXT,
|
||||
UNIQUE(node_type, example_name)
|
||||
);
|
||||
```
|
||||
|
||||
### 3.2 Migration Process
|
||||
|
||||
1. **Data Extraction Script** (`scripts/migrate-properties.ts`):
|
||||
- Parse existing property schemas
|
||||
- Extract individual properties with metadata
|
||||
- Deduplicate properties with conditions
|
||||
- Populate new tables
|
||||
|
||||
2. **Backward Compatibility**:
|
||||
- Keep existing tables and tools
|
||||
- Add feature flag for new tools
|
||||
- Gradual migration over 2 weeks
|
||||
|
||||
### 3.3 Advanced Tools
|
||||
|
||||
**get_property_dependencies**:
|
||||
```typescript
|
||||
interface GetPropertyDependenciesInput {
|
||||
nodeType: string;
|
||||
property: string;
|
||||
}
|
||||
|
||||
interface GetPropertyDependenciesOutput {
|
||||
property: string;
|
||||
requires: Record<string, any>;
|
||||
enables: string[];
|
||||
conflicts: string[];
|
||||
requiredChain: string[]; // Step-by-step to enable
|
||||
alternatives: Array<{
|
||||
description: string;
|
||||
properties: object;
|
||||
}>;
|
||||
}
|
||||
```
|
||||
|
||||
**get_node_compatibility**:
|
||||
```typescript
|
||||
// Check which nodes work well together
|
||||
interface GetNodeCompatibilityInput {
|
||||
sourceNode: string;
|
||||
targetNode: string;
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Timeline
|
||||
|
||||
### Week 1: Foundation
|
||||
- [ ] Implement get_node_essentials with hardcoded essentials
|
||||
- [ ] Create examples database for top 10 nodes
|
||||
- [ ] Deploy updated tool descriptions
|
||||
- [ ] Test with HTTP Request and Webhook nodes
|
||||
|
||||
### Week 2: Expand Coverage
|
||||
- [ ] Add essentials for 20 more nodes
|
||||
- [ ] Implement basic property search
|
||||
- [ ] Create 5 task templates
|
||||
- [ ] Add validation for common errors
|
||||
|
||||
### Week 3: Enhanced Features
|
||||
- [ ] Build property parser service
|
||||
- [ ] Implement get_node_for_task
|
||||
- [ ] Add validate_node_config
|
||||
- [ ] Create property categorization
|
||||
|
||||
### Week 4: Testing & Refinement
|
||||
- [ ] Load test with complex nodes
|
||||
- [ ] Refine essential property lists
|
||||
- [ ] Add more task templates
|
||||
- [ ] Gather user feedback
|
||||
|
||||
### Month 2: Full Migration
|
||||
- [ ] Design new database schema
|
||||
- [ ] Build migration scripts
|
||||
- [ ] Implement property deduplication
|
||||
- [ ] Add dependency tracking
|
||||
- [ ] Deploy progressively
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- Property parser accuracy
|
||||
- Essential property extraction
|
||||
- Validation rule correctness
|
||||
- Task template validity
|
||||
|
||||
### Integration Tests
|
||||
- Tool response times (<100ms)
|
||||
- Data size reduction (>90%)
|
||||
- Backward compatibility
|
||||
- Error handling
|
||||
|
||||
### User Testing
|
||||
- Time to configure nodes
|
||||
- Error rates
|
||||
- Task completion success
|
||||
- AI agent performance
|
||||
|
||||
## Success Metrics
|
||||
|
||||
| Metric | Current | Target | Measurement |
|
||||
|--------|---------|--------|-------------|
|
||||
| Average properties returned | 200+ | 15 | get_node_essentials response |
|
||||
| Response size | 100KB+ | <5KB | JSON byte count |
|
||||
| Time to configure node | 5-10 min | <1 min | User testing |
|
||||
| Configuration errors | 40% | <10% | Validation logs |
|
||||
| AI token usage | High | -75% | Token counter |
|
||||
| Tool calls per task | 5-10 | 2-3 | Usage analytics |
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
### Technical Risks
|
||||
1. **Property Parsing Complexity**
|
||||
- Mitigation: Start with simple nodes, handle edge cases gradually
|
||||
- Fallback: Return original schema if parsing fails
|
||||
|
||||
2. **Performance Impact**
|
||||
- Mitigation: Cache parsed properties, use indexes
|
||||
- Monitor: Response times, add performance tests
|
||||
|
||||
3. **Data Quality**
|
||||
- Mitigation: Validate all transformations
|
||||
- Test: Compare outputs with original data
|
||||
|
||||
### Compatibility Risks
|
||||
1. **Breaking Changes**
|
||||
- Mitigation: New tools alongside old ones
|
||||
- Deprecation: 3-month warning period
|
||||
|
||||
2. **Schema Evolution**
|
||||
- Mitigation: Version property schemas
|
||||
- Handle: Multiple n8n versions
|
||||
|
||||
## Configuration Management
|
||||
|
||||
### Essential Properties Lists
|
||||
|
||||
Store in `src/data/essential-properties.json`:
|
||||
```json
|
||||
{
|
||||
"nodes-base.httpRequest": {
|
||||
"required": ["url"],
|
||||
"common": ["method", "authentication", "sendBody", "contentType"],
|
||||
"categories": {
|
||||
"authentication": ["authentication", "genericAuthType", "nodeCredentialType"],
|
||||
"request": ["sendBody", "contentType", "jsonBody", "bodyParameters"],
|
||||
"headers": ["sendHeaders", "headerParameters"],
|
||||
"advanced": ["options.timeout", "options.proxy", "options.redirect"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Feature Flags
|
||||
|
||||
```typescript
|
||||
const FEATURES = {
|
||||
USE_NODE_ESSENTIALS: process.env.USE_NODE_ESSENTIALS !== 'false',
|
||||
ENABLE_PROPERTY_SEARCH: process.env.ENABLE_PROPERTY_SEARCH === 'true',
|
||||
USE_NEW_SCHEMA: process.env.USE_NEW_SCHEMA === 'true'
|
||||
};
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Immediate Actions**:
|
||||
- Create essential properties list for HTTP Request node
|
||||
- Implement get_node_essentials tool
|
||||
- Test with real AI agents
|
||||
- Gather feedback
|
||||
|
||||
2. **Week 1 Deliverables**:
|
||||
- Working get_node_essentials for top 10 nodes
|
||||
- Basic examples database
|
||||
- Performance benchmarks
|
||||
- User feedback collection
|
||||
|
||||
3. **Success Criteria**:
|
||||
- 90% reduction in data size
|
||||
- 75% reduction in configuration time
|
||||
- Positive AI agent feedback
|
||||
- No regression in functionality
|
||||
|
||||
## Conclusion
|
||||
|
||||
This implementation strategy transforms the n8n MCP from a complex documentation server into an AI-friendly configuration assistant. By focusing on progressive disclosure and task-oriented access patterns, we can reduce complexity by 95% while actually improving functionality. The phased approach ensures we deliver value quickly while building toward a fully optimized solution.
|
||||
|
||||
The key insight: **AI agents need just enough information at the right time, not everything at once**. This strategy delivers exactly that.
|
||||
@@ -1,145 +0,0 @@
|
||||
# MCP Implementation Summary
|
||||
|
||||
## What Was Implemented
|
||||
|
||||
### 1. PropertyFilter Service (`src/services/property-filter.ts`)
|
||||
- ✅ Created comprehensive property filtering service
|
||||
- ✅ Added curated essential property lists for 20 most-used nodes
|
||||
- ✅ Implemented intelligent property simplification
|
||||
- ✅ Added property search functionality with relevance scoring
|
||||
- ✅ Automatic fallback for unconfigured nodes
|
||||
|
||||
### 2. ExampleGenerator Service (`src/services/example-generator.ts`)
|
||||
- ✅ Created example generation service
|
||||
- ✅ Added working examples for 20 nodes (minimal, common, advanced)
|
||||
- ✅ Implemented smart default value generation
|
||||
- ✅ Context-aware example selection
|
||||
|
||||
### 3. New MCP Tools
|
||||
- ✅ **get_node_essentials**: Returns only essential properties with 95% size reduction
|
||||
- ✅ **search_node_properties**: Search for specific properties within nodes
|
||||
|
||||
### 4. Server Implementation (`src/mcp/server-update.ts`)
|
||||
- ✅ Added handlers for new tools
|
||||
- ✅ Integrated PropertyFilter and ExampleGenerator services
|
||||
- ✅ Maintained backward compatibility
|
||||
- ✅ Added proper error handling and alternative node type resolution
|
||||
|
||||
### 5. Testing & Documentation
|
||||
- ✅ Created comprehensive test script (`scripts/test-essentials.ts`)
|
||||
- ✅ Created quick validation script (`scripts/quick-test.ts`)
|
||||
- ✅ Updated CLAUDE.md with new features
|
||||
- ✅ Created user guide (MCP_ESSENTIALS_README.md)
|
||||
- ✅ Documented implementation strategy and decisions
|
||||
|
||||
## Key Achievements
|
||||
|
||||
### Size Reduction
|
||||
- HTTP Request node: 100KB+ → 4.2KB (96% reduction)
|
||||
- Webhook node: 45KB → 2.1KB (95% reduction)
|
||||
- Code node: 38KB → 1.8KB (95% reduction)
|
||||
- Average reduction across 20 nodes: **94.3%**
|
||||
|
||||
### Property Reduction
|
||||
- HTTP Request: 245 properties → 6 essential properties
|
||||
- Postgres: 180 properties → 5 essential properties
|
||||
- Average: 200+ properties → 10-20 essential properties
|
||||
|
||||
### Performance Improvement
|
||||
- Response time: 50-100ms → 10-20ms
|
||||
- AI token usage: Reduced by ~75%
|
||||
- Configuration time: 5-10 minutes → <1 minute
|
||||
|
||||
## How It Works
|
||||
|
||||
### 1. Progressive Information Disclosure
|
||||
```
|
||||
Level 1: get_node_essentials (5KB) - Basic configuration
|
||||
Level 2: search_node_properties - Find specific options
|
||||
Level 3: get_node_documentation - Understand usage
|
||||
Level 4: get_node_info (100KB+) - Complete details (rarely needed)
|
||||
```
|
||||
|
||||
### 2. Smart Property Filtering
|
||||
- Required properties always included
|
||||
- Common properties based on usage patterns
|
||||
- Complex nested structures simplified
|
||||
- Conditional properties explained clearly
|
||||
|
||||
### 3. Working Examples
|
||||
- Minimal: Bare minimum to get started
|
||||
- Common: Typical use cases
|
||||
- Advanced: Complex configurations
|
||||
|
||||
## Testing the Implementation
|
||||
|
||||
### Quick Test
|
||||
```bash
|
||||
# Build the project
|
||||
npm run build
|
||||
|
||||
# Run quick test
|
||||
npm start < test-commands.txt
|
||||
```
|
||||
|
||||
Where `test-commands.txt` contains:
|
||||
```json
|
||||
{"jsonrpc":"2.0","method":"tools/call","params":{"name":"get_node_essentials","arguments":{"nodeType":"nodes-base.httpRequest"}},"id":1}
|
||||
```
|
||||
|
||||
### Comprehensive Test
|
||||
```bash
|
||||
# Run full test suite
|
||||
npm run build
|
||||
node scripts/test-essentials.js
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Immediate Improvements
|
||||
1. Add more node configurations (currently 20, target 50+)
|
||||
2. Refine essential property lists based on usage
|
||||
3. Add more sophisticated examples
|
||||
4. Implement caching for better performance
|
||||
|
||||
### Future Enhancements
|
||||
1. **Task-based configurations**: "I want to post JSON with authentication"
|
||||
2. **Configuration validation**: Check if config is valid before use
|
||||
3. **Property dependency resolution**: "To use property X, first enable Y"
|
||||
4. **Workflow patterns**: Common node combinations
|
||||
|
||||
### Maintenance Tasks
|
||||
1. Update essential properties when new n8n versions are released
|
||||
2. Monitor which properties AI agents search for most
|
||||
3. Add new nodes as they become popular
|
||||
4. Refine examples based on user feedback
|
||||
|
||||
## Integration Notes
|
||||
|
||||
### For Claude Desktop
|
||||
The new tools are automatically available. Recommended usage:
|
||||
```javascript
|
||||
// Always start with essentials
|
||||
const config = await get_node_essentials("nodes-base.httpRequest");
|
||||
|
||||
// Use the examples
|
||||
const myConfig = { ...config.examples.common };
|
||||
myConfig.url = "https://my-api.com";
|
||||
```
|
||||
|
||||
### For Other AI Agents
|
||||
The tools follow standard MCP protocol and can be used by any MCP-compatible client.
|
||||
|
||||
## Success Metrics to Track
|
||||
|
||||
1. **Usage patterns**: Which nodes use get_node_essentials vs get_node_info
|
||||
2. **Search queries**: Most common property searches
|
||||
3. **Error rates**: Configuration errors before/after
|
||||
4. **Time to configure**: How long to build working workflows
|
||||
5. **AI feedback**: Success rates and pain points
|
||||
|
||||
## Conclusion
|
||||
|
||||
The implementation successfully addresses the core problem of information overload in the n8n MCP. By providing progressive disclosure of information and focusing on what AI agents actually need, we've made n8n workflow building with AI agents practical and efficient.
|
||||
|
||||
The 95% reduction in response size, combined with working examples and intelligent property filtering, transforms the experience from frustrating to delightful. AI agents can now configure n8n nodes in seconds instead of minutes, with much higher success rates.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,168 +0,0 @@
|
||||
# MCP Improvements - Implementation Summary
|
||||
|
||||
## Overview
|
||||
|
||||
This document summarizes the improvements implemented based on Claude Desktop evaluation feedback. The implementation addressed key issues with the MCP tools, particularly the `get_node_info` tool's usability for AI agents.
|
||||
|
||||
## Implemented Improvements
|
||||
|
||||
### 1. ✅ New Tool: `get_node_essentials`
|
||||
- **Purpose**: Provides only the 10-20 most important properties for a node
|
||||
- **Size Reduction**: 95% reduction (100KB+ → ~5KB)
|
||||
- **Features**:
|
||||
- Returns only required and common properties
|
||||
- Includes working examples for 20 most-used nodes
|
||||
- Shows operations available for the node
|
||||
- Includes metadata about the node
|
||||
|
||||
### 2. ✅ New Tool: `search_node_properties`
|
||||
- **Purpose**: Search for specific properties within a node
|
||||
- **Use Case**: Find authentication options, headers, body parameters without loading all properties
|
||||
- **Features**:
|
||||
- Full-text search across property names, descriptions, and display names
|
||||
- Returns property paths for nested properties
|
||||
- Shows only matching properties with their configurations
|
||||
|
||||
### 3. ✅ New Tool: `get_node_for_task`
|
||||
- **Purpose**: Get pre-configured node settings for common tasks
|
||||
- **Tasks Available**: 14 pre-configured templates including:
|
||||
- `post_json_request` - Send JSON to an API
|
||||
- `receive_webhook` - Set up webhook endpoint
|
||||
- `query_postgres` - Query PostgreSQL database
|
||||
- `chat_with_ai` - Send message to AI model
|
||||
- And 10 more...
|
||||
- **Features**:
|
||||
- Ready-to-use configurations
|
||||
- Clear indication of what user must provide
|
||||
- Optional enhancements and notes
|
||||
|
||||
### 4. ✅ New Tool: `list_tasks`
|
||||
- **Purpose**: Discover available task templates
|
||||
- **Categories**:
|
||||
- HTTP/API
|
||||
- Webhooks
|
||||
- Database
|
||||
- AI/LangChain
|
||||
- Data Processing
|
||||
- Communication
|
||||
|
||||
### 5. ✅ New Tool: `validate_node_config`
|
||||
- **Purpose**: Validate node configurations before use
|
||||
- **Checks**:
|
||||
- Missing required properties
|
||||
- Type errors
|
||||
- Invalid values
|
||||
- Security issues (hardcoded credentials, SQL injection risks)
|
||||
- Common mistakes
|
||||
- **Features**:
|
||||
- Specific error messages with fixes
|
||||
- Warnings for potential issues
|
||||
- Autofix suggestions
|
||||
- Shows which properties are visible/hidden based on config
|
||||
|
||||
### 6. ✅ New Tool: `get_property_dependencies`
|
||||
- **Purpose**: Analyze property dependencies and visibility conditions
|
||||
- **Features**:
|
||||
- Shows which properties control others
|
||||
- Describes visibility conditions in human-readable format
|
||||
- Analyzes impact of partial configuration
|
||||
- Provides dependency graph
|
||||
- Suggests key properties to configure first
|
||||
|
||||
### 7. ✅ Enhanced Property Descriptions
|
||||
- **Improvement**: All properties now have meaningful descriptions
|
||||
- **Method**:
|
||||
- Extracts from multiple fields (description, hint, placeholder, displayName)
|
||||
- Generates descriptions based on property names and types when missing
|
||||
- Uses dictionary of common property descriptions
|
||||
- **Result**: 100% of properties in essentials have descriptions
|
||||
|
||||
### 8. ✅ Version Information
|
||||
- **Added**: Version information to essentials response
|
||||
- **Includes**:
|
||||
- Node version (e.g., "4.2" for HTTP Request)
|
||||
- isVersioned flag
|
||||
- Development style in metadata
|
||||
|
||||
## Services Architecture
|
||||
|
||||
### New Services Created:
|
||||
|
||||
1. **PropertyFilter** (`src/services/property-filter.ts`)
|
||||
- Filters properties to essentials
|
||||
- Curated lists for 20 most-used nodes
|
||||
- Property search functionality
|
||||
- Description extraction and generation
|
||||
|
||||
2. **ExampleGenerator** (`src/services/example-generator.ts`)
|
||||
- Provides working examples for each node
|
||||
- Minimal, common, and advanced examples
|
||||
- Context-aware examples based on node type
|
||||
|
||||
3. **TaskTemplates** (`src/services/task-templates.ts`)
|
||||
- Pre-configured node settings for 14 common tasks
|
||||
- Clear user requirements
|
||||
- Optional enhancements
|
||||
- Implementation notes
|
||||
|
||||
4. **ConfigValidator** (`src/services/config-validator.ts`)
|
||||
- Comprehensive configuration validation
|
||||
- Type checking and value validation
|
||||
- Security checks
|
||||
- Node-specific validations
|
||||
- Visibility analysis
|
||||
|
||||
5. **PropertyDependencies** (`src/services/property-dependencies.ts`)
|
||||
- Analyzes property dependencies
|
||||
- Visibility condition extraction
|
||||
- Dependency graph generation
|
||||
- Configuration impact analysis
|
||||
|
||||
## Results
|
||||
|
||||
### Size Reduction Achieved:
|
||||
- HTTP Request: 100KB+ → 2.6KB (97.4% reduction)
|
||||
- Webhook: 45KB → 1.8KB (96% reduction)
|
||||
- Code: 38KB → 1.2KB (96.8% reduction)
|
||||
- Average: **95%+ size reduction**
|
||||
|
||||
### Coverage:
|
||||
- ✅ 100% of essential properties have descriptions
|
||||
- ✅ 20 nodes have curated essential properties
|
||||
- ✅ 14 common tasks have templates
|
||||
- ✅ All nodes can be validated
|
||||
|
||||
### AI Agent Benefits:
|
||||
1. **Faster responses** - 95% less data to process
|
||||
2. **Better understanding** - All properties have descriptions
|
||||
3. **Quick start** - Task templates provide instant configurations
|
||||
4. **Error prevention** - Validation catches issues before execution
|
||||
5. **Smart configuration** - Dependencies help configure in correct order
|
||||
|
||||
## Remaining Tasks (Lower Priority)
|
||||
|
||||
1. **Create more AI node examples** - Especially for LangChain nodes
|
||||
2. **Handle duplicate properties better** - Some nodes have properties that appear multiple times
|
||||
3. **Add more task templates** - Based on user feedback
|
||||
4. **Extend curated properties** - Add more nodes to PropertyFilter
|
||||
|
||||
## Testing Summary
|
||||
|
||||
All improvements have been tested with:
|
||||
- ✅ Unit tests for each service
|
||||
- ✅ Integration tests with real node data
|
||||
- ✅ Size reduction measurements
|
||||
- ✅ Property description coverage tests
|
||||
- ✅ Validation accuracy tests
|
||||
|
||||
## Conclusion
|
||||
|
||||
The implementation successfully addresses the main issues identified in the Claude Desktop evaluation:
|
||||
- ✅ `get_node_info` timeout/failure - Fixed with essentials
|
||||
- ✅ 100KB+ responses - Reduced to <5KB
|
||||
- ✅ Empty property descriptions - 100% coverage
|
||||
- ✅ Missing configuration guidance - Task templates
|
||||
- ✅ No validation - Comprehensive validator
|
||||
- ✅ Hidden dependencies - Dependency analyzer
|
||||
|
||||
The MCP tools are now significantly more usable for AI agents, with faster responses, better guidance, and error prevention.
|
||||
@@ -1,381 +0,0 @@
|
||||
# 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
|
||||
|
||||
1. **Comprehensive property extraction** - All properties with types, options, displayOptions, etc.
|
||||
2. **Efficient storage** - JSON columns allow flexibility while maintaining query performance
|
||||
3. **Complete metadata** - Operations, credentials, documentation all properly extracted
|
||||
4. **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:
|
||||
|
||||
```typescript
|
||||
// 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`:
|
||||
|
||||
```typescript
|
||||
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`:
|
||||
|
||||
```typescript
|
||||
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:
|
||||
|
||||
```typescript
|
||||
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`:
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
- [x] Implement PropertyFilter service
|
||||
- [x] Create get_node_essentials tool
|
||||
- [x] Add curated essential lists for top 20 nodes
|
||||
- [x] 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
|
||||
|
||||
1. **No database schema changes needed** - Work with existing JSON structure
|
||||
2. **Focus on filtering, not restructuring** - Properties are already well-structured
|
||||
3. **Build intelligence layers** - Add smart filtering and validation on top
|
||||
4. **Leverage existing extraction** - Don't duplicate the excellent work already done
|
||||
5. **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
|
||||
|
||||
1. **Implement PropertyFilter** with hardcoded essentials for HTTP Request node
|
||||
2. **Test size reduction** with real AI agents
|
||||
3. **Iterate on essential property lists** based on usage
|
||||
4. **Add task templates** for common use cases
|
||||
5. **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.
|
||||
@@ -1,299 +0,0 @@
|
||||
# MCP Implementation Technical Decisions
|
||||
|
||||
## Architecture Decisions
|
||||
|
||||
### 1. Incremental Enhancement vs. Complete Rewrite
|
||||
|
||||
**Decision**: Incremental enhancement with backward compatibility
|
||||
|
||||
**Rationale**:
|
||||
- Minimizes risk and allows testing at each stage
|
||||
- Existing tools continue to work during migration
|
||||
- Can deliver value immediately without waiting for full implementation
|
||||
- Easier rollback if issues arise
|
||||
|
||||
**Implementation**:
|
||||
- New tools alongside existing ones (get_node_essentials + get_node_info)
|
||||
- Feature flags for gradual rollout
|
||||
- Shared service layer for data access
|
||||
|
||||
### 2. Data Storage Strategy
|
||||
|
||||
**Decision**: Hybrid approach - start with JSON parsing, migrate to relational structure
|
||||
|
||||
**Phase 1** (Immediate):
|
||||
- Parse existing JSON property schemas on-demand
|
||||
- Cache parsed results in memory
|
||||
- Store essential property lists in configuration files
|
||||
|
||||
**Phase 2** (Month 2):
|
||||
- Migrate to property-level relational tables
|
||||
- Maintain JSON schemas for backward compatibility
|
||||
- Use materialized views for performance
|
||||
|
||||
**Rationale**:
|
||||
- Delivers immediate improvements without database changes
|
||||
- Allows time to design optimal schema
|
||||
- Provides fallback during migration
|
||||
|
||||
### 3. Property Categorization
|
||||
|
||||
**Decision**: Multi-dimensional categorization
|
||||
|
||||
**Categories**:
|
||||
1. **By Importance**: required > essential > common > advanced
|
||||
2. **By Function**: authentication, request, response, processing, output
|
||||
3. **By Complexity**: basic, intermediate, expert
|
||||
4. **By Usage**: always, frequent, occasional, rare
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
interface PropertyMetadata {
|
||||
importance: 'required' | 'essential' | 'common' | 'advanced';
|
||||
category: 'auth' | 'request' | 'response' | 'processing' | 'output';
|
||||
complexity: 'basic' | 'intermediate' | 'expert';
|
||||
usageFrequency: number; // 0-100
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Property Deduplication Strategy
|
||||
|
||||
**Decision**: Single source of truth with condition variants
|
||||
|
||||
**Approach**:
|
||||
- Each property appears once in the data model
|
||||
- Conditions stored as metadata
|
||||
- Runtime resolution based on current configuration
|
||||
|
||||
**Example**:
|
||||
```typescript
|
||||
{
|
||||
name: "httpMethod",
|
||||
type: "dynamic",
|
||||
baseType: "select",
|
||||
variants: [
|
||||
{
|
||||
condition: { multipleMethods: false },
|
||||
config: { multiple: false, default: "GET" }
|
||||
},
|
||||
{
|
||||
condition: { multipleMethods: true },
|
||||
config: { multiple: true, default: ["GET", "POST"] }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 5. API Response Optimization
|
||||
|
||||
**Decision**: Progressive disclosure with explicit detail levels
|
||||
|
||||
**Levels**:
|
||||
1. **Minimal**: Just enough to identify and use (1-2KB)
|
||||
2. **Essential**: Common use cases covered (5KB)
|
||||
3. **Standard**: Full functional details (20KB)
|
||||
4. **Complete**: Everything including metadata (100KB+)
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
interface NodeInfoRequest {
|
||||
nodeType: string;
|
||||
level: 'minimal' | 'essential' | 'standard' | 'complete';
|
||||
include?: ('examples' | 'documentation' | 'source')[];
|
||||
propertyFilter?: {
|
||||
categories?: string[];
|
||||
importance?: string[];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Caching Strategy
|
||||
|
||||
**Decision**: Multi-layer caching with TTL
|
||||
|
||||
**Layers**:
|
||||
1. **Request Cache**: 5-minute TTL for identical requests
|
||||
2. **Parsed Property Cache**: 1-hour TTL for parsed structures
|
||||
3. **Essential Properties**: Pre-computed at startup
|
||||
4. **Database Query Cache**: 30-minute TTL for complex queries
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
class CacheManager {
|
||||
private requestCache = new LRUCache<string, any>({ ttl: 5 * 60 * 1000 });
|
||||
private propertyCache = new LRUCache<string, ParsedProperty[]>({ ttl: 60 * 60 * 1000 });
|
||||
private essentialsCache = new Map<string, NodeEssentials>();
|
||||
}
|
||||
```
|
||||
|
||||
### 7. Error Handling Philosophy
|
||||
|
||||
**Decision**: Graceful degradation with helpful fallbacks
|
||||
|
||||
**Principles**:
|
||||
- Never return empty responses if data exists
|
||||
- Provide partial data rather than errors
|
||||
- Include suggestions for fixing issues
|
||||
- Log errors but don't expose internals
|
||||
|
||||
**Example**:
|
||||
```typescript
|
||||
try {
|
||||
return getOptimizedResponse(nodeType);
|
||||
} catch (error) {
|
||||
logger.warn(`Failed to optimize response for ${nodeType}, falling back`);
|
||||
return {
|
||||
...getBasicResponse(nodeType),
|
||||
_warning: "Using simplified response due to processing error"
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 8. Search Implementation
|
||||
|
||||
**Decision**: Multi-strategy search with ranking
|
||||
|
||||
**Strategies**:
|
||||
1. **Exact match**: Property name exact match (weight: 10)
|
||||
2. **Prefix match**: Property name starts with query (weight: 8)
|
||||
3. **Contains match**: Property name contains query (weight: 5)
|
||||
4. **Description match**: Description contains query (weight: 3)
|
||||
5. **Fuzzy match**: Levenshtein distance < 2 (weight: 1)
|
||||
|
||||
**Ranking factors**:
|
||||
- Match quality
|
||||
- Property importance
|
||||
- Usage frequency
|
||||
- Position in hierarchy
|
||||
|
||||
### 9. Task Template Design
|
||||
|
||||
**Decision**: Declarative templates with validation
|
||||
|
||||
**Structure**:
|
||||
```typescript
|
||||
interface TaskTemplate {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
difficulty: 'beginner' | 'intermediate' | 'advanced';
|
||||
|
||||
// What this task accomplishes
|
||||
objectives: string[];
|
||||
|
||||
// Required configuration
|
||||
nodeType: string;
|
||||
configuration: object;
|
||||
|
||||
// User inputs needed
|
||||
inputs: Array<{
|
||||
property: string;
|
||||
description: string;
|
||||
example?: any;
|
||||
validation?: string; // Regex or function name
|
||||
}>;
|
||||
|
||||
// Additional options
|
||||
enhancements: Array<{
|
||||
property: string;
|
||||
description: string;
|
||||
when?: string; // Condition for relevance
|
||||
}>;
|
||||
|
||||
// Success criteria
|
||||
validation: {
|
||||
required: string[];
|
||||
warnings: Array<{
|
||||
condition: string;
|
||||
message: string;
|
||||
}>;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 10. Performance Targets
|
||||
|
||||
**Decision**: Strict performance budgets
|
||||
|
||||
**Targets**:
|
||||
- get_node_essentials: <50ms response time
|
||||
- search_node_properties: <100ms for 1000 properties
|
||||
- validate_node_config: <20ms
|
||||
- Memory overhead: <100MB for full cache
|
||||
- Startup time: <5s including cache warming
|
||||
|
||||
**Monitoring**:
|
||||
```typescript
|
||||
class PerformanceMonitor {
|
||||
private metrics = new Map<string, number[]>();
|
||||
|
||||
track(operation: string, duration: number) {
|
||||
if (duration > PERFORMANCE_BUDGETS[operation]) {
|
||||
logger.warn(`Performance budget exceeded: ${operation} took ${duration}ms`);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### 1. Input Validation
|
||||
- Sanitize all user inputs
|
||||
- Validate node types against whitelist
|
||||
- Limit response sizes
|
||||
- Rate limiting for expensive operations
|
||||
|
||||
### 2. Data Privacy
|
||||
- No sensitive data in responses
|
||||
- Redact credentials from examples
|
||||
- Anonymize usage metrics
|
||||
- Clear audit logging
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Phase 1: Shadow Mode
|
||||
- New tools run alongside old ones
|
||||
- Metrics collection to validate improvements
|
||||
- A/B testing with subset of users
|
||||
|
||||
### Phase 2: Gradual Rollout
|
||||
- Feature flags for new tools
|
||||
- Progressive user migration
|
||||
- Monitoring and rollback capability
|
||||
|
||||
### Phase 3: Deprecation
|
||||
- Mark old tools as deprecated
|
||||
- 3-month transition period
|
||||
- Migration guides and tooling
|
||||
|
||||
## Future Considerations
|
||||
|
||||
### 1. AI Model Integration
|
||||
- Property embeddings for semantic search
|
||||
- ML-based property importance ranking
|
||||
- Automated example generation
|
||||
- Predictive configuration
|
||||
|
||||
### 2. Workflow Analysis
|
||||
- Learn from successful workflows
|
||||
- Identify common patterns
|
||||
- Suggest optimal configurations
|
||||
- Error pattern detection
|
||||
|
||||
### 3. Real-time Assistance
|
||||
- WebSocket support for interactive configuration
|
||||
- Progressive property revelation
|
||||
- Context-aware suggestions
|
||||
- Collaborative editing support
|
||||
|
||||
## Conclusion
|
||||
|
||||
These technical decisions prioritize:
|
||||
1. **Immediate value delivery** through incremental improvements
|
||||
2. **AI-first design** optimizing for token efficiency
|
||||
3. **Performance** with strict budgets and caching
|
||||
4. **Reliability** through graceful degradation
|
||||
5. **Future flexibility** with extensible architecture
|
||||
|
||||
The implementation follows a pragmatic approach that delivers quick wins while building toward a comprehensive solution.
|
||||
@@ -1,294 +0,0 @@
|
||||
# MCP V2 Final Plan - MVP Approach
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Forget the 4-week enterprise architecture. Here's how to fix everything in 3 days.
|
||||
|
||||
## Day 1 (Monday) - Deploy & Debug
|
||||
|
||||
### 1. Fix Deployment (1 hour)
|
||||
```bash
|
||||
# Just build and push
|
||||
docker build -t ghcr.io/czlonkowski/n8n-mcp:latest .
|
||||
docker push ghcr.io/czlonkowski/n8n-mcp:latest
|
||||
```
|
||||
|
||||
### 2. Add Version & Test Endpoints (30 min)
|
||||
```typescript
|
||||
// In http-server-fixed.ts
|
||||
app.get('/version', (req, res) => {
|
||||
res.json({
|
||||
version: '2.4.1',
|
||||
buildTime: new Date().toISOString(),
|
||||
tools: n8nDocumentationToolsFinal.map(t => t.name),
|
||||
commit: process.env.GIT_COMMIT || 'unknown'
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/test-tools', async (req, res) => {
|
||||
try {
|
||||
const result = await server.executeTool('get_node_essentials', { nodeType: 'nodes-base.httpRequest' });
|
||||
res.json({ status: 'ok', hasData: !!result, toolCount: n8nDocumentationToolsFinal.length });
|
||||
} catch (error) {
|
||||
res.json({ status: 'error', message: error.message });
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Debug list_nodes (1 hour)
|
||||
```typescript
|
||||
// Add ONE line to see what's broken
|
||||
private async listNodes(filters: any = {}): Promise<any> {
|
||||
console.log('DEBUG list_nodes:', { filters, query, params }); // ADD THIS
|
||||
// ... rest of code
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Debug list_ai_tools (30 min)
|
||||
```sql
|
||||
-- Run this query to check
|
||||
SELECT COUNT(*) as ai_count FROM nodes WHERE is_ai_tool = 1;
|
||||
-- If 0, the column isn't populated. Fix in rebuild script.
|
||||
```
|
||||
|
||||
## Day 2 (Tuesday) - Core Fixes
|
||||
|
||||
### 1. Fix Multi-Word Search (2 hours)
|
||||
```typescript
|
||||
// Replace the search function in server-update.ts
|
||||
private async searchNodes(query: string, limit: number = 20): Promise<any> {
|
||||
// Split query into words
|
||||
// Handle exact phrase searches with quotes
|
||||
if (query.startsWith('"') && query.endsWith('"')) {
|
||||
const exactPhrase = query.slice(1, -1);
|
||||
const nodes = this.db!.prepare(`
|
||||
SELECT * FROM nodes
|
||||
WHERE node_type LIKE ? OR display_name LIKE ? OR description LIKE ?
|
||||
ORDER BY display_name
|
||||
LIMIT ?
|
||||
`).all(`%${exactPhrase}%`, `%${exactPhrase}%`, `%${exactPhrase}%`, limit) as NodeRow[];
|
||||
|
||||
return { query, results: this.formatNodeResults(nodes), totalCount: nodes.length };
|
||||
}
|
||||
|
||||
// Split into words for normal search
|
||||
const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 0);
|
||||
|
||||
if (words.length === 0) {
|
||||
return { query, results: [], totalCount: 0 };
|
||||
}
|
||||
|
||||
// Build conditions for each word
|
||||
const conditions = words.map(() =>
|
||||
'(node_type LIKE ? OR display_name LIKE ? OR description LIKE ?)'
|
||||
).join(' OR ');
|
||||
|
||||
const params = words.flatMap(w => [`%${w}%`, `%${w}%`, `%${w}%`]);
|
||||
params.push(limit);
|
||||
|
||||
const nodes = this.db!.prepare(`
|
||||
SELECT DISTINCT * FROM nodes
|
||||
WHERE ${conditions}
|
||||
ORDER BY display_name
|
||||
LIMIT ?
|
||||
`).all(...params) as NodeRow[];
|
||||
|
||||
return {
|
||||
query,
|
||||
results: nodes.map(node => ({
|
||||
nodeType: node.node_type,
|
||||
displayName: node.display_name,
|
||||
description: node.description,
|
||||
category: node.category,
|
||||
package: node.package_name
|
||||
})),
|
||||
totalCount: nodes.length
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Simple Property Deduplication (2 hours)
|
||||
```typescript
|
||||
// Add to PropertyFilter.ts
|
||||
static deduplicateProperties(properties: any[]): any[] {
|
||||
const seen = new Map<string, any>();
|
||||
|
||||
return properties.filter(prop => {
|
||||
// Create unique key from name + conditions
|
||||
const conditions = JSON.stringify(prop.displayOptions || {});
|
||||
const key = `${prop.name}_${conditions}`;
|
||||
|
||||
if (seen.has(key)) {
|
||||
return false; // Skip duplicate
|
||||
}
|
||||
|
||||
seen.set(key, prop);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// Use in getEssentials
|
||||
static getEssentials(allProperties: any[], nodeType: string): FilteredProperties {
|
||||
// Deduplicate first
|
||||
const uniqueProperties = this.deduplicateProperties(allProperties);
|
||||
|
||||
// ... rest of existing code
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Fix Package Name Mismatch (1 hour)
|
||||
```typescript
|
||||
// In listNodes, be more flexible with package names
|
||||
if (filters.package) {
|
||||
// Handle both formats
|
||||
const packageVariants = [
|
||||
filters.package,
|
||||
`@n8n/${filters.package}`,
|
||||
filters.package.replace('@n8n/', '')
|
||||
];
|
||||
query += ' AND package_name IN (' + packageVariants.map(() => '?').join(',') + ')';
|
||||
params.push(...packageVariants);
|
||||
}
|
||||
```
|
||||
|
||||
## Day 3 (Wednesday) - Polish & Test
|
||||
|
||||
### 1. Add Simple Memory Cache (2 hours)
|
||||
```typescript
|
||||
// Super simple cache - no frameworks needed
|
||||
class SimpleCache {
|
||||
private cache = new Map<string, { data: any; expires: number }>();
|
||||
|
||||
constructor() {
|
||||
// Clean up expired entries every minute
|
||||
setInterval(() => {
|
||||
const now = Date.now();
|
||||
for (const [key, item] of this.cache.entries()) {
|
||||
if (item.expires < now) this.cache.delete(key);
|
||||
}
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
get(key: string): any {
|
||||
const item = this.cache.get(key);
|
||||
if (!item || item.expires < Date.now()) {
|
||||
this.cache.delete(key);
|
||||
return null;
|
||||
}
|
||||
return item.data;
|
||||
}
|
||||
|
||||
set(key: string, data: any, ttlSeconds: number = 300): void {
|
||||
this.cache.set(key, {
|
||||
data,
|
||||
expires: Date.now() + (ttlSeconds * 1000)
|
||||
});
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Use in server
|
||||
const cache = new SimpleCache();
|
||||
|
||||
// Example in getNodeEssentials
|
||||
const cacheKey = `essentials:${nodeType}`;
|
||||
const cached = cache.get(cacheKey);
|
||||
if (cached) return cached;
|
||||
|
||||
// ... get data ...
|
||||
cache.set(cacheKey, result, 3600); // Cache for 1 hour
|
||||
```
|
||||
|
||||
### 2. Add Basic Documentation Fallback (1 hour)
|
||||
```typescript
|
||||
// In getNodeDocumentation
|
||||
if (!node.documentation) {
|
||||
const essentials = await this.getNodeEssentials(nodeType);
|
||||
|
||||
return {
|
||||
nodeType: node.node_type,
|
||||
displayName: node.display_name,
|
||||
documentation: `
|
||||
# ${node.display_name}
|
||||
|
||||
${node.description || 'No description available.'}
|
||||
|
||||
## Common Properties
|
||||
|
||||
${essentials.commonProperties.map(p =>
|
||||
`### ${p.displayName}\n${p.description || `Type: ${p.type}`}`
|
||||
).join('\n\n')}
|
||||
|
||||
## Note
|
||||
Full documentation is being prepared. For now, use get_node_essentials for configuration help.
|
||||
`,
|
||||
hasDocumentation: false
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Testing Checklist (2 hours)
|
||||
- [ ] Rebuild and deploy Docker image
|
||||
- [ ] Test all tools appear in Claude Desktop
|
||||
- [ ] Test multi-word search: "send slack message"
|
||||
- [ ] Test list_nodes with package filter
|
||||
- [ ] Test list_ai_tools returns 263 nodes
|
||||
- [ ] Verify no duplicate properties in webhook/email nodes
|
||||
- [ ] Check response times with cache
|
||||
|
||||
## Total Time: 3 Days
|
||||
|
||||
### Day 1: 3 hours of actual work
|
||||
### Day 2: 5 hours of actual work
|
||||
### Day 3: 5 hours of actual work
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
```bash
|
||||
# Before starting, tag current version
|
||||
docker pull ghcr.io/czlonkowski/n8n-mcp:latest
|
||||
docker tag ghcr.io/czlonkowski/n8n-mcp:latest ghcr.io/czlonkowski/n8n-mcp:v2.4.0-backup
|
||||
|
||||
# If anything breaks, instant rollback:
|
||||
docker tag ghcr.io/czlonkowski/n8n-mcp:v2.4.0-backup ghcr.io/czlonkowski/n8n-mcp:latest
|
||||
docker push ghcr.io/czlonkowski/n8n-mcp:latest
|
||||
```
|
||||
|
||||
## What We're NOT Doing
|
||||
|
||||
- ❌ No complex deployment verifiers
|
||||
- ❌ No semantic search
|
||||
- ❌ No AI documentation generators
|
||||
- ❌ No workflow assistants
|
||||
- ❌ No real-time validators
|
||||
- ❌ No enterprise caching frameworks
|
||||
- ❌ No complex service architectures
|
||||
|
||||
## Success Metrics
|
||||
|
||||
- ✅ All tools visible in Claude Desktop
|
||||
- ✅ Multi-word search works
|
||||
- ✅ No duplicate properties
|
||||
- ✅ list_nodes and list_ai_tools return results
|
||||
- ✅ Basic caching improves performance
|
||||
|
||||
## Code Changes Summary
|
||||
|
||||
1. **http-server-fixed.ts**: Add version endpoint (5 lines)
|
||||
2. **server-update.ts**: Fix search (20 lines), add debug logs (2 lines)
|
||||
3. **property-filter.ts**: Add deduplication (15 lines)
|
||||
4. **New file: simple-cache.ts**: Basic cache (20 lines)
|
||||
|
||||
Total new code: ~62 lines
|
||||
|
||||
## Next Steps After MVP
|
||||
|
||||
Only after everything above works perfectly:
|
||||
1. Monitor actual performance - add better caching IF needed
|
||||
2. Collect user feedback on search - improve IF needed
|
||||
3. Generate better docs for AI nodes IF users complain
|
||||
|
||||
But not before. Ship the fixes first.
|
||||
@@ -1,163 +0,0 @@
|
||||
# Release Guide
|
||||
|
||||
This guide explains how to create releases for n8n-MCP and how Docker tags are managed.
|
||||
|
||||
## Version Tag Strategy
|
||||
|
||||
When you create a Git tag starting with `v`, the GitHub Actions workflow automatically builds and pushes Docker images with the following tags:
|
||||
|
||||
### Example: Creating Release v1.2.3
|
||||
|
||||
```bash
|
||||
# Create and push a version tag
|
||||
git tag -a v1.2.3 -m "Release version 1.2.3"
|
||||
git push origin v1.2.3
|
||||
```
|
||||
|
||||
This will automatically create the following Docker tags:
|
||||
- `ghcr.io/czlonkowski/n8n-mcp:1.2.3` (exact version)
|
||||
- `ghcr.io/czlonkowski/n8n-mcp:1.2` (minor version)
|
||||
- `ghcr.io/czlonkowski/n8n-mcp:1` (major version)
|
||||
- `ghcr.io/czlonkowski/n8n-mcp:latest` (if from main branch)
|
||||
|
||||
## Tag Types Explained
|
||||
|
||||
### Latest Tag
|
||||
- **When**: Every push to main branch
|
||||
- **Usage**: Default tag for users who want the latest stable version
|
||||
- **Example**: `docker pull ghcr.io/czlonkowski/n8n-mcp:latest`
|
||||
|
||||
### Version Tags
|
||||
- **When**: When you create a Git tag like `v1.2.3`
|
||||
- **Usage**: Users who want a specific version
|
||||
- **Example**: `docker pull ghcr.io/czlonkowski/n8n-mcp:1.2.3`
|
||||
|
||||
### Branch Tags
|
||||
- **When**: Every push to a branch
|
||||
- **Usage**: Testing specific branches
|
||||
- **Example**: `docker pull ghcr.io/czlonkowski/n8n-mcp:main`
|
||||
|
||||
### SHA Tags
|
||||
- **When**: Every commit
|
||||
- **Usage**: Debugging specific commits
|
||||
- **Example**: `docker pull ghcr.io/czlonkowski/n8n-mcp:main-abc123`
|
||||
|
||||
## Release Process
|
||||
|
||||
### 1. Prepare Release
|
||||
```bash
|
||||
# Update version in package.json
|
||||
npm version patch # or minor/major
|
||||
|
||||
# Update CHANGELOG.md
|
||||
echo "## v1.2.3 - $(date +%Y-%m-%d)" >> CHANGELOG.md
|
||||
echo "- Feature: Added X" >> CHANGELOG.md
|
||||
echo "- Fix: Fixed Y" >> CHANGELOG.md
|
||||
|
||||
# Commit changes
|
||||
git add -A
|
||||
git commit -m "chore: prepare release v1.2.3"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### 2. Create Release Tag
|
||||
```bash
|
||||
# Create annotated tag
|
||||
git tag -a v1.2.3 -m "Release v1.2.3
|
||||
|
||||
- Feature: Added X
|
||||
- Fix: Fixed Y"
|
||||
|
||||
# Push tag to trigger Docker build
|
||||
git push origin v1.2.3
|
||||
```
|
||||
|
||||
### 3. Create GitHub Release
|
||||
```bash
|
||||
# Using GitHub CLI
|
||||
gh release create v1.2.3 \
|
||||
--title "Release v1.2.3" \
|
||||
--notes "See CHANGELOG.md for details" \
|
||||
--latest
|
||||
```
|
||||
|
||||
### 4. Verify Docker Images
|
||||
```bash
|
||||
# Wait for GitHub Actions to complete, then verify
|
||||
docker pull ghcr.io/czlonkowski/n8n-mcp:1.2.3
|
||||
docker pull ghcr.io/czlonkowski/n8n-mcp:latest
|
||||
|
||||
# Test the new version
|
||||
docker run --rm ghcr.io/czlonkowski/n8n-mcp:1.2.3 --version
|
||||
```
|
||||
|
||||
## Semantic Versioning
|
||||
|
||||
Follow [Semantic Versioning](https://semver.org/):
|
||||
|
||||
- **MAJOR** (1.0.0 → 2.0.0): Breaking changes
|
||||
- **MINOR** (1.0.0 → 1.1.0): New features, backwards compatible
|
||||
- **PATCH** (1.0.0 → 1.0.1): Bug fixes, backwards compatible
|
||||
|
||||
### Examples:
|
||||
- Breaking API change → v2.0.0
|
||||
- New MCP tool added → v1.1.0
|
||||
- Bug fix in parser → v1.0.1
|
||||
|
||||
## Pre-releases
|
||||
|
||||
For testing releases:
|
||||
```bash
|
||||
# Create pre-release tag
|
||||
git tag -a v1.2.3-beta.1 -m "Beta release"
|
||||
git push origin v1.2.3-beta.1
|
||||
```
|
||||
|
||||
This creates:
|
||||
- `ghcr.io/czlonkowski/n8n-mcp:1.2.3-beta.1`
|
||||
|
||||
## Docker Compose Updates
|
||||
|
||||
When releasing, update documentation to reference specific versions:
|
||||
|
||||
```yaml
|
||||
# Stable version (recommended for production)
|
||||
services:
|
||||
n8n-mcp:
|
||||
image: ghcr.io/czlonkowski/n8n-mcp:1.2
|
||||
|
||||
# Latest version (for testing)
|
||||
services:
|
||||
n8n-mcp:
|
||||
image: ghcr.io/czlonkowski/n8n-mcp:latest
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always test** before creating a release tag
|
||||
2. **Update documentation** to reference new versions
|
||||
3. **Use annotated tags** (`-a` flag) with descriptive messages
|
||||
4. **Follow semver** for version numbers
|
||||
5. **Update CHANGELOG.md** with every release
|
||||
|
||||
## Rollback Process
|
||||
|
||||
If a release has issues:
|
||||
|
||||
```bash
|
||||
# Users can pin to previous version
|
||||
docker pull ghcr.io/czlonkowski/n8n-mcp:1.1.0
|
||||
|
||||
# Or use minor version for automatic patches
|
||||
docker pull ghcr.io/czlonkowski/n8n-mcp:1.1
|
||||
```
|
||||
|
||||
## Checking Available Tags
|
||||
|
||||
```bash
|
||||
# Using Docker Hub API (for public registries)
|
||||
curl -s https://ghcr.io/v2/czlonkowski/n8n-mcp/tags/list
|
||||
|
||||
# Or check GitHub packages page
|
||||
# https://github.com/czlonkowski/n8n-mcp/pkgs/container/n8n-mcp
|
||||
```
|
||||
@@ -1,262 +0,0 @@
|
||||
# Troubleshooting Guide
|
||||
|
||||
Quick solutions for common n8n-MCP issues.
|
||||
|
||||
## 🎯 Quick Fixes
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| "Stream is not readable" | Set `USE_FIXED_HTTP=true` (fixed in v2.3.2) |
|
||||
| "TransformStream is not defined" | Update to Node.js 18+ on client |
|
||||
| Server not appearing in Claude | Restart Claude Desktop completely |
|
||||
| Authentication failed | Check AUTH_TOKEN matches exactly |
|
||||
| Database not found | Run `npm run rebuild` or `docker compose exec n8n-mcp npm run rebuild` |
|
||||
|
||||
## 🌐 HTTP Server Issues
|
||||
|
||||
### "Stream is not readable" Error
|
||||
|
||||
**✅ Fixed in v2.3.2** - Set `USE_FIXED_HTTP=true`
|
||||
|
||||
```bash
|
||||
# Docker
|
||||
docker run -e USE_FIXED_HTTP=true ...
|
||||
|
||||
# Local
|
||||
export USE_FIXED_HTTP=true
|
||||
npm run start:http
|
||||
```
|
||||
|
||||
### "TransformStream is not defined" (Client)
|
||||
|
||||
**Cause**: Node.js < 18 on client machine
|
||||
|
||||
**Fix**: Update Node.js
|
||||
```bash
|
||||
# Check version
|
||||
node --version # Must be v18.0.0+
|
||||
|
||||
# Update via nvm
|
||||
nvm install 18
|
||||
nvm use 18
|
||||
```
|
||||
|
||||
### Authentication Failed
|
||||
|
||||
**Check these:**
|
||||
1. Token length: `echo -n "$AUTH_TOKEN" | wc -c` (32+ chars)
|
||||
2. No extra quotes in .env file
|
||||
3. Exact match between server and client
|
||||
4. Test with curl:
|
||||
```bash
|
||||
curl -H "Authorization: Bearer $AUTH_TOKEN" \
|
||||
http://localhost:3000/health
|
||||
```
|
||||
|
||||
## 🐳 Docker Issues
|
||||
|
||||
### Container Won't Start
|
||||
|
||||
```bash
|
||||
# 1. Check port availability
|
||||
lsof -i :3000
|
||||
|
||||
# 2. View logs
|
||||
docker compose logs -f
|
||||
|
||||
# 3. Clean and retry
|
||||
docker compose down
|
||||
docker system prune -f
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Database Issues
|
||||
|
||||
```bash
|
||||
# Rebuild database inside container
|
||||
docker compose exec n8n-mcp npm run rebuild
|
||||
|
||||
# Or copy from host
|
||||
docker cp data/nodes.db n8n-mcp:/app/data/
|
||||
docker compose restart
|
||||
```
|
||||
|
||||
### Environment Variables Not Loading
|
||||
|
||||
```bash
|
||||
# Verify .env file
|
||||
cat .env
|
||||
|
||||
# Check loaded config
|
||||
docker compose config
|
||||
|
||||
# Force reload
|
||||
docker compose down
|
||||
docker compose --env-file .env up -d
|
||||
```
|
||||
|
||||
## 📦 Installation Issues
|
||||
|
||||
### npm install Fails
|
||||
|
||||
```bash
|
||||
# Clean install
|
||||
rm -rf node_modules package-lock.json
|
||||
npm cache clean --force
|
||||
npm install
|
||||
```
|
||||
|
||||
**Note**: The project automatically falls back to sql.js if better-sqlite3 fails.
|
||||
|
||||
### Build Errors
|
||||
|
||||
```bash
|
||||
# Clean rebuild
|
||||
rm -rf dist
|
||||
npm run build
|
||||
|
||||
# If TypeScript errors
|
||||
npm install --save-dev @types/node
|
||||
npm run typecheck
|
||||
```
|
||||
|
||||
## ⚡ Runtime Errors
|
||||
|
||||
### MCP Tools Not Available in Claude
|
||||
|
||||
1. **Restart Claude Desktop** (Cmd/Ctrl+R)
|
||||
2. **Check server status:**
|
||||
```bash
|
||||
# Docker
|
||||
docker compose ps
|
||||
|
||||
# Local
|
||||
curl http://localhost:3000/health
|
||||
```
|
||||
3. **Verify configuration path** is absolute
|
||||
4. **Check Claude logs**: View > Developer > Logs
|
||||
|
||||
## 🖥️ Claude Desktop Issues
|
||||
|
||||
### Server Not Appearing
|
||||
|
||||
**Checklist:**
|
||||
- ✅ Used absolute paths (not ~/)
|
||||
- ✅ Valid JSON syntax
|
||||
- ✅ Restarted Claude completely
|
||||
- ✅ Server is running
|
||||
|
||||
```bash
|
||||
# Validate config
|
||||
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json | jq .
|
||||
```
|
||||
|
||||
### Remote Connection Issues
|
||||
|
||||
**"TransformStream is not defined":**
|
||||
- Update to Node.js 18+
|
||||
- Or use Docker stdio mode instead
|
||||
|
||||
**"Server disconnected":**
|
||||
- Check AUTH_TOKEN matches
|
||||
- Verify server is accessible
|
||||
- Check for VPN interference
|
||||
|
||||
## 🗄️ Database Problems
|
||||
|
||||
### Quick Fixes
|
||||
|
||||
```bash
|
||||
# Rebuild database
|
||||
npm run rebuild
|
||||
|
||||
# Validate
|
||||
npm run validate
|
||||
npm run test-nodes
|
||||
|
||||
# For Docker
|
||||
docker compose exec n8n-mcp npm run rebuild
|
||||
```
|
||||
|
||||
### Database Locked
|
||||
|
||||
```bash
|
||||
# Find lock
|
||||
lsof data/nodes.db
|
||||
|
||||
# Force restart
|
||||
killall node
|
||||
npm start
|
||||
```
|
||||
|
||||
## 🌐 Network Issues
|
||||
|
||||
### Connection Refused
|
||||
|
||||
```bash
|
||||
# Check server
|
||||
curl http://localhost:3000/health
|
||||
|
||||
# Check firewall
|
||||
sudo ufw status
|
||||
|
||||
# Test from outside
|
||||
curl https://your-server.com/health
|
||||
```
|
||||
|
||||
### SSL Certificate Issues
|
||||
|
||||
- Use HTTP for local development
|
||||
- Use reverse proxy (nginx/Caddy) for HTTPS
|
||||
- See [HTTP Deployment Guide](./HTTP_DEPLOYMENT.md)
|
||||
|
||||
## 🚀 Performance Issues
|
||||
|
||||
### Slow Response Times
|
||||
|
||||
```bash
|
||||
# Check memory
|
||||
docker stats n8n-mcp
|
||||
|
||||
# Increase limits
|
||||
# docker-compose.yml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
```
|
||||
|
||||
**Expected performance:**
|
||||
- Response time: ~12ms
|
||||
- Memory usage: 50-100MB
|
||||
- Database queries: <5ms
|
||||
|
||||
## 🆘 Still Need Help?
|
||||
|
||||
### Debug Mode
|
||||
|
||||
```bash
|
||||
# Enable verbose logging
|
||||
LOG_LEVEL=debug npm start
|
||||
|
||||
# Docker debug
|
||||
docker compose logs -f --tail 100
|
||||
```
|
||||
|
||||
### Get Support
|
||||
|
||||
1. **Check existing issues**: [GitHub Issues](https://github.com/czlonkowski/n8n-mcp/issues)
|
||||
2. **Ask questions**: [GitHub Discussions](https://github.com/czlonkowski/n8n-mcp/discussions)
|
||||
3. **Report bugs**: Include:
|
||||
- Error messages
|
||||
- Steps to reproduce
|
||||
- Environment details
|
||||
- Logs with `LOG_LEVEL=debug`
|
||||
|
||||
### Common Solutions Summary
|
||||
|
||||
1. 🔄 **Always restart Claude** after config changes
|
||||
2. 📋 **Use exact configuration** from examples
|
||||
3. 🔍 **Check logs** for specific errors
|
||||
4. 🆙 **Update Node.js** to v18+ for remote connections
|
||||
5. 🔒 **Verify AUTH_TOKEN** matches exactly
|
||||
81
test-mcp-tools.js
Executable file
81
test-mcp-tools.js
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
// Start the MCP server
|
||||
const server = spawn('node', ['dist/mcp/index.js'], {
|
||||
env: {
|
||||
...process.env,
|
||||
MCP_MODE: 'stdio',
|
||||
LOG_LEVEL: 'error',
|
||||
DISABLE_CONSOLE_OUTPUT: 'true'
|
||||
},
|
||||
stdio: ['pipe', 'pipe', 'inherit']
|
||||
});
|
||||
|
||||
// Send list_tools request
|
||||
const request = {
|
||||
jsonrpc: "2.0",
|
||||
method: "tools/list",
|
||||
id: 1
|
||||
};
|
||||
|
||||
server.stdin.write(JSON.stringify(request) + '\n');
|
||||
|
||||
// Collect response
|
||||
let responseData = '';
|
||||
server.stdout.on('data', (data) => {
|
||||
responseData += data.toString();
|
||||
|
||||
// Try to parse each line
|
||||
const lines = responseData.split('\n');
|
||||
for (const line of lines) {
|
||||
if (line.trim()) {
|
||||
try {
|
||||
const response = JSON.parse(line);
|
||||
if (response.result && response.result.tools) {
|
||||
console.log('MCP Server Tools Report');
|
||||
console.log('======================');
|
||||
console.log(`Total tools: ${response.result.tools.length}`);
|
||||
console.log('\nTools list:');
|
||||
response.result.tools.forEach(tool => {
|
||||
console.log(`- ${tool.name}`);
|
||||
});
|
||||
|
||||
// Check for specific tools
|
||||
const expectedTools = [
|
||||
'get_node_for_task',
|
||||
'validate_node_config',
|
||||
'get_property_dependencies',
|
||||
'list_tasks',
|
||||
'search_node_properties',
|
||||
'get_node_essentials'
|
||||
];
|
||||
|
||||
console.log('\nNew tools check:');
|
||||
expectedTools.forEach(toolName => {
|
||||
const found = response.result.tools.find(t => t.name === toolName);
|
||||
console.log(`- ${toolName}: ${found ? '✅ Found' : '❌ Missing'}`);
|
||||
});
|
||||
|
||||
server.kill();
|
||||
process.exit(0);
|
||||
}
|
||||
} catch (e) {
|
||||
// Not a complete JSON response yet
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Timeout after 5 seconds
|
||||
setTimeout(() => {
|
||||
console.error('Timeout: No response from MCP server');
|
||||
server.kill();
|
||||
process.exit(1);
|
||||
}, 5000);
|
||||
|
||||
server.on('error', (err) => {
|
||||
console.error('Failed to start MCP server:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user