@utaba/ucm-mcp-server 1.0.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.
Files changed (80) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +79 -0
  3. package/dist/clients/UcmApiClient.d.ts +53 -0
  4. package/dist/clients/UcmApiClient.js +297 -0
  5. package/dist/index.d.ts +3 -0
  6. package/dist/index.js +68 -0
  7. package/dist/interfaces/ILogger.d.ts +8 -0
  8. package/dist/interfaces/ILogger.js +4 -0
  9. package/dist/interfaces/IMcpTool.d.ts +7 -0
  10. package/dist/interfaces/IMcpTool.js +3 -0
  11. package/dist/logging/ConsoleLogger.d.ts +16 -0
  12. package/dist/logging/ConsoleLogger.js +45 -0
  13. package/dist/logging/LoggerFactory.d.ts +9 -0
  14. package/dist/logging/LoggerFactory.js +12 -0
  15. package/dist/server/McpConfig.d.ts +26 -0
  16. package/dist/server/McpConfig.js +93 -0
  17. package/dist/server/McpHandler.d.ts +12 -0
  18. package/dist/server/McpHandler.js +69 -0
  19. package/dist/server/McpServer.d.ts +15 -0
  20. package/dist/server/McpServer.js +49 -0
  21. package/dist/server/ToolRegistry.d.ts +22 -0
  22. package/dist/server/ToolRegistry.js +85 -0
  23. package/dist/tools/artifacts/GetArtifactController.d.ts +34 -0
  24. package/dist/tools/artifacts/GetArtifactController.js +397 -0
  25. package/dist/tools/artifacts/GetLatestController.d.ts +39 -0
  26. package/dist/tools/artifacts/GetLatestController.js +469 -0
  27. package/dist/tools/artifacts/ListVersionsController.d.ts +43 -0
  28. package/dist/tools/artifacts/ListVersionsController.js +530 -0
  29. package/dist/tools/artifacts/PublishArtifactController.d.ts +37 -0
  30. package/dist/tools/artifacts/PublishArtifactController.js +605 -0
  31. package/dist/tools/base/BaseToolController.d.ts +16 -0
  32. package/dist/tools/base/BaseToolController.js +32 -0
  33. package/dist/tools/core/DeleteArtifactTool.d.ts +11 -0
  34. package/dist/tools/core/DeleteArtifactTool.js +82 -0
  35. package/dist/tools/core/GetArtifactTool.d.ts +13 -0
  36. package/dist/tools/core/GetArtifactTool.js +125 -0
  37. package/dist/tools/core/GetArtifactVersionsTool.d.ts +11 -0
  38. package/dist/tools/core/GetArtifactVersionsTool.js +63 -0
  39. package/dist/tools/core/GetChunkTool.d.ts +11 -0
  40. package/dist/tools/core/GetChunkTool.js +56 -0
  41. package/dist/tools/core/ListArtifactsTool.d.ts +11 -0
  42. package/dist/tools/core/ListArtifactsTool.js +84 -0
  43. package/dist/tools/core/PublishArtifactFromFileTool.d.ts +15 -0
  44. package/dist/tools/core/PublishArtifactFromFileTool.js +256 -0
  45. package/dist/tools/core/PublishArtifactTool.d.ts +13 -0
  46. package/dist/tools/core/PublishArtifactTool.js +197 -0
  47. package/dist/tools/discovery/BrowseCategoriesController.d.ts +25 -0
  48. package/dist/tools/discovery/BrowseCategoriesController.js +400 -0
  49. package/dist/tools/discovery/FindByPurposeController.d.ts +12 -0
  50. package/dist/tools/discovery/FindByPurposeController.js +131 -0
  51. package/dist/tools/discovery/ListAuthorsController.d.ts +20 -0
  52. package/dist/tools/discovery/ListAuthorsController.js +274 -0
  53. package/dist/tools/discovery/SearchArtifactsController.d.ts +14 -0
  54. package/dist/tools/discovery/SearchArtifactsController.js +226 -0
  55. package/dist/tools/list/ListNamespaceController.d.ts +1 -0
  56. package/dist/tools/list/ListNamespaceController.js +8 -0
  57. package/dist/tools/navigation/ExploreNamespaceController.d.ts +35 -0
  58. package/dist/tools/navigation/ExploreNamespaceController.js +548 -0
  59. package/dist/tools/utility/AuthorIndexTool.d.ts +11 -0
  60. package/dist/tools/utility/AuthorIndexTool.js +48 -0
  61. package/dist/tools/utility/HealthCheckController.d.ts +11 -0
  62. package/dist/tools/utility/HealthCheckController.js +56 -0
  63. package/dist/tools/utility/ListRepositoriesTool.d.ts +11 -0
  64. package/dist/tools/utility/ListRepositoriesTool.js +70 -0
  65. package/dist/tools/utility/QuickstartTool.d.ts +11 -0
  66. package/dist/tools/utility/QuickstartTool.js +36 -0
  67. package/dist/tools/utility/ValidatePathController.d.ts +30 -0
  68. package/dist/tools/utility/ValidatePathController.js +465 -0
  69. package/dist/types/UcmApiTypes.d.ts +40 -0
  70. package/dist/types/UcmApiTypes.js +4 -0
  71. package/dist/utils/McpErrorHandler.d.ts +25 -0
  72. package/dist/utils/McpErrorHandler.js +67 -0
  73. package/dist/utils/PathUtils.d.ts +61 -0
  74. package/dist/utils/PathUtils.js +178 -0
  75. package/dist/utils/ResponseChunker.d.ts +25 -0
  76. package/dist/utils/ResponseChunker.js +79 -0
  77. package/dist/utils/ValidationUtils.d.ts +10 -0
  78. package/dist/utils/ValidationUtils.js +50 -0
  79. package/package.json +37 -0
  80. package/package.json.backup +37 -0
