@utaba/ucm-mcp-server 6.5.0 → 6.6.0

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.
Files changed (198) hide show
  1. package/dist/clients/UcmLocalApiClient.d.ts +175 -2
  2. package/dist/clients/UcmLocalApiClient.js +203 -3
  3. package/dist/index.js +1 -1
  4. package/dist/mcp-server/clients/UcmLocalApiClient.d.ts +399 -0
  5. package/dist/mcp-server/clients/UcmLocalApiClient.js +719 -0
  6. package/dist/mcp-server/index.d.ts +3 -0
  7. package/dist/mcp-server/index.js +68 -0
  8. package/dist/mcp-server/interfaces/ILogger.d.ts +8 -0
  9. package/dist/mcp-server/interfaces/ILogger.js +4 -0
  10. package/dist/mcp-server/interfaces/IMcpTool.d.ts +7 -0
  11. package/dist/mcp-server/interfaces/IMcpTool.js +3 -0
  12. package/dist/mcp-server/logging/ConsoleLogger.d.ts +16 -0
  13. package/dist/mcp-server/logging/ConsoleLogger.js +45 -0
  14. package/dist/mcp-server/logging/LoggerFactory.d.ts +9 -0
  15. package/dist/mcp-server/logging/LoggerFactory.js +12 -0
  16. package/dist/mcp-server/server/McpConfig.d.ts +26 -0
  17. package/dist/mcp-server/server/McpConfig.js +90 -0
  18. package/dist/mcp-server/server/McpHandler.d.ts +12 -0
  19. package/dist/mcp-server/server/McpHandler.js +84 -0
  20. package/dist/mcp-server/server/McpServer.d.ts +15 -0
  21. package/dist/mcp-server/server/McpServer.js +49 -0
  22. package/dist/mcp-server/server/ToolRegistry.d.ts +23 -0
  23. package/dist/mcp-server/server/ToolRegistry.js +169 -0
  24. package/dist/mcp-server/tools/authorization/ListAuthorizationsTool.d.ts +21 -0
  25. package/dist/mcp-server/tools/authorization/ListAuthorizationsTool.js +146 -0
  26. package/dist/mcp-server/tools/authorization/SignOutTool.d.ts +23 -0
  27. package/dist/mcp-server/tools/authorization/SignOutTool.js +128 -0
  28. package/dist/mcp-server/tools/base/BaseToolController.d.ts +19 -0
  29. package/dist/mcp-server/tools/base/BaseToolController.js +58 -0
  30. package/dist/mcp-server/tools/connections/AccessConnectionTool.d.ts +21 -0
  31. package/dist/mcp-server/tools/connections/AccessConnectionTool.js +107 -0
  32. package/dist/mcp-server/tools/connections/CallRemoteToolTool.d.ts +22 -0
  33. package/dist/mcp-server/tools/connections/CallRemoteToolTool.js +124 -0
  34. package/dist/mcp-server/tools/core/DeleteArtifactTool.d.ts +11 -0
  35. package/dist/mcp-server/tools/core/DeleteArtifactTool.js +83 -0
  36. package/dist/mcp-server/tools/core/EditArtifactMetadataTool.d.ts +12 -0
  37. package/dist/mcp-server/tools/core/EditArtifactMetadataTool.js +173 -0
  38. package/dist/mcp-server/tools/core/GetArtifactTool.d.ts +13 -0
  39. package/dist/mcp-server/tools/core/GetArtifactTool.js +124 -0
  40. package/dist/mcp-server/tools/core/GetArtifactVersionsTool.d.ts +11 -0
  41. package/dist/mcp-server/tools/core/GetArtifactVersionsTool.js +63 -0
  42. package/dist/mcp-server/tools/core/GetChunkTool.d.ts +11 -0
  43. package/dist/mcp-server/tools/core/GetChunkTool.js +56 -0
  44. package/dist/mcp-server/tools/core/ListArtifactsTool.d.ts +11 -0
  45. package/dist/mcp-server/tools/core/ListArtifactsTool.js +84 -0
  46. package/dist/mcp-server/tools/core/MoveArtifactTool.d.ts +12 -0
  47. package/dist/mcp-server/tools/core/MoveArtifactTool.js +104 -0
  48. package/dist/mcp-server/tools/core/PublishArtifactFromFileTool.d.ts +15 -0
  49. package/dist/mcp-server/tools/core/PublishArtifactFromFileTool.js +277 -0
  50. package/dist/mcp-server/tools/core/PublishArtifactTool.d.ts +13 -0
  51. package/dist/mcp-server/tools/core/PublishArtifactTool.js +218 -0
  52. package/dist/mcp-server/tools/core/SearchArtifactsTool.d.ts +11 -0
  53. package/dist/mcp-server/tools/core/SearchArtifactsTool.js +137 -0
  54. package/dist/mcp-server/tools/list/ListNamespaceController.d.ts +1 -0
  55. package/dist/mcp-server/tools/list/ListNamespaceController.js +8 -0
  56. package/dist/mcp-server/tools/memory-graph/GraphCreateEntitiesTool.d.ts +14 -0
  57. package/dist/mcp-server/tools/memory-graph/GraphCreateEntitiesTool.js +58 -0
  58. package/dist/mcp-server/tools/memory-graph/GraphCreateRelationshipsTool.d.ts +14 -0
  59. package/dist/mcp-server/tools/memory-graph/GraphCreateRelationshipsTool.js +57 -0
  60. package/dist/mcp-server/tools/memory-graph/GraphCreateTool.d.ts +14 -0
  61. package/dist/mcp-server/tools/memory-graph/GraphCreateTool.js +64 -0
  62. package/dist/mcp-server/tools/memory-graph/GraphDeleteEntitiesTool.d.ts +14 -0
  63. package/dist/mcp-server/tools/memory-graph/GraphDeleteEntitiesTool.js +45 -0
  64. package/dist/mcp-server/tools/memory-graph/GraphDeleteRelationshipsTool.d.ts +14 -0
  65. package/dist/mcp-server/tools/memory-graph/GraphDeleteRelationshipsTool.js +45 -0
  66. package/dist/mcp-server/tools/memory-graph/GraphExploreTool.d.ts +14 -0
  67. package/dist/mcp-server/tools/memory-graph/GraphExploreTool.js +73 -0
  68. package/dist/mcp-server/tools/memory-graph/GraphFindEntitiesTool.d.ts +14 -0
  69. package/dist/mcp-server/tools/memory-graph/GraphFindEntitiesTool.js +68 -0
  70. package/dist/mcp-server/tools/memory-graph/GraphFindPathsTool.d.ts +14 -0
  71. package/dist/mcp-server/tools/memory-graph/GraphFindPathsTool.js +62 -0
  72. package/dist/mcp-server/tools/memory-graph/GraphGetEntityTool.d.ts +14 -0
  73. package/dist/mcp-server/tools/memory-graph/GraphGetEntityTool.js +49 -0
  74. package/dist/mcp-server/tools/memory-graph/GraphGetRelationshipsTool.d.ts +14 -0
  75. package/dist/mcp-server/tools/memory-graph/GraphGetRelationshipsTool.js +62 -0
  76. package/dist/mcp-server/tools/memory-graph/GraphListTemplatesTool.d.ts +14 -0
  77. package/dist/mcp-server/tools/memory-graph/GraphListTemplatesTool.js +34 -0
  78. package/dist/mcp-server/tools/memory-graph/GraphListTool.d.ts +14 -0
  79. package/dist/mcp-server/tools/memory-graph/GraphListTool.js +45 -0
  80. package/dist/mcp-server/tools/memory-graph/GraphOpenTool.d.ts +15 -0
  81. package/dist/mcp-server/tools/memory-graph/GraphOpenTool.js +50 -0
  82. package/dist/mcp-server/tools/memory-graph/GraphProposeVocabularyTool.d.ts +14 -0
  83. package/dist/mcp-server/tools/memory-graph/GraphProposeVocabularyTool.js +108 -0
  84. package/dist/mcp-server/tools/memory-graph/GraphSearchTool.d.ts +14 -0
  85. package/dist/mcp-server/tools/memory-graph/GraphSearchTool.js +94 -0
  86. package/dist/mcp-server/tools/memory-graph/GraphTraverseTool.d.ts +14 -0
  87. package/dist/mcp-server/tools/memory-graph/GraphTraverseTool.js +114 -0
  88. package/dist/mcp-server/tools/memory-graph/GraphUpdateEntitiesTool.d.ts +14 -0
  89. package/dist/mcp-server/tools/memory-graph/GraphUpdateEntitiesTool.js +58 -0
  90. package/dist/mcp-server/tools/memory-graph/KnowledgeSetListTool.d.ts +14 -0
  91. package/dist/mcp-server/tools/memory-graph/KnowledgeSetListTool.js +25 -0
  92. package/dist/mcp-server/tools/memory-graph/KnowledgeSetOpenTool.d.ts +14 -0
  93. package/dist/mcp-server/tools/memory-graph/KnowledgeSetOpenTool.js +31 -0
  94. package/dist/mcp-server/tools/repository/CreateRepositoryTool.d.ts +12 -0
  95. package/dist/mcp-server/tools/repository/CreateRepositoryTool.js +116 -0
  96. package/dist/mcp-server/tools/repository/GetRepositoryTool.d.ts +12 -0
  97. package/dist/mcp-server/tools/repository/GetRepositoryTool.js +85 -0
  98. package/dist/mcp-server/tools/repository/UpdateRepositoryTool.d.ts +12 -0
  99. package/dist/mcp-server/tools/repository/UpdateRepositoryTool.js +115 -0
  100. package/dist/mcp-server/tools/sharepoint/SharePointListConnectionsTool.d.ts +19 -0
  101. package/dist/mcp-server/tools/sharepoint/SharePointListConnectionsTool.js +90 -0
  102. package/dist/mcp-server/tools/sharepoint/SharePointListFoldersTool.d.ts +21 -0
  103. package/dist/mcp-server/tools/sharepoint/SharePointListFoldersTool.js +133 -0
  104. package/dist/mcp-server/tools/sharepoint/SharePointReadFileTool.d.ts +22 -0
  105. package/dist/mcp-server/tools/sharepoint/SharePointReadFileTool.js +146 -0
  106. package/dist/mcp-server/tools/sharepoint/SharePointReadRelatedFileTool.d.ts +18 -0
  107. package/dist/mcp-server/tools/sharepoint/SharePointReadRelatedFileTool.js +108 -0
  108. package/dist/mcp-server/tools/sharepoint/SharePointSearchTool.d.ts +22 -0
  109. package/dist/mcp-server/tools/sharepoint/SharePointSearchTool.js +125 -0
  110. package/dist/mcp-server/tools/utility/AuthorIndexTool.d.ts +11 -0
  111. package/dist/mcp-server/tools/utility/AuthorIndexTool.js +49 -0
  112. package/dist/mcp-server/tools/utility/AuthorRecentsTool.d.ts +11 -0
  113. package/dist/mcp-server/tools/utility/AuthorRecentsTool.js +49 -0
  114. package/dist/mcp-server/tools/utility/ListRepositoriesTool.d.ts +11 -0
  115. package/dist/mcp-server/tools/utility/ListRepositoriesTool.js +68 -0
  116. package/dist/mcp-server/tools/utility/QuickstartTool.d.ts +11 -0
  117. package/dist/mcp-server/tools/utility/QuickstartTool.js +36 -0
  118. package/dist/mcp-server/types/UcmApiTypes.d.ts +40 -0
  119. package/dist/mcp-server/types/UcmApiTypes.js +4 -0
  120. package/dist/mcp-server/utils/McpErrorHandler.d.ts +25 -0
  121. package/dist/mcp-server/utils/McpErrorHandler.js +67 -0
  122. package/dist/mcp-server/utils/PathUtils.d.ts +61 -0
  123. package/dist/mcp-server/utils/PathUtils.js +178 -0
  124. package/dist/mcp-server/utils/ResponseChunker.d.ts +25 -0
  125. package/dist/mcp-server/utils/ResponseChunker.js +79 -0
  126. package/dist/mcp-server/utils/SharePointErrorHandler.d.ts +34 -0
  127. package/dist/mcp-server/utils/SharePointErrorHandler.js +55 -0
  128. package/dist/schemas/memory-graph-tool-schemas.d.ts +789 -0
  129. package/dist/schemas/memory-graph-tool-schemas.js +181 -0
  130. package/dist/server/ToolRegistry.js +42 -8
  131. package/dist/tools/authorization/ListAuthorizationsTool.js +2 -2
  132. package/dist/tools/authorization/SignOutTool.js +2 -2
  133. package/dist/tools/connections/AccessConnectionTool.js +8 -6
  134. package/dist/tools/connections/CallRemoteToolTool.js +4 -4
  135. package/dist/tools/core/DeleteArtifactTool.js +5 -4
  136. package/dist/tools/core/EditArtifactMetadataTool.js +1 -1
  137. package/dist/tools/core/GetArtifactTool.js +1 -1
  138. package/dist/tools/core/GetArtifactVersionsTool.js +1 -1
  139. package/dist/tools/core/GetChunkTool.js +1 -1
  140. package/dist/tools/core/ListArtifactsTool.js +1 -1
  141. package/dist/tools/core/MoveArtifactTool.js +1 -1
  142. package/dist/tools/core/PublishArtifactFromFileTool.js +1 -1
  143. package/dist/tools/core/PublishArtifactTool.js +2 -2
  144. package/dist/tools/core/SearchArtifactsTool.js +7 -6
  145. package/dist/tools/memory-graph/GraphCreateEntitiesTool.d.ts +11 -0
  146. package/dist/tools/memory-graph/GraphCreateEntitiesTool.js +56 -0
  147. package/dist/tools/memory-graph/GraphCreateRelationshipsTool.d.ts +11 -0
  148. package/dist/tools/memory-graph/GraphCreateRelationshipsTool.js +55 -0
  149. package/dist/tools/memory-graph/GraphCreateTool.d.ts +11 -0
  150. package/dist/tools/memory-graph/GraphCreateTool.js +62 -0
  151. package/dist/tools/memory-graph/GraphDeleteEntitiesTool.d.ts +11 -0
  152. package/dist/tools/memory-graph/GraphDeleteEntitiesTool.js +43 -0
  153. package/dist/tools/memory-graph/GraphDeleteRelationshipsTool.d.ts +11 -0
  154. package/dist/tools/memory-graph/GraphDeleteRelationshipsTool.js +43 -0
  155. package/dist/tools/memory-graph/GraphExploreTool.d.ts +11 -0
  156. package/dist/tools/memory-graph/GraphExploreTool.js +71 -0
  157. package/dist/tools/memory-graph/GraphFindEntitiesTool.d.ts +11 -0
  158. package/dist/tools/memory-graph/GraphFindEntitiesTool.js +66 -0
  159. package/dist/tools/memory-graph/GraphFindPathsTool.d.ts +11 -0
  160. package/dist/tools/memory-graph/GraphFindPathsTool.js +60 -0
  161. package/dist/tools/memory-graph/GraphGetEntityTool.d.ts +11 -0
  162. package/dist/tools/memory-graph/GraphGetEntityTool.js +47 -0
  163. package/dist/tools/memory-graph/GraphGetRelationshipsTool.d.ts +11 -0
  164. package/dist/tools/memory-graph/GraphGetRelationshipsTool.js +60 -0
  165. package/dist/tools/memory-graph/GraphGetStatsTool.d.ts +11 -0
  166. package/dist/tools/memory-graph/GraphGetStatsTool.js +42 -0
  167. package/dist/tools/memory-graph/GraphListTemplatesTool.d.ts +11 -0
  168. package/dist/tools/memory-graph/GraphListTemplatesTool.js +32 -0
  169. package/dist/tools/memory-graph/GraphListTool.d.ts +11 -0
  170. package/dist/tools/memory-graph/GraphListTool.js +43 -0
  171. package/dist/tools/memory-graph/GraphOpenTool.d.ts +12 -0
  172. package/dist/tools/memory-graph/GraphOpenTool.js +48 -0
  173. package/dist/tools/memory-graph/GraphProposeVocabularyTool.d.ts +11 -0
  174. package/dist/tools/memory-graph/GraphProposeVocabularyTool.js +104 -0
  175. package/dist/tools/memory-graph/GraphRemoveRelationshipsTool.d.ts +11 -0
  176. package/dist/tools/memory-graph/GraphRemoveRelationshipsTool.js +47 -0
  177. package/dist/tools/memory-graph/GraphSearchTool.d.ts +11 -0
  178. package/dist/tools/memory-graph/GraphSearchTool.js +92 -0
  179. package/dist/tools/memory-graph/GraphTraverseTool.d.ts +11 -0
  180. package/dist/tools/memory-graph/GraphTraverseTool.js +112 -0
  181. package/dist/tools/memory-graph/GraphUpdateEntitiesTool.d.ts +11 -0
  182. package/dist/tools/memory-graph/GraphUpdateEntitiesTool.js +56 -0
  183. package/dist/tools/memory-graph/KnowledgeSetListTool.d.ts +11 -0
  184. package/dist/tools/memory-graph/KnowledgeSetListTool.js +23 -0
  185. package/dist/tools/memory-graph/KnowledgeSetOpenTool.d.ts +11 -0
  186. package/dist/tools/memory-graph/KnowledgeSetOpenTool.js +29 -0
  187. package/dist/tools/repository/CreateRepositoryTool.js +10 -9
  188. package/dist/tools/repository/GetRepositoryTool.js +15 -15
  189. package/dist/tools/repository/UpdateRepositoryTool.js +10 -9
  190. package/dist/tools/sharepoint/SharePointListConnectionsTool.js +1 -1
  191. package/dist/tools/sharepoint/SharePointListFoldersTool.js +1 -1
  192. package/dist/tools/utility/AuthorIndexTool.js +6 -5
  193. package/dist/tools/utility/AuthorRecentsTool.js +6 -5
  194. package/dist/tools/utility/HealthCheckController.js +1 -1
  195. package/dist/tools/utility/ListRepositoriesTool.js +5 -4
  196. package/dist/utils/McpErrorHandler.js +1 -1
  197. package/package.json +1 -1
  198. package/package.json.backup +1 -1
