@utaba/ucm-mcp-server
Version:
Universal Context Manager MCP Server - AI-native artifact management
125 lines • 6.81 kB
JavaScript
import { BaseToolController } from '../base/BaseToolController.js';
import { McpError, McpErrorCode } from '../../utils/McpErrorHandler.js';
export class UpdateRepositoryTool extends BaseToolController {
constructor(ucmClient, logger, publishingAuthorId) {
super(ucmClient, logger, publishingAuthorId);
}
get name() {
return 'mcp_ucm_update_repository';
}
get description() {
const authorInfo = this.publishingAuthorId ? ` Your author id is '${this.publishingAuthorId}'.` : '';
return `Update repository metadata including display name, description, and visibility settings. Note: Repository names cannot be changed after creation as they serve as permanent identifiers in the namespace path.${authorInfo}`;
}
get inputSchema() {
return {
type: 'object',
properties: {
author: {
type: 'string',
description: this.publishingAuthorId ? `Author identifier: ${this.publishingAuthorId}` : 'Author identifier (e.g., "utaba", "1064600359")',
minLength: 1,
maxLength: 50
},
repository: {
type: 'string',
description: 'Repository to update (e.g., "main", "project-alpha") however the name will not change. Only the displayname can be updated after creation.',
minLength: 1,
maxLength: 200
},
displayName: {
type: 'string',
description: 'New human-readable display name for the repository (optional)',
maxLength: 255
},
description: {
type: 'string',
description: 'New repository description (optional)',
maxLength: 1000
},
isPublic: {
type: 'boolean',
description: 'Whether the repository should be public (currently not supported, must be false)'
}
},
required: ['author', 'repository'],
additionalProperties: false
};
}
validateParams(params) {
super.validateParams(params);
if (!params.author || typeof params.author !== 'string' || params.author.trim() === '') {
throw new McpError(McpErrorCode.InvalidParams, 'Author identifier is required and cannot be empty');
}
if (!params.repository || typeof params.repository !== 'string' || params.repository.trim() === '') {
throw new McpError(McpErrorCode.InvalidParams, 'Repository name is required and cannot be empty');
}
// Validate at least one field to update is provided
const updateFields = ['displayName', 'description', 'isPublic'];
const hasUpdateField = updateFields.some(field => params[field] !== undefined);
if (!hasUpdateField) {
throw new McpError(McpErrorCode.InvalidParams, 'At least one field to update must be provided (displayName, description, or isPublic)');
}
// Validate displayName length if provided
if (params.displayName !== undefined && params.displayName.length > 255) {
throw new McpError(McpErrorCode.InvalidParams, 'Display name cannot exceed 255 characters');
}
// Validate description length if provided
if (params.description !== undefined && params.description.length > 1000) {
throw new McpError(McpErrorCode.InvalidParams, 'Description cannot exceed 1,000 characters');
}
// Validate isPublic - public repositories are not yet supported
if (params.isPublic === true) {
throw new McpError(McpErrorCode.InvalidParams, 'Public repositories are not yet supported. Set isPublic to false or omit the parameter.');
}
}
async handleExecute(params) {
this.logger.info('UpdateRepositoryTool', `Updating repository ${params.repository} for author ${params.author}`);
try {
// Build update data from provided parameters
const updateData = {};
if (params.displayName !== undefined) {
updateData.displayName = params.displayName;
}
if (params.description !== undefined) {
updateData.description = params.description;
}
if (params.isPublic !== undefined) {
updateData.isPublic = params.isPublic;
}
const result = await this.ucmClient.updateRepository(params.author, params.repository, updateData);
this.logger.info('UpdateRepositoryTool', `Repository updated successfully: ${params.repository}`);
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: true,
message: `Repository '${params.repository}' updated successfully for author '${params.author}'`,
repository: result,
updatedFields: Object.keys(updateData),
webUrl: `${process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000'}/repository/${result.id || params.repository}/settings`
}, null, 2)
}
]
};
}
catch (error) {
this.logger.error('UpdateRepositoryTool', 'Failed to update repository', '', error);
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
// Handle specific error cases
if (errorMessage.includes('not found') || errorMessage.includes('404')) {
throw new McpError(McpErrorCode.InvalidParams, `Repository '${params.repository}' not found for author '${params.author}'. Please verify the repository name and author identifier.`);
}
if (errorMessage.includes('403') || errorMessage.includes('Forbidden')) {
throw new McpError(McpErrorCode.InvalidParams, `Access denied to update repository '${params.repository}' for author '${params.author}'. You may not have permission to modify this repository.`);
}
if (errorMessage.includes('validation') || errorMessage.includes('invalid')) {
throw new McpError(McpErrorCode.InvalidParams, `Repository update failed due to validation error: ${errorMessage}`);
}
// Generic error
throw new McpError(McpErrorCode.InternalError, `Failed to update repository: ${errorMessage}`);
}
}
}
//# sourceMappingURL=UpdateRepositoryTool.js.map