@utaba/ucm-mcp-server 1.1.5 → 1.1.7

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.
@@ -30,13 +30,14 @@ export declare class UcmApiClient {
30
30
  limit?: number;
31
31
  }): Promise<ArtifactData[]>;
32
32
  searchArtifactsByText(searchParams: {
33
- searchText: string;
33
+ searchText?: string;
34
34
  namespace?: string;
35
35
  author?: string;
36
36
  repository?: string;
37
37
  category?: string;
38
38
  subcategory?: string;
39
39
  filename?: string;
40
+ tags?: string;
40
41
  offset?: number;
41
42
  limit?: number;
42
43
  }): Promise<{
@@ -92,5 +93,19 @@ export declare class UcmApiClient {
92
93
  };
93
94
  _links?: any;
94
95
  }>;
96
+ submitFeedback(data: {
97
+ title: string;
98
+ body: string;
99
+ reportType: 'issue' | 'feedback';
100
+ tags?: string;
101
+ }): Promise<any>;
102
+ editArtifactMetadata(author: string, repository: string, category: string, subcategory: string, filename: string, data: {
103
+ updateDescription?: string;
104
+ updateNamespace?: string;
105
+ updateFilename?: string;
106
+ updateMimeType?: string;
107
+ updateTechnology?: string;
108
+ updateTags?: string;
109
+ }): Promise<any>;
95
110
  }
96
111
  //# sourceMappingURL=UcmApiClient.d.ts.map
@@ -188,7 +188,13 @@ export class UcmApiClient {
188
188
  // New API structure with query params
189
189
  Object.entries(data.queryParams).forEach(([key, value]) => {
190
190
  if (value !== undefined && value !== null && value !== '') {
191
- params.append(key, String(value));
191
+ // Handle arrays (e.g., tags) by JSON stringifying them
192
+ if (Array.isArray(value)) {
193
+ params.append(key, JSON.stringify(value));
194
+ }
195
+ else {
196
+ params.append(key, String(value));
197
+ }
192
198
  }
193
199
  });
194
200
  // Send raw content as text/plain body
@@ -216,7 +222,13 @@ export class UcmApiClient {
216
222
  // New API structure with query params
217
223
  Object.entries(data.queryParams).forEach(([key, value]) => {
218
224
  if (value !== undefined && value !== null && value !== '') {
219
- params.append(key, String(value));
225
+ // Handle arrays (e.g., tags) by JSON stringifying them
226
+ if (Array.isArray(value)) {
227
+ params.append(key, JSON.stringify(value));
228
+ }
229
+ else {
230
+ params.append(key, String(value));
231
+ }
220
232
  }
221
233
  });
222
234
  // Send raw content as text/plain body
@@ -346,5 +358,16 @@ export class UcmApiClient {
346
358
  const response = await client.get(url);
347
359
  return response.data;
348
360
  }
361
+ async submitFeedback(data) {
362
+ const client = this.ensureClient();
363
+ const response = await client.post('/api/v1/feedback', data);
364
+ return response.data;
365
+ }
366
+ async editArtifactMetadata(author, repository, category, subcategory, filename, data) {
367
+ const client = this.ensureClient();
368
+ const url = this.buildApiPath('authors', author, repository, category, subcategory, filename) + '/edit';
369
+ const response = await client.post(url, data);
370
+ return response.data;
371
+ }
349
372
  }
350
373
  //# sourceMappingURL=UcmApiClient.js.map
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "ucm-mcp-server",
3
+ "version": "1.1.5",
4
+ "description": "Universal Context Manager MCP Server - AI-native artifact management",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "ucm-mcp-server": "dist/index.js"
9
+ },
10
+ "keywords": [
11
+ "mcp",
12
+ "model-context-protocol",
13
+ "ucm",
14
+ "universal-context-manager",
15
+ "context-engineering",
16
+ "ai",
17
+ "context-manager",
18
+ "utaba"
19
+ ],
20
+ "author": {
21
+ "name": "Utaba AI",
22
+ "url": "https://utaba.ai"
23
+ },
24
+ "license": "BSD-3-Clause",
25
+ "homepage": "https://ucm.utaba.ai",
26
+ "dependencies": {
27
+ "@modelcontextprotocol/sdk": "^1.0.0",
28
+ "commander": "^14.0.0",
29
+ "axios": "^1.10.0"
30
+ },
31
+ "engines": {
32
+ "node": ">=18.0.0"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ }
37
+ }
@@ -5,6 +5,7 @@ import { QuickstartTool } from '../tools/utility/QuickstartTool.js';
5
5
  import { AuthorIndexTool } from '../tools/utility/AuthorIndexTool.js';
