@utaba/ucm-mcp-server
Version:
Universal Context Manager MCP Server - AI-native artifact management
125 lines • 6.75 kB
JavaScript
import { BaseToolController } from '../base/BaseToolController.js';
import { McpError, McpErrorCode } from '../../utils/McpErrorHandler.js';
export class CreateRepositoryTool extends BaseToolController {
constructor(ucmClient, logger, publishingAuthorId) {
super(ucmClient, logger, publishingAuthorId);
}
get name() {
return 'mcp_ucm_create_repository';
}
get description() {
const authorInfo = this.publishingAuthorId ? ` Your author id is '${this.publishingAuthorId}'.` : '';
return `Create a new repository for a specific author. Repository names must be unique within the author namespace and follow UCM naming conventions (3-200 characters, start with letter, alphanumeric and hyphens only, no consecutive hyphens).${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
},
repositoryName: {
type: 'string',
description: 'Unique repository name (3-200 characters, start with letter, alphanumeric and hyphens only)',
minLength: 3,
maxLength: 200,
pattern: '^[a-z][a-z0-9-]{2,199}$'
},
displayName: {
type: 'string',
description: 'Human-readable display name for the repository (optional)',
maxLength: 255
},
description: {
type: 'string',
description: 'Repository description (optional)',
maxLength: 1000
},
isPublic: {
type: 'boolean',
description: 'Whether the repository is public (defaults to false, public repositories not yet supported)',
default: false
}
},
required: ['author', 'repositoryName'],
additionalProperties: false
};
}
validateParams(params) {
super.validateParams(params);
// Additional validation
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.repositoryName || typeof params.repositoryName !== 'string' || params.repositoryName.trim() === '') {
throw new McpError(McpErrorCode.InvalidParams, 'Repository name is required and cannot be empty');
}
// Validate repository name format
const namePattern = /^[a-z][a-z0-9-]{2,199}$/;
if (!namePattern.test(params.repositoryName)) {
throw new McpError(McpErrorCode.InvalidParams, 'Repository name must be 3-200 characters, start with a lowercase letter, and contain only lowercase letters, numbers, and hyphens (no consecutive hyphens)');
}
// Check for consecutive hyphens
if (params.repositoryName.includes('--')) {
throw new McpError(McpErrorCode.InvalidParams, 'Repository name cannot contain consecutive hyphens');
}
// Validate displayName length if provided
if (params.displayName && params.displayName.length > 255) {
throw new McpError(McpErrorCode.InvalidParams, 'Display name cannot exceed 255 characters');
}
// Validate description length if provided
if (params.description && 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('CreateRepositoryTool', `Creating repository ${params.repositoryName} for author ${params.author}`);
try {
const repositoryData = {
repositoryName: params.repositoryName,
displayName: params.displayName,
description: params.description,
isPublic: params.isPublic || false
};
const result = await this.ucmClient.createRepository(params.author, repositoryData);
this.logger.info('CreateRepositoryTool', `Repository created successfully: ${params.repositoryName}`);
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: true,
message: `Repository '${params.repositoryName}' created successfully for author '${params.author}'`,
repository: result,
webUrl: `${process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000'}/repository/${result.id || params.repositoryName}`
}, null, 2)
}
]
};
}
catch (error) {
this.logger.error('CreateRepositoryTool', 'Failed to create repository', '', error);
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
// Handle specific error cases
if (errorMessage.includes('already exists') || errorMessage.includes('NAME_EXISTS')) {
throw new McpError(McpErrorCode.InvalidParams, `Repository name '${params.repositoryName}' already exists for author '${params.author}'. Please choose a different name.`);
}
if (errorMessage.includes('not found') || errorMessage.includes('404')) {
throw new McpError(McpErrorCode.InvalidParams, `Author '${params.author}' not found. Please verify the author identifier.`);
}
if (errorMessage.includes('validation') || errorMessage.includes('invalid')) {
throw new McpError(McpErrorCode.InvalidParams, `Repository creation failed due to validation error: ${errorMessage}`);
}
// Generic error
throw new McpError(McpErrorCode.InternalError, `Failed to create repository: ${errorMessage}`);
}
}
}
//# sourceMappingURL=CreateRepositoryTool.js.map