@@ -0,0 +1,277 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ import { parsePath } from '../../utils/PathUtils.js';
3
+ import { McpError, McpErrorCode } from '../../utils/McpErrorHandler.js';
4
+ import { readFileSync, existsSync, statSync } from 'fs';
5
+ import { fileURLToPath } from 'url';
6
+ export class PublishArtifactFromFileTool extends BaseToolController {
7
+ constructor(ucmClient, logger, publishingAuthorId) {
8
+ super(ucmClient, logger, publishingAuthorId);
9
+ }
10
+ get name() {
11
+ return 'ucm_artifact_publish_from_file';
12
+ }
13
+ get description() {
14
+ return 'Create or update UCM artifacts from a file URI. Supports versioning. PREFERRED METHOD: Use this tool for file-based content as it is much faster and more efficient. Pass the local file path as a file:// URI (e.g., "file:///path/to/file.txt").';
15
+ }
16
+ get inputSchema() {
17
+ return {
18
+ type: 'object',
19
+ properties: {
20
+ path: {
21
+ type: 'string',
22
+ description: `Artifact namespace path (e.g., "${this.publishingAuthorId || '1234567890'}/main/commands/user")`,
23
+ minLength: 1,
24
+ maxLength: 200
25
+ },
26
+ filename: {
27
+ type: 'string',
28
+ description: 'Filename with extension (e.g., "CreateUserCommand.ts")',
29
+ minLength: 1,
30
+ maxLength: 100
31
+ },
32
+ fileUri: {
33
+ type: 'string',
34
+ description: 'File URI pointing to the content file (e.g., "file:///tmp/large-file.txt"). Use local file paths converted to file:// URIs.',
35
+ minLength: 1
36
+ },
37
+ description: {
38
+ type: 'string',
39
+ description: 'Optional description of the artifact'
40
+ },
41
+ version: {
42
+ type: 'string',
43
+ description: 'Semantic version (e.g., "1.0.0") - optional, defaults to 1.0.0 for new artifacts'
44
+ },
45
+ technology: {
46
+ type: 'string',
47
+ description: 'Technology stack (e.g., "typescript", "python"). Optional and will attempt to auto-detect'
48
+ },
49
+ mimeType: {
50
+ type: 'string',
51
+ description: 'MIME type (auto-detected if not provided)'
52
+ },
53
+ tags: {
54
+ type: 'array',
55
+ description: 'Optional array of tags for categorization',
56
+ items: {
57
+ type: 'string'
58
+ }
59
+ }
60
+ },
61
+ required: ['path', 'filename', 'fileUri']
62
+ };
63
+ }
64
+ async handleExecute(params) {
65
+ const { path, filename, fileUri, description, version, technology, mimeType, tags } = params;
66
+ this.logger.debug('PublishArtifactFromFileTool', `Publishing artifact from file: ${fileUri}`, '', {
67
+ path: `${path}/${filename}`,
68
+ version: version
69
+ });
70
+ try {
71
+ // Parse and validate the file URI
72
+ const filePath = this.parseFileUri(fileUri);
73
+ // Read the file content
74
+ const content = this.readFileContent(filePath);
75
+ this.logger.debug('PublishArtifactFromFileTool', `File read successfully: ${filePath}`, '', {
76
+ size: content.length
77
+ });
78
+ // Validate path depth - must be exactly 4 segments: author/repository/category/subcategory
79
+ const cleanPathParts = path.replace(/^\/+|\/+$/g, '').split('/').filter((p) => p.length > 0);
80
+ if (cleanPathParts.length > 4) {
81
+ throw new McpError(McpErrorCode.InvalidParams, `Path has too many segments (got ${cleanPathParts.length}, maximum is 4). ` +
82
+ `The path must follow the structure: author/repository/category/subcategory. ` +
83
+ `The filename is a separate parameter. Do not add additional sub-levels. ` +
84
+ `Example: "${this.publishingAuthorId || '1234567890'}/main/commands/user"`);
85
+ }
86
+ // Parse the path to extract components
87
+ const pathComponents = parsePath(path);
88
+ // Validate path components exist including repository
89
+ if (!pathComponents.author || !pathComponents.repository || !pathComponents.category || !pathComponents.subcategory) {
90
+ throw new McpError(McpErrorCode.InvalidParams, `Path must contain author, repository, category, and subcategory (e.g., "${this.publishingAuthorId || '1234567890'}/main/commands/user")`);
91
+ }
92
+ // Validate repository is 'main' for MVP
93
+ // if (pathComponents.repository !== 'main') {
94
+ // throw new McpError(
95
+ // McpErrorCode.InvalidParams,
96
+ // `Repository must be 'main' for MVP. Received: "${pathComponents.repository}"`
97
+ // );
98
+ // }
99
+ // Prepare the publish data - new API expects content in body and metadata in query params
100
+ const publishData = {
101
+ content, // Raw text content from file
102
+ queryParams: {
103
+ filename,
104
+ version: version ? version.replace(/^v/, '') : undefined, // Remove v prefix if present, undefined if not provided
105
+ description: description,
106
+ technology: technology,
107
+ mimeType: mimeType || this.detectMimeType(filename),
108
+ tags: tags
109
+ }
110
+ };
111
+ // Always use POST endpoint - the API will detect create vs update automatically
112
+ const result = await this.ucmClient.publishArtifact(pathComponents.author, pathComponents.repository, pathComponents.category, pathComponents.subcategory, publishData);
113
+ // Handle response structure - API might return wrapped in 'data' or direct
114
+ const artifactData = result.data || result;
115
+ // Build successful response - url comes from API (set by PublishArtifactCommand)
116
+ const namespacePath = `${pathComponents.author}/${pathComponents.repository}/${pathComponents.category}/${pathComponents.subcategory}`;
117
+ const response = {
118
+ success: true,
119
+ artifact: {
120
+ id: artifactData.id,
121
+ namespace: namespacePath,
122
+ filename,
123
+ version: publishData.queryParams.version,
124
+ name: filename, // Use filename as name, matching what the API does
125
+ description: description,
126
+ author: pathComponents.author,
127
+ technology: technology,
128
+ fileSize: content.length,
129
+ mimeType: publishData.queryParams.mimeType,
130
+ createdAt: artifactData.createdAt,
131
+ publishedAt: artifactData.publishedAt,
132
+ sourceFile: filePath
133
+ },
134
+ url: artifactData.url,
135
+ links: {
136
+ self: `/api/v1/authors/${namespacePath}/${filename}`,
137
+ download: `/api/v1/files/${namespacePath}/${filename}`,
138
+ versions: `/api/v1/authors/${namespacePath}/${filename}/versions`
139
+ }
140
+ };
141
+ this.logger.info('PublishArtifactFromFileTool', `Artifact published successfully from file: ${filePath}`, '', {
142
+ path: `${path}/${filename}`,
143
+ version: publishData.queryParams.version,
144
+ size: content.length,
145
+ id: artifactData.id
146
+ });
147
+ return response;
148
+ }
149
+ catch (error) {
150
+ this.logger.error('PublishArtifactFromFileTool', `Failed to publish artifact from file: ${fileUri}`, '', error);
151
+ // Enhanced error handling for publish operations
152
+ const errorMessage = error instanceof Error ? error.message : String(error);
153
+ // Handle ENOENT errors that might come from the API or filesystem
154
+ if (errorMessage?.includes('ENOENT') || errorMessage?.includes('no such file or directory')) {
155
+ throw new McpError(McpErrorCode.InvalidParams, `File not found: The specified file "${fileUri}" does not exist. Please verify:
156
+ 1. The file path is correct and complete
157
+ 2. The file exists at the specified location
158
+ 3. You have permission to access the file
159
+ 4. The file URI uses the correct format: file:///full/path/to/file.ext`);
160
+ }
161
+ if (errorMessage?.includes('already exists')) {
162
+ throw new McpError(McpErrorCode.InvalidParams, 'Artifact version already exists. The API automatically handles updates to existing artifacts.');
163
+ }
164
+ if (errorMessage?.includes('Author not found')) {
165
+ let authorCustomMessage = '';
166
+ if (this.publishingAuthorId) {
167
+ authorCustomMessage = `Did you mean '${this.publishingAuthorId}'`;
168
+ }
169
+ throw new McpError(McpErrorCode.InvalidParams, `Author '${parsePath(path).author}' not found. ${authorCustomMessage}`);
170
+ }
171
+ if (errorMessage?.includes('technology') && errorMessage?.includes('required')) {
172
+ throw new McpError(McpErrorCode.InvalidParams, `This namespace with category "${parsePath(path).category}" requires a technology to be specified. Please provide the technology parameter (e.g., "typescript", "python", "nextjs").`);
173
+ }
174
+ if (errorMessage?.includes('Invalid namespace format')) {
175
+ throw new McpError(McpErrorCode.InvalidParams, `Invalid namespace format: "${path}". The namespace must follow the pattern "${this.publishingAuthorId || 'author'}/repository/category/subcategory" where repository is 'main' (for MVP) and category is one of: commands, services, patterns, implementations, contracts, guidance, project. Example: "utaba/main/commands/user"`);
176
+ }
177
+ throw error;
178
+ }
179
+ }
180
+ validateParams(params) {
181
+ super.validateParams(params);
182
+ const { fileUri, version } = params;
183
+ // Validate file URI
184
+ if (!fileUri || typeof fileUri !== 'string') {
185
+ throw new McpError(McpErrorCode.InvalidParams, 'fileUri is required and must be a string');
186
+ }
187
+ // Validate file URI format
188
+ if (!fileUri.startsWith('file://')) {
189
+ throw new McpError(McpErrorCode.InvalidParams, 'fileUri must be a valid file URI starting with "file://"');
190
+ }
191
+ // Validate version format if provided
192
+ if (version && version.length > 0) {
193
+ const versionPattern = /^v?[0-9]+\.[0-9]+\.[0-9]+$/;
194
+ if (!versionPattern.test(version)) {
195
+ throw new McpError(McpErrorCode.InvalidParams, 'version must follow semantic versioning format (e.g., "1.0.0" or "v1.0.0")');
196
+ }
197
+ }
198
+ }
199
+ parseFileUri(fileUri) {
200
+ try {
201
+ // Convert file URI to file path
202
+ const filePath = fileURLToPath(fileUri);
203
+ // Security check - ensure file is accessible and not attempting path traversal
204
+ if (filePath.includes('..') || filePath.includes('~')) {
205
+ throw new McpError(McpErrorCode.InvalidParams, 'File path contains invalid characters or path traversal attempts');
206
+ }
207
+ return filePath;
208
+ }
209
+ catch (error) {
210
+ throw new McpError(McpErrorCode.InvalidParams, `Invalid file URI: ${fileUri}. Must be a valid file:// URI.`);
211
+ }
212
+ }
213
+ readFileContent(filePath) {
214
+ try {
215
+ // Check if file exists
216
+ if (!existsSync(filePath)) {
217
+ throw new McpError(McpErrorCode.InvalidParams, `File not found: ${filePath}. Please verify the file path is correct and the file exists.`);
218
+ }
219
+ // Check file size (maintain reasonable limit for memory usage)
220
+ const stats = statSync(filePath);
221
+ const maxFileSize = 100 * 1024 * 1024; // 100MB limit
222
+ if (stats.size > maxFileSize) {
223
+ throw new McpError(McpErrorCode.InvalidParams, `File size (${stats.size} bytes) exceeds maximum limit of ${maxFileSize} bytes`);
224
+ }
225
+ // Read file content
226
+ const content = readFileSync(filePath, 'utf8');
227
+ return content;
228
+ }
229
+ catch (error) {
230
+ if (error instanceof McpError) {
231
+ throw error;
232
+ }
233
+ // Handle specific filesystem errors with AI-friendly messages
234
+ if (error instanceof Error) {
235
+ if (error.message.includes('ENOENT') || error.message.includes('no such file or directory')) {
236
+ throw new McpError(McpErrorCode.InvalidParams, `File not found: ${filePath}. The file does not exist at the specified path. Please check that:
237
+ 1. The file path is correct
238
+ 2. The file has not been moved or deleted
239
+ 3. You have permission to access the file
240
+ 4. The path uses forward slashes (/), not backslashes (\\)`);
241
+ }
242
+ if (error.message.includes('EACCES') || error.message.includes('permission denied')) {
243
+ throw new McpError(McpErrorCode.InvalidParams, `Permission denied: Cannot read file ${filePath}. Please check file permissions.`);
244
+ }
245
+ if (error.message.includes('EISDIR') || error.message.includes('illegal operation on a directory')) {
246
+ throw new McpError(McpErrorCode.InvalidParams, `Invalid file path: ${filePath} is a directory, not a file. Please specify the full path to a file.`);
247
+ }
248
+ }
249
+ throw new McpError(McpErrorCode.InternalError, `Failed to read file: ${error instanceof Error ? error.message : String(error)}`);
250
+ }
251
+ }
252
+ detectMimeType(filename) {
253
+ const ext = filename.split('.').pop()?.toLowerCase();
254
+ const mimeTypes = {
255
+ 'ts': 'application/typescript',
256
+ 'js': 'application/javascript',
257
+ 'json': 'application/json',
258
+ 'md': 'text/markdown',
259
+ 'txt': 'text/plain',
260
+ 'yaml': 'text/yaml',
261
+ 'yml': 'text/yaml',
262
+ 'html': 'text/html',
263
+ 'css': 'text/css',
264
+ 'py': 'text/x-python',
265
+ 'java': 'text/x-java',
266
+ 'cs': 'text/x-csharp',
267
+ 'go': 'text/x-go',
268
+ 'rs': 'text/x-rust',
269
+ 'cpp': 'text/x-c++',
270
+ 'c': 'text/x-c',
271
+ 'sh': 'text/x-shellscript',
272
+ 'xml': 'application/xml'
273
+ };
274
+ return mimeTypes[ext || ''] || 'text/plain';
275
+ }
276
+ }
277
+ //# sourceMappingURL=PublishArtifactFromFileTool.js.map
@@ -0,0 +1,13 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ import { UcmLocalApiClient } from '../../clients/UcmLocalApiClient.js';
3
+ import { ILogger } from '../../interfaces/ILogger.js';
4
+ export declare class PublishArtifactTool extends BaseToolController {
5
+ constructor(ucmClient: UcmLocalApiClient, logger: ILogger, publishingAuthorId?: string);
6
+ get name(): string;
7
+ get description(): string;
8
+ get inputSchema(): any;
9
+ protected handleExecute(params: any): Promise<any>;
10
+ protected validateParams(params: any): void;
11
+ private detectMimeType;
12
+ }
13
+ //# sourceMappingURL=PublishArtifactTool.d.ts.map
@@ -0,0 +1,218 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ import { parsePath } from '../../utils/PathUtils.js';
3
+ import { McpError, McpErrorCode } from '../../utils/McpErrorHandler.js';
4
+ export class PublishArtifactTool extends BaseToolController {
5
+ constructor(ucmClient, logger, publishingAuthorId) {
6
+ super(ucmClient, logger, publishingAuthorId);
7
+ }
8
+ get name() {
9
+ return 'ucm_artifact_publish';
10
+ }
11
+ get description() {
12
+ return 'Create or update UCM artifacts with content and metadata. Supports versioning and automatic conflict detection. The API automatically detects whether to create or update based on existing artifacts. NOTE: Only use this tool for small data - use ucm_artifact_publish_from_file for files as it is much faster and more efficient.';
13
+ }
14
+ get inputSchema() {
15
+ return {
16
+ type: 'object',
17
+ properties: {
18
+ path: {
19
+ type: 'string',
20
+ description: `Artifact namespace path (e.g., "${this.publishingAuthorId || '1234567890'}/main/commands/user")`,
21
+ minLength: 1,
22
+ maxLength: 200
23
+ },
24
+ filename: {
25
+ type: 'string',
26
+ description: 'Filename with extension (e.g., "CreateUserCommand.ts")',
27
+ minLength: 1,
28
+ maxLength: 100
29
+ },
30
+ content: {
31
+ type: 'string',
32
+ description: 'The artifact content as text',
33
+ minLength: 1
34
+ },
35
+ description: {
36
+ type: 'string',
37
+ description: 'Optional description of the artifact'
38
+ },
39
+ version: {
40
+ type: 'string',
41
+ description: 'Semantic version (e.g., "1.0.0") - optional, defaults to 1.0.0 for new artifacts'
42
+ },
43
+ technology: {
44
+ type: 'string',
45
+ description: 'Technology stack (e.g., "typescript", "python"). Optional - only required for certain categories like "implementations"'
46
+ },
47
+ mimeType: {
48
+ type: 'string',
49
+ description: 'MIME type (auto-detected if not provided)'
50
+ },
51
+ tags: {
52
+ type: 'array',
53
+ description: 'Optional array of tags for categorization',
54
+ items: {
55
+ type: 'string'
56
+ }
57
+ }
58
+ },
59
+ required: ['path', 'filename', 'content']
60
+ };
61
+ }
62
+ async handleExecute(params) {
63
+ const { path, filename, content, description, version, technology, mimeType, tags } = params;
64
+ this.logger.debug('PublishArtifactTool', `Publishing artifact: ${path}/${filename}`, '', {
65
+ version: version,
66
+ size: content.length
67
+ });
68
+ try {
69
+ // Validate path depth - must be exactly 4 segments: author/repository/category/subcategory
70
+ const cleanPath = path.replace(/^\/+|\/+$/g, '').split('/').filter((p) => p.length > 0);
71
+ if (cleanPath.length > 4) {
72
+ throw new McpError(McpErrorCode.InvalidParams, `Path has too many segments (got ${cleanPath.length}, maximum is 4). ` +
73
+ `The path must follow the structure: author/repository/category/subcategory. ` +
74
+ `The filename is a separate parameter. Do not add additional sub-levels. ` +
75
+ `Example: "${this.publishingAuthorId || '1234567890'}/main/commands/user"`);
76
+ }
77
+ // Parse the path to extract components
78
+ const pathComponents = parsePath(path);
79
+ // Validate path components exist including repository
80
+ if (!pathComponents.author || !pathComponents.repository || !pathComponents.category || !pathComponents.subcategory) {
81
+ throw new McpError(McpErrorCode.InvalidParams, 'Path must contain author, repository, category, and subcategory (e.g., "utaba/main/commands/user")');
82
+ }
83
+ // Validate repository is 'main' for MVP
84
+ // if (pathComponents.repository !== 'main') {
85
+ // throw new McpError(
86
+ // McpErrorCode.InvalidParams,
87
+ // `Repository must be 'main' for MVP. Received: "${pathComponents.repository}"`
88
+ // );
89
+ // }
90
+ // Prepare the publish data - new API expects content in body and metadata in query params
91
+ const publishData = {
92
+ content, // Raw text content
93
+ queryParams: {
94
+ filename,
95
+ version: version ? version.replace(/^v/, '') : undefined, // Remove v prefix if present, undefined if not provided
96
+ description: description,
97
+ technology: technology,
98
+ mimeType: mimeType || this.detectMimeType(filename),
99
+ tags: tags
100
+ }
101
+ };
102
+ // Always use POST endpoint - the API will detect create vs update automatically
103
+ const result = await this.ucmClient.publishArtifact(pathComponents.author, pathComponents.repository, pathComponents.category, pathComponents.subcategory, publishData);
104
+ // Handle response structure - API might return wrapped in 'data' or direct
105
+ const artifactData = result.data || result;
106
+ // Build successful response - url comes from API (set by PublishArtifactCommand)
107
+ const namespacePath = `${pathComponents.author}/${pathComponents.repository}/${pathComponents.category}/${pathComponents.subcategory}`;
108
+ const response = {
109
+ success: true,
110
+ artifact: {
111
+ id: artifactData.id,
112
+ namespace: namespacePath,
113
+ filename,
114
+ version: publishData.queryParams.version,
115
+ name: filename, // Use filename as name, matching what the API does
116
+ description: description,
117
+ author: pathComponents.author,
118
+ technology: technology,
119
+ fileSize: content.length,
120
+ mimeType: publishData.queryParams.mimeType,
121
+ createdAt: artifactData.createdAt,
122
+ publishedAt: artifactData.publishedAt
123
+ },
124
+ url: artifactData.url,
125
+ links: {
126
+ self: `/api/v1/authors/${namespacePath}/${filename}`,
127
+ download: `/api/v1/files/${namespacePath}/${filename}`,
128
+ versions: `/api/v1/authors/${namespacePath}/${filename}/versions`
129
+ }
130
+ };
131
+ this.logger.info('PublishArtifactTool', `Artifact published successfully: ${path}/${filename}`, '', {
132
+ version: publishData.queryParams.version,
133
+ size: content.length,
134
+ id: artifactData.id
135
+ });
136
+ return response;
137
+ }
138
+ catch (error) {
139
+ this.logger.error('PublishArtifactTool', `Failed to publish artifact: ${path}/${filename}`, '', error);
140
+ // Enhanced error handling for publish operations
141
+ const errorMessage = error instanceof Error ? error.message : String(error);
142
+ // if (errorMessage?.includes('Version is required')) {
143
+ // throw new McpError(
144
+ // McpErrorCode.InvalidParams,
145
+ // 'Version is required in metadata.version field'
146
+ // );
147
+ // }
148
+ if (errorMessage?.includes('already exists')) {
149
+ throw new McpError(McpErrorCode.InvalidParams, 'Artifact version already exists. The API automatically handles updates to existing artifacts.');
150
+ }
151
+ if (errorMessage?.includes('Author not found')) {
152
+ let authorCustomMessage = '';
153
+ if (this.publishingAuthorId) {
154
+ authorCustomMessage = `Did you mean '${this.publishingAuthorId}'`;
155
+ }
156
+ throw new McpError(McpErrorCode.InvalidParams, `Author '${parsePath(path).author}' not found. ${authorCustomMessage}`);
157
+ }
158
+ if (errorMessage?.includes('technology') && errorMessage?.includes('required')) {
159
+ throw new McpError(McpErrorCode.InvalidParams, `This namespace with category "${parsePath(path).category}" requires a technology to be specified. Please provide the technology parameter (e.g., "typescript", "python", "nextjs").`);
160
+ }
161
+ // Handle ENOENT errors that might come from the API
162
+ if (errorMessage?.includes('ENOENT') || errorMessage?.includes('no such file or directory')) {
163
+ throw new McpError(McpErrorCode.InvalidParams, `Resource not found. This error typically occurs when:
164
+ 1. A required file or directory is missing
165
+ 2. The namespace path is incorrect
166
+ 3. The UCM server cannot access required resources
167
+ Please verify your input parameters and try again.`);
168
+ }
169
+ if (errorMessage?.includes('Invalid namespace format')) {
170
+ throw new McpError(McpErrorCode.InvalidParams, `Invalid namespace format: "${errorMessage}". The namespace must follow the pattern "${this.publishingAuthorId || 'author'}/repository/category/subcategory" where repository is 'main' (for MVP) and category is one of: commands, services, patterns, implementations, contracts, guidance, project. Example: "${this.publishingAuthorId || '0000000000'}/main/commands/user"`);
171
+ }
172
+ throw error;
173
+ }
174
+ }
175
+ validateParams(params) {
176
+ super.validateParams(params);
177
+ const { content, version } = params;
178
+ // Validate version format if provided
179
+ if (version && version.length > 0) {
180
+ const versionPattern = /^v?[0-9]+\.[0-9]+\.[0-9]+$/;
181
+ if (!versionPattern.test(version)) {
182
+ throw new McpError(McpErrorCode.InvalidParams, 'version must follow semantic versioning format (e.g., "1.0.0" or "v1.0.0")');
183
+ }
184
+ }
185
+ // Validate content
186
+ if (!content || typeof content !== 'string') {
187
+ throw new McpError(McpErrorCode.InvalidParams, 'content is required and must be a string');
188
+ }
189
+ if (content.length > 10 * 1024 * 1024) { // 10MB limit
190
+ throw new McpError(McpErrorCode.InvalidParams, 'content size exceeds 10MB limit');
191
+ }
192
+ }
193
+ detectMimeType(filename) {
194
+ const ext = filename.split('.').pop()?.toLowerCase();
195
+ const mimeTypes = {
196
+ 'ts': 'application/typescript',
197
+ 'js': 'application/javascript',
198
+ 'json': 'application/json',
199
+ 'md': 'text/markdown',
200
+ 'txt': 'text/plain',
201
+ 'yaml': 'text/yaml',
202
+ 'yml': 'text/yaml',
203
+ 'html': 'text/html',
204
+ 'css': 'text/css',
205
+ 'py': 'text/x-python',
206
+ 'java': 'text/x-java',
207
+ 'cs': 'text/x-csharp',
208
+ 'go': 'text/x-go',
209
+ 'rs': 'text/x-rust',
210
+ 'cpp': 'text/x-c++',
211
+ 'c': 'text/x-c',
212
+ 'sh': 'text/x-shellscript',
213
+ 'xml': 'application/xml'
214
+ };
215
+ return mimeTypes[ext || ''] || 'text/plain';
216
+ }
217
+ }
218
+ //# sourceMappingURL=PublishArtifactTool.js.map
@@ -0,0 +1,11 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ import { UcmLocalApiClient } from '../../clients/UcmLocalApiClient.js';
3
+ import { ILogger } from '../../interfaces/ILogger.js';
4
+ export declare class SearchArtifactsTool extends BaseToolController {
5
+ constructor(ucmClient: UcmLocalApiClient, logger: ILogger, publishingAuthorId?: string);
6
+ get name(): string;
7
+ get description(): string;
8
+ get inputSchema(): any;
9
+ protected handleExecute(params: any): Promise<any>;
10
+ }
11
+ //# sourceMappingURL=SearchArtifactsTool.d.ts.map
@@ -0,0 +1,137 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ export class SearchArtifactsTool extends BaseToolController {
3
+ constructor(ucmClient, logger, publishingAuthorId) {
4
+ super(ucmClient, logger, publishingAuthorId);
5
+ }
6
+ get name() {
7
+ return 'ucm_artifact_search';
8
+ }
9
+ get description() {
10
+ return `Search your workspaces by text across multiple metadata fields. Searches namespace, filename, description, and tags fields. ${this.publishingAuthorId ? "Your workspace value is '" + this.publishingAuthorId + "'" : ''}`;
11
+ }
12
+ get inputSchema() {
13
+ return {
14
+ type: 'object',
15
+ properties: {
16
+ searchText: {
17
+ type: 'string',
18
+ description: 'Text to search across namespace, repository, category, subcategory, filename, description, and tags (case-insensitive)',
19
+ minLength: 1,
20
+ maxLength: 200
21
+ },
22
+ namespace: {
23
+ type: 'string',
24
+ description: 'Optional namespace filter (e.g., "main/commands/user")',
25
+ maxLength: 200
26
+ },
27
+ workspace: {
28
+ type: 'string',
29
+ description: `Optional workspace filter. Leave empty to search your workspaces. ${this.publishingAuthorId ? '(e.g., "' + this.publishingAuthorId + '")' : ''}`,
30
+ maxLength: 50
31
+ },
32
+ repository: {
33
+ type: 'string',
34
+ description: 'Optional repository filter',
35
+ maxLength: 200
36
+ },
37
+ category: {
38
+ type: 'string',
39
+ description: 'Optional category filter (e.g., "commands", "services", "patterns")',
40
+ maxLength: 50
41
+ },
42
+ subcategory: {
43
+ type: 'string',
44
+ description: 'Optional subcategory filter (e.g., "user", "auth", "database")',
45
+ maxLength: 50
46
+ },
47
+ filename: {
48
+ type: 'string',
49
+ description: 'Optional filename filter (e.g., "CreateUserCommand.ts")',
50
+ maxLength: 100
51
+ },
52
+ tags: {
53
+ type: 'string',
54
+ description: 'Optional tags filter - comma-separated list of tags to search for',
55
+ maxLength: 500
56
+ },
57
+ offset: {
58
+ type: 'number',
59
+ description: 'Number of items to skip for pagination (default: 0)',
60
+ minimum: 0
61
+ },
62
+ limit: {
63
+ type: 'number',
64
+ description: 'Maximum number of items to return (default: 20, max: 100)',
65
+ minimum: 1,
66
+ maximum: 100
67
+ }
68
+ },
69
+ required: []
70
+ };
71
+ }
72
+ async handleExecute(params) {
73
+ const { searchText, namespace, workspace, repository, category, subcategory, filename, tags, offset, limit } = params;
74
+ const author = workspace;
75
+ this.logger.debug('SearchArtifactsTool', `Searching with filters`, '', {
76
+ searchText,
77
+ namespace,
78
+ author,
79
+ repository,
80
+ category,
81
+ subcategory,
82
+ filename,
83
+ tags,
84
+ offset: offset || 0,
85
+ limit: limit || 20
86
+ });
87
+ try {
88
+ // Call the new search API endpoint
89
+ const response = await this.ucmClient.searchArtifactsByText({
90
+ searchText,
91
+ namespace,
92
+ author,
93
+ repository, // Don't default to 'main' - let it search all repositories when undefined
94
+ category,
95
+ subcategory,
96
+ filename,
97
+ tags,
98
+ offset: offset || 0,
99
+ limit: limit || 20
100
+ });
101
+ this.logger.info('SearchArtifactsTool', `Found ${response.data.length} artifacts matching filters`, '', {
102
+ totalResults: response.pagination.total,
103
+ filters: { searchText, namespace, author, repository, category, subcategory, filename, tags }
104
+ });
105
+ // Return structured search results (only include filters that were actually provided)
106
+ const appliedFilters = {};
107
+ if (searchText)
108
+ appliedFilters.searchText = searchText;
109
+ if (namespace)
110
+ appliedFilters.namespace = namespace;
111
+ if (author)
112
+ appliedFilters.author = author;
113
+ if (repository)
114
+ appliedFilters.repository = repository;
115
+ if (category)
116
+ appliedFilters.category = category;
117
+ if (subcategory)
118
+ appliedFilters.subcategory = subcategory;
119
+ if (filename)
120
+ appliedFilters.filename = filename;
121
+ if (tags)
122
+ appliedFilters.tags = tags;
123
+ return {
124
+ filters: appliedFilters,
125
+ results: response.data,
126
+ pagination: response.pagination,
127
+ hasMore: response.pagination.hasMore,
128
+ _links: response._links
129
+ };
130
+ }
131
+ catch (error) {
132
+ this.logger.error('SearchArtifactsTool', `Failed to search with provided filters`, '', error);
133
+ throw error;
134
+ }
135
+ }
136
+ }
137
+ //# sourceMappingURL=SearchArtifactsTool.js.map
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=ListNamespaceController.d.ts.map