@vfarcic/dot-ai 0.90.0 → 0.91.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.
@@ -0,0 +1,468 @@
1
+ "use strict";
2
+ /**
3
+ * OpenAPI 3.0 Specification Generator
4
+ *
5
+ * Automatically generates OpenAPI 3.0 documentation from the tool registry.
6
+ * Creates comprehensive API documentation with proper schemas and examples.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.OpenApiGenerator = void 0;
10
+ /**
11
+ * OpenAPI 3.0 specification generator
12
+ */
13
+ class OpenApiGenerator {
14
+ registry;
15
+ logger;
16
+ config;
17
+ specCache;
18
+ lastCacheUpdate = 0;
19
+ cacheValidityMs = 60000; // 1 minute
20
+ constructor(registry, logger, config = {}) {
21
+ this.registry = registry;
22
+ this.logger = logger;
23
+ this.config = {
24
+ title: 'DevOps AI Toolkit REST API',
25
+ description: 'REST API gateway for DevOps AI Toolkit MCP tools - provides HTTP access to all AI-powered DevOps automation capabilities',
26
+ version: '1.0.0',
27
+ basePath: '/api',
28
+ apiVersion: 'v1',
29
+ serverUrl: 'http://localhost:3456',
30
+ ...config
31
+ };
32
+ }
33
+ /**
34
+ * Generate complete OpenAPI 3.0 specification
35
+ */
36
+ generateSpec() {
37
+ // Check cache validity
38
+ const now = Date.now();
39
+ if (this.specCache && (now - this.lastCacheUpdate) < this.cacheValidityMs) {
40
+ this.logger.debug('Returning cached OpenAPI specification');
41
+ return this.specCache;
42
+ }
43
+ this.logger.info('Generating OpenAPI 3.0 specification', {
44
+ toolCount: this.registry.getToolCount(),
45
+ cacheExpired: !this.specCache || (now - this.lastCacheUpdate) >= this.cacheValidityMs
46
+ });
47
+ const tools = this.registry.getAllTools();
48
+ const categories = this.registry.getCategories();
49
+ const spec = {
50
+ openapi: '3.0.0',
51
+ info: this.generateInfo(),
52
+ servers: this.generateServers(),
53
+ paths: this.generatePaths(tools),
54
+ components: this.generateComponents(tools),
55
+ tags: this.generateTags(categories)
56
+ };
57
+ // Cache the generated spec
58
+ this.specCache = spec;
59
+ this.lastCacheUpdate = now;
60
+ this.logger.info('OpenAPI specification generated successfully', {
61
+ pathCount: Object.keys(spec.paths).length,
62
+ componentCount: Object.keys(spec.components?.schemas || {}).length,
63
+ tagCount: spec.tags?.length || 0
64
+ });
65
+ return spec;
66
+ }
67
+ /**
68
+ * Generate API info section
69
+ */
70
+ generateInfo() {
71
+ const info = {
72
+ title: this.config.title,
73
+ description: this.config.description,
74
+ version: this.config.version,
75
+ contact: {
76
+ name: 'Viktor Farcic',
77
+ url: 'https://devopstoolkit.live/',
78
+ email: 'viktor@farcic.com'
79
+ },
80
+ license: {
81
+ name: 'MIT',
82
+ url: 'https://github.com/vfarcic/dot-ai/blob/main/LICENSE'
83
+ }
84
+ };
85
+ return info;
86
+ }
87
+ /**
88
+ * Generate server definitions
89
+ */
90
+ generateServers() {
91
+ return [
92
+ {
93
+ url: this.config.serverUrl || 'http://localhost:3456',
94
+ description: 'DevOps AI Toolkit MCP Server'
95
+ }
96
+ ];
97
+ }
98
+ /**
99
+ * Generate paths for all endpoints
100
+ */
101
+ generatePaths(tools) {
102
+ const paths = {};
103
+ const basePath = `${this.config.basePath}/${this.config.apiVersion}`;
104
+ // Tool discovery endpoint
105
+ paths[`${basePath}/tools`] = {
106
+ get: {
107
+ summary: 'Discover available tools',
108
+ description: 'Get a list of all available tools with their schemas and metadata',
109
+ tags: ['Tool Discovery'],
110
+ parameters: [
111
+ {
112
+ name: 'category',
113
+ in: 'query',
114
+ description: 'Filter tools by category',
115
+ required: false,
116
+ schema: { type: 'string' }
117
+ },
118
+ {
119
+ name: 'tag',
120
+ in: 'query',
121
+ description: 'Filter tools by tag',
122
+ required: false,
123
+ schema: { type: 'string' }
124
+ },
125
+ {
126
+ name: 'search',
127
+ in: 'query',
128
+ description: 'Search tools by name or description',
129
+ required: false,
130
+ schema: { type: 'string' }
131
+ }
132
+ ],
133
+ responses: {
134
+ 200: {
135
+ description: 'List of available tools',
136
+ content: {
137
+ 'application/json': {
138
+ schema: { $ref: '#/components/schemas/ToolDiscoveryResponse' }
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ };
145
+ // Individual tool execution endpoints
146
+ for (const tool of tools) {
147
+ paths[`${basePath}/tools/${tool.name}`] = {
148
+ post: {
149
+ summary: `Execute ${tool.name} tool`,
150
+ description: tool.description,
151
+ tags: [tool.category || 'Tools'],
152
+ requestBody: {
153
+ required: true,
154
+ content: {
155
+ 'application/json': {
156
+ schema: { $ref: `#/components/schemas/${tool.name}Request` },
157
+ example: this.generateExampleForTool(tool)
158
+ }
159
+ }
160
+ },
161
+ responses: {
162
+ 200: {
163
+ description: 'Tool execution result',
164
+ content: {
165
+ 'application/json': {
166
+ schema: { $ref: '#/components/schemas/ToolExecutionResponse' }
167
+ }
168
+ }
169
+ },
170
+ 400: {
171
+ description: 'Bad request - invalid parameters',
172
+ content: {
173
+ 'application/json': {
174
+ schema: { $ref: '#/components/schemas/ErrorResponse' }
175
+ }
176
+ }
177
+ },
178
+ 404: {
179
+ description: 'Tool not found',
180
+ content: {
181
+ 'application/json': {
182
+ schema: { $ref: '#/components/schemas/ErrorResponse' }
183
+ }
184
+ }
185
+ },
186
+ 500: {
187
+ description: 'Internal server error',
188
+ content: {
189
+ 'application/json': {
190
+ schema: { $ref: '#/components/schemas/ErrorResponse' }
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
196
+ };
197
+ }
198
+ // OpenAPI specification endpoint
199
+ paths[`${basePath}/openapi`] = {
200
+ get: {
201
+ summary: 'Get OpenAPI specification',
202
+ description: 'Returns the complete OpenAPI 3.0 specification for this API',
203
+ tags: ['Documentation'],
204
+ responses: {
205
+ 200: {
206
+ description: 'OpenAPI specification',
207
+ content: {
208
+ 'application/json': {
209
+ schema: {
210
+ type: 'object',
211
+ description: 'OpenAPI 3.0 specification'
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+ }
218
+ };
219
+ return paths;
220
+ }
221
+ /**
222
+ * Generate component schemas
223
+ */
224
+ generateComponents(tools) {
225
+ const schemas = {};
226
+ // Base response schemas
227
+ schemas.RestApiResponse = {
228
+ type: 'object',
229
+ properties: {
230
+ success: { type: 'boolean', description: 'Whether the request was successful' },
231
+ data: { type: 'object', description: 'Response data' },
232
+ error: {
233
+ type: 'object',
234
+ properties: {
235
+ code: { type: 'string', description: 'Error code' },
236
+ message: { type: 'string', description: 'Error message' },
237
+ details: { type: 'object', description: 'Additional error details' }
238
+ }
239
+ },
240
+ meta: {
241
+ type: 'object',
242
+ properties: {
243
+ timestamp: { type: 'string', format: 'date-time', description: 'Response timestamp' },
244
+ requestId: { type: 'string', description: 'Unique request identifier' },
245
+ version: { type: 'string', description: 'API version' }
246
+ }
247
+ }
248
+ },
249
+ required: ['success']
250
+ };
251
+ schemas.ToolExecutionResponse = {
252
+ allOf: [
253
+ { $ref: '#/components/schemas/RestApiResponse' },
254
+ {
255
+ type: 'object',
256
+ properties: {
257
+ data: {
258
+ type: 'object',
259
+ properties: {
260
+ result: { type: 'object', description: 'Tool execution result' },
261
+ tool: { type: 'string', description: 'Name of the executed tool' },
262
+ executionTime: { type: 'number', description: 'Execution time in milliseconds' }
263
+ }
264
+ }
265
+ }
266
+ }
267
+ ]
268
+ };
269
+ schemas.ToolDiscoveryResponse = {
270
+ allOf: [
271
+ { $ref: '#/components/schemas/RestApiResponse' },
272
+ {
273
+ type: 'object',
274
+ properties: {
275
+ data: {
276
+ type: 'object',
277
+ properties: {
278
+ tools: {
279
+ type: 'array',
280
+ items: { $ref: '#/components/schemas/ToolInfo' }
281
+ },
282
+ total: { type: 'number', description: 'Total number of tools' },
283
+ categories: {
284
+ type: 'array',
285
+ items: { type: 'string' },
286
+ description: 'Available tool categories'
287
+ },
288
+ tags: {
289
+ type: 'array',
290
+ items: { type: 'string' },
291
+ description: 'Available tool tags'
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }
297
+ ]
298
+ };
299
+ schemas.ToolInfo = {
300
+ type: 'object',
301
+ properties: {
302
+ name: { type: 'string', description: 'Tool name' },
303
+ description: { type: 'string', description: 'Tool description' },
304
+ schema: { type: 'object', description: 'Tool input schema' },
305
+ category: { type: 'string', description: 'Tool category' },
306
+ tags: {
307
+ type: 'array',
308
+ items: { type: 'string' },
309
+ description: 'Tool tags'
310
+ }
311
+ },
312
+ required: ['name', 'description', 'schema']
313
+ };
314
+ schemas.ErrorResponse = {
315
+ allOf: [
316
+ { $ref: '#/components/schemas/RestApiResponse' },
317
+ {
318
+ type: 'object',
319
+ properties: {
320
+ success: { type: 'boolean', enum: [false] },
321
+ error: {
322
+ type: 'object',
323
+ properties: {
324
+ code: { type: 'string' },
325
+ message: { type: 'string' },
326
+ details: { type: 'object' }
327
+ },
328
+ required: ['code', 'message']
329
+ }
330
+ },
331
+ required: ['error']
332
+ }
333
+ ]
334
+ };
335
+ // Individual tool request schemas
336
+ for (const tool of tools) {
337
+ schemas[`${tool.name}Request`] = tool.schema;
338
+ }
339
+ return {
340
+ schemas
341
+ };
342
+ }
343
+ /**
344
+ * Generate tags for grouping endpoints
345
+ */
346
+ generateTags(categories) {
347
+ const tags = [
348
+ {
349
+ name: 'Tool Discovery',
350
+ description: 'Endpoints for discovering available tools and their capabilities'
351
+ },
352
+ {
353
+ name: 'Documentation',
354
+ description: 'API documentation and specification endpoints'
355
+ }
356
+ ];
357
+ // Add category-based tags
358
+ for (const category of categories) {
359
+ tags.push({
360
+ name: category,
361
+ description: `${category} tools and operations`
362
+ });
363
+ }
364
+ // Add generic tools tag for uncategorized tools
365
+ if (this.registry.getAllTools().some(tool => !tool.category)) {
366
+ tags.push({
367
+ name: 'Tools',
368
+ description: 'General purpose tools and utilities'
369
+ });
370
+ }
371
+ return tags;
372
+ }
373
+ /**
374
+ * Generate example request body for a tool
375
+ */
376
+ generateExampleForTool(tool) {
377
+ const example = {};
378
+ try {
379
+ const schema = tool.schema;
380
+ if (schema.properties) {
381
+ for (const [propName, propSchema] of Object.entries(schema.properties)) {
382
+ example[propName] = this.generateExampleValue(propSchema, propName);
383
+ }
384
+ }
385
+ }
386
+ catch (error) {
387
+ this.logger.warn('Failed to generate example for tool', {
388
+ toolName: tool.name,
389
+ error: error instanceof Error ? error.message : String(error)
390
+ });
391
+ }
392
+ return example;
393
+ }
394
+ /**
395
+ * Generate example value for a property schema
396
+ */
397
+ generateExampleValue(propSchema, propName) {
398
+ if (propSchema.example !== undefined) {
399
+ return propSchema.example;
400
+ }
401
+ switch (propSchema.type) {
402
+ case 'string':
403
+ if (propSchema.enum) {
404
+ return propSchema.enum[0];
405
+ }
406
+ if (propName.toLowerCase().includes('email')) {
407
+ return 'user@example.com';
408
+ }
409
+ if (propName.toLowerCase().includes('url')) {
410
+ return 'https://example.com';
411
+ }
412
+ if (propName.toLowerCase().includes('name')) {
413
+ return `example ${propName}`;
414
+ }
415
+ if (propName.toLowerCase().includes('intent')) {
416
+ return 'deploy web application with PostgreSQL database';
417
+ }
418
+ return `example ${propName}`;
419
+ case 'number':
420
+ case 'integer':
421
+ if (propName.toLowerCase().includes('port')) {
422
+ return 8080;
423
+ }
424
+ if (propName.toLowerCase().includes('timeout')) {
425
+ return 30;
426
+ }
427
+ return 42;
428
+ case 'boolean':
429
+ return false;
430
+ case 'array':
431
+ return [this.generateExampleValue(propSchema.items, 'item')];
432
+ case 'object': {
433
+ const objExample = {};
434
+ if (propSchema.properties) {
435
+ for (const [subPropName, subPropSchema] of Object.entries(propSchema.properties)) {
436
+ objExample[subPropName] = this.generateExampleValue(subPropSchema, subPropName);
437
+ }
438
+ }
439
+ return objExample;
440
+ }
441
+ default:
442
+ return `example ${propName}`;
443
+ }
444
+ }
445
+ /**
446
+ * Invalidate the specification cache
447
+ */
448
+ invalidateCache() {
449
+ this.specCache = undefined;
450
+ this.lastCacheUpdate = 0;
451
+ this.logger.debug('OpenAPI specification cache invalidated');
452
+ }
453
+ /**
454
+ * Update configuration
455
+ */
456
+ updateConfig(newConfig) {
457
+ this.config = { ...this.config, ...newConfig };
458
+ this.invalidateCache();
459
+ this.logger.info('OpenAPI generator configuration updated');
460
+ }
461
+ /**
462
+ * Get current configuration
463
+ */
464
+ getConfig() {
465
+ return { ...this.config };
466
+ }
467
+ }
468
+ exports.OpenApiGenerator = OpenApiGenerator;
@@ -0,0 +1,124 @@
1
+ /**
2
+ * REST API Router for MCP Tools
3
+ *
4
+ * Provides HTTP REST endpoints for all registered MCP tools.
5
+ * Handles routing, validation, execution, and response formatting.
6
+ */
7
+ import { IncomingMessage, ServerResponse } from 'node:http';
8
+ import { RestToolRegistry, ToolInfo } from './rest-registry';
9
+ import { Logger } from '../core/error-handling';
10
+ import { DotAI } from '../core/index';
11
+ /**
12
+ * HTTP status codes for REST responses
13
+ */
14
+ export declare enum HttpStatus {
15
+ OK = 200,
16
+ BAD_REQUEST = 400,
17
+ NOT_FOUND = 404,
18
+ METHOD_NOT_ALLOWED = 405,
19
+ INTERNAL_SERVER_ERROR = 500
20
+ }
21
+ /**
22
+ * Standard REST API response format
23
+ */
24
+ export interface RestApiResponse {
25
+ success: boolean;
26
+ data?: any;
27
+ error?: {
28
+ code: string;
29
+ message: string;
30
+ details?: any;
31
+ };
32
+ meta?: {
33
+ timestamp: string;
34
+ requestId?: string;
35
+ version: string;
36
+ };
37
+ }
38
+ /**
39
+ * Tool execution response format
40
+ */
41
+ export interface ToolExecutionResponse extends RestApiResponse {
42
+ data?: {
43
+ result: any;
44
+ tool: string;
45
+ executionTime?: number;
46
+ };
47
+ }
48
+ /**
49
+ * Tool discovery response format
50
+ */
51
+ export interface ToolDiscoveryResponse extends RestApiResponse {
52
+ data?: {
53
+ tools: ToolInfo[];
54
+ total: number;
55
+ categories?: string[];
56
+ tags?: string[];
57
+ };
58
+ }
59
+ /**
60
+ * REST API router configuration
61
+ */
62
+ export interface RestApiConfig {
63
+ basePath: string;
64
+ version: string;
65
+ enableCors: boolean;
66
+ requestTimeout: number;
67
+ }
68
+ /**
69
+ * REST API Router for MCP tools
70
+ */
71
+ export declare class RestApiRouter {
72
+ private registry;
73
+ private logger;
74
+ private dotAI;
75
+ private config;
76
+ private openApiGenerator;
77
+ private requestCounter;
78
+ constructor(registry: RestToolRegistry, dotAI: DotAI, logger: Logger, config?: Partial<RestApiConfig>);
79
+ /**
80
+ * Handle incoming HTTP requests for REST API
81
+ */
82
+ handleRequest(req: IncomingMessage, res: ServerResponse, body?: any): Promise<void>;
83
+ /**
84
+ * Parse API path and extract route information
85
+ */
86
+ private parseApiPath;
87
+ /**
88
+ * Handle tool discovery requests
89
+ */
90
+ private handleToolDiscovery;
91
+ /**
92
+ * Handle tool execution requests
93
+ */
94
+ private handleToolExecution;
95
+ /**
96
+ * Handle OpenAPI specification requests
97
+ */
98
+ private handleOpenApiSpec;
99
+ /**
100
+ * Set CORS headers
101
+ */
102
+ private setCorsHeaders;
103
+ /**
104
+ * Send JSON response
105
+ */
106
+ private sendJsonResponse;
107
+ /**
108
+ * Send error response
109
+ */
110
+ private sendErrorResponse;
111
+ /**
112
+ * Generate unique request ID
113
+ */
114
+ private generateRequestId;
115
+ /**
116
+ * Check if the given path matches the REST API pattern
117
+ */
118
+ isApiRequest(pathname: string): boolean;
119
+ /**
120
+ * Get API configuration
121
+ */
122
+ getConfig(): RestApiConfig;
123
+ }
124
+ //# sourceMappingURL=rest-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../../src/interfaces/rest-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE5D,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC;;GAEG;AACH,oBAAY,UAAU;IACpB,EAAE,MAAM;IACR,WAAW,MAAM;IACjB,SAAS,MAAM;IACf,kBAAkB,MAAM;IACxB,qBAAqB,MAAM;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,GAAG,CAAC;KACf,CAAC;IACF,IAAI,CAAC,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC5D,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,GAAG,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC5D,IAAI,CAAC,EAAE;QACL,KAAK,EAAE,QAAQ,EAAE,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,cAAc,CAAa;gBAGjC,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM;IAoBrC;;OAEG;IACG,aAAa,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IA+EzF;;OAEG;IACH,OAAO,CAAC,YAAY;IAmCpB;;OAEG;YACW,mBAAmB;IA2CjC;;OAEG;YACW,mBAAmB;IA8FjC;;OAEG;YACW,iBAAiB;IA8B/B;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;OAEG;YACW,gBAAgB;IAK9B;;OAEG;YACW,iBAAiB;IAyB/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIvC;;OAEG;IACH,SAAS,IAAI,aAAa;CAG3B"}