n8n-mcp 2.23.0 → 2.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -53,6 +53,7 @@ const property_filter_1 = require("../services/property-filter");
53
53
  const task_templates_1 = require("../services/task-templates");
54
54
  const enhanced_config_validator_1 = require("../services/enhanced-config-validator");
55
55
  const property_dependencies_1 = require("../services/property-dependencies");
56
+ const type_structure_service_1 = require("../services/type-structure-service");
56
57
  const simple_cache_1 = require("../utils/simple-cache");
57
58
  const template_service_1 = require("../templates/template-service");
58
59
  const workflow_validator_1 = require("../services/workflow-validator");
@@ -727,9 +728,6 @@ class N8NDocumentationMCPServer {
727
728
  return this.getToolsDocumentation(args.topic, args.depth);
728
729
  case 'list_nodes':
729
730
  return this.listNodes(args);
730
- case 'get_node_info':
731
- this.validateToolParams(name, args, ['nodeType']);
732
- return this.getNodeInfo(args.nodeType);
733
731
  case 'search_nodes':
734
732
  this.validateToolParams(name, args, ['query']);
735
733
  const limit = args.limit !== undefined ? Number(args.limit) || 20 : 20;
@@ -741,9 +739,9 @@ class N8NDocumentationMCPServer {
741
739
  return this.getNodeDocumentation(args.nodeType);
742
740
  case 'get_database_statistics':
743
741
  return this.getDatabaseStatistics();
744
- case 'get_node_essentials':
742
+ case 'get_node':
745
743
  this.validateToolParams(name, args, ['nodeType']);
746
- return this.getNodeEssentials(args.nodeType, args.includeExamples);
744
+ return this.getNode(args.nodeType, args.detail, args.mode, args.includeTypeInfo, args.includeExamples, args.fromVersion, args.toVersion);
747
745
  case 'search_node_properties':
748
746
  this.validateToolParams(name, args, ['nodeType', 'query']);
749
747
  const maxResults = args.maxResults !== undefined ? Number(args.maxResults) || 20 : 20;
@@ -1723,6 +1721,236 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
1723
1721
  this.cache.set(cacheKey, result, 3600);
1724
1722
  return result;
1725
1723
  }
1724
+ async getNode(nodeType, detail = 'standard', mode = 'info', includeTypeInfo, includeExamples, fromVersion, toVersion) {
1725
+ await this.ensureInitialized();
1726
+ if (!this.repository)
1727
+ throw new Error('Repository not initialized');
1728
+ const validDetailLevels = ['minimal', 'standard', 'full'];
1729
+ const validModes = ['info', 'versions', 'compare', 'breaking', 'migrations'];
1730
+ if (!validDetailLevels.includes(detail)) {
1731
+ throw new Error(`get_node: Invalid detail level "${detail}". Valid options: ${validDetailLevels.join(', ')}`);
1732
+ }
1733
+ if (!validModes.includes(mode)) {
1734
+ throw new Error(`get_node: Invalid mode "${mode}". Valid options: ${validModes.join(', ')}`);
1735
+ }
1736
+ const normalizedType = node_type_normalizer_1.NodeTypeNormalizer.normalizeToFullForm(nodeType);
1737
+ if (mode !== 'info') {
1738
+ return this.handleVersionMode(normalizedType, mode, fromVersion, toVersion);
1739
+ }
1740
+ return this.handleInfoMode(normalizedType, detail, includeTypeInfo, includeExamples);
1741
+ }
1742
+ async handleInfoMode(nodeType, detail, includeTypeInfo, includeExamples) {
1743
+ switch (detail) {
1744
+ case 'minimal': {
1745
+ let node = this.repository.getNode(nodeType);
1746
+ if (!node) {
1747
+ const alternatives = (0, node_utils_1.getNodeTypeAlternatives)(nodeType);
1748
+ for (const alt of alternatives) {
1749
+ const found = this.repository.getNode(alt);
1750
+ if (found) {
1751
+ node = found;
1752
+ break;
1753
+ }
1754
+ }
1755
+ }
1756
+ if (!node) {
1757
+ throw new Error(`Node ${nodeType} not found`);
1758
+ }
1759
+ return {
1760
+ nodeType: node.nodeType,
1761
+ workflowNodeType: (0, node_utils_1.getWorkflowNodeType)(node.package ?? 'n8n-nodes-base', node.nodeType),
1762
+ displayName: node.displayName,
1763
+ description: node.description,
1764
+ category: node.category,
1765
+ package: node.package,
1766
+ isAITool: node.isAITool,
1767
+ isTrigger: node.isTrigger,
1768
+ isWebhook: node.isWebhook
1769
+ };
1770
+ }
1771
+ case 'standard': {
1772
+ const essentials = await this.getNodeEssentials(nodeType, includeExamples);
1773
+ const versionSummary = this.getVersionSummary(nodeType);
1774
+ if (includeTypeInfo) {
1775
+ essentials.requiredProperties = this.enrichPropertiesWithTypeInfo(essentials.requiredProperties);
1776
+ essentials.commonProperties = this.enrichPropertiesWithTypeInfo(essentials.commonProperties);
1777
+ }
1778
+ return {
1779
+ ...essentials,
1780
+ versionInfo: versionSummary
1781
+ };
1782
+ }
1783
+ case 'full': {
1784
+ const fullInfo = await this.getNodeInfo(nodeType);
1785
+ const versionSummary = this.getVersionSummary(nodeType);
1786
+ if (includeTypeInfo && fullInfo.properties) {
1787
+ fullInfo.properties = this.enrichPropertiesWithTypeInfo(fullInfo.properties);
1788
+ }
1789
+ return {
1790
+ ...fullInfo,
1791
+ versionInfo: versionSummary
1792
+ };
1793
+ }
1794
+ default:
1795
+ throw new Error(`Unknown detail level: ${detail}`);
1796
+ }
1797
+ }
1798
+ async handleVersionMode(nodeType, mode, fromVersion, toVersion) {
1799
+ switch (mode) {
1800
+ case 'versions':
1801
+ return this.getVersionHistory(nodeType);
1802
+ case 'compare':
1803
+ if (!fromVersion) {
1804
+ throw new Error(`get_node: fromVersion is required for compare mode (nodeType: ${nodeType})`);
1805
+ }
1806
+ return this.compareVersions(nodeType, fromVersion, toVersion);
1807
+ case 'breaking':
1808
+ if (!fromVersion) {
1809
+ throw new Error(`get_node: fromVersion is required for breaking mode (nodeType: ${nodeType})`);
1810
+ }
1811
+ return this.getBreakingChanges(nodeType, fromVersion, toVersion);
1812
+ case 'migrations':
1813
+ if (!fromVersion || !toVersion) {
1814
+ throw new Error(`get_node: Both fromVersion and toVersion are required for migrations mode (nodeType: ${nodeType})`);
1815
+ }
1816
+ return this.getMigrations(nodeType, fromVersion, toVersion);
1817
+ default:
1818
+ throw new Error(`get_node: Unknown mode: ${mode} (nodeType: ${nodeType})`);
1819
+ }
1820
+ }
1821
+ getVersionSummary(nodeType) {
1822
+ const cacheKey = `version-summary:${nodeType}`;
1823
+ const cached = this.cache.get(cacheKey);
1824
+ if (cached) {
1825
+ return cached;
1826
+ }
1827
+ const versions = this.repository.getNodeVersions(nodeType);
1828
+ const latest = this.repository.getLatestNodeVersion(nodeType);
1829
+ const summary = {
1830
+ currentVersion: latest?.version || 'unknown',
1831
+ totalVersions: versions.length,
1832
+ hasVersionHistory: versions.length > 0
1833
+ };
1834
+ this.cache.set(cacheKey, summary, 86400000);
1835
+ return summary;
1836
+ }
1837
+ getVersionHistory(nodeType) {
1838
+ const versions = this.repository.getNodeVersions(nodeType);
1839
+ return {
1840
+ nodeType,
1841
+ totalVersions: versions.length,
1842
+ versions: versions.map(v => ({
1843
+ version: v.version,
1844
+ isCurrent: v.isCurrentMax,
1845
+ minimumN8nVersion: v.minimumN8nVersion,
1846
+ releasedAt: v.releasedAt,
1847
+ hasBreakingChanges: (v.breakingChanges || []).length > 0,
1848
+ breakingChangesCount: (v.breakingChanges || []).length,
1849
+ deprecatedProperties: v.deprecatedProperties || [],
1850
+ addedProperties: v.addedProperties || []
1851
+ })),
1852
+ available: versions.length > 0,
1853
+ message: versions.length === 0 ?
1854
+ 'No version history available. Version tracking may not be enabled for this node.' :
1855
+ undefined
1856
+ };
1857
+ }
1858
+ compareVersions(nodeType, fromVersion, toVersion) {
1859
+ const latest = this.repository.getLatestNodeVersion(nodeType);
1860
+ const targetVersion = toVersion || latest?.version;
1861
+ if (!targetVersion) {
1862
+ throw new Error('No target version available');
1863
+ }
1864
+ const changes = this.repository.getPropertyChanges(nodeType, fromVersion, targetVersion);
1865
+ return {
1866
+ nodeType,
1867
+ fromVersion,
1868
+ toVersion: targetVersion,
1869
+ totalChanges: changes.length,
1870
+ breakingChanges: changes.filter(c => c.isBreaking).length,
1871
+ changes: changes.map(c => ({
1872
+ property: c.propertyName,
1873
+ changeType: c.changeType,
1874
+ isBreaking: c.isBreaking,
1875
+ severity: c.severity,
1876
+ oldValue: c.oldValue,
1877
+ newValue: c.newValue,
1878
+ migrationHint: c.migrationHint,
1879
+ autoMigratable: c.autoMigratable
1880
+ }))
1881
+ };
1882
+ }
1883
+ getBreakingChanges(nodeType, fromVersion, toVersion) {
1884
+ const breakingChanges = this.repository.getBreakingChanges(nodeType, fromVersion, toVersion);
1885
+ return {
1886
+ nodeType,
1887
+ fromVersion,
1888
+ toVersion: toVersion || 'latest',
1889
+ totalBreakingChanges: breakingChanges.length,
1890
+ changes: breakingChanges.map(c => ({
1891
+ fromVersion: c.fromVersion,
1892
+ toVersion: c.toVersion,
1893
+ property: c.propertyName,
1894
+ changeType: c.changeType,
1895
+ severity: c.severity,
1896
+ migrationHint: c.migrationHint,
1897
+ oldValue: c.oldValue,
1898
+ newValue: c.newValue
1899
+ })),
1900
+ upgradeSafe: breakingChanges.length === 0
1901
+ };
1902
+ }
1903
+ getMigrations(nodeType, fromVersion, toVersion) {
1904
+ const migrations = this.repository.getAutoMigratableChanges(nodeType, fromVersion, toVersion);
1905
+ const allChanges = this.repository.getPropertyChanges(nodeType, fromVersion, toVersion);
1906
+ return {
1907
+ nodeType,
1908
+ fromVersion,
1909
+ toVersion,
1910
+ autoMigratableChanges: migrations.length,
1911
+ totalChanges: allChanges.length,
1912
+ migrations: migrations.map(m => ({
1913
+ property: m.propertyName,
1914
+ changeType: m.changeType,
1915
+ migrationStrategy: m.migrationStrategy,
1916
+ severity: m.severity
1917
+ })),
1918
+ requiresManualMigration: migrations.length < allChanges.length
1919
+ };
1920
+ }
1921
+ enrichPropertyWithTypeInfo(property) {
1922
+ if (!property || !property.type)
1923
+ return property;
1924
+ const structure = type_structure_service_1.TypeStructureService.getStructure(property.type);
1925
+ if (!structure)
1926
+ return property;
1927
+ return {
1928
+ ...property,
1929
+ typeInfo: {
1930
+ category: structure.type,
1931
+ jsType: structure.jsType,
1932
+ description: structure.description,
1933
+ isComplex: type_structure_service_1.TypeStructureService.isComplexType(property.type),
1934
+ isPrimitive: type_structure_service_1.TypeStructureService.isPrimitiveType(property.type),
1935
+ allowsExpressions: structure.validation?.allowExpressions ?? true,
1936
+ allowsEmpty: structure.validation?.allowEmpty ?? false,
1937
+ ...(structure.structure && {
1938
+ structureHints: {
1939
+ hasProperties: !!structure.structure.properties,
1940
+ hasItems: !!structure.structure.items,
1941
+ isFlexible: structure.structure.flexible ?? false,
1942
+ requiredFields: structure.structure.required ?? []
1943
+ }
1944
+ }),
1945
+ ...(structure.notes && { notes: structure.notes })
1946
+ }
1947
+ };
1948
+ }
1949
+ enrichPropertiesWithTypeInfo(properties) {
1950
+ if (!properties || !Array.isArray(properties))
1951
+ return properties;
1952
+ return properties.map((prop) => this.enrichPropertyWithTypeInfo(prop));
1953
+ }
1726
1954
  async searchNodeProperties(nodeType, query, maxResults = 20) {
1727
1955
  await this.ensureInitialized();
1728
1956
  if (!this.repository)