6
6
  import { AuthorRecentsTool } from '../tools/utility/AuthorRecentsTool.js';
7
7
  import { ListRepositoriesTool } from '../tools/utility/ListRepositoriesTool.js';
8
+ import { SubmitFeedbackTool } from '../tools/utility/SubmitFeedbackTool.js';
8
9
  // Import core tools
9
10
  import { GetArtifactTool } from '../tools/core/GetArtifactTool.js';
10
11
  import { GetChunkTool } from '../tools/core/GetChunkTool.js';
@@ -14,6 +15,7 @@ import { ListArtifactsTool } from '../tools/core/ListArtifactsTool.js';
14
15
  import { DeleteArtifactTool } from '../tools/core/DeleteArtifactTool.js';
15
16
  import { GetArtifactVersionsTool } from '../tools/core/GetArtifactVersionsTool.js';
16
17
  import { SearchArtifactsTool } from '../tools/core/SearchArtifactsTool.js';
18
+ import { EditArtifactMetadataTool } from '../tools/core/EditArtifactMetadataTool.js';
17
19
  // Import repository tools
18
20
  import { CreateRepositoryTool } from '../tools/repository/CreateRepositoryTool.js';
19
21
  import { GetRepositoryTool } from '../tools/repository/GetRepositoryTool.js';
