UNPKG

@utaba/ucm-mcp-server

Version:

Universal Context Manager MCP Server - AI Productivity Platform

124 lines 6.01 kB
import { BaseToolController } from '../base/BaseToolController.js'; import { ResponseChunker } from '../../utils/ResponseChunker.js'; import { parsePath } from '../../utils/PathUtils.js'; export class GetArtifactTool extends BaseToolController { trustedAuthors; constructor(ucmClient, logger, publishingAuthorId, trustedAuthors = []) { super(ucmClient, logger, publishingAuthorId); this.trustedAuthors = trustedAuthors; } get name() { return 'ucm_get_artifact'; } get description() { return 'Retrieve UCM artifact content with metadata. Large files are automatically chunked.'; } get inputSchema() { return { type: 'object', properties: { path: { type: 'string', description: `Full artifact path with optional version (e.g., "${this.publishingAuthorId || '1234567890'}/main/commands/user/CreateUserCommand.ts" or "${this.publishingAuthorId || '1234567890'}/main/commands/user/CreateUserCommand.ts@1.0.0")`, minLength: 1, maxLength: 200 }, includeMetadata: { type: 'boolean', description: 'Include artifact metadata in response', default: true } }, required: ['path'] }; } async handleExecute(params) { let { path, includeMetadata = true } = params; this.logger.debug('GetArtifactTool', `Retrieving artifact: ${path}`); try { // Parse the path to extract components if (!path) path = ""; const pathComponents = parsePath(path); // Validate that path contains all required components including repository if (!pathComponents.author || !pathComponents.repository || !pathComponents.category || !pathComponents.subcategory || !pathComponents.filename) { throw new Error(`Path must include all components: author/repository/category/subcategory/filename.ext. Expected format: "author/repository/category/subcategory/filename.ext" or "author/repository/category/subcategory/filename.ext@version". Received: "${path}"`); } // Get artifact from API const artifact = await this.ucmClient.getArtifact(pathComponents.author, pathComponents.repository, pathComponents.category, pathComponents.subcategory, pathComponents.filename, pathComponents.version); // Extract content - it should always be a string in the API response if (!artifact.content) { throw new Error('Artifact has no content'); } const content = artifact.content; // Check if author is trusted const author = artifact.metadata?.author || pathComponents.author; const isTrusted = this.trustedAuthors.includes(author); // Build response const response = { content, path: artifact.path || path, filename: pathComponents.filename // filename comes from parsed path }; // Add security warning for untrusted authors if (!isTrusted && this.publishingAuthorId && this.publishingAuthorId != pathComponents.author) { response.securityWarning = `⚠️ SECURITY WARNING: This artifact is from author '${author}' who is not in your trusted authors list. Please review the code carefully before using it.`; } // Add metadata if requested if (includeMetadata) { response.metadata = { id: artifact.id, version: artifact.metadata?.version || pathComponents.version || 'latest', description: artifact.metadata?.description, author: author, repository: pathComponents.repository, category: artifact.metadata?.category || pathComponents.category, subcategory: artifact.metadata?.subcategory || pathComponents.subcategory, technology: artifact.metadata?.technology, tags: artifact.metadata?.tags || [], contractVersion: artifact.metadata?.contractVersion, size: content.length, mimeType: this.detectMimeType(pathComponents.filename), lastUpdated: artifact.lastUpdated, publishedAt: artifact.publishedAt, }; } // Apply chunking if needed const chunkedResponse = ResponseChunker.chunk(response); this.logger.info('GetArtifactTool', `Artifact retrieved: ${path}`, '', { size: content.length, chunked: chunkedResponse.chunk ? true : false }); return chunkedResponse; } catch (error) { this.logger.error('GetArtifactTool', `Failed to retrieve artifact: ${path}`, '', error); throw error; } } detectMimeType(filename) { const ext = filename.split('.').pop()?.toLowerCase(); const mimeTypes = { 'ts': 'application/typescript', 'js': 'application/javascript', 'json': 'application/json', 'md': 'text/markdown', 'txt': 'text/plain', 'yaml': 'text/yaml', 'yml': 'text/yaml', 'html': 'text/html', 'css': 'text/css', 'py': 'text/x-python', 'java': 'text/x-java', 'cs': 'text/x-csharp', 'go': 'text/x-go', 'rs': 'text/x-rust', 'cpp': 'text/x-c++', 'c': 'text/x-c', 'sh': 'text/x-shellscript', 'xml': 'application/xml' }; return mimeTypes[ext || ''] || 'text/plain'; } } //# sourceMappingURL=GetArtifactTool.js.map