@@ -0,0 +1,67 @@
1
+ // MCP-specific error handling following MCP standards
2
+ export var McpErrorCode;
3
+ (function (McpErrorCode) {
4
+ McpErrorCode[McpErrorCode["ParseError"] = -32700] = "ParseError";
5
+ McpErrorCode[McpErrorCode["InvalidRequest"] = -32600] = "InvalidRequest";
6
+ McpErrorCode[McpErrorCode["MethodNotFound"] = -32601] = "MethodNotFound";
7
+ McpErrorCode[McpErrorCode["InvalidParams"] = -32602] = "InvalidParams";
8
+ McpErrorCode[McpErrorCode["InternalError"] = -32603] = "InternalError";
9
+ McpErrorCode[McpErrorCode["ExternalServiceUnavailable"] = -32001] = "ExternalServiceUnavailable"; // External resource offline/unavailable
10
+ })(McpErrorCode || (McpErrorCode = {}));
11
+ export class McpError extends Error {
12
+ code;
13
+ data;
14
+ constructor(code, message, data) {
15
+ super(message);
16
+ this.code = code;
17
+ this.data = data;
18
+ this.name = 'McpError';
19
+ }
20
+ toResponse() {
21
+ return {
22
+ error: {
23
+ code: this.code,
24
+ message: this.message,
25
+ data: this.data
26
+ }
27
+ };
28
+ }
29
+ }
30
+ export class McpErrorHandler {
31
+ static formatError(error) {
32
+ if (error instanceof McpError) {
33
+ return error;
34
+ }
35
+ if (error.error) {
36
+ error = error.error;
37
+ }
38
+ if (error instanceof McpError) {
39
+ return error;
40
+ }
41
+ // Extract error message from various sources
42
+ let message = error.message || error.toString();
43
+ if (!message) {
44
+ message = JSON.stringify(error);
45
+ }
46
+ // Map common errors to MCP error codes
47
+ if (message?.includes('not found')) {
48
+ return new McpError(McpErrorCode.InvalidParams, message, { originalError: error });
49
+ }
50
+ if (message?.includes('validation')) {
51
+ return new McpError(McpErrorCode.InvalidParams, 'Parameter validation failed', { originalError: error });
52
+ }
53
+ if (message?.includes('ECONNREFUSED')) {
54
+ return new McpError(McpErrorCode.ExternalServiceUnavailable, 'External API is unavailable, try the mcp_ucm_health_check tool', { originalError: error });
55
+ }
56
+ if (message?.includes('validation') || message?.includes('invalid') ||
57
+ message?.includes('required') || message?.includes('must be')) {
58
+ return new McpError(McpErrorCode.InvalidParams, message, { originalError: error });
59
+ }
60
+ if (message?.includes('UCM API server error')) {
61
+ return new McpError(McpErrorCode.InternalError, message, { originalError: error });
62
+ }
63
+ // Don't leak internal errors
64
+ return new McpError(McpErrorCode.InternalError, message || 'An internal error occurred');
65
+ }
66
+ }
67
+ //# sourceMappingURL=McpErrorHandler.js.map
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Utility functions for parsing UCM paths into component parts
3
+ */
4
+ export interface ParsedPath {
5
+ author?: string | undefined;
6
+ repository?: string | undefined;
7
+ category?: string | undefined;
8
+ subcategory?: string | undefined;
9
+ filename?: string;
10
+ version?: string;
11
+ }
12
+ /**
13
+ * Parse a UCM path into its component parts
14
+ * Supports formats like:
15
+ * - "utaba/main/commands/user" (namespace only)
16
+ * - "utaba/main/commands/user/CreateUserCommand.ts" (with filename)
17
+ * - "utaba/main/commands/user/CreateUserCommand.ts@1.0.0" (with version)
18
+ */
19
+ export declare function parsePath(path: string): ParsedPath;
20
+ /**
21
+ * Build a namespace path from components (author/repository/category/subcategory)
22
+ */
23
+ export declare function buildNamespacePath(author: string, repository: string, category: string, subcategory: string): string;
24
+ /**
25
+ * Build a full path with filename and optional version
26
+ */
27
+ export declare function buildFullPath(author: string, repository: string, category: string, subcategory: string, filename?: string, version?: string): string;
28
+ /**
29
+ * Extract namespace from a full path
30
+ */
31
+ export declare function extractNamespace(path: string): string;
32
+ /**
33
+ * Validate if a path follows UCM naming conventions
34
+ */
35
+ export declare function validatePath(path: string): {
36
+ isValid: boolean;
37
+ errors: string[];
38
+ };
39
+ /**
40
+ * Compare two semantic versions
41
+ * Returns: -1 if version1 < version2, 0 if equal, 1 if version1 > version2
42
+ */
43
+ export declare function compareVersions(version1: string, version2: string): number;
44
+ /**
45
+ * Check if a version is greater than another version
46
+ */
47
+ export declare function isVersionGreater(version1: string, version2: string): boolean;
48
+ /**
49
+ * Check if a version is less than another version
50
+ */
51
+ export declare function isVersionLess(version1: string, version2: string): boolean;
52
+ /**
53
+ * Check if two versions are equal
54
+ */
55
+ export declare function isVersionEqual(version1: string, version2: string): boolean;
56
+ /**
57
+ * Increment the patch version of a semantic version
58
+ * Examples: 1.0.0 -> 1.0.1, 2.1.5 -> 2.1.6
59
+ */
60
+ export declare function incrementPatchVersion(version: string): string;
61
+ //# sourceMappingURL=PathUtils.d.ts.map
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Utility functions for parsing UCM paths into component parts
3
+ */
4
+ /**
5
+ * Parse a UCM path into its component parts
6
+ * Supports formats like:
7
+ * - "utaba/main/commands/user" (namespace only)
8
+ * - "utaba/main/commands/user/CreateUserCommand.ts" (with filename)
9
+ * - "utaba/main/commands/user/CreateUserCommand.ts@1.0.0" (with version)
10
+ */
11
+ export function parsePath(path) {
12
+ if (!path)
13
+ path = "";
14
+ // Remove leading/trailing slashes
15
+ const cleanPath = path.replace(/^\/+|\/+$/g, '');
16
+ // Split into parts
17
+ const parts = cleanPath.split('/');
18
+ const result = {
19
+ author: parts.length > 0 ? parts[0] : undefined,
20
+ repository: parts.length > 1 ? parts[1] : undefined,
21
+ category: parts.length > 2 ? parts[2] : undefined,
22
+ subcategory: parts.length > 3 ? parts[3] : undefined,
23
+ };
24
+ if (parts.length > 4) {
25
+ let filenameParts = parts[4].split('@');
26
+ //filename
27
+ result.filename = filenameParts[0];
28
+ if (filenameParts.length > 1) {
29
+ result.version = filenameParts[1];
30
+ }
31
+ }
32
+ return result;
33
+ }
34
+ /**
35
+ * Build a namespace path from components (author/repository/category/subcategory)
36
+ */
37
+ export function buildNamespacePath(author, repository, category, subcategory) {
38
+ return `${author}/${repository}/${category}/${subcategory}`;
39
+ }
40
+ /**
41
+ * Build a full path with filename and optional version
42
+ */
43
+ export function buildFullPath(author, repository, category, subcategory, filename, version) {
44
+ let path = buildNamespacePath(author, repository, category, subcategory);
45
+ if (filename) {
46
+ path += `/${filename}`;
47
+ if (version) {
48
+ path += `@${version}`;
49
+ }
50
+ }
51
+ return path;
52
+ }
53
+ /**
54
+ * Extract namespace from a full path
55
+ */
56
+ export function extractNamespace(path) {
57
+ const parsed = parsePath(path);
58
+ return buildNamespacePath(parsed.author || '', parsed.repository || '', parsed.category || '', parsed.subcategory || '');
59
+ }
60
+ /**
61
+ * Validate if a path follows UCM naming conventions
62
+ */
63
+ export function validatePath(path) {
64
+ const errors = [];
65
+ try {
66
+ const parsed = parsePath(path);
67
+ // Validate author (lowercase alphanumeric and hyphens)
68
+ if (!/^[a-z0-9-]+$/.test(parsed.author || '')) {
69
+ errors.push('Author must contain only lowercase letters, numbers, and hyphens');
70
+ }
71
+ // Validate repository (lowercase alphanumeric and hyphens)
72
+ if (!/^[a-z0-9-]+$/.test(parsed.repository || '')) {
73
+ errors.push('Repository must contain only lowercase letters, numbers, and hyphens');
74
+ }
75
+ // Validate category (must be valid UCM category)
76
+ const validCategories = ['commands', 'services', 'patterns', 'implementations', 'contracts', 'guidance', 'project'];
77
+ if (!validCategories.includes(parsed.category || '')) {
78
+ errors.push(`Category must be one of: ${validCategories.join(', ')}`);
79
+ }
80
+ // Validate subcategory (lowercase alphanumeric and hyphens)
81
+ if (!/^[a-z0-9-]+$/.test(parsed.subcategory || '')) {
82
+ errors.push('Subcategory must contain only lowercase letters, numbers, and hyphens');
83
+ }
84
+ // Validate filename if present
85
+ if (parsed.filename) {
86
+ if (!/^[a-zA-Z0-9._-]+\.[a-z]+$/.test(parsed.filename)) {
87
+ errors.push('Filename must be valid with an extension');
88
+ }
89
+ }
90
+ // Validate version if present
91
+ if (parsed.version) {
92
+ if (!/^v?\d+\.\d+\.\d+(-[a-z0-9-]+)?(\+[a-z0-9-]+)?$/.test(parsed.version)) {
93
+ errors.push('Version must follow semantic versioning (e.g., 1.0.0, v2.1.0)');
94
+ }
95
+ }
96
+ }
97
+ catch (error) {
98
+ errors.push(error instanceof Error ? error.message : 'Invalid path format');
99
+ }
100
+ return {
101
+ isValid: errors.length === 0,
102
+ errors
103
+ };
104
+ }
105
+ /**
106
+ * Compare two semantic versions
107
+ * Returns: -1 if version1 < version2, 0 if equal, 1 if version1 > version2
108
+ */
109
+ export function compareVersions(version1, version2) {
110
+ // Normalize versions by removing 'v' prefix if present
111
+ const v1 = version1.replace(/^v/, '');
112
+ const v2 = version2.replace(/^v/, '');
113
+ // Split versions into parts
114
+ const parts1 = v1.split(/[.-]/);
115
+ const parts2 = v2.split(/[.-]/);
116
+ // Compare major, minor, patch
117
+ for (let i = 0; i < 3; i++) {
118
+ const num1 = parseInt(parts1[i] || '0', 10);
119
+ const num2 = parseInt(parts2[i] || '0', 10);
120
+ if (num1 > num2)
121
+ return 1;
122
+ if (num1 < num2)
123
+ return -1;
124
+ }
125
+ // If major.minor.patch are equal, compare pre-release versions
126
+ const preRelease1 = parts1.slice(3).join('.');
127
+ const preRelease2 = parts2.slice(3).join('.');
128
+ // No pre-release is greater than pre-release
129
+ if (!preRelease1 && preRelease2)
130
+ return 1;
131
+ if (preRelease1 && !preRelease2)
132
+ return -1;
133
+ if (!preRelease1 && !preRelease2)
134
+ return 0;
135
+ // Compare pre-release versions lexically
136
+ return preRelease1.localeCompare(preRelease2);
137
+ }
138
+ /**
139
+ * Check if a version is greater than another version
140
+ */
141
+ export function isVersionGreater(version1, version2) {
142
+ return compareVersions(version1, version2) > 0;
143
+ }
144
+ /**
145
+ * Check if a version is less than another version
146
+ */
147
+ export function isVersionLess(version1, version2) {
148
+ return compareVersions(version1, version2) < 0;
149
+ }
150
+ /**
151
+ * Check if two versions are equal
152
+ */
153
+ export function isVersionEqual(version1, version2) {
154
+ return compareVersions(version1, version2) === 0;
155
+ }
156
+ /**
157
+ * Increment the patch version of a semantic version
158
+ * Examples: 1.0.0 -> 1.0.1, 2.1.5 -> 2.1.6
159
+ */
160
+ export function incrementPatchVersion(version) {
161
+ // Normalize version by removing 'v' prefix if present
162
+ const normalized = version.replace(/^v/, '');
163
+ // Split version into parts
164
+ const parts = normalized.split('.');
165
+ if (parts.length < 3) {
166
+ throw new Error(`Invalid semantic version format: ${version}`);
167
+ }
168
+ // Parse major, minor, patch
169
+ const major = parseInt(parts[0], 10);
170
+ const minor = parseInt(parts[1], 10);
171
+ const patch = parseInt(parts[2].split('-')[0], 10); // Handle pre-release versions
172
+ if (isNaN(major) || isNaN(minor) || isNaN(patch)) {
173
+ throw new Error(`Invalid semantic version format: ${version}`);
174
+ }
175
+ // Increment patch version
176
+ return `${major}.${minor}.${patch + 1}`;
177
+ }
178
+ //# sourceMappingURL=PathUtils.js.map
@@ -0,0 +1,25 @@
1
+ export interface ChunkedResponse {
2
+ chunk: {
3
+ id: string;
4
+ sequence: number;
5
+ total: number;
6
+ data: string;
7
+ };
8
+ hasMore: boolean;
9
+ }
10
+ export declare class ResponseChunker {
11
+ private static readonly MAX_CHUNK_SIZE;
12
+ private static chunks;
13
+ private static readonly CHUNK_TTL;
14
+ private static chunkTimestamps;
15
+ static chunk(data: any, chunkId?: string): ChunkedResponse | any;
16
+ static getNextChunk(chunkId: string, sequence: number): ChunkedResponse | null;
17
+ static cleanup(chunkId: string): void;
18
+ static cleanupExpired(): void;
19
+ static getChunkInfo(chunkId: string): {
20
+ exists: boolean;
21
+ total?: number;
22
+ expires?: number;
23
+ };
24
+ }
25
+ //# sourceMappingURL=ResponseChunker.d.ts.map
@@ -0,0 +1,79 @@
1
+ export class ResponseChunker {
2
+ static MAX_CHUNK_SIZE = 20000; // ~20k characters to stay under token limit
3
+ static chunks = new Map();
4
+ static CHUNK_TTL = 5 * 60 * 1000; // 5 minutes
5
+ static chunkTimestamps = new Map();
6
+ static chunk(data, chunkId) {
7
+ const serialized = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
8
+ // If small enough, return as-is
9
+ if (serialized.length < this.MAX_CHUNK_SIZE) {
10
+ return data;
11
+ }
12
+ // Generate chunk ID if not provided
13
+ const id = chunkId || `ucm_chunk_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
14
+ // Split into chunks
15
+ const chunks = [];
16
+ for (let i = 0; i < serialized.length; i += this.MAX_CHUNK_SIZE) {
17
+ chunks.push(serialized.slice(i, i + this.MAX_CHUNK_SIZE));
18
+ }
19
+ // Store chunks for retrieval with timestamp
20
+ this.chunks.set(id, chunks);
21
+ this.chunkTimestamps.set(id, Date.now());
22
+ // Schedule cleanup after TTL
23
+ setTimeout(() => {
24
+ this.cleanup(id);
25
+ }, this.CHUNK_TTL);
26
+ // Return first chunk with metadata
27
+ return {
28
+ chunk: {
29
+ id,
30
+ sequence: 0,
31
+ total: chunks.length,
32
+ data: chunks[0]
33
+ },
34
+ hasMore: chunks.length > 1
35
+ };
36
+ }
37
+ static getNextChunk(chunkId, sequence) {
38
+ const chunks = this.chunks.get(chunkId);
39
+ if (!chunks || sequence >= chunks.length || sequence < 0) {
40
+ return null;
41
+ }
42
+ // Update timestamp to extend TTL
43
+ this.chunkTimestamps.set(chunkId, Date.now());
44
+ return {
45
+ chunk: {
46
+ id: chunkId,
47
+ sequence,
48
+ total: chunks.length,
49
+ data: chunks[sequence]
50
+ },
51
+ hasMore: sequence < chunks.length - 1
52
+ };
53
+ }
54
+ static cleanup(chunkId) {
55
+ this.chunks.delete(chunkId);
56
+ this.chunkTimestamps.delete(chunkId);
57
+ }
58
+ static cleanupExpired() {
59
+ const now = Date.now();
60
+ for (const [id, timestamp] of this.chunkTimestamps.entries()) {
61
+ if (now - timestamp > this.CHUNK_TTL) {
62
+ this.cleanup(id);
63
+ }
64
+ }
65
+ }
66
+ static getChunkInfo(chunkId) {
67
+ const chunks = this.chunks.get(chunkId);
68
+ const timestamp = this.chunkTimestamps.get(chunkId);
69
+ if (!chunks || !timestamp) {
70
+ return { exists: false };
71
+ }
72
+ return {
73
+ exists: true,
74
+ total: chunks.length,
75
+ expires: timestamp + this.CHUNK_TTL
76
+ };
77
+ }
78
+ }
79
+ //# sourceMappingURL=ResponseChunker.js.map
@@ -0,0 +1,10 @@
1
+ export declare class ValidationUtils {
2
+ static validateArtifactPath(path: string): void;
3
+ static sanitizeSearchQuery(query: string): string;
4
+ static validateContentSize(content: string, maxSize?: number): void;
5
+ static validatePageParams(offset?: number, limit?: number): void;
6
+ static validateAuthorId(authorId: string): void;
7
+ static validateCategory(category: string): void;
8
+ static validateVersion(version: string): void;
9
+ }
10
+ //# sourceMappingURL=ValidationUtils.d.ts.map
@@ -0,0 +1,50 @@
1
+ import { McpError, McpErrorCode } from './McpErrorHandler.js';
2
+ export class ValidationUtils {
3
+ static validateArtifactPath(path) {
4
+ // Prevent path traversal
5
+ if (path.includes('..') || path.includes('//')) {
6
+ throw new McpError(McpErrorCode.InvalidParams, 'Invalid artifact path');
7
+ }
8
+ }
9
+ static sanitizeSearchQuery(query) {
10
+ // Remove potentially dangerous characters
11
+ return query.replace(/[<>\"'&]/g, '').trim();
12
+ }
13
+ static validateContentSize(content, maxSize = 1024 * 1024) {
14
+ if (content.length > maxSize) {
15
+ throw new McpError(McpErrorCode.InvalidParams, 'Content size exceeds maximum allowed');
16
+ }
17
+ }
18
+ static validatePageParams(offset = 0, limit = 20) {
19
+ if (offset < 0) {
20
+ throw new McpError(McpErrorCode.InvalidParams, 'Offset must be non-negative');
21
+ }
22
+ if (limit < 1 || limit > 100) {
23
+ throw new McpError(McpErrorCode.InvalidParams, 'Limit must be between 1 and 100');
24
+ }
25
+ }
26
+ static validateAuthorId(authorId) {
27
+ if (!authorId || typeof authorId !== 'string') {
28
+ throw new McpError(McpErrorCode.InvalidParams, 'Author ID is required and must be a string');
29
+ }
30
+ // Basic validation - alphanumeric, hyphens, underscores
31
+ const authorRegex = /^[a-zA-Z0-9\-_]+$/;
32
+ if (!authorRegex.test(authorId)) {
33
+ throw new McpError(McpErrorCode.InvalidParams, 'Author ID contains invalid characters');
34
+ }
35
+ }
36
+ static validateCategory(category) {
37
+ const validCategories = ['commands', 'services', 'patterns', 'implementations', 'contracts', 'guidance'];
38
+ if (!validCategories.includes(category)) {
39
+ throw new McpError(McpErrorCode.InvalidParams, `Invalid category. Must be one of: ${validCategories.join(', ')}`);
40
+ }
41
+ }
42
+ static validateVersion(version) {
43
+ // Semantic version validation
44
+ const versionRegex = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9\-_]+)?$/;
45
+ if (!versionRegex.test(version)) {
46
+ throw new McpError(McpErrorCode.InvalidParams, 'Version must follow semantic versioning format');
47
+ }
48
+ }
49
+ }
50
+ //# sourceMappingURL=ValidationUtils.js.map
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@utaba/ucm-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "Universal Context Manager MCP Server - AI-native artifact management",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "ucm-mcp-server": "dist/index.js"
9
+ },
10
+ "keywords": [
11
+ "mcp",
12
+ "model-context-protocol",
13
+ "ucm",
14
+ "universal-context-manager",
15
+ "ai",
16
+ "context-manager",
17
+ "micro-blocks",
18
+ "utaba"
19
+ ],
20
+ "author": {
21
+ "name": "Utaba AI",
22
+ "url": "https://utaba.ai"
23
+ },
24
+ "license": "BSD-3-Clause",
25
+ "homepage": "https://ucm.utaba.ai",
26
+ "dependencies": {
27
+ "@modelcontextprotocol/sdk": "^1.0.0",
28
+ "commander": "^14.0.0",
29
+ "axios": "^1.10.0"
30
+ },
31
+ "engines": {
32
+ "node": ">=18.0.0"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ }
37
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "ucm-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "Universal Context Manager MCP Server - AI-native artifact management",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "ucm-mcp-server": "dist/index.js"
9
+ },
10
+ "keywords": [
11
+ "mcp",
12
+ "model-context-protocol",
13
+ "ucm",
14
+ "universal-context-manager",
15
+ "ai",
16
+ "context-manager",
17
+ "micro-blocks",
18
+ "utaba"
19
+ ],
20
+ "author": {
21
+ "name": "Utaba AI",
22
+ "url": "https://utaba.ai"
23
+ },
24
+ "license": "BSD-3-Clause",
25
+ "homepage": "https://ucm.utaba.ai",
26
+ "dependencies": {
27
+ "@modelcontextprotocol/sdk": "^1.0.0",
28
+ "commander": "^14.0.0",
29
+ "axios": "^1.10.0"
30
+ },
31
+ "engines": {
32
+ "node": ">=18.0.0"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ }
37
+ }