@@ -41,6 +43,7 @@ export class ToolRegistry {
41
43
  this.registerTool(new AuthorIndexTool(this.ucmClient, this.logger, this.authorId));
42
44
  this.registerTool(new AuthorRecentsTool(this.ucmClient, this.logger, this.authorId));
43
45
  this.registerTool(new ListRepositoriesTool(this.ucmClient, this.logger, this.authorId));
46
+ this.registerTool(new SubmitFeedbackTool(this.ucmClient, this.logger, this.authorId));
44
47
  // Register core tools
45
48
  this.registerTool(new GetArtifactTool(this.ucmClient, this.logger, this.authorId, this.trustedAuthors));
46
49
  this.registerTool(new GetChunkTool(this.ucmClient, this.logger, this.authorId));
@@ -50,6 +53,7 @@ export class ToolRegistry {
50
53
  this.registerTool(new DeleteArtifactTool(this.ucmClient, this.logger, this.authorId));
51
54
  this.registerTool(new GetArtifactVersionsTool(this.ucmClient, this.logger, this.authorId));
52
55
  this.registerTool(new SearchArtifactsTool(this.ucmClient, this.logger, this.authorId));
56
+ this.registerTool(new EditArtifactMetadataTool(this.ucmClient, this.logger, this.authorId));
53
57
  // Register repository tools
54
58
  this.registerTool(new CreateRepositoryTool(this.ucmClient, this.logger, this.authorId));
55
59
  this.registerTool(new GetRepositoryTool(this.ucmClient, this.logger, this.authorId));
@@ -0,0 +1,12 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ import { UcmApiClient } from '../../clients/UcmApiClient.js';
3
+ import { ILogger } from '../../interfaces/ILogger.js';
4
+ export declare class EditArtifactMetadataTool extends BaseToolController {
5
+ constructor(ucmClient: UcmApiClient, 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
+ }
12
+ //# sourceMappingURL=EditArtifactMetadataTool.d.ts.map
@@ -0,0 +1,173 @@
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 EditArtifactMetadataTool extends BaseToolController {
5
+ constructor(ucmClient, logger, publishingAuthorId) {
6
+ super(ucmClient, logger, publishingAuthorId);
7
+ }
8
+ get name() {
9
+ return 'mcp_ucm_edit_artifact_metadata';
10
+ }
11
+ get description() {
12
+ return 'Edit artifact metadata and optionally move artifacts to new locations. Supports updating description, namespace, filename, MIME type, technology, and tags. Move operations affect all versions while metadata-only updates apply to latest version only.';
13
+ }
14
+ get inputSchema() {
15
+ return {
16
+ type: 'object',
17
+ properties: {
18
+ path: {
19
+ type: 'string',
20
+ description: `Full artifact path (e.g., "${this.publishingAuthorId || '1234567890'}/main/commands/user/CreateUserCommand.ts")`,
21
+ minLength: 1,
22
+ maxLength: 250
23
+ },
24
+ updateDescription: {
25
+ type: 'string',
26
+ description: 'New description for the artifact (up to 1000 characters)',
27
+ maxLength: 1000
28
+ },
29
+ updateNamespace: {
30
+ type: 'string',
31
+ description: 'New namespace path to move artifact to (e.g., "utaba/main/services/user")',
32
+ maxLength: 200
33
+ },
34
+ updateFilename: {
35
+ type: 'string',
36
+ description: 'New filename for the artifact (e.g., "UserService.ts")',
37
+ maxLength: 100
38
+ },
39
+ updateMimeType: {
40
+ type: 'string',
41
+ description: 'New MIME type for the artifact (e.g., "application/typescript")',
42
+ maxLength: 100
43
+ },
44
+ updateTechnology: {
45
+ type: 'string',
46
+ description: 'New technology stack (e.g., "typescript", "python", "nextjs")',
47
+ maxLength: 50
48
+ },
49
+ updateTags: {
50
+ type: 'string',
51
+ description: 'New comma-separated tags for categorization',
52
+ maxLength: 500
53
+ }
54
+ },
55
+ required: ['path'],
56
+ additionalProperties: false
57
+ };
58
+ }
59
+ async handleExecute(params) {
60
+ const { path, updateDescription, updateNamespace, updateFilename, updateMimeType, updateTechnology, updateTags } = params;
61
+ this.logger.debug('EditArtifactMetadataTool', `Editing artifact metadata: ${path}`, '', {
62
+ hasDescriptionUpdate: !!updateDescription,
63
+ hasNamespaceUpdate: !!updateNamespace,
64
+ hasFilenameUpdate: !!updateFilename
65
+ });
66
+ try {
67
+ // Parse the current path to extract components
68
+ const pathComponents = parsePath(path);
69
+ // Validate path components exist including repository
70
+ if (!pathComponents.author || !pathComponents.repository || !pathComponents.category || !pathComponents.subcategory || !pathComponents.filename) {
71
+ throw new McpError(McpErrorCode.InvalidParams, 'Path must contain author, repository, category, subcategory, and filename (e.g., "utaba/main/commands/user/CreateUserCommand.ts")');
72
+ }
73
+ // Validate that at least one update field is provided
74
+ const hasUpdates = !!(updateDescription || updateNamespace || updateFilename || updateMimeType || updateTechnology || updateTags);
75
+ if (!hasUpdates) {
76
+ throw new McpError(McpErrorCode.InvalidParams, 'At least one update field must be provided (updateDescription, updateNamespace, updateFilename, updateMimeType, updateTechnology, or updateTags)');
77
+ }
78
+ // Prepare the edit data
79
+ const editData = {};
80
+ if (updateDescription !== undefined)
81
+ editData.updateDescription = updateDescription;
82
+ if (updateNamespace !== undefined)
83
+ editData.updateNamespace = updateNamespace;
84
+ if (updateFilename !== undefined)
85
+ editData.updateFilename = updateFilename;
86
+ if (updateMimeType !== undefined)
87
+ editData.updateMimeType = updateMimeType;
88
+ if (updateTechnology !== undefined)
89
+ editData.updateTechnology = updateTechnology;
90
+ if (updateTags !== undefined)
91
+ editData.updateTags = updateTags;
92
+ // Call the API to edit the artifact metadata
93
+ const result = await this.ucmClient.editArtifactMetadata(pathComponents.author, pathComponents.repository, pathComponents.category, pathComponents.subcategory, pathComponents.filename, editData);
94
+ // Handle response structure - API might return wrapped in 'data' or direct
95
+ const responseData = result.data || result;
96
+ // Build successful response with operation details
97
+ const isMove = !!(updateNamespace || updateFilename);
98
+ const operation = isMove ? 'move' : 'metadata_update';
99
+ const response = {
100
+ success: true,
101
+ operation,
102
+ artifact: {
103
+ originalPath: path,
104
+ newPath: isMove ?
105
+ `${updateNamespace || `${pathComponents.author}/${pathComponents.repository}/${pathComponents.category}/${pathComponents.subcategory}`}/${updateFilename || pathComponents.filename}` :
106
+ path,
107
+ updatedFields: Object.keys(editData),
108
+ affectedVersions: responseData.affectedVersions || (isMove ? 'all' : 'latest'),
109
+ },
110
+ details: responseData.details || 'Artifact metadata updated successfully',
111
+ _links: responseData._links || {}
112
+ };
113
+ this.logger.info('EditArtifactMetadataTool', `Artifact edited successfully: ${path}`, '', {
114
+ operation,
115
+ updatedFields: Object.keys(editData),
116
+ affectedVersions: response.artifact.affectedVersions
117
+ });
118
+ return response;
119
+ }
120
+ catch (error) {
121
+ this.logger.error('EditArtifactMetadataTool', `Failed to edit artifact: ${path}`, '', error);
122
+ // Enhanced error handling for edit operations
123
+ const errorMessage = error instanceof Error ? error.message : String(error);
124
+ if (errorMessage?.includes('not found')) {
125
+ throw new McpError(McpErrorCode.InvalidParams, `Artifact not found at path: ${path}. Please verify the path is correct and the artifact exists.`);
126
+ }
127
+ if (errorMessage?.includes('permission') || errorMessage?.includes('unauthorized')) {
128
+ throw new McpError(McpErrorCode.InvalidParams, `Insufficient permissions to edit artifact at: ${path}. You must have write access to both source and destination namespaces for move operations.`);
129
+ }
130
+ if (errorMessage?.includes('destination already exists')) {
131
+ throw new McpError(McpErrorCode.InvalidParams, 'Destination artifact already exists. Choose a different filename or namespace for move operations.');
132
+ }
133
+ if (errorMessage?.includes('Invalid namespace format')) {
134
+ throw new McpError(McpErrorCode.InvalidParams, `Invalid namespace format in updateNamespace. Must follow pattern "author/repository/category/subcategory". Example: "${this.publishingAuthorId || '0000000000'}/main/services/user"`);
135
+ }
136
+ if (errorMessage?.includes('Author not found')) {
137
+ throw new McpError(McpErrorCode.InvalidParams, `Author not found. Ensure the path uses a valid author identifier.`);
138
+ }
139
+ throw error;
140
+ }
141
+ }
142
+ validateParams(params) {
143
+ super.validateParams(params);
144
+ const { path, updateNamespace, updateFilename, updateDescription } = params;
145
+ // Validate path format
146
+ if (!path || typeof path !== 'string') {
147
+ throw new McpError(McpErrorCode.InvalidParams, 'path is required and must be a string');
148
+ }
149
+ // Basic path validation - should contain at least author/repository/category/subcategory/filename
150
+ const pathParts = path.split('/');
151
+ if (pathParts.length < 5) {
152
+ throw new McpError(McpErrorCode.InvalidParams, 'path must contain at least author/repository/category/subcategory/filename');
153
+ }
154
+ // Validate updateNamespace format if provided
155
+ if (updateNamespace && updateNamespace.length > 0) {
156
+ const namespaceParts = updateNamespace.split('/');
157
+ if (namespaceParts.length !== 4) {
158
+ throw new McpError(McpErrorCode.InvalidParams, 'updateNamespace must follow format "author/repository/category/subcategory"');
159
+ }
160
+ }
161
+ // Validate updateFilename if provided
162
+ if (updateFilename && updateFilename.length > 0) {
163
+ if (!/^[^\/\\:*?"<>|]+\.[a-zA-Z0-9]+$/.test(updateFilename)) {
164
+ throw new McpError(McpErrorCode.InvalidParams, 'updateFilename must be a valid filename with extension (e.g., "UserService.ts")');
165
+ }
166
+ }
167
+ // Validate description length
168
+ if (updateDescription && updateDescription.length > 1000) {
169
+ throw new McpError(McpErrorCode.InvalidParams, 'updateDescription cannot exceed 1000 characters');
170
+ }
171
+ }
172
+ }
173
+ //# sourceMappingURL=EditArtifactMetadataTool.js.map
@@ -49,13 +49,20 @@ export class PublishArtifactFromFileTool extends BaseToolController {
49
49
  mimeType: {
50
50
  type: 'string',
51
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
+ }
52
59
  }
53
60
  },
54
61
  required: ['path', 'filename', 'fileUri']
55
62
  };
56
63
  }
57
64
  async handleExecute(params) {
58
- const { path, filename, fileUri, description, version, technology, mimeType } = params;
65
+ const { path, filename, fileUri, description, version, technology, mimeType, tags } = params;
59
66
  this.logger.debug('PublishArtifactFromFileTool', `Publishing artifact from file: ${fileUri}`, '', {
60
67
  path: `${path}/${filename}`,
61
68
  version: version
@@ -89,7 +96,8 @@ export class PublishArtifactFromFileTool extends BaseToolController {
89
96
  version: version ? version.replace(/^v/, '') : undefined, // Remove v prefix if present, undefined if not provided
90
97
  description: description,
91
98
  technology: technology,
92
- mimeType: mimeType || this.detectMimeType(filename)
99
+ mimeType: mimeType || this.detectMimeType(filename),
100
+ tags: tags
93
101
  }
94
102
  };
95
103
  // Always use POST endpoint - the API will detect create vs update automatically
@@ -47,13 +47,20 @@ export class PublishArtifactTool extends BaseToolController {
47
47
  mimeType: {
48
48
  type: 'string',
49
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
+ }
50
57
  }
51
58
  },
52
59
  required: ['path', 'filename', 'content']
53
60
  };
54
61
  }
