@utaba/ucm-mcp-server 1.0.7 → 1.1.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.
- package/dist/clients/UcmApiClient.d.ts +21 -0
- package/dist/clients/UcmApiClient.js +21 -1
- package/dist/server/ToolRegistry.js +4 -0
- package/dist/tools/core/SearchArtifactsTool.d.ts +11 -0
- package/dist/tools/core/SearchArtifactsTool.js +119 -0
- package/dist/tools/utility/AuthorIndexTool.js +2 -2
- package/dist/tools/utility/AuthorRecentsTool.d.ts +11 -0
- package/dist/tools/utility/AuthorRecentsTool.js +48 -0
- package/package.json +1 -1
- package/package.json.backup +1 -1
|
@@ -29,6 +29,26 @@ export declare class UcmApiClient {
|
|
|
29
29
|
offset?: number;
|
|
30
30
|
limit?: number;
|
|
31
31
|
}): Promise<ArtifactData[]>;
|
|
32
|
+
searchArtifactsByText(searchParams: {
|
|
33
|
+
searchText: string;
|
|
34
|
+
namespace?: string;
|
|
35
|
+
author?: string;
|
|
36
|
+
repository?: string;
|
|
37
|
+
category?: string;
|
|
38
|
+
subcategory?: string;
|
|
39
|
+
filename?: string;
|
|
40
|
+
offset?: number;
|
|
41
|
+
limit?: number;
|
|
42
|
+
}): Promise<{
|
|
43
|
+
data: any[];
|
|
44
|
+
pagination: {
|
|
45
|
+
offset: number;
|
|
46
|
+
limit: number;
|
|
47
|
+
total: number;
|
|
48
|
+
hasMore: boolean;
|
|
49
|
+
};
|
|
50
|
+
_links?: any;
|
|
51
|
+
}>;
|
|
32
52
|
publishArtifact(author: string, repository: string, category: string, subcategory: string, data: any): Promise<ArtifactData>;
|
|
33
53
|
updateArtifact(author: string, repository: string, category: string, subcategory: string, filename: string, version: string, data: any): Promise<ArtifactData>;
|
|
34
54
|
deleteArtifact(author: string, repository: string, category: string, subcategory: string, filename: string, version?: string): Promise<any>;
|
|
@@ -40,6 +60,7 @@ export declare class UcmApiClient {
|
|
|
40
60
|
}>;
|
|
41
61
|
getQuickstart(): Promise<string>;
|
|
42
62
|
getAuthorIndex(author: string, repository?: string): Promise<string>;
|
|
63
|
+
getAuthorRecents(author: string): Promise<string>;
|
|
43
64
|
/**
|
|
44
65
|
* Cleanup method to properly dispose of HTTP client resources
|
|
45
66
|
* This helps prevent memory leaks from accumulated AbortSignal listeners
|
|
@@ -26,7 +26,7 @@ export class UcmApiClient {
|
|
|
26
26
|
const url = error.config?.url;
|
|
27
27
|
const errorMessage = apiError?.message || apiError?.error || error.message || JSON.stringify(apiError);
|
|
28
28
|
if (status === 404) {
|
|
29
|
-
return Promise.reject(new Error(`Resource not found: ${errorMessage}`));
|
|
29
|
+
return Promise.reject(new Error(`Resource not found at ${url}: ${errorMessage}`));
|
|
30
30
|
}
|
|
31
31
|
if (status >= 500) {
|
|
32
32
|
// For 5xx errors, include API error details if available
|
|
@@ -168,6 +168,17 @@ export class UcmApiClient {
|
|
|
168
168
|
const response = await client.get(`/api/v1/artifacts?${params}`);
|
|
169
169
|
return response.data;
|
|
170
170
|
}
|
|
171
|
+
async searchArtifactsByText(searchParams) {
|
|
172
|
+
const params = new URLSearchParams();
|
|
173
|
+
// Add all parameters to URL
|
|
174
|
+
Object.entries(searchParams).forEach(([key, value]) => {
|
|
175
|
+
if (value !== undefined)
|
|
176
|
+
params.append(key, value.toString());
|
|
177
|
+
});
|
|
178
|
+
const client = this.ensureClient();
|
|
179
|
+
const response = await client.get(`/api/v1/search/artifacts?${params}`);
|
|
180
|
+
return response.data;
|
|
181
|
+
}
|
|
171
182
|
async publishArtifact(author, repository, category, subcategory, data) {
|
|
172
183
|
// Default repository to 'main' for MVP
|
|
173
184
|
const repo = repository || 'main';
|
|
@@ -274,6 +285,15 @@ export class UcmApiClient {
|
|
|
274
285
|
});
|
|
275
286
|
return response.data;
|
|
276
287
|
}
|
|
288
|
+
async getAuthorRecents(author) {
|
|
289
|
+
const client = this.ensureClient();
|
|
290
|
+
// Author-level recent activity (using new resources API structure)
|
|
291
|
+
const url = `/api/v1/resources/author/${author}/recents`;
|
|
292
|
+
const response = await client.get(url, {
|
|
293
|
+
headers: { 'accept': 'text/markdown' }
|
|
294
|
+
});
|
|
295
|
+
return response.data;
|
|
296
|
+
}
|
|
277
297
|
/**
|
|
278
298
|
* Cleanup method to properly dispose of HTTP client resources
|
|
279
299
|
* This helps prevent memory leaks from accumulated AbortSignal listeners
|
|
@@ -3,6 +3,7 @@ import { McpError, McpErrorCode } from '../utils/McpErrorHandler.js';
|
|
|
3
3
|
import { HealthCheckController } from '../tools/utility/HealthCheckController.js';
|
|
4
4
|
import { QuickstartTool } from '../tools/utility/QuickstartTool.js';
|
|
5
5
|
import { AuthorIndexTool } from '../tools/utility/AuthorIndexTool.js';
|
|
6
|
+
import { AuthorRecentsTool } from '../tools/utility/AuthorRecentsTool.js';
|
|
6
7
|
import { ListRepositoriesTool } from '../tools/utility/ListRepositoriesTool.js';
|
|
7
8
|
// Import core tools
|
|
8
9
|
import { GetArtifactTool } from '../tools/core/GetArtifactTool.js';
|
|
@@ -12,6 +13,7 @@ import { PublishArtifactFromFileTool } from '../tools/core/PublishArtifactFromFi
|
|
|
12
13
|
import { ListArtifactsTool } from '../tools/core/ListArtifactsTool.js';
|
|
13
14
|
import { DeleteArtifactTool } from '../tools/core/DeleteArtifactTool.js';
|
|
14
15
|
import { GetArtifactVersionsTool } from '../tools/core/GetArtifactVersionsTool.js';
|
|
16
|
+
import { SearchArtifactsTool } from '../tools/core/SearchArtifactsTool.js';
|
|
15
17
|
// Import repository tools
|
|
16
18
|
import { CreateRepositoryTool } from '../tools/repository/CreateRepositoryTool.js';
|
|
17
19
|
import { GetRepositoryTool } from '../tools/repository/GetRepositoryTool.js';
|
|
@@ -37,6 +39,7 @@ export class ToolRegistry {
|
|
|
37
39
|
this.registerTool(new QuickstartTool(this.ucmClient, this.logger, this.authorId));
|
|
38
40
|
this.registerTool(new HealthCheckController(this.ucmClient, this.logger, this.authorId));
|
|
39
41
|
this.registerTool(new AuthorIndexTool(this.ucmClient, this.logger, this.authorId));
|
|
42
|
+
this.registerTool(new AuthorRecentsTool(this.ucmClient, this.logger, this.authorId));
|
|
40
43
|
this.registerTool(new ListRepositoriesTool(this.ucmClient, this.logger, this.authorId));
|
|
41
44
|
// Register core tools
|
|
42
45
|
this.registerTool(new GetArtifactTool(this.ucmClient, this.logger, this.authorId, this.trustedAuthors));
|
|
@@ -46,6 +49,7 @@ export class ToolRegistry {
|
|
|
46
49
|
this.registerTool(new ListArtifactsTool(this.ucmClient, this.logger, this.authorId));
|
|
47
50
|
this.registerTool(new DeleteArtifactTool(this.ucmClient, this.logger, this.authorId));
|
|
48
51
|
this.registerTool(new GetArtifactVersionsTool(this.ucmClient, this.logger, this.authorId));
|
|
52
|
+
this.registerTool(new SearchArtifactsTool(this.ucmClient, this.logger, this.authorId));
|
|
49
53
|
// Register repository tools
|
|
50
54
|
this.registerTool(new CreateRepositoryTool(this.ucmClient, this.logger, this.authorId));
|
|
51
55
|
this.registerTool(new GetRepositoryTool(this.ucmClient, this.logger, this.authorId));
|
|
@@ -0,0 +1,11 @@
|
|
|
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 SearchArtifactsTool 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
|
+
}
|
|
11
|
+
//# sourceMappingURL=SearchArtifactsTool.d.ts.map
|
|
@@ -0,0 +1,119 @@
|
|
|
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 'mcp_ucm_search_artifacts';
|
|
8
|
+
}
|
|
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 + "'" : ''}`;
|
|
11
|
+
}
|
|
12
|
+
get inputSchema() {
|
|
13
|
+
return {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
searchText: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
description: 'Required text to search across namespace, repository, category, subcategory, filename, and description (case-insensitive)',
|
|
19
|
+
minLength: 1,
|
|
20
|
+
maxLength: 200
|
|
21
|
+
},
|
|
22
|
+
namespace: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'Optional namespace filter (e.g., "utaba/main/commands/user")',
|
|
25
|
+
maxLength: 200
|
|
26
|
+
},
|
|
27
|
+
author: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: `Optional. Leave empty to search your own author and public authors. '(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
|
+
offset: {
|
|
53
|
+
type: 'number',
|
|
54
|
+
description: 'Number of items to skip for pagination (default: 0)',
|
|
55
|
+
minimum: 0
|
|
56
|
+
},
|
|
57
|
+
limit: {
|
|
58
|
+
type: 'number',
|
|
59
|
+
description: 'Maximum number of items to return (default: 20, max: 100)',
|
|
60
|
+
minimum: 1,
|
|
61
|
+
maximum: 100
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
required: ['searchText']
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
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`, '', {
|
|
70
|
+
namespace,
|
|
71
|
+
author,
|
|
72
|
+
repository: repository || 'main',
|
|
73
|
+
category,
|
|
74
|
+
subcategory,
|
|
75
|
+
filename,
|
|
76
|
+
offset: offset || 0,
|
|
77
|
+
limit: limit || 20
|
|
78
|
+
});
|
|
79
|
+
try {
|
|
80
|
+
// Call the new search API endpoint
|
|
81
|
+
const response = await this.ucmClient.searchArtifactsByText({
|
|
82
|
+
searchText,
|
|
83
|
+
namespace,
|
|
84
|
+
author,
|
|
85
|
+
repository: repository || 'main', // Default to 'main' for MVP
|
|
86
|
+
category,
|
|
87
|
+
subcategory,
|
|
88
|
+
filename,
|
|
89
|
+
offset: offset || 0,
|
|
90
|
+
limit: limit || 20
|
|
91
|
+
});
|
|
92
|
+
this.logger.info('SearchArtifactsTool', `Found ${response.data.length} artifacts matching: "${searchText}"`, '', {
|
|
93
|
+
totalResults: response.pagination.total,
|
|
94
|
+
filters: { namespace, author, repository, category, subcategory, filename }
|
|
95
|
+
});
|
|
96
|
+
// Return structured search results
|
|
97
|
+
return {
|
|
98
|
+
searchText,
|
|
99
|
+
filters: {
|
|
100
|
+
namespace,
|
|
101
|
+
author,
|
|
102
|
+
repository: repository || 'main',
|
|
103
|
+
category,
|
|
104
|
+
subcategory,
|
|
105
|
+
filename
|
|
106
|
+
},
|
|
107
|
+
results: response.data,
|
|
108
|
+
pagination: response.pagination,
|
|
109
|
+
hasMore: response.pagination.hasMore,
|
|
110
|
+
_links: response._links
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
this.logger.error('SearchArtifactsTool', `Failed to search for: "${searchText}"`, '', error);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=SearchArtifactsTool.js.map
|
|
@@ -37,8 +37,8 @@ export class AuthorIndexTool extends BaseToolController {
|
|
|
37
37
|
catch (error) {
|
|
38
38
|
let errorMessage = `Failed to retrieve author index for ${author}.`;
|
|
39
39
|
if (this.publishingAuthorId && author != this.publishingAuthorId) {
|
|
40
|
-
errorMessage += `
|
|
41
|
-
error.message = error.message += `
|
|
40
|
+
errorMessage += ` did you mean '${this.publishingAuthorId}'`;
|
|
41
|
+
error.message = error.message += ` did you mean '${this.publishingAuthorId}'`;
|
|
42
42
|
}
|
|
43
43
|
this.logger.error('AuthorIndexTool', `${errorMessage}`, '', error);
|
|
44
44
|
throw error;
|
|
@@ -0,0 +1,11 @@
|
|
|
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 AuthorRecentsTool 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
|
+
}
|
|
11
|
+
//# sourceMappingURL=AuthorRecentsTool.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { BaseToolController } from '../base/BaseToolController.js';
|
|
2
|
+
export class AuthorRecentsTool extends BaseToolController {
|
|
3
|
+
constructor(ucmClient, logger, publishingAuthorId) {
|
|
4
|
+
super(ucmClient, logger, publishingAuthorId);
|
|
5
|
+
}
|
|
6
|
+
get name() {
|
|
7
|
+
return 'mcp_ucm_get_author_recents';
|
|
8
|
+
}
|
|
9
|
+
get description() {
|
|
10
|
+
return `Generate author activity tracking showing the 20 most recently modified artifacts within an author context. Your author id is '${this.publishingAuthorId}'`;
|
|
11
|
+
}
|
|
12
|
+
get inputSchema() {
|
|
13
|
+
return {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
author: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
description: `Author identifier: ${this.publishingAuthorId || '1234567890'}`
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
required: ['author']
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async handleExecute(params) {
|
|
25
|
+
const { author } = params;
|
|
26
|
+
this.logger.debug('AuthorRecentsTool', `Retrieving author recents for: ${author}`);
|
|
27
|
+
try {
|
|
28
|
+
// Get author recent activity content from API
|
|
29
|
+
const authorRecentsContent = await this.ucmClient.getAuthorRecents(author);
|
|
30
|
+
this.logger.info('AuthorRecentsTool', 'Author recents retrieved successfully', '', {
|
|
31
|
+
author,
|
|
32
|
+
contentLength: authorRecentsContent.length,
|
|
33
|
+
source: `UCM API /api/v1/resources/author/${author}/recents`
|
|
34
|
+
});
|
|
35
|
+
return authorRecentsContent;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
let errorMessage = `Failed to retrieve author recents for ${author}.`;
|
|
39
|
+
if (this.publishingAuthorId && author != this.publishingAuthorId) {
|
|
40
|
+
errorMessage += ` did you mean '${this.publishingAuthorId}'?`;
|
|
41
|
+
error.message = error.message += ` did you mean '${this.publishingAuthorId}'?`;
|
|
42
|
+
}
|
|
43
|
+
this.logger.error('AuthorRecentsTool', `${errorMessage}`, '', error);
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=AuthorRecentsTool.js.map
|
package/package.json
CHANGED