@utaba/ucm-mcp-server
Version:
Universal Context Manager MCP Server - AI Productivity Platform
145 lines • 6.86 kB
JavaScript
/**
* SharePointReadFileTool
* Read and convert SharePoint files to text
*/
import { BaseToolController } from '../base/BaseToolController.js';
import { McpError, McpErrorCode } from '../../utils/McpErrorHandler.js';
import { SharePointErrorHandler } from '../../utils/SharePointErrorHandler.js';
export class SharePointReadFileTool extends BaseToolController {
constructor(ucmClient, logger, publishingAuthorId) {
super(ucmClient, logger, publishingAuthorId);
}
get name() {
return 'ucm_sharepoint_read_file';
}
get description() {
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).';
}
get inputSchema() {
return {
type: 'object',
properties: {
connectionId: {
type: 'string',
description: 'SharePoint connection ID to use for reading file (get this from list_connections)',
minLength: 36,
maxLength: 36
},
webUrl: {
type: 'string',
description: 'SharePoint file URL (e.g., "https://contoso.sharepoint.com/sites/Sales/Shared Documents/report.docx") OR relative path ("/Shared Documents/report.docx")',
minLength: 1,
maxLength: 2000
},
extractMetadata: {
type: 'boolean',
description: 'Include file metadata in response (default: true)'
},
offset: {
type: 'number',
description: 'Number of characters to skip from the start of the content (default: 0). Pagination for text content only - ignored for binary/image files.',
minimum: 0
},
limit: {
type: 'number',
description: 'Maximum number of characters to return (default: unlimited). Pagination for text content only - ignored for binary/image files.',
minimum: 1
}
},
required: ['connectionId', 'webUrl'],
additionalProperties: false
};
}
validateParams(params) {
super.validateParams(params);
// Validate connectionId is UUID format
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
if (!uuidPattern.test(params.connectionId)) {
throw new McpError(McpErrorCode.InvalidParams, 'Connection ID must be a valid UUID');
}
// Validate that webUrl is provided
if (!params.webUrl || typeof params.webUrl !== 'string' || params.webUrl.trim() === '') {
throw new McpError(McpErrorCode.InvalidParams, 'File URL is required and must be a non-empty string');
}
// Set boolean defaults
if (params.extractMetadata === undefined) {
params.extractMetadata = true;
}
// Validate and set offset/limit defaults
if (params.offset !== undefined) {
if (typeof params.offset !== 'number' || params.offset < 0) {
throw new McpError(McpErrorCode.InvalidParams, 'Offset must be a non-negative number');
}
}
else {
params.offset = 0;
}
if (params.limit !== undefined) {
if (typeof params.limit !== 'number' || params.limit < 1) {
throw new McpError(McpErrorCode.InvalidParams, 'Limit must be a positive number');
}
}
}
async handleExecute(params) {
this.logger.info('SharePointReadFileTool', `Reading file: ${params.webUrl} (offset: ${params.offset || 0}, limit: ${params.limit || 'unlimited'})`);
try {
// Call the API to read and convert SharePoint file
// organizationId is auto-detected from auth token in V1 API
const readParams = {
fileUrl: params.webUrl, // Map webUrl parameter to fileUrl for internal command
extractMetadata: params.extractMetadata
};
// Add pagination parameters if provided
if (params.offset !== undefined) {
readParams.offset = params.offset;
}
if (params.limit !== undefined) {
readParams.limit = params.limit;
}
// Make API call via UCM client (V1 API)
const result = await this.ucmClient.sharePointReadFile(params.connectionId, readParams);
this.logger.info('SharePointReadFileTool', `File read successfully: ${result.fileName}`);
// Format response
const response = {
success: true,
fileName: result.fileName,
fileType: result.fileType,
contentLength: result.contentLength,
returnedLength: result.returnedLength,
offset: result.offset,
hasMore: result.hasMore,
content: result.content,
conversionNotes: result.conversionNotes,
convertedAt: result.convertedAt
};
// Add nextOffset if there's more content
if (result.hasMore && result.nextOffset !== undefined) {
response.nextOffset = result.nextOffset;
}
// Include metadata if requested
if (params.extractMetadata && result.metadata) {
response.metadata = result.metadata;
}
return {
content: [
{
type: 'text',
text: JSON.stringify(response, null, 2)
}
]
};
}
catch (error) {
// Handle ReadFile-specific errors first
if (error?.response?.status === 400 && error?.response?.data?.error === 'TENANT_MISMATCH') {
throw new McpError(McpErrorCode.InvalidParams, 'File URL does not match the connection tenant');
}
if (error?.response?.status === 413 || error?.message?.includes('size')) {
throw new McpError(McpErrorCode.InvalidParams, 'File exceeds maximum size limit of 20MB');
}
// Delegate to common SharePoint error handler for generic errors
return SharePointErrorHandler.handle(error, this.logger, 'SharePointReadFileTool');
}
}
}
//# sourceMappingURL=SharePointReadFileTool.js.map