55
62
  async handleExecute(params) {
56
- const { path, filename, content, description, version, technology, mimeType } = params;
63
+ const { path, filename, content, description, version, technology, mimeType, tags } = params;
57
64
  this.logger.debug('PublishArtifactTool', `Publishing artifact: ${path}/${filename}`, '', {
58
65
  version: version,
59
66
  size: content.length
@@ -80,7 +87,8 @@ export class PublishArtifactTool extends BaseToolController {
80
87
  version: version ? version.replace(/^v/, '') : undefined, // Remove v prefix if present, undefined if not provided
81
88
  description: description,
82
89
  technology: technology,
83
- mimeType: mimeType || this.detectMimeType(filename)
90
+ mimeType: mimeType || this.detectMimeType(filename),
91
+ tags: tags
84
92
  }
85
93
  };
86
94
  // Always use POST endpoint - the API will detect create vs update automatically
@@ -7,7 +7,7 @@ export class SearchArtifactsTool extends BaseToolController {
7
7
  return 'mcp_ucm_search_artifacts';
8
8
  }
9
9
  get description() {
10
- return `Search artifacts by text across multiple metadata fields with privacy filtering. Searches namespace, filename, and description fields. ${this.publishingAuthorId ? "Your author value is '" + this.publishingAuthorId + "'" : ''}`;
10
+ return `Search artifacts by text across multiple metadata fields with privacy filtering. Searches namespace, filename, description, and tags fields. ${this.publishingAuthorId ? "Your author value is '" + this.publishingAuthorId + "'" : ''}`;
11
11
  }
12
12
  get inputSchema() {
13
13
  return {
@@ -15,7 +15,7 @@ export class SearchArtifactsTool extends BaseToolController {
15
15
  properties: {
16
16
  searchText: {
17
17
  type: 'string',
18
- description: 'Required text to search across namespace, repository, category, subcategory, filename, and description (case-insensitive)',
18
+ description: 'Text to search across namespace, repository, category, subcategory, filename, description, and tags (case-insensitive)',
19
19
  minLength: 1,
20
20
  maxLength: 200
21
21
  },
@@ -49,6 +49,11 @@ export class SearchArtifactsTool extends BaseToolController {
49
49
  description: 'Optional filename filter (e.g., "CreateUserCommand.ts")',
50
50
  maxLength: 100
51
51
  },
52
+ tags: {
53
+ type: 'string',
54
+ description: 'Optional tags filter - comma-separated list of tags to search for',
55
+ maxLength: 500
56
+ },
52
57
  offset: {
53
58
  type: 'number',
54
59
  description: 'Number of items to skip for pagination (default: 0)',
@@ -61,18 +66,20 @@ export class SearchArtifactsTool extends BaseToolController {
61
66
  maximum: 100
62
67
  }
63
68
  },
64
- required: ['searchText']
69
+ required: []
65
70
  };
66
71
  }
67
72
  async handleExecute(params) {
68
- const { searchText, namespace, author, repository, category, subcategory, filename, offset, limit } = params;
69
- this.logger.debug('SearchArtifactsTool', `Searching for: "${searchText}" with filters`, '', {
73
+ const { searchText, namespace, author, repository, category, subcategory, filename, tags, offset, limit } = params;
74
+ this.logger.debug('SearchArtifactsTool', `Searching with filters`, '', {
75
+ searchText,
70
76
  namespace,
71
77
  author,
72
- repository: repository || 'main',
78
+ repository,
73
79
  category,
74
80
  subcategory,
75
81
  filename,
82
+ tags,
76
83
  offset: offset || 0,
77
84
  limit: limit || 20
78
85
  });
@@ -82,28 +89,38 @@ export class SearchArtifactsTool extends BaseToolController {
82
89
  searchText,
83
90
  namespace,
84
91
  author,
85
- repository: repository || 'main', // Default to 'main' for MVP
92
+ repository, // Don't default to 'main' - let it search all repositories when undefined
86
93
  category,
87
94
  subcategory,
88
95
  filename,
96
+ tags,
89
97
  offset: offset || 0,
90
98
  limit: limit || 20
91
99
  });
92
- this.logger.info('SearchArtifactsTool', `Found ${response.data.length} artifacts matching: "${searchText}"`, '', {
100
+ this.logger.info('SearchArtifactsTool', `Found ${response.data.length} artifacts matching filters`, '', {
93
101
  totalResults: response.pagination.total,
94
- filters: { namespace, author, repository, category, subcategory, filename }
102
+ filters: { searchText, namespace, author, repository, category, subcategory, filename, tags }
95
103
  });
96
- // Return structured search results
104
+ // Return structured search results (only include filters that were actually provided)
105
+ const appliedFilters = {};
106
+ if (searchText)
107
+ appliedFilters.searchText = searchText;
108
+ if (namespace)
109
+ appliedFilters.namespace = namespace;
110
+ if (author)
111
+ appliedFilters.author = author;
112
+ if (repository)
113
+ appliedFilters.repository = repository;
114
+ if (category)
115
+ appliedFilters.category = category;
116
+ if (subcategory)
117
+ appliedFilters.subcategory = subcategory;
118
+ if (filename)
119
+ appliedFilters.filename = filename;
120
+ if (tags)
121
+ appliedFilters.tags = tags;
97
122
  return {
98
- searchText,
99
- filters: {
100
- namespace,
101
- author,
102
- repository: repository || 'main',
103
- category,
104
- subcategory,
105
- filename
106
- },
123
+ filters: appliedFilters,
107
124
  results: response.data,
108
125
  pagination: response.pagination,
109
126
  hasMore: response.pagination.hasMore,
@@ -111,7 +128,7 @@ export class SearchArtifactsTool extends BaseToolController {
111
128
  };
112
129
  }
113
130
  catch (error) {
114
- this.logger.error('SearchArtifactsTool', `Failed to search for: "${searchText}"`, '', error);
131
+ this.logger.error('SearchArtifactsTool', `Failed to search with provided filters`, '', error);
115
132
  throw error;
116
133
  }
117
134
  }
@@ -9,7 +9,7 @@ export class CreateRepositoryTool extends BaseToolController {
9
9
  }
10
10
  get description() {
11
11
  const authorInfo = this.publishingAuthorId ? ` Your author id is '${this.publishingAuthorId}'.` : '';
12
- return `Create a new repository for a specific author. Repository names must be unique within the author namespace and follow UCM naming conventions (3-200 characters, start with letter, alphanumeric and hyphens only, no consecutive hyphens).${authorInfo}`;
12
+ return `Create a new repository for a specific author. Repository names must be unique within the author namespace and follow UCM naming conventions. (3-200 characters, start with letter, alphanumeric and hyphens only, no consecutive hyphens).${authorInfo}`;
13
13
  }
14
14
  get inputSchema() {
15
15
  return {
@@ -10,8 +10,7 @@ export class DeleteRepositoryGuidanceTool extends BaseToolController {
10
10
  return 'mcp_ucm_delete_repository_guidance';
11
11
  }
12
12
  get description() {
13
- const authorInfo = this.publishingAuthorId ? ` Your author id is '${this.publishingAuthorId}'.` : '';
14
- return `Provides guidance for deleting a repository via the web UI. Repository deletion is intentionally not available through the MCP tools to prevent accidental deletion. This tool returns the web URL where the user can safely delete the repository with proper confirmation dialogs.${authorInfo}`;
13
+ return `Provides guidance for deleting a repository via the web UI.`;
15
14
  }
16
15
  get inputSchema() {
17
16
  return {
@@ -1,4 +1,6 @@
1
1
  import { BaseToolController } from '../base/BaseToolController.js';
2
+ //import packageJson from '../../../../publish/package.json' assert { type: 'json' };
3
+ const version = '1.1.7'; //TODO: tried to sync this with packageJson but it didn't work.
2
4
  export class HealthCheckController extends BaseToolController {
3
5
  constructor(ucmClient, logger, publishingAuthorId) {
4
6
  super(ucmClient, logger, publishingAuthorId);
@@ -25,7 +27,8 @@ export class HealthCheckController extends BaseToolController {
25
27
  mcpServer: {
26
28
  status: 'running',
27
29
  timestamp: new Date().toISOString(),
28
- uptime: process.uptime()
30
+ uptime: process.uptime(),
31
+ version: version
29
32
  },
30
33
  ucmApi: {
31
34
  status: 'connected',
@@ -43,7 +46,8 @@ export class HealthCheckController extends BaseToolController {
43
46
  mcpServer: {
44
47
  status: 'running',
45
48
  timestamp: new Date().toISOString(),
46
- uptime: process.uptime()
49
+ uptime: process.uptime(),
50
+ version: version
47
51
  },
48
52
  ucmApi: {
49
53
  status: 'disconnected',
@@ -0,0 +1,16 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ import { UcmApiClient } from '../../clients/UcmApiClient.js';
3
+ import { ILogger } from '../../interfaces/ILogger.js';
4
+ export declare class SubmitFeedbackTool extends BaseToolController {
5
+ constructor(ucmClient: UcmApiClient, logger: ILogger, publishingAuthorId?: string);
6
+ get name(): string;
7
+ get description(): string;
8
+ get inputSchema(): any;
9
+ protected handleExecute(params: {
10
+ title: string;
11
+ body: string;
12
+ reportType: 'issue' | 'feedback';
13
+ tags?: string;
14
+ }): Promise<any>;
15
+ }
16
+ //# sourceMappingURL=SubmitFeedbackTool.d.ts.map
@@ -0,0 +1,68 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ export class SubmitFeedbackTool extends BaseToolController {
3
+ constructor(ucmClient, logger, publishingAuthorId) {
4
+ super(ucmClient, logger, publishingAuthorId);
5
+ }
6
+ get name() {
7
+ return 'mcp_ucm_submit_user_issue_or_feedback';
8
+ }
9
+ get description() {
10
+ return 'Submit user feedback, bug reports, feature requests ONLY if the user requests it and they want to send details to the UCM development team. Do NOT include sensitive or project related details. Ask the user before submitting the data if it is appropriate.';
11
+ }
12
+ get inputSchema() {
13
+ return {
14
+ type: 'object',
15
+ properties: {
16
+ title: {
17
+ type: 'string',
18
+ description: 'Brief title for the feedback or issue (1-100 characters)',
19
+ minLength: 1,
20
+ maxLength: 100
21
+ },
22
+ body: {
23
+ type: 'string',
24
+ description: 'Detailed description of the feedback or issue (1-1000 characters)',
25
+ minLength: 1,
26
+ maxLength: 1000
27
+ },
28
+ reportType: {
29
+ type: 'string',
30
+ enum: ['issue', 'feedback'],
31
+ description: 'Type of report: "issue" for bug reports and problems, "feedback" for feature requests and general feedback'
32
+ },
33
+ tags: {
34
+ type: 'string',
35
+ description: 'Optional comma-separated tags for categorization (e.g., "ui,bug,performance")',
36
+ maxLength: 1000
37
+ }
38
+ },
39
+ required: ['title', 'body', 'reportType']
40
+ };
41
+ }
42
+ async handleExecute(params) {
43
+ this.logger.info('SubmitFeedbackTool', `Submitting ${params.reportType}: ${params.title}`);
44
+ try {
45
+ const result = await this.ucmClient.submitFeedback({
46
+ title: params.title,
47
+ body: params.body,
48
+ reportType: params.reportType,
49
+ tags: params.tags
50
+ });
51
+ this.logger.info('SubmitFeedbackTool', `Successfully submitted ${params.reportType} with ID: ${result.feedbackId}`);
52
+ return {
53
+ success: true,
54
+ feedbackId: result.feedbackId,
55
+ submittedAt: result.createdAt,
56
+ message: result.message,
57
+ reportType: params.reportType,
58
+ title: params.title
59
+ };
60
+ }
61
+ catch (error) {
62
+ const errorMessage = error instanceof Error ? error.message : String(error);
63
+ this.logger.error('SubmitFeedbackTool', `Failed to submit ${params.reportType}: ${errorMessage}`, '', error);
64
+ throw error;
65
+ }
66
+ }
67
+ }
68
+ //# sourceMappingURL=SubmitFeedbackTool.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utaba/ucm-mcp-server",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "Universal Context Manager MCP Server - AI-native artifact management",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ucm-mcp-server",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "Universal Context Manager MCP Server - AI-native artifact management",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",