@utaba/ucm-mcp-server 5.0.0 → 5.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/server/ToolRegistry.js +3 -1
- package/dist/tools/core/MoveArtifactTool.d.ts +12 -0
- package/dist/tools/core/MoveArtifactTool.js +104 -0
- package/dist/tools/core/PublishArtifactFromFileTool.js +8 -0
- package/dist/tools/core/PublishArtifactTool.js +8 -0
- package/dist/tools/sharepoint/SharePointListConnectionsTool.d.ts +3 -3
- package/dist/tools/sharepoint/SharePointListConnectionsTool.js +5 -5
- package/dist/tools/utility/HealthCheckController.js +1 -1
- package/package.json +1 -1
- package/package.json.backup +1 -1
|
@@ -16,13 +16,14 @@ import { DeleteArtifactTool } from '../tools/core/DeleteArtifactTool.js';
|
|
|
16
16
|
import { GetArtifactVersionsTool } from '../tools/core/GetArtifactVersionsTool.js';
|
|
17
17
|
import { SearchArtifactsTool } from '../tools/core/SearchArtifactsTool.js';
|
|
18
18
|
import { EditArtifactMetadataTool } from '../tools/core/EditArtifactMetadataTool.js';
|
|
19
|
+
import { MoveArtifactTool } from '../tools/core/MoveArtifactTool.js';
|
|
19
20
|
// Import repository tools
|
|
20
21
|
import { CreateRepositoryTool } from '../tools/repository/CreateRepositoryTool.js';
|
|
21
22
|
import { GetRepositoryTool } from '../tools/repository/GetRepositoryTool.js';
|
|
22
23
|
import { UpdateRepositoryTool } from '../tools/repository/UpdateRepositoryTool.js';
|
|
23
24
|
import { DeleteRepositoryGuidanceTool } from '../tools/repository/DeleteRepositoryGuidanceTool.js';
|
|
24
25
|
// Import connection/SharePoint tools
|
|
25
|
-
import {
|
|
26
|
+
import { ListConnectionsTool } from '../tools/sharepoint/SharePointListConnectionsTool.js';
|
|
26
27
|
// DEPRECATED: Legacy SharePoint tools - use ucm_call_remote_tool via unified gateway instead
|
|
27
28
|
// Commented out 2026-02-13 - pending confirmation that unified gateway works correctly
|
|
28
29
|
// import { SharePointSearchTool } from '../tools/sharepoint/SharePointSearchTool.js';
|
|
@@ -68,6 +69,7 @@ export class ToolRegistry {
|
|
|
68
69
|
this.registerTool(new GetArtifactVersionsTool(this.ucmClient, this.logger, this.authorId));
|
|
69
70
|
this.registerTool(new SearchArtifactsTool(this.ucmClient, this.logger, this.authorId));
|
|
70
71
|
this.registerTool(new EditArtifactMetadataTool(this.ucmClient, this.logger, this.authorId));
|
|
72
|
+
this.registerTool(new MoveArtifactTool(this.ucmClient, this.logger, this.authorId));
|
|
71
73
|
// Register repository tools
|
|
72
74
|
this.registerTool(new CreateRepositoryTool(this.ucmClient, this.logger, this.authorId));
|
|
73
75
|
this.registerTool(new GetRepositoryTool(this.ucmClient, this.logger, this.authorId));
|
|
@@ -0,0 +1,12 @@
|
|
|
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 MoveArtifactTool extends BaseToolController {
|
|
5
|
+
constructor(ucmClient: UcmLocalApiClient, logger: ILogger, publishingAuthorId?: string);
|
|
6
|
+
get name(): string;
|
|
7
|
+
get description(): string;
|
|
8
|
+
get inputSchema(): Record<string, unknown>;
|
|
9
|
+
protected handleExecute(params: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
10
|
+
protected validateParams(params: Record<string, unknown>): void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=MoveArtifactTool.d.ts.map
|
|
@@ -0,0 +1,104 @@
|
|
|
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 MoveArtifactTool extends BaseToolController {
|
|
5
|
+
constructor(ucmClient, logger, publishingAuthorId) {
|
|
6
|
+
super(ucmClient, logger, publishingAuthorId);
|
|
7
|
+
}
|
|
8
|
+
get name() {
|
|
9
|
+
return 'ucm_move_artifact';
|
|
10
|
+
}
|
|
11
|
+
get description() {
|
|
12
|
+
return 'Move an artifact from one namespace location to another. All versions are moved. Requires read access on source and write access on destination.';
|
|
13
|
+
}
|
|
14
|
+
get inputSchema() {
|
|
15
|
+
return {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
sourcePath: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: `Full source artifact path (e.g., "${this.publishingAuthorId || '1234567890'}/main/commands/user/CreateUserCommand.ts")`,
|
|
21
|
+
minLength: 1,
|
|
22
|
+
maxLength: 250
|
|
23
|
+
},
|
|
24
|
+
destinationPath: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: `Full destination artifact path (e.g., "${this.publishingAuthorId || '1234567890'}/main/services/user/UserService.ts")`,
|
|
27
|
+
minLength: 1,
|
|
28
|
+
maxLength: 250
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
required: ['sourcePath', 'destinationPath'],
|
|
32
|
+
additionalProperties: false
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async handleExecute(params) {
|
|
36
|
+
const { sourcePath, destinationPath } = params;
|
|
37
|
+
this.logger.debug('MoveArtifactTool', `Moving artifact: ${sourcePath} → ${destinationPath}`);
|
|
38
|
+
try {
|
|
39
|
+
const source = parsePath(sourcePath);
|
|
40
|
+
const dest = parsePath(destinationPath);
|
|
41
|
+
// Build destination namespace (author/repository/category/subcategory)
|
|
42
|
+
const destNamespace = `${dest.author}/${dest.repository}/${dest.category}/${dest.subcategory}`;
|
|
43
|
+
const result = await this.ucmClient.editArtifactMetadata(source.author, source.repository, source.category, source.subcategory, source.filename, {
|
|
44
|
+
updateNamespace: destNamespace,
|
|
45
|
+
updateFilename: dest.filename
|
|
46
|
+
});
|
|
47
|
+
const responseData = result.data || result;
|
|
48
|
+
const response = {
|
|
49
|
+
success: true,
|
|
50
|
+
operation: 'move',
|
|
51
|
+
artifact: {
|
|
52
|
+
originalPath: sourcePath,
|
|
53
|
+
newPath: destinationPath,
|
|
54
|
+
affectedVersions: responseData.affectedVersions || 'all'
|
|
55
|
+
},
|
|
56
|
+
details: responseData.details || `Artifact moved from ${sourcePath} to ${destinationPath}`,
|
|
57
|
+
_links: responseData._links || {}
|
|
58
|
+
};
|
|
59
|
+
this.logger.info('MoveArtifactTool', `Artifact moved successfully: ${sourcePath} → ${destinationPath}`);
|
|
60
|
+
return response;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
this.logger.error('MoveArtifactTool', `Failed to move artifact: ${sourcePath} → ${destinationPath}`, '', error);
|
|
64
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
65
|
+
if (errorMessage?.includes('not found')) {
|
|
66
|
+
throw new McpError(McpErrorCode.InvalidParams, `Artifact not found at path: ${sourcePath}. Please verify the path is correct and the artifact exists.`);
|
|
67
|
+
}
|
|
68
|
+
if (errorMessage?.includes('permission') || errorMessage?.includes('unauthorized')) {
|
|
69
|
+
throw new McpError(McpErrorCode.InvalidParams, `Insufficient permissions. You need read access on the source and write access on the destination namespace.`);
|
|
70
|
+
}
|
|
71
|
+
if (errorMessage?.includes('destination already exists')) {
|
|
72
|
+
throw new McpError(McpErrorCode.InvalidParams, `An artifact already exists at: ${destinationPath}. Choose a different destination.`);
|
|
73
|
+
}
|
|
74
|
+
if (errorMessage?.includes('Author not found')) {
|
|
75
|
+
throw new McpError(McpErrorCode.InvalidParams, `Author not found. Ensure both source and destination paths use valid author identifiers.`);
|
|
76
|
+
}
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
validateParams(params) {
|
|
81
|
+
super.validateParams(params);
|
|
82
|
+
const { sourcePath, destinationPath } = params;
|
|
83
|
+
// Validate source path
|
|
84
|
+
const sourceParts = sourcePath.split('/');
|
|
85
|
+
if (sourceParts.length < 5) {
|
|
86
|
+
throw new McpError(McpErrorCode.InvalidParams, 'sourcePath must contain author/repository/category/subcategory/filename');
|
|
87
|
+
}
|
|
88
|
+
// Validate destination path
|
|
89
|
+
const destParts = destinationPath.split('/');
|
|
90
|
+
if (destParts.length < 5) {
|
|
91
|
+
throw new McpError(McpErrorCode.InvalidParams, 'destinationPath must contain author/repository/category/subcategory/filename');
|
|
92
|
+
}
|
|
93
|
+
// Validate destination filename
|
|
94
|
+
const destFilename = destParts[destParts.length - 1];
|
|
95
|
+
if (!/^[^\/\\:*?"<>|]+\.[a-zA-Z0-9]+$/.test(destFilename)) {
|
|
96
|
+
throw new McpError(McpErrorCode.InvalidParams, 'destinationPath filename must be valid with an extension (e.g., "UserService.ts")');
|
|
97
|
+
}
|
|
98
|
+
// Source and destination must differ
|
|
99
|
+
if (sourcePath === destinationPath) {
|
|
100
|
+
throw new McpError(McpErrorCode.InvalidParams, 'sourcePath and destinationPath must be different');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=MoveArtifactTool.js.map
|
|
@@ -75,6 +75,14 @@ export class PublishArtifactFromFileTool extends BaseToolController {
|
|
|
75
75
|
this.logger.debug('PublishArtifactFromFileTool', `File read successfully: ${filePath}`, '', {
|
|
76
76
|
size: content.length
|
|
77
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
|
+
}
|
|
78
86
|
// Parse the path to extract components
|
|
79
87
|
const pathComponents = parsePath(path);
|
|
80
88
|
// Validate path components exist including repository
|
|
@@ -66,6 +66,14 @@ export class PublishArtifactTool extends BaseToolController {
|
|
|
66
66
|
size: content.length
|
|
67
67
|
});
|
|
68
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
|
+
}
|
|
69
77
|
// Parse the path to extract components
|
|
70
78
|
const pathComponents = parsePath(path);
|
|
71
79
|
// Validate path components exist including repository
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* List all
|
|
2
|
+
* ListConnectionsTool
|
|
3
|
+
* List all external connections available to the user
|
|
4
4
|
*/
|
|
5
5
|
import { BaseToolController } from '../base/BaseToolController.js';
|
|
6
6
|
import { UcmLocalApiClient } from '../../clients/UcmLocalApiClient.js';
|
|
7
7
|
import { ILogger } from '../../interfaces/ILogger.js';
|
|
8
|
-
export declare class
|
|
8
|
+
export declare class ListConnectionsTool extends BaseToolController {
|
|
9
9
|
constructor(ucmClient: UcmLocalApiClient, logger: ILogger, publishingAuthorId?: string);
|
|
10
10
|
get name(): string;
|
|
11
11
|
get description(): string;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* List all
|
|
2
|
+
* ListConnectionsTool
|
|
3
|
+
* List all external connections available to the user
|
|
4
4
|
*/
|
|
5
5
|
import { BaseToolController } from '../base/BaseToolController.js';
|
|
6
6
|
import { McpError, McpErrorCode } from '../../utils/McpErrorHandler.js';
|
|
7
|
-
export class
|
|
7
|
+
export class ListConnectionsTool extends BaseToolController {
|
|
8
8
|
constructor(ucmClient, logger, publishingAuthorId) {
|
|
9
9
|
super(ucmClient, logger, publishingAuthorId);
|
|
10
10
|
}
|
|
@@ -49,7 +49,7 @@ export class SharePointListConnectionsTool extends BaseToolController {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
async handleExecute(params) {
|
|
52
|
-
this.logger.info('
|
|
52
|
+
this.logger.info('ListConnectionsTool', `Listing external connections (limit: ${params.limit || 20}, offset: ${params.offset || 0})`);
|
|
53
53
|
try {
|
|
54
54
|
// Get organizationId from auth ticket (via UcmApiClient)
|
|
55
55
|
// Call API to list connections with pagination params
|
|
@@ -70,7 +70,7 @@ export class SharePointListConnectionsTool extends BaseToolController {
|
|
|
70
70
|
status: error?.response?.status,
|
|
71
71
|
data: error?.response?.data
|
|
72
72
|
};
|
|
73
|
-
this.logger.error('
|
|
73
|
+
this.logger.error('ListConnectionsTool', 'Failed to list connections', '', sanitizedError);
|
|
74
74
|
if (error instanceof McpError) {
|
|
75
75
|
throw error;
|
|
76
76
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BaseToolController } from '../base/BaseToolController.js';
|
|
2
2
|
//import packageJson from '../../../../publish/package.json' assert { type: 'json' };
|
|
3
|
-
const version = '
|
|
3
|
+
const version = '5.1.0'; //TODO: tried to sync this with packageJson but it didn't work.
|
|
4
4
|
export class HealthCheckController extends BaseToolController {
|
|
5
5
|
constructor(ucmClient, logger, publishingAuthorId) {
|
|
6
6
|
super(ucmClient, logger, publishingAuthorId);
|
package/package.json
CHANGED