@utaba/ucm-mcp-server 4.2.2 → 4.3.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 +49 -4
- package/dist/clients/UcmApiClient.js +71 -4
- package/dist/clients/UcmLocalApiClient.d.ts +165 -0
- package/dist/clients/UcmLocalApiClient.js +460 -0
- package/dist/index.js +3 -4
- package/dist/server/McpConfig.d.ts +0 -2
- package/dist/server/McpConfig.js +1 -5
- package/dist/server/McpServer.js +2 -7
- package/dist/server/ToolRegistry.js +14 -0
- package/dist/tools/repository/CreateRepositoryTool.js +2 -12
- package/dist/tools/repository/UpdateRepositoryTool.js +4 -15
- package/dist/tools/sharepoint/SharePointListConnectionsTool.d.ts +19 -0
- package/dist/tools/sharepoint/SharePointListConnectionsTool.js +84 -0
- package/dist/tools/sharepoint/SharePointListFoldersTool.d.ts +21 -0
- package/dist/tools/sharepoint/SharePointListFoldersTool.js +140 -0
- package/dist/tools/sharepoint/SharePointReadFileTool.d.ts +22 -0
- package/dist/tools/sharepoint/SharePointReadFileTool.js +145 -0
- package/dist/tools/sharepoint/SharePointReadRelatedFileTool.d.ts +18 -0
- package/dist/tools/sharepoint/SharePointReadRelatedFileTool.js +102 -0
- package/dist/tools/sharepoint/SharePointSearchTool.d.ts +22 -0
- package/dist/tools/sharepoint/SharePointSearchTool.js +134 -0
- package/dist/tools/sharepoint/SharePointSignOutTool.d.ts +22 -0
- package/dist/tools/sharepoint/SharePointSignOutTool.js +108 -0
- package/dist/utils/SharePointErrorHandler.d.ts +28 -0
- package/dist/utils/SharePointErrorHandler.js +47 -0
- package/package.json +1 -1
- package/package.json.backup +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharePointListConnectionsTool
|
|
3
|
+
* List all SharePoint connections available to the user
|
|
4
|
+
*/
|
|
5
|
+
import { BaseToolController } from '../base/BaseToolController.js';
|
|
6
|
+
import { UcmLocalApiClient } from '../../clients/UcmLocalApiClient.js';
|
|
7
|
+
import { ILogger } from '../../interfaces/ILogger.js';
|
|
8
|
+
export declare class SharePointListConnectionsTool extends BaseToolController {
|
|
9
|
+
constructor(ucmClient: UcmLocalApiClient, logger: ILogger, publishingAuthorId?: string);
|
|
10
|
+
get name(): string;
|
|
11
|
+
get description(): string;
|
|
12
|
+
get inputSchema(): any;
|
|
13
|
+
protected validateParams(params: any): void;
|
|
14
|
+
protected handleExecute(params: {
|
|
15
|
+
limit?: number;
|
|
16
|
+
offset?: number;
|
|
17
|
+
}): Promise<any>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=SharePointListConnectionsTool.d.ts.map
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharePointListConnectionsTool
|
|
3
|
+
* List all SharePoint connections available to the user
|
|
4
|
+
*/
|
|
5
|
+
import { BaseToolController } from '../base/BaseToolController.js';
|
|
6
|
+
import { McpError, McpErrorCode } from '../../utils/McpErrorHandler.js';
|
|
7
|
+
export class SharePointListConnectionsTool extends BaseToolController {
|
|
8
|
+
constructor(ucmClient, logger, publishingAuthorId) {
|
|
9
|
+
super(ucmClient, logger, publishingAuthorId);
|
|
10
|
+
}
|
|
11
|
+
get name() {
|
|
12
|
+
return 'ucm_list_connections';
|
|
13
|
+
}
|
|
14
|
+
get description() {
|
|
15
|
+
return 'List all External connections including SharePoint available to the user. Returns connection details, use this to discover available connections before searching or browsing.';
|
|
16
|
+
}
|
|
17
|
+
get inputSchema() {
|
|
18
|
+
return {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
limit: {
|
|
22
|
+
type: 'number',
|
|
23
|
+
description: 'Maximum number of connections to return (default: 20, max: 100)',
|
|
24
|
+
minimum: 1,
|
|
25
|
+
maximum: 100
|
|
26
|
+
},
|
|
27
|
+
offset: {
|
|
28
|
+
type: 'number',
|
|
29
|
+
description: 'Number of connections to skip for pagination (default: 0)',
|
|
30
|
+
minimum: 0
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
required: []
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
validateParams(params) {
|
|
37
|
+
super.validateParams(params);
|
|
38
|
+
// Validate limit if provided
|
|
39
|
+
if (params.limit !== undefined) {
|
|
40
|
+
if (typeof params.limit !== 'number' || params.limit < 1 || params.limit > 100) {
|
|
41
|
+
throw new McpError(McpErrorCode.InvalidParams, 'Limit must be a number between 1 and 100');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Validate offset if provided
|
|
45
|
+
if (params.offset !== undefined) {
|
|
46
|
+
if (typeof params.offset !== 'number' || params.offset < 0) {
|
|
47
|
+
throw new McpError(McpErrorCode.InvalidParams, 'Offset must be a number greater than or equal to 0');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async handleExecute(params) {
|
|
52
|
+
this.logger.info('SharePointListConnectionsTool', `Listing SharePoint connections (limit: ${params.limit || 20}, offset: ${params.offset || 0})`);
|
|
53
|
+
try {
|
|
54
|
+
// Get organizationId from auth ticket (via UcmApiClient)
|
|
55
|
+
// Call API to list connections with pagination params
|
|
56
|
+
const result = await this.ucmClient.listExternalConnections({
|
|
57
|
+
limit: params.limit,
|
|
58
|
+
offset: params.offset
|
|
59
|
+
});
|
|
60
|
+
this.logger.info('listConnections', 'Connections retrieved successfully', '', {
|
|
61
|
+
contentLength: result.length,
|
|
62
|
+
source: 'UCM API /api/v1/connections'
|
|
63
|
+
});
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
this.logger.error('SharePointListConnectionsTool: Failed to list connections', error);
|
|
68
|
+
if (error instanceof McpError) {
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
// Handle API errors
|
|
72
|
+
if (error.response) {
|
|
73
|
+
const status = error.response.status;
|
|
74
|
+
const errorData = error.response.data;
|
|
75
|
+
if (status === 401 || status === 403) {
|
|
76
|
+
throw new McpError(McpErrorCode.InvalidRequest, `Access denied: ${errorData?.message || 'Not authorized to list SharePoint connections'}`);
|
|
77
|
+
}
|
|
78
|
+
throw new McpError(McpErrorCode.InternalError, `API error: ${errorData?.message || error.message}`);
|
|
79
|
+
}
|
|
80
|
+
throw new McpError(McpErrorCode.InternalError, `Failed to list external connections: ${error.message}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=SharePointListConnectionsTool.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharePointListFoldersTool
|
|
3
|
+
* List folders in SharePoint document library
|
|
4
|
+
*/
|
|
5
|
+
import { BaseToolController } from '../base/BaseToolController.js';
|
|
6
|
+
import { UcmLocalApiClient } from '../../clients/UcmLocalApiClient.js';
|
|
7
|
+
import { ILogger } from '../../interfaces/ILogger.js';
|
|
8
|
+
export declare class SharePointListFoldersTool extends BaseToolController {
|
|
9
|
+
constructor(ucmClient: UcmLocalApiClient, logger: ILogger, publishingAuthorId?: string);
|
|
10
|
+
get name(): string;
|
|
11
|
+
get description(): string;
|
|
12
|
+
get inputSchema(): any;
|
|
13
|
+
protected validateParams(params: any): void;
|
|
14
|
+
protected handleExecute(params: {
|
|
15
|
+
connectionId: string;
|
|
16
|
+
folderPath?: string;
|
|
17
|
+
limit?: number;
|
|
18
|
+
offset?: number;
|
|
19
|
+
}): Promise<any>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=SharePointListFoldersTool.d.ts.map
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharePointListFoldersTool
|
|
3
|
+
* List folders in SharePoint document library
|
|
4
|
+
*/
|
|
5
|
+
import { BaseToolController } from '../base/BaseToolController.js';
|
|
6
|
+
import { McpError, McpErrorCode } from '../../utils/McpErrorHandler.js';
|
|
7
|
+
import { SharePointErrorHandler } from '../../utils/SharePointErrorHandler.js';
|
|
8
|
+
export class SharePointListFoldersTool extends BaseToolController {
|
|
9
|
+
constructor(ucmClient, logger, publishingAuthorId) {
|
|
10
|
+
super(ucmClient, logger, publishingAuthorId);
|
|
11
|
+
}
|
|
12
|
+
get name() {
|
|
13
|
+
return 'ucm_sharepoint_list_folders';
|
|
14
|
+
}
|
|
15
|
+
get description() {
|
|
16
|
+
return 'Browse SharePoint hierarchically: "/" lists document libraries, "/LibraryName" lists library root, "/LibraryName/Folder" lists subfolder. Supports pagination. Use ucm_list_connections first to get connection ID.';
|
|
17
|
+
}
|
|
18
|
+
get inputSchema() {
|
|
19
|
+
return {
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
connectionId: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'SharePoint connection ID to use for listing folders (get this from list_connections)',
|
|
25
|
+
minLength: 36,
|
|
26
|
+
maxLength: 36
|
|
27
|
+
},
|
|
28
|
+
folderPath: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'Path: "/" = list libraries (e.g., Documents, Sales), "/Documents" = list library root, "/Documents/Projects" = list subfolder. Default: "/"',
|
|
31
|
+
maxLength: 1000
|
|
32
|
+
},
|
|
33
|
+
limit: {
|
|
34
|
+
type: 'number',
|
|
35
|
+
description: 'Maximum number of items to return (default: 50, max: 200)',
|
|
36
|
+
minimum: 1,
|
|
37
|
+
maximum: 200
|
|
38
|
+
},
|
|
39
|
+
offset: {
|
|
40
|
+
type: 'number',
|
|
41
|
+
description: 'Number of items to skip for pagination (default: 0)',
|
|
42
|
+
minimum: 0
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
required: ['connectionId'],
|
|
46
|
+
additionalProperties: false
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
validateParams(params) {
|
|
50
|
+
super.validateParams(params);
|
|
51
|
+
// Validate connectionId is UUID format
|
|
52
|
+
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
53
|
+
if (!uuidPattern.test(params.connectionId)) {
|
|
54
|
+
throw new McpError(McpErrorCode.InvalidParams, 'Connection ID must be a valid UUID');
|
|
55
|
+
}
|
|
56
|
+
// Set default folder path if not provided
|
|
57
|
+
if (!params.folderPath) {
|
|
58
|
+
params.folderPath = '/';
|
|
59
|
+
}
|
|
60
|
+
// Validate folder path format
|
|
61
|
+
if (params.folderPath && typeof params.folderPath !== 'string') {
|
|
62
|
+
throw new McpError(McpErrorCode.InvalidParams, 'Folder path must be a string');
|
|
63
|
+
}
|
|
64
|
+
// Ensure folder path starts with /
|
|
65
|
+
if (params.folderPath && !params.folderPath.startsWith('/')) {
|
|
66
|
+
params.folderPath = '/' + params.folderPath;
|
|
67
|
+
}
|
|
68
|
+
// Validate and set default limit
|
|
69
|
+
if (params.limit !== undefined) {
|
|
70
|
+
if (typeof params.limit !== 'number' || params.limit < 1 || params.limit > 200) {
|
|
71
|
+
throw new McpError(McpErrorCode.InvalidParams, 'Limit must be between 1 and 200');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
params.limit = 50;
|
|
76
|
+
}
|
|
77
|
+
// Validate and set default offset
|
|
78
|
+
if (params.offset !== undefined) {
|
|
79
|
+
if (typeof params.offset !== 'number' || params.offset < 0) {
|
|
80
|
+
throw new McpError(McpErrorCode.InvalidParams, 'Offset must be 0 or greater');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
params.offset = 0;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async handleExecute(params) {
|
|
88
|
+
this.logger.info('SharePointListFoldersTool', `Listing folders at path: ${params.folderPath}`);
|
|
89
|
+
try {
|
|
90
|
+
// Call the API to list SharePoint folders
|
|
91
|
+
// organizationId is auto-detected from auth token in V1 API
|
|
92
|
+
const listParams = {
|
|
93
|
+
folderPath: params.folderPath,
|
|
94
|
+
limit: params.limit,
|
|
95
|
+
offset: params.offset
|
|
96
|
+
};
|
|
97
|
+
// Make API call via UCM client (V1 API)
|
|
98
|
+
const result = await this.ucmClient.sharePointListFolders(params.connectionId, listParams);
|
|
99
|
+
this.logger.info('SharePointListFoldersTool', `Listed ${result.folders?.length || 0} folders and ${result.files?.length || 0} files`);
|
|
100
|
+
// Format response from V1 API
|
|
101
|
+
const response = {
|
|
102
|
+
success: true,
|
|
103
|
+
path: result.path || params.folderPath,
|
|
104
|
+
totalFolders: result.totalFolders || 0,
|
|
105
|
+
totalFiles: result.totalFiles || 0,
|
|
106
|
+
total: result.total || 0,
|
|
107
|
+
hasMore: result.hasMore || false,
|
|
108
|
+
limit: params.limit,
|
|
109
|
+
offset: params.offset,
|
|
110
|
+
folders: result.folders?.map((folder) => ({
|
|
111
|
+
name: folder.name,
|
|
112
|
+
webUrl: folder.webUrl,
|
|
113
|
+
size: folder.size,
|
|
114
|
+
createdDateTime: folder.createdDateTime,
|
|
115
|
+
lastModifiedDateTime: folder.lastModifiedDateTime
|
|
116
|
+
})) || [],
|
|
117
|
+
files: result.files?.map((file) => ({
|
|
118
|
+
name: file.name,
|
|
119
|
+
webUrl: file.webUrl,
|
|
120
|
+
size: file.size,
|
|
121
|
+
mimeType: file.mimeType,
|
|
122
|
+
createdDateTime: file.createdDateTime,
|
|
123
|
+
lastModifiedDateTime: file.lastModifiedDateTime
|
|
124
|
+
})) || []
|
|
125
|
+
};
|
|
126
|
+
return {
|
|
127
|
+
content: [
|
|
128
|
+
{
|
|
129
|
+
type: 'text',
|
|
130
|
+
text: JSON.stringify(response, null, 2)
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
return SharePointErrorHandler.handle(error, this.logger, 'SharePointListFoldersTool');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=SharePointListFoldersTool.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharePointReadFileTool
|
|
3
|
+
* Read and convert SharePoint files to text
|
|
4
|
+
*/
|
|
5
|
+
import { BaseToolController } from '../base/BaseToolController.js';
|
|
6
|
+
import { UcmLocalApiClient } from '../../clients/UcmLocalApiClient.js';
|
|
7
|
+
import { ILogger } from '../../interfaces/ILogger.js';
|
|
8
|
+
export declare class SharePointReadFileTool extends BaseToolController {
|
|
9
|
+
constructor(ucmClient: UcmLocalApiClient, logger: ILogger, publishingAuthorId?: string);
|
|
10
|
+
get name(): string;
|
|
11
|
+
get description(): string;
|
|
12
|
+
get inputSchema(): any;
|
|
13
|
+
protected validateParams(params: any): void;
|
|
14
|
+
protected handleExecute(params: {
|
|
15
|
+
connectionId: string;
|
|
16
|
+
webUrl: string;
|
|
17
|
+
extractMetadata?: boolean;
|
|
18
|
+
offset?: number;
|
|
19
|
+
limit?: number;
|
|
20
|
+
}): Promise<any>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=SharePointReadFileTool.d.ts.map
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharePointReadFileTool
|
|
3
|
+
* Read and convert SharePoint files to text
|
|
4
|
+
*/
|
|
5
|
+
import { BaseToolController } from '../base/BaseToolController.js';
|
|
6
|
+
import { McpError, McpErrorCode } from '../../utils/McpErrorHandler.js';
|
|
7
|
+
import { SharePointErrorHandler } from '../../utils/SharePointErrorHandler.js';
|
|
8
|
+
export class SharePointReadFileTool extends BaseToolController {
|
|
9
|
+
constructor(ucmClient, logger, publishingAuthorId) {
|
|
10
|
+
super(ucmClient, logger, publishingAuthorId);
|
|
11
|
+
}
|
|
12
|
+
get name() {
|
|
13
|
+
return 'ucm_sharepoint_read_file';
|
|
14
|
+
}
|
|
15
|
+
get description() {
|
|
16
|
+
return 'Read a file from SharePoint and convert it to text. Supports Office documents (Word, Excel, PowerPoint), PDFs, and text files. Maximum file size is 20MB. Provide either a full SharePoint URL or relative path. Supports pagination with offset/limit for TEXT CONTENT ONLY. Pagination parameters are ignored for binary files (images, PDFs with embedded images).';
|
|
17
|
+
}
|
|
18
|
+
get inputSchema() {
|
|
19
|
+
return {
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
connectionId: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'SharePoint connection ID to use for reading file (get this from list_connections)',
|
|
25
|
+
minLength: 36,
|
|
26
|
+
maxLength: 36
|
|
27
|
+
},
|
|
28
|
+
webUrl: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'SharePoint file URL (e.g., "https://contoso.sharepoint.com/sites/Sales/Shared Documents/report.docx") OR relative path ("/Shared Documents/report.docx")',
|
|
31
|
+
minLength: 1,
|
|
32
|
+
maxLength: 2000
|
|
33
|
+
},
|
|
34
|
+
extractMetadata: {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Include file metadata in response (default: true)'
|
|
37
|
+
},
|
|
38
|
+
offset: {
|
|
39
|
+
type: 'number',
|
|
40
|
+
description: 'Number of characters to skip from the start of the content (default: 0). Pagination for text content only - ignored for binary/image files.',
|
|
41
|
+
minimum: 0
|
|
42
|
+
},
|
|
43
|
+
limit: {
|
|
44
|
+
type: 'number',
|
|
45
|
+
description: 'Maximum number of characters to return (default: unlimited). Pagination for text content only - ignored for binary/image files.',
|
|
46
|
+
minimum: 1
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
required: ['connectionId', 'webUrl'],
|
|
50
|
+
additionalProperties: false
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
validateParams(params) {
|
|
54
|
+
super.validateParams(params);
|
|
55
|
+
// Validate connectionId is UUID format
|
|
56
|
+
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
57
|
+
if (!uuidPattern.test(params.connectionId)) {
|
|
58
|
+
throw new McpError(McpErrorCode.InvalidParams, 'Connection ID must be a valid UUID');
|
|
59
|
+
}
|
|
60
|
+
// Validate that webUrl is provided
|
|
61
|
+
if (!params.webUrl || typeof params.webUrl !== 'string' || params.webUrl.trim() === '') {
|
|
62
|
+
throw new McpError(McpErrorCode.InvalidParams, 'File URL is required and must be a non-empty string');
|
|
63
|
+
}
|
|
64
|
+
// Set boolean defaults
|
|
65
|
+
if (params.extractMetadata === undefined) {
|
|
66
|
+
params.extractMetadata = true;
|
|
67
|
+
}
|
|
68
|
+
// Validate and set offset/limit defaults
|
|
69
|
+
if (params.offset !== undefined) {
|
|
70
|
+
if (typeof params.offset !== 'number' || params.offset < 0) {
|
|
71
|
+
throw new McpError(McpErrorCode.InvalidParams, 'Offset must be a non-negative number');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
params.offset = 0;
|
|
76
|
+
}
|
|
77
|
+
if (params.limit !== undefined) {
|
|
78
|
+
if (typeof params.limit !== 'number' || params.limit < 1) {
|
|
79
|
+
throw new McpError(McpErrorCode.InvalidParams, 'Limit must be a positive number');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async handleExecute(params) {
|
|
84
|
+
this.logger.info('SharePointReadFileTool', `Reading file: ${params.webUrl} (offset: ${params.offset || 0}, limit: ${params.limit || 'unlimited'})`);
|
|
85
|
+
try {
|
|
86
|
+
// Call the API to read and convert SharePoint file
|
|
87
|
+
// organizationId is auto-detected from auth token in V1 API
|
|
88
|
+
const readParams = {
|
|
89
|
+
fileUrl: params.webUrl, // Map webUrl parameter to fileUrl for internal command
|
|
90
|
+
extractMetadata: params.extractMetadata
|
|
91
|
+
};
|
|
92
|
+
// Add pagination parameters if provided
|
|
93
|
+
if (params.offset !== undefined) {
|
|
94
|
+
readParams.offset = params.offset;
|
|
95
|
+
}
|
|
96
|
+
if (params.limit !== undefined) {
|
|
97
|
+
readParams.limit = params.limit;
|
|
98
|
+
}
|
|
99
|
+
// Make API call via UCM client (V1 API)
|
|
100
|
+
const result = await this.ucmClient.sharePointReadFile(params.connectionId, readParams);
|
|
101
|
+
this.logger.info('SharePointReadFileTool', `File read successfully: ${result.fileName}`);
|
|
102
|
+
// Format response
|
|
103
|
+
const response = {
|
|
104
|
+
success: true,
|
|
105
|
+
fileName: result.fileName,
|
|
106
|
+
fileType: result.fileType,
|
|
107
|
+
contentLength: result.contentLength,
|
|
108
|
+
returnedLength: result.returnedLength,
|
|
109
|
+
offset: result.offset,
|
|
110
|
+
hasMore: result.hasMore,
|
|
111
|
+
content: result.content,
|
|
112
|
+
conversionNotes: result.conversionNotes,
|
|
113
|
+
convertedAt: result.convertedAt
|
|
114
|
+
};
|
|
115
|
+
// Add nextOffset if there's more content
|
|
116
|
+
if (result.hasMore && result.nextOffset !== undefined) {
|
|
117
|
+
response.nextOffset = result.nextOffset;
|
|
118
|
+
}
|
|
119
|
+
// Include metadata if requested
|
|
120
|
+
if (params.extractMetadata && result.metadata) {
|
|
121
|
+
response.metadata = result.metadata;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
content: [
|
|
125
|
+
{
|
|
126
|
+
type: 'text',
|
|
127
|
+
text: JSON.stringify(response, null, 2)
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
// Handle ReadFile-specific errors first
|
|
134
|
+
if (error?.response?.status === 400 && error?.response?.data?.error === 'TENANT_MISMATCH') {
|
|
135
|
+
throw new McpError(McpErrorCode.InvalidParams, 'File URL does not match the connection tenant');
|
|
136
|
+
}
|
|
137
|
+
if (error?.response?.status === 413 || error?.message?.includes('size')) {
|
|
138
|
+
throw new McpError(McpErrorCode.InvalidParams, 'File exceeds maximum size limit of 20MB');
|
|
139
|
+
}
|
|
140
|
+
// Delegate to common SharePoint error handler for generic errors
|
|
141
|
+
return SharePointErrorHandler.handle(error, this.logger, 'SharePointReadFileTool');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=SharePointReadFileTool.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharePointReadRelatedFileTool
|
|
3
|
+
* Retrieve related file (image/embedded file) extracted from a SharePoint document
|
|
4
|
+
*/
|
|
5
|
+
import { BaseToolController } from '../base/BaseToolController.js';
|
|
6
|
+
import { UcmLocalApiClient } from '../../clients/UcmLocalApiClient.js';
|
|
7
|
+
import { ILogger } from '../../interfaces/ILogger.js';
|
|
8
|
+
export declare class SharePointReadRelatedFileTool extends BaseToolController {
|
|
9
|
+
constructor(ucmClient: UcmLocalApiClient, logger: ILogger, publishingAuthorId?: string);
|
|
10
|
+
get name(): string;
|
|
11
|
+
get description(): string;
|
|
12
|
+
get inputSchema(): any;
|
|
13
|
+
protected validateParams(params: any): void;
|
|
14
|
+
protected handleExecute(params: {
|
|
15
|
+
uri: string;
|
|
16
|
+
}): Promise<any>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=SharePointReadRelatedFileTool.d.ts.map
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharePointReadRelatedFileTool
|
|
3
|
+
* Retrieve related file (image/embedded file) extracted from a SharePoint document
|
|
4
|
+
*/
|
|
5
|
+
import { BaseToolController } from '../base/BaseToolController.js';
|
|
6
|
+
import { McpError, McpErrorCode } from '../../utils/McpErrorHandler.js';
|
|
7
|
+
export class SharePointReadRelatedFileTool extends BaseToolController {
|
|
8
|
+
constructor(ucmClient, logger, publishingAuthorId) {
|
|
9
|
+
super(ucmClient, logger, publishingAuthorId);
|
|
10
|
+
}
|
|
11
|
+
get name() {
|
|
12
|
+
return 'ucm_sharepoint_read_relatedfile';
|
|
13
|
+
}
|
|
14
|
+
get description() {
|
|
15
|
+
return 'Retrieve a related file (image or embedded file) that was extracted from a SharePoint document. Pass the full URI from markdown. Returns complete file. Large images (>500KB original size) may fail with size limit error.';
|
|
16
|
+
}
|
|
17
|
+
get inputSchema() {
|
|
18
|
+
return {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
uri: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Full URI from markdown (e.g., "file1.jpg?connectionId=...&fileId=...&eTag=..." or without protocol prefix)',
|
|
24
|
+
minLength: 1,
|
|
25
|
+
maxLength: 2000
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
required: ['uri'],
|
|
29
|
+
additionalProperties: false
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
validateParams(params) {
|
|
33
|
+
super.validateParams(params);
|
|
34
|
+
// Validate URI is provided and is a non-empty string
|
|
35
|
+
if (!params.uri || typeof params.uri !== 'string' || params.uri.trim() === '') {
|
|
36
|
+
throw new McpError(McpErrorCode.InvalidParams, 'URI is required and must be a non-empty string');
|
|
37
|
+
}
|
|
38
|
+
// Don't validate format - let server handle parsing and auto-correction
|
|
39
|
+
}
|
|
40
|
+
async handleExecute(params) {
|
|
41
|
+
this.logger.info('SharePointReadRelatedFileTool', `Reading related file from URI: ${params.uri}`);
|
|
42
|
+
try {
|
|
43
|
+
// Call the API to read the related file (no pagination - always complete file)
|
|
44
|
+
const result = await this.ucmClient.sharePointReadRelatedFile(params.uri);
|
|
45
|
+
this.logger.info('SharePointReadRelatedFileTool', `Related file retrieved: ${result.fileName}, size: ${result.size} bytes, content length: ${result.content.length} chars`);
|
|
46
|
+
// Check if base64 content exceeds safe MCP token limit (~15,000 characters)
|
|
47
|
+
// This prevents MCP response errors for large images
|
|
48
|
+
if (result.content.length > 15000) {
|
|
49
|
+
throw new McpError(McpErrorCode.InternalError, 'Image file too large for MCP response. Please resize the image in SharePoint or use the web UI to download.');
|
|
50
|
+
}
|
|
51
|
+
// Check if this is an image file - return as image resource for visual analysis
|
|
52
|
+
if (result.mimeType && result.mimeType.startsWith('image/')) {
|
|
53
|
+
return {
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: 'image',
|
|
57
|
+
data: result.content, // base64 encoded image data
|
|
58
|
+
mimeType: result.mimeType
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: 'text',
|
|
62
|
+
text: `Image: ${result.fileName}\nSize: ${result.size} bytes\nType: ${result.mimeType}`
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// For non-image files, return file information as JSON
|
|
68
|
+
const response = {
|
|
69
|
+
success: true,
|
|
70
|
+
fileName: result.fileName,
|
|
71
|
+
mimeType: result.mimeType,
|
|
72
|
+
size: result.size,
|
|
73
|
+
contentLength: result.content.length,
|
|
74
|
+
content: result.content, // base64 encoded binary data
|
|
75
|
+
encoding: 'base64'
|
|
76
|
+
};
|
|
77
|
+
return {
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: 'text',
|
|
81
|
+
text: JSON.stringify(response, null, 2)
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
this.logger.error('SharePointReadRelatedFileTool', 'Read related file operation failed', '', error);
|
|
88
|
+
// Format error response
|
|
89
|
+
if (error?.response?.status === 404) {
|
|
90
|
+
throw new McpError(McpErrorCode.InvalidParams, 'Related file not found. File may no longer be available. Re-read the parent document to access related files.');
|
|
91
|
+
}
|
|
92
|
+
if (error?.response?.status === 401 || error?.response?.status === 403) {
|
|
93
|
+
throw new McpError(McpErrorCode.InvalidParams, 'Not authorized to access this SharePoint connection or file');
|
|
94
|
+
}
|
|
95
|
+
if (error?.response?.status === 400) {
|
|
96
|
+
throw new McpError(McpErrorCode.InvalidParams, error?.response?.data?.message || 'Invalid request parameters');
|
|
97
|
+
}
|
|
98
|
+
throw new McpError(McpErrorCode.InternalError, `SharePoint read related file failed: ${error?.message || 'Unknown error'}`, { originalError: error?.message });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=SharePointReadRelatedFileTool.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharePointSearchTool
|
|
3
|
+
* Search SharePoint documents with text query
|
|
4
|
+
*/
|
|
5
|
+
import { BaseToolController } from '../base/BaseToolController.js';
|
|
6
|
+
import { UcmLocalApiClient } from '../../clients/UcmLocalApiClient.js';
|
|
7
|
+
import { ILogger } from '../../interfaces/ILogger.js';
|
|
8
|
+
export declare class SharePointSearchTool extends BaseToolController {
|
|
9
|
+
constructor(ucmClient: UcmLocalApiClient, logger: ILogger, publishingAuthorId?: string);
|
|
10
|
+
get name(): string;
|
|
11
|
+
get description(): string;
|
|
12
|
+
get inputSchema(): any;
|
|
13
|
+
protected validateParams(params: any): void;
|
|
14
|
+
protected handleExecute(params: {
|
|
15
|
+
connectionId: string;
|
|
16
|
+
query: string;
|
|
17
|
+
limit?: number;
|
|
18
|
+
offset?: number;
|
|
19
|
+
fileType?: string;
|
|
20
|
+
}): Promise<any>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=SharePointSearchTool.d.ts.map
|