@vfarcic/dot-ai 1.0.2 → 1.1.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.
- package/README.md +1 -0
- package/dist/core/ai-provider.interface.d.ts +12 -8
- package/dist/core/ai-provider.interface.d.ts.map +1 -1
- package/dist/core/artifacthub.d.ts +1 -1
- package/dist/core/artifacthub.d.ts.map +1 -1
- package/dist/core/base-vector-service.d.ts +22 -9
- package/dist/core/base-vector-service.d.ts.map +1 -1
- package/dist/core/base-vector-service.js +106 -37
- package/dist/core/capabilities.d.ts.map +1 -1
- package/dist/core/capabilities.js +5 -2
- package/dist/core/capability-operations.d.ts +55 -7
- package/dist/core/capability-operations.d.ts.map +1 -1
- package/dist/core/capability-operations.js +1 -3
- package/dist/core/capability-scan-workflow.d.ts +64 -8
- package/dist/core/capability-scan-workflow.d.ts.map +1 -1
- package/dist/core/capability-scan-workflow.js +14 -13
- package/dist/core/capability-tools.d.ts +1 -1
- package/dist/core/capability-tools.d.ts.map +1 -1
- package/dist/core/capability-tools.js +1 -1
- package/dist/core/capability-vector-service.d.ts +3 -4
- package/dist/core/capability-vector-service.d.ts.map +1 -1
- package/dist/core/capability-vector-service.js +2 -2
- package/dist/core/command-executor.d.ts +3 -4
- package/dist/core/command-executor.d.ts.map +1 -1
- package/dist/core/command-executor.js +8 -4
- package/dist/core/crd-availability.d.ts +3 -5
- package/dist/core/crd-availability.d.ts.map +1 -1
- package/dist/core/crd-availability.js +8 -18
- package/dist/core/deploy-operation.d.ts +6 -5
- package/dist/core/deploy-operation.d.ts.map +1 -1
- package/dist/core/deploy-operation.js +16 -10
- package/dist/core/discovery.d.ts +6 -14
- package/dist/core/discovery.d.ts.map +1 -1
- package/dist/core/discovery.js +35 -51
- package/dist/core/embedding-service.d.ts.map +1 -1
- package/dist/core/embedding-service.js +1 -1
- package/dist/core/error-handling.d.ts +13 -13
- package/dist/core/error-handling.d.ts.map +1 -1
- package/dist/core/error-handling.js +2 -3
- package/dist/core/generic-session-manager.d.ts +2 -2
- package/dist/core/generic-session-manager.d.ts.map +1 -1
- package/dist/core/helm-types.d.ts +5 -5
- package/dist/core/helm-types.d.ts.map +1 -1
- package/dist/core/index.d.ts +4 -11
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +8 -14
- package/dist/core/knowledge-types.d.ts +114 -0
- package/dist/core/knowledge-types.d.ts.map +1 -0
- package/dist/core/knowledge-types.js +10 -0
- package/dist/core/memory.d.ts +12 -12
- package/dist/core/memory.d.ts.map +1 -1
- package/dist/core/mermaid-tools.d.ts +24 -1
- package/dist/core/mermaid-tools.d.ts.map +1 -1
- package/dist/core/mermaid-tools.js +10 -8
- package/dist/core/packaging.d.ts +23 -1
- package/dist/core/packaging.d.ts.map +1 -1
- package/dist/core/pattern-operations.d.ts +32 -9
- package/dist/core/pattern-operations.d.ts.map +1 -1
- package/dist/core/pattern-operations.js +17 -22
- package/dist/core/pattern-vector-service.d.ts +3 -4
- package/dist/core/pattern-vector-service.d.ts.map +1 -1
- package/dist/core/pattern-vector-service.js +2 -2
- package/dist/core/platform-utils.d.ts +2 -2
- package/dist/core/platform-utils.d.ts.map +1 -1
- package/dist/core/plugin-manager.d.ts +6 -2
- package/dist/core/plugin-manager.d.ts.map +1 -1
- package/dist/core/plugin-manager.js +9 -16
- package/dist/core/plugin-registry.d.ts +59 -0
- package/dist/core/plugin-registry.d.ts.map +1 -0
- package/dist/core/plugin-registry.js +80 -0
- package/dist/core/policy-operations.d.ts +101 -21
- package/dist/core/policy-operations.d.ts.map +1 -1
- package/dist/core/policy-operations.js +45 -47
- package/dist/core/policy-vector-service.d.ts +3 -4
- package/dist/core/policy-vector-service.d.ts.map +1 -1
- package/dist/core/policy-vector-service.js +2 -2
- package/dist/core/providers/host-provider.d.ts +1 -1
- package/dist/core/providers/host-provider.d.ts.map +1 -1
- package/dist/core/providers/host-provider.js +2 -2
- package/dist/core/providers/provider-debug-utils.d.ts +2 -2
- package/dist/core/providers/provider-debug-utils.d.ts.map +1 -1
- package/dist/core/providers/tool-utils.d.ts +10 -2
- package/dist/core/providers/tool-utils.d.ts.map +1 -1
- package/dist/core/providers/tool-utils.js +2 -2
- package/dist/core/providers/vercel-provider.d.ts.map +1 -1
- package/dist/core/providers/vercel-provider.js +29 -23
- package/dist/core/resource-tools.d.ts +29 -1
- package/dist/core/resource-tools.d.ts.map +1 -1
- package/dist/core/resource-vector-service.d.ts +3 -4
- package/dist/core/resource-vector-service.d.ts.map +1 -1
- package/dist/core/resource-vector-service.js +2 -2
- package/dist/core/schema.d.ts +15 -14
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +32 -34
- package/dist/core/shared-prompt-loader.d.ts +1 -1
- package/dist/core/shared-prompt-loader.d.ts.map +1 -1
- package/dist/core/solution-cr.js +1 -1
- package/dist/core/solution-utils.d.ts +22 -3
- package/dist/core/solution-utils.d.ts.map +1 -1
- package/dist/core/solution-utils.js +1 -1
- package/dist/core/telemetry/client.d.ts +0 -6
- package/dist/core/telemetry/client.d.ts.map +1 -1
- package/dist/core/telemetry/client.js +6 -17
- package/dist/core/telemetry/config.js +1 -1
- package/dist/core/telemetry/index.d.ts +1 -1
- package/dist/core/telemetry/index.d.ts.map +1 -1
- package/dist/core/telemetry/index.js +1 -2
- package/dist/core/tracing/tool-tracing.d.ts +1 -1
- package/dist/core/tracing/tool-tracing.d.ts.map +1 -1
- package/dist/core/unified-creation-session.d.ts +15 -8
- package/dist/core/unified-creation-session.d.ts.map +1 -1
- package/dist/core/unified-creation-session.js +19 -19
- package/dist/core/unified-creation-types.d.ts +2 -2
- package/dist/core/unified-creation-types.d.ts.map +1 -1
- package/dist/core/visualization.d.ts +1 -1
- package/dist/core/visualization.d.ts.map +1 -1
- package/dist/core/workflow.d.ts +8 -5
- package/dist/core/workflow.d.ts.map +1 -1
- package/dist/evaluation/dataset-analyzer.d.ts +13 -7
- package/dist/evaluation/dataset-analyzer.d.ts.map +1 -1
- package/dist/evaluation/dataset-analyzer.js +1 -1
- package/dist/evaluation/datasets/loader.d.ts +2 -2
- package/dist/evaluation/datasets/loader.d.ts.map +1 -1
- package/dist/evaluation/eval-runner.js +7 -5
- package/dist/evaluation/evaluators/base-comparative.d.ts +1 -1
- package/dist/evaluation/evaluators/base-comparative.d.ts.map +1 -1
- package/dist/evaluation/evaluators/base-comparative.js +4 -3
- package/dist/evaluation/evaluators/base.d.ts +5 -5
- package/dist/evaluation/evaluators/base.d.ts.map +1 -1
- package/dist/evaluation/evaluators/capability-comparative.js +1 -1
- package/dist/evaluation/platform-synthesizer.d.ts.map +1 -1
- package/dist/interfaces/mcp.d.ts.map +1 -1
- package/dist/interfaces/mcp.js +26 -15
- package/dist/interfaces/openapi-generator.d.ts +116 -12
- package/dist/interfaces/openapi-generator.d.ts.map +1 -1
- package/dist/interfaces/openapi-generator.js +490 -199
- package/dist/interfaces/rest-api.d.ts +28 -6
- package/dist/interfaces/rest-api.d.ts.map +1 -1
- package/dist/interfaces/rest-api.js +436 -245
- package/dist/interfaces/rest-registry.d.ts +4 -4
- package/dist/interfaces/rest-registry.d.ts.map +1 -1
- package/dist/interfaces/rest-registry.js +6 -5
- package/dist/interfaces/rest-route-registry.d.ts +165 -0
- package/dist/interfaces/rest-route-registry.d.ts.map +1 -0
- package/dist/interfaces/rest-route-registry.js +230 -0
- package/dist/interfaces/routes/index.d.ts +22 -0
- package/dist/interfaces/routes/index.d.ts.map +1 -0
- package/dist/interfaces/routes/index.js +347 -0
- package/dist/interfaces/schemas/common.d.ts +177 -0
- package/dist/interfaces/schemas/common.d.ts.map +1 -0
- package/dist/interfaces/schemas/common.js +102 -0
- package/dist/interfaces/schemas/events.d.ts +131 -0
- package/dist/interfaces/schemas/events.d.ts.map +1 -0
- package/dist/interfaces/schemas/events.js +66 -0
- package/dist/interfaces/schemas/index.d.ts +21 -0
- package/dist/interfaces/schemas/index.d.ts.map +1 -0
- package/dist/interfaces/schemas/index.js +138 -0
- package/dist/interfaces/schemas/knowledge.d.ts +210 -0
- package/dist/interfaces/schemas/knowledge.d.ts.map +1 -0
- package/dist/interfaces/schemas/knowledge.js +117 -0
- package/dist/interfaces/schemas/logs.d.ts +82 -0
- package/dist/interfaces/schemas/logs.d.ts.map +1 -0
- package/dist/interfaces/schemas/logs.js +46 -0
- package/dist/interfaces/schemas/prompts.d.ts +191 -0
- package/dist/interfaces/schemas/prompts.d.ts.map +1 -0
- package/dist/interfaces/schemas/prompts.js +91 -0
- package/dist/interfaces/schemas/resources.d.ts +378 -0
- package/dist/interfaces/schemas/resources.d.ts.map +1 -0
- package/dist/interfaces/schemas/resources.js +173 -0
- package/dist/interfaces/schemas/sessions.d.ts +90 -0
- package/dist/interfaces/schemas/sessions.d.ts.map +1 -0
- package/dist/interfaces/schemas/sessions.js +56 -0
- package/dist/interfaces/schemas/tools.d.ts +194 -0
- package/dist/interfaces/schemas/tools.d.ts.map +1 -0
- package/dist/interfaces/schemas/tools.js +101 -0
- package/dist/interfaces/schemas/visualization.d.ts +373 -0
- package/dist/interfaces/schemas/visualization.d.ts.map +1 -0
- package/dist/interfaces/schemas/visualization.js +134 -0
- package/dist/mcp/server.js +5 -4
- package/dist/tools/answer-question.d.ts +1 -1
- package/dist/tools/answer-question.d.ts.map +1 -1
- package/dist/tools/answer-question.js +9 -8
- package/dist/tools/deploy-manifests.d.ts +4 -2
- package/dist/tools/deploy-manifests.d.ts.map +1 -1
- package/dist/tools/deploy-manifests.js +10 -6
- package/dist/tools/generate-manifests.d.ts.map +1 -1
- package/dist/tools/generate-manifests.js +28 -20
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +6 -1
- package/dist/tools/manage-knowledge.d.ts +77 -0
- package/dist/tools/manage-knowledge.d.ts.map +1 -0
- package/dist/tools/manage-knowledge.js +573 -0
- package/dist/tools/operate-analysis.d.ts +31 -2
- package/dist/tools/operate-analysis.d.ts.map +1 -1
- package/dist/tools/operate-execution.d.ts +2 -3
- package/dist/tools/operate-execution.d.ts.map +1 -1
- package/dist/tools/operate-execution.js +7 -7
- package/dist/tools/operate.d.ts +7 -2
- package/dist/tools/operate.d.ts.map +1 -1
- package/dist/tools/operate.js +2 -2
- package/dist/tools/organizational-data.d.ts +30 -4
- package/dist/tools/organizational-data.d.ts.map +1 -1
- package/dist/tools/organizational-data.js +24 -19
- package/dist/tools/project-setup/discovery.d.ts.map +1 -1
- package/dist/tools/project-setup/generate-scope.d.ts +1 -1
- package/dist/tools/project-setup/generate-scope.d.ts.map +1 -1
- package/dist/tools/project-setup/types.d.ts +1 -0
- package/dist/tools/project-setup/types.d.ts.map +1 -1
- package/dist/tools/prompts.d.ts +28 -2
- package/dist/tools/prompts.d.ts.map +1 -1
- package/dist/tools/query.d.ts +17 -3
- package/dist/tools/query.d.ts.map +1 -1
- package/dist/tools/query.js +1 -7
- package/dist/tools/recommend.d.ts +24 -6
- package/dist/tools/recommend.d.ts.map +1 -1
- package/dist/tools/recommend.js +18 -15
- package/dist/tools/remediate.d.ts +12 -3
- package/dist/tools/remediate.d.ts.map +1 -1
- package/dist/tools/remediate.js +22 -14
- package/dist/tools/version.d.ts +19 -5
- package/dist/tools/version.d.ts.map +1 -1
- package/dist/tools/version.js +106 -54
- package/package.json +11 -5
- package/prompts/knowledge-ask.md +29 -0
- package/dist/core/vector-db-service.d.ts +0 -108
- package/dist/core/vector-db-service.d.ts.map +0 -1
- package/dist/core/vector-db-service.js +0 -647
|
@@ -2,23 +2,31 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* OpenAPI 3.0 Specification Generator
|
|
4
4
|
*
|
|
5
|
-
* Automatically generates OpenAPI 3.0 documentation from the tool registry
|
|
6
|
-
*
|
|
5
|
+
* Automatically generates OpenAPI 3.0 documentation from the tool registry
|
|
6
|
+
* and REST route registry.
|
|
7
|
+
*
|
|
8
|
+
* PRD #354: REST API Route Registry with Auto-Generated OpenAPI and Test Fixtures
|
|
9
|
+
* - Generates paths from RestRouteRegistry for all REST endpoints
|
|
10
|
+
* - Converts Zod schemas to JSON Schema for complete API documentation
|
|
7
11
|
*/
|
|
8
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
13
|
exports.OpenApiGenerator = void 0;
|
|
14
|
+
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
10
15
|
/**
|
|
11
16
|
* OpenAPI 3.0 specification generator
|
|
12
17
|
*/
|
|
13
18
|
class OpenApiGenerator {
|
|
14
|
-
|
|
19
|
+
toolRegistry;
|
|
20
|
+
routeRegistry;
|
|
15
21
|
logger;
|
|
16
22
|
config;
|
|
17
23
|
specCache;
|
|
18
24
|
lastCacheUpdate = 0;
|
|
19
25
|
cacheValidityMs = 60000; // 1 minute
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
schemaCache = new Map();
|
|
27
|
+
constructor(toolRegistry, logger, config = {}, routeRegistry) {
|
|
28
|
+
this.toolRegistry = toolRegistry;
|
|
29
|
+
this.routeRegistry = routeRegistry;
|
|
22
30
|
this.logger = logger;
|
|
23
31
|
this.config = {
|
|
24
32
|
title: 'DevOps AI Toolkit REST API',
|
|
@@ -27,7 +35,7 @@ class OpenApiGenerator {
|
|
|
27
35
|
basePath: '/api',
|
|
28
36
|
apiVersion: 'v1',
|
|
29
37
|
serverUrl: 'http://localhost:3456',
|
|
30
|
-
...config
|
|
38
|
+
...config,
|
|
31
39
|
};
|
|
32
40
|
}
|
|
33
41
|
/**
|
|
@@ -36,23 +44,45 @@ class OpenApiGenerator {
|
|
|
36
44
|
generateSpec() {
|
|
37
45
|
// Check cache validity
|
|
38
46
|
const now = Date.now();
|
|
39
|
-
if (this.specCache &&
|
|
47
|
+
if (this.specCache && now - this.lastCacheUpdate < this.cacheValidityMs) {
|
|
40
48
|
this.logger.debug('Returning cached OpenAPI specification');
|
|
41
49
|
return this.specCache;
|
|
42
50
|
}
|
|
43
51
|
this.logger.info('Generating OpenAPI 3.0 specification', {
|
|
44
|
-
toolCount: this.
|
|
45
|
-
|
|
52
|
+
toolCount: this.toolRegistry.getToolCount(),
|
|
53
|
+
routeCount: this.routeRegistry?.getRouteCount() ?? 0,
|
|
54
|
+
cacheExpired: !this.specCache || now - this.lastCacheUpdate >= this.cacheValidityMs,
|
|
46
55
|
});
|
|
47
|
-
const tools = this.
|
|
48
|
-
const categories = this.
|
|
56
|
+
const tools = this.toolRegistry.getAllTools();
|
|
57
|
+
const categories = this.toolRegistry.getCategories();
|
|
58
|
+
// Generate paths from tool registry (MCP tools)
|
|
59
|
+
const toolPaths = this.generateToolPaths(tools);
|
|
60
|
+
// Generate paths from route registry (REST endpoints) - PRD #354
|
|
61
|
+
const routePaths = this.routeRegistry
|
|
62
|
+
? this.generateRoutePaths()
|
|
63
|
+
: {};
|
|
64
|
+
// Generate component schemas
|
|
65
|
+
const toolSchemas = this.generateToolSchemas(tools);
|
|
66
|
+
const routeSchemas = this.routeRegistry
|
|
67
|
+
? this.generateRouteSchemas()
|
|
68
|
+
: {};
|
|
49
69
|
const spec = {
|
|
50
70
|
openapi: '3.0.0',
|
|
51
71
|
info: this.generateInfo(),
|
|
52
72
|
servers: this.generateServers(),
|
|
53
|
-
paths:
|
|
54
|
-
|
|
55
|
-
|
|
73
|
+
paths: {
|
|
74
|
+
...this.generateBasePaths(),
|
|
75
|
+
...toolPaths,
|
|
76
|
+
...routePaths,
|
|
77
|
+
},
|
|
78
|
+
components: {
|
|
79
|
+
schemas: {
|
|
80
|
+
...this.generateBaseSchemas(),
|
|
81
|
+
...toolSchemas,
|
|
82
|
+
...routeSchemas,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
tags: this.generateTags(categories),
|
|
56
86
|
};
|
|
57
87
|
// Cache the generated spec
|
|
58
88
|
this.specCache = spec;
|
|
@@ -60,7 +90,7 @@ class OpenApiGenerator {
|
|
|
60
90
|
this.logger.info('OpenAPI specification generated successfully', {
|
|
61
91
|
pathCount: Object.keys(spec.paths).length,
|
|
62
92
|
componentCount: Object.keys(spec.components?.schemas || {}).length,
|
|
63
|
-
tagCount: spec.tags?.length || 0
|
|
93
|
+
tagCount: spec.tags?.length || 0,
|
|
64
94
|
});
|
|
65
95
|
return spec;
|
|
66
96
|
}
|
|
@@ -96,11 +126,10 @@ class OpenApiGenerator {
|
|
|
96
126
|
];
|
|
97
127
|
}
|
|
98
128
|
/**
|
|
99
|
-
* Generate paths
|
|
129
|
+
* Generate base paths (MCP Protocol endpoints)
|
|
100
130
|
*/
|
|
101
|
-
|
|
131
|
+
generateBasePaths() {
|
|
102
132
|
const paths = {};
|
|
103
|
-
const basePath = `${this.config.basePath}/${this.config.apiVersion}`;
|
|
104
133
|
// MCP Protocol Endpoints
|
|
105
134
|
paths['/'] = {
|
|
106
135
|
get: {
|
|
@@ -115,20 +144,20 @@ class OpenApiGenerator {
|
|
|
115
144
|
'text/event-stream': {
|
|
116
145
|
schema: {
|
|
117
146
|
type: 'string',
|
|
118
|
-
description: 'Server-Sent Events stream'
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
147
|
+
description: 'Server-Sent Events stream',
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
},
|
|
122
151
|
},
|
|
123
152
|
405: {
|
|
124
153
|
description: 'Method not allowed - server does not support SSE',
|
|
125
154
|
content: {
|
|
126
155
|
'application/json': {
|
|
127
|
-
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
156
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' },
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
},
|
|
132
161
|
},
|
|
133
162
|
post: {
|
|
134
163
|
summary: 'Send MCP JSON-RPC message',
|
|
@@ -151,10 +180,10 @@ class OpenApiGenerator {
|
|
|
151
180
|
capabilities: {},
|
|
152
181
|
clientInfo: {
|
|
153
182
|
name: 'example-client',
|
|
154
|
-
version: '1.0.0'
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
183
|
+
version: '1.0.0',
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
},
|
|
158
187
|
},
|
|
159
188
|
toolCall: {
|
|
160
189
|
summary: 'Call a tool',
|
|
@@ -164,81 +193,48 @@ class OpenApiGenerator {
|
|
|
164
193
|
method: 'tools/call',
|
|
165
194
|
params: {
|
|
166
195
|
name: 'version',
|
|
167
|
-
arguments: {}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
196
|
+
arguments: {},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
},
|
|
174
203
|
},
|
|
175
204
|
responses: {
|
|
176
205
|
200: {
|
|
177
206
|
description: 'JSON-RPC response or SSE stream',
|
|
178
207
|
content: {
|
|
179
208
|
'application/json': {
|
|
180
|
-
schema: { $ref: '#/components/schemas/McpJsonRpcResponse' }
|
|
209
|
+
schema: { $ref: '#/components/schemas/McpJsonRpcResponse' },
|
|
181
210
|
},
|
|
182
211
|
'text/event-stream': {
|
|
183
212
|
schema: {
|
|
184
213
|
type: 'string',
|
|
185
|
-
description: 'Server-Sent Events stream with JSON-RPC messages'
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
214
|
+
description: 'Server-Sent Events stream with JSON-RPC messages',
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
189
218
|
},
|
|
190
219
|
400: {
|
|
191
220
|
description: 'Bad request - invalid JSON-RPC message',
|
|
192
221
|
content: {
|
|
193
222
|
'application/json': {
|
|
194
|
-
schema: { $ref: '#/components/schemas/McpJsonRpcError' }
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
// Tool discovery endpoint
|
|
202
|
-
paths[`${basePath}/tools`] = {
|
|
203
|
-
get: {
|
|
204
|
-
summary: 'Discover available tools',
|
|
205
|
-
description: 'Get a list of all available tools with their schemas and metadata',
|
|
206
|
-
tags: ['Tool Discovery'],
|
|
207
|
-
parameters: [
|
|
208
|
-
{
|
|
209
|
-
name: 'category',
|
|
210
|
-
in: 'query',
|
|
211
|
-
description: 'Filter tools by category',
|
|
212
|
-
required: false,
|
|
213
|
-
schema: { type: 'string' }
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
name: 'tag',
|
|
217
|
-
in: 'query',
|
|
218
|
-
description: 'Filter tools by tag',
|
|
219
|
-
required: false,
|
|
220
|
-
schema: { type: 'string' }
|
|
223
|
+
schema: { $ref: '#/components/schemas/McpJsonRpcError' },
|
|
224
|
+
},
|
|
225
|
+
},
|
|
221
226
|
},
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
in: 'query',
|
|
225
|
-
description: 'Search tools by name or description',
|
|
226
|
-
required: false,
|
|
227
|
-
schema: { type: 'string' }
|
|
228
|
-
}
|
|
229
|
-
],
|
|
230
|
-
responses: {
|
|
231
|
-
200: {
|
|
232
|
-
description: 'List of available tools',
|
|
233
|
-
content: {
|
|
234
|
-
'application/json': {
|
|
235
|
-
schema: { $ref: '#/components/schemas/ToolDiscoveryResponse' }
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
227
|
+
},
|
|
228
|
+
},
|
|
241
229
|
};
|
|
230
|
+
return paths;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Generate paths for MCP tool endpoints
|
|
234
|
+
*/
|
|
235
|
+
generateToolPaths(tools) {
|
|
236
|
+
const paths = {};
|
|
237
|
+
const basePath = `${this.config.basePath}/${this.config.apiVersion}`;
|
|
242
238
|
// Individual tool execution endpoints
|
|
243
239
|
for (const tool of tools) {
|
|
244
240
|
paths[`${basePath}/tools/${tool.name}`] = {
|
|
@@ -251,99 +247,303 @@ class OpenApiGenerator {
|
|
|
251
247
|
content: {
|
|
252
248
|
'application/json': {
|
|
253
249
|
schema: { $ref: `#/components/schemas/${tool.name}Request` },
|
|
254
|
-
example: this.generateExampleForTool(tool)
|
|
255
|
-
}
|
|
256
|
-
}
|
|
250
|
+
example: this.generateExampleForTool(tool),
|
|
251
|
+
},
|
|
252
|
+
},
|
|
257
253
|
},
|
|
258
254
|
responses: {
|
|
259
255
|
200: {
|
|
260
256
|
description: 'Tool execution result',
|
|
261
257
|
content: {
|
|
262
258
|
'application/json': {
|
|
263
|
-
schema: { $ref: '#/components/schemas/ToolExecutionResponse' }
|
|
264
|
-
}
|
|
265
|
-
}
|
|
259
|
+
schema: { $ref: '#/components/schemas/ToolExecutionResponse' },
|
|
260
|
+
},
|
|
261
|
+
},
|
|
266
262
|
},
|
|
267
263
|
400: {
|
|
268
264
|
description: 'Bad request - invalid parameters',
|
|
269
265
|
content: {
|
|
270
266
|
'application/json': {
|
|
271
|
-
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
272
|
-
}
|
|
273
|
-
}
|
|
267
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' },
|
|
268
|
+
},
|
|
269
|
+
},
|
|
274
270
|
},
|
|
275
271
|
404: {
|
|
276
272
|
description: 'Tool not found',
|
|
277
273
|
content: {
|
|
278
274
|
'application/json': {
|
|
279
|
-
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
280
|
-
}
|
|
281
|
-
}
|
|
275
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' },
|
|
276
|
+
},
|
|
277
|
+
},
|
|
282
278
|
},
|
|
283
279
|
500: {
|
|
284
280
|
description: 'Internal server error',
|
|
285
281
|
content: {
|
|
286
282
|
'application/json': {
|
|
287
|
-
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
283
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' },
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
},
|
|
293
289
|
};
|
|
294
290
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
291
|
+
return paths;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Generate paths from REST route registry
|
|
295
|
+
* PRD #354: Auto-generates OpenAPI paths from registered routes
|
|
296
|
+
*/
|
|
297
|
+
generateRoutePaths() {
|
|
298
|
+
if (!this.routeRegistry) {
|
|
299
|
+
return {};
|
|
300
|
+
}
|
|
301
|
+
const paths = {};
|
|
302
|
+
const routes = this.routeRegistry.getAllRoutes();
|
|
303
|
+
for (const route of routes) {
|
|
304
|
+
const openApiPath = this.convertPathToOpenApi(route.path);
|
|
305
|
+
const method = route.method.toLowerCase();
|
|
306
|
+
// Initialize path object if not exists
|
|
307
|
+
if (!paths[openApiPath]) {
|
|
308
|
+
paths[openApiPath] = {};
|
|
314
309
|
}
|
|
315
|
-
|
|
310
|
+
paths[openApiPath][method] = this.routeToOpenApiOperation(route);
|
|
311
|
+
}
|
|
316
312
|
return paths;
|
|
317
313
|
}
|
|
318
314
|
/**
|
|
319
|
-
*
|
|
315
|
+
* Convert Express-style path to OpenAPI path format
|
|
316
|
+
* Example: "/api/v1/visualize/:sessionId" -> "/api/v1/visualize/{sessionId}"
|
|
317
|
+
*/
|
|
318
|
+
convertPathToOpenApi(path) {
|
|
319
|
+
return path.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, '{$1}');
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Convert a route definition to an OpenAPI operation object
|
|
323
|
+
*/
|
|
324
|
+
routeToOpenApiOperation(route) {
|
|
325
|
+
const operation = {
|
|
326
|
+
summary: route.description,
|
|
327
|
+
description: route.description,
|
|
328
|
+
tags: route.tags,
|
|
329
|
+
responses: {},
|
|
330
|
+
};
|
|
331
|
+
// Add path parameters
|
|
332
|
+
const pathParams = this.extractPathParams(route.path);
|
|
333
|
+
if (pathParams.length > 0 || route.query) {
|
|
334
|
+
operation.parameters = [];
|
|
335
|
+
// Add path parameters
|
|
336
|
+
for (const paramName of pathParams) {
|
|
337
|
+
const paramSchema = this.getParamSchemaFromRoute(route, paramName);
|
|
338
|
+
operation.parameters.push({
|
|
339
|
+
name: paramName,
|
|
340
|
+
in: 'path',
|
|
341
|
+
required: true,
|
|
342
|
+
description: paramSchema?.description || `${paramName} parameter`,
|
|
343
|
+
schema: paramSchema || { type: 'string' },
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
// Add query parameters from Zod schema
|
|
347
|
+
if (route.query) {
|
|
348
|
+
const queryParams = this.zodSchemaToParameters(route.query, 'query');
|
|
349
|
+
operation.parameters.push(...queryParams);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// Add request body for POST/PUT/DELETE with body schema
|
|
353
|
+
if (route.body && ['POST', 'PUT', 'DELETE'].includes(route.method)) {
|
|
354
|
+
const schemaName = this.getSchemaName(route, 'Request');
|
|
355
|
+
operation.requestBody = {
|
|
356
|
+
required: true,
|
|
357
|
+
content: {
|
|
358
|
+
'application/json': {
|
|
359
|
+
schema: { $ref: `#/components/schemas/${schemaName}` },
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
// Add success response
|
|
365
|
+
const responseSchemaName = this.getSchemaName(route, 'Response');
|
|
366
|
+
operation.responses['200'] = {
|
|
367
|
+
description: 'Successful response',
|
|
368
|
+
content: {
|
|
369
|
+
'application/json': {
|
|
370
|
+
schema: { $ref: `#/components/schemas/${responseSchemaName}` },
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
};
|
|
374
|
+
// Add error responses
|
|
375
|
+
if (route.errorResponses) {
|
|
376
|
+
for (const statusCode of Object.keys(route.errorResponses)) {
|
|
377
|
+
const errorSchemaName = this.getSchemaName(route, `Error${statusCode}`);
|
|
378
|
+
operation.responses[statusCode] = {
|
|
379
|
+
description: this.getErrorDescription(Number(statusCode)),
|
|
380
|
+
content: {
|
|
381
|
+
'application/json': {
|
|
382
|
+
schema: { $ref: `#/components/schemas/${errorSchemaName}` },
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return operation;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Extract path parameter names from a route path
|
|
320
392
|
*/
|
|
321
|
-
|
|
393
|
+
extractPathParams(path) {
|
|
394
|
+
const params = [];
|
|
395
|
+
const regex = /:([a-zA-Z_][a-zA-Z0-9_]*)/g;
|
|
396
|
+
let match;
|
|
397
|
+
while ((match = regex.exec(path)) !== null) {
|
|
398
|
+
params.push(match[1]);
|
|
399
|
+
}
|
|
400
|
+
return params;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Get parameter schema from route's params Zod schema
|
|
404
|
+
*/
|
|
405
|
+
getParamSchemaFromRoute(route, paramName) {
|
|
406
|
+
if (!route.params) {
|
|
407
|
+
return { type: 'string' };
|
|
408
|
+
}
|
|
409
|
+
try {
|
|
410
|
+
const jsonSchema = this.zodSchemaToJsonSchema(route.params);
|
|
411
|
+
return jsonSchema.properties?.[paramName] || { type: 'string' };
|
|
412
|
+
}
|
|
413
|
+
catch {
|
|
414
|
+
return { type: 'string' };
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Convert Zod schema to OpenAPI parameters array
|
|
419
|
+
*/
|
|
420
|
+
zodSchemaToParameters(schema, location) {
|
|
421
|
+
const parameters = [];
|
|
422
|
+
try {
|
|
423
|
+
const jsonSchema = this.zodSchemaToJsonSchema(schema);
|
|
424
|
+
const properties = jsonSchema.properties || {};
|
|
425
|
+
const required = jsonSchema.required || [];
|
|
426
|
+
for (const [name, propSchema] of Object.entries(properties)) {
|
|
427
|
+
const propObj = propSchema;
|
|
428
|
+
parameters.push({
|
|
429
|
+
name,
|
|
430
|
+
in: location,
|
|
431
|
+
required: required.includes(name),
|
|
432
|
+
description: propObj.description || `${name} parameter`,
|
|
433
|
+
schema: propObj,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
this.logger.warn('Failed to convert Zod schema to parameters', {
|
|
439
|
+
error: error instanceof Error ? error.message : String(error),
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
return parameters;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Generate unique schema name for a route
|
|
446
|
+
*/
|
|
447
|
+
getSchemaName(route, suffix) {
|
|
448
|
+
// Convert path to PascalCase name
|
|
449
|
+
// e.g., "/api/v1/visualize/:sessionId" -> "VisualizeSessionId"
|
|
450
|
+
const pathParts = route.path
|
|
451
|
+
.replace(/^\/api\/v\d+\//, '') // Remove /api/v1/ prefix
|
|
452
|
+
.split('/')
|
|
453
|
+
.filter((part) => part.length > 0)
|
|
454
|
+
.map((part) => {
|
|
455
|
+
// Remove : prefix for params and capitalize
|
|
456
|
+
const cleaned = part.replace(/^:/, '');
|
|
457
|
+
return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
|
|
458
|
+
});
|
|
459
|
+
const baseName = pathParts.join('');
|
|
460
|
+
return `${baseName}${route.method.charAt(0)}${route.method.slice(1).toLowerCase()}${suffix}`;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Get human-readable error description for status code
|
|
464
|
+
*/
|
|
465
|
+
getErrorDescription(statusCode) {
|
|
466
|
+
const descriptions = {
|
|
467
|
+
400: 'Bad request - invalid parameters',
|
|
468
|
+
401: 'Unauthorized - authentication required',
|
|
469
|
+
403: 'Forbidden - insufficient permissions',
|
|
470
|
+
404: 'Not found',
|
|
471
|
+
405: 'Method not allowed',
|
|
472
|
+
409: 'Conflict',
|
|
473
|
+
422: 'Unprocessable entity',
|
|
474
|
+
500: 'Internal server error',
|
|
475
|
+
502: 'Bad gateway',
|
|
476
|
+
503: 'Service unavailable',
|
|
477
|
+
};
|
|
478
|
+
return descriptions[statusCode] || `Error ${statusCode}`;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Convert Zod schema to JSON Schema with caching
|
|
482
|
+
*/
|
|
483
|
+
zodSchemaToJsonSchema(schema) {
|
|
484
|
+
const cacheKey = JSON.stringify(schema);
|
|
485
|
+
if (this.schemaCache.has(cacheKey)) {
|
|
486
|
+
return this.schemaCache.get(cacheKey);
|
|
487
|
+
}
|
|
488
|
+
try {
|
|
489
|
+
// The zodToJsonSchema function accepts ZodSchema but TypeScript needs a cast
|
|
490
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Zod type compatibility workaround
|
|
491
|
+
const jsonSchema = (0, zod_to_json_schema_1.zodToJsonSchema)(schema, {
|
|
492
|
+
target: 'openApi3',
|
|
493
|
+
$refStrategy: 'none', // Inline all schemas
|
|
494
|
+
});
|
|
495
|
+
// Remove $schema property if present (not valid in OpenAPI component schemas)
|
|
496
|
+
const result = { ...jsonSchema };
|
|
497
|
+
delete result.$schema;
|
|
498
|
+
this.schemaCache.set(cacheKey, result);
|
|
499
|
+
return result;
|
|
500
|
+
}
|
|
501
|
+
catch (error) {
|
|
502
|
+
this.logger.warn('Failed to convert Zod schema to JSON Schema', {
|
|
503
|
+
error: error instanceof Error ? error.message : String(error),
|
|
504
|
+
});
|
|
505
|
+
return { type: 'object' };
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Generate base component schemas (shared across all endpoints)
|
|
510
|
+
*/
|
|
511
|
+
generateBaseSchemas() {
|
|
322
512
|
const schemas = {};
|
|
323
513
|
// Base response schemas
|
|
324
514
|
schemas.RestApiResponse = {
|
|
325
515
|
type: 'object',
|
|
326
516
|
properties: {
|
|
327
|
-
success: {
|
|
517
|
+
success: {
|
|
518
|
+
type: 'boolean',
|
|
519
|
+
description: 'Whether the request was successful',
|
|
520
|
+
},
|
|
328
521
|
data: { type: 'object', description: 'Response data' },
|
|
329
522
|
error: {
|
|
330
523
|
type: 'object',
|
|
331
524
|
properties: {
|
|
332
525
|
code: { type: 'string', description: 'Error code' },
|
|
333
526
|
message: { type: 'string', description: 'Error message' },
|
|
334
|
-
details: { type: 'object', description: 'Additional error details' }
|
|
335
|
-
}
|
|
527
|
+
details: { type: 'object', description: 'Additional error details' },
|
|
528
|
+
},
|
|
336
529
|
},
|
|
337
530
|
meta: {
|
|
338
531
|
type: 'object',
|
|
339
532
|
properties: {
|
|
340
|
-
timestamp: {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
533
|
+
timestamp: {
|
|
534
|
+
type: 'string',
|
|
535
|
+
format: 'date-time',
|
|
536
|
+
description: 'Response timestamp',
|
|
537
|
+
},
|
|
538
|
+
requestId: {
|
|
539
|
+
type: 'string',
|
|
540
|
+
description: 'Unique request identifier',
|
|
541
|
+
},
|
|
542
|
+
version: { type: 'string', description: 'API version' },
|
|
543
|
+
},
|
|
544
|
+
},
|
|
345
545
|
},
|
|
346
|
-
required: ['success']
|
|
546
|
+
required: ['success'],
|
|
347
547
|
};
|
|
348
548
|
schemas.ToolExecutionResponse = {
|
|
349
549
|
allOf: [
|
|
@@ -354,14 +554,23 @@ class OpenApiGenerator {
|
|
|
354
554
|
data: {
|
|
355
555
|
type: 'object',
|
|
356
556
|
properties: {
|
|
357
|
-
result: {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
557
|
+
result: {
|
|
558
|
+
type: 'object',
|
|
559
|
+
description: 'Tool execution result',
|
|
560
|
+
},
|
|
561
|
+
tool: {
|
|
562
|
+
type: 'string',
|
|
563
|
+
description: 'Name of the executed tool',
|
|
564
|
+
},
|
|
565
|
+
executionTime: {
|
|
566
|
+
type: 'number',
|
|
567
|
+
description: 'Execution time in milliseconds',
|
|
568
|
+
},
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
},
|
|
573
|
+
],
|
|
365
574
|
};
|
|
366
575
|
schemas.ToolDiscoveryResponse = {
|
|
367
576
|
allOf: [
|
|
@@ -374,24 +583,27 @@ class OpenApiGenerator {
|
|
|
374
583
|
properties: {
|
|
375
584
|
tools: {
|
|
376
585
|
type: 'array',
|
|
377
|
-
items: { $ref: '#/components/schemas/ToolInfo' }
|
|
586
|
+
items: { $ref: '#/components/schemas/ToolInfo' },
|
|
587
|
+
},
|
|
588
|
+
total: {
|
|
589
|
+
type: 'number',
|
|
590
|
+
description: 'Total number of tools',
|
|
378
591
|
},
|
|
379
|
-
total: { type: 'number', description: 'Total number of tools' },
|
|
380
592
|
categories: {
|
|
381
593
|
type: 'array',
|
|
382
594
|
items: { type: 'string' },
|
|
383
|
-
description: 'Available tool categories'
|
|
595
|
+
description: 'Available tool categories',
|
|
384
596
|
},
|
|
385
597
|
tags: {
|
|
386
598
|
type: 'array',
|
|
387
599
|
items: { type: 'string' },
|
|
388
|
-
description: 'Available tool tags'
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
]
|
|
600
|
+
description: 'Available tool tags',
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
},
|
|
605
|
+
},
|
|
606
|
+
],
|
|
395
607
|
};
|
|
396
608
|
schemas.ToolInfo = {
|
|
397
609
|
type: 'object',
|
|
@@ -403,10 +615,10 @@ class OpenApiGenerator {
|
|
|
403
615
|
tags: {
|
|
404
616
|
type: 'array',
|
|
405
617
|
items: { type: 'string' },
|
|
406
|
-
description: 'Tool tags'
|
|
407
|
-
}
|
|
618
|
+
description: 'Tool tags',
|
|
619
|
+
},
|
|
408
620
|
},
|
|
409
|
-
required: ['name', 'description', 'schema']
|
|
621
|
+
required: ['name', 'description', 'schema'],
|
|
410
622
|
};
|
|
411
623
|
schemas.ErrorResponse = {
|
|
412
624
|
allOf: [
|
|
@@ -420,70 +632,128 @@ class OpenApiGenerator {
|
|
|
420
632
|
properties: {
|
|
421
633
|
code: { type: 'string' },
|
|
422
634
|
message: { type: 'string' },
|
|
423
|
-
details: { type: 'object' }
|
|
635
|
+
details: { type: 'object' },
|
|
424
636
|
},
|
|
425
|
-
required: ['code', 'message']
|
|
426
|
-
}
|
|
637
|
+
required: ['code', 'message'],
|
|
638
|
+
},
|
|
427
639
|
},
|
|
428
|
-
required: ['error']
|
|
429
|
-
}
|
|
430
|
-
]
|
|
640
|
+
required: ['error'],
|
|
641
|
+
},
|
|
642
|
+
],
|
|
431
643
|
};
|
|
432
644
|
// MCP JSON-RPC schemas
|
|
433
645
|
schemas.McpJsonRpcRequest = {
|
|
434
646
|
type: 'object',
|
|
435
647
|
description: 'JSON-RPC 2.0 request message for MCP protocol',
|
|
436
648
|
properties: {
|
|
437
|
-
jsonrpc: {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
649
|
+
jsonrpc: {
|
|
650
|
+
type: 'string',
|
|
651
|
+
enum: ['2.0'],
|
|
652
|
+
description: 'JSON-RPC version',
|
|
653
|
+
},
|
|
654
|
+
id: {
|
|
655
|
+
type: ['number', 'string', 'null'],
|
|
656
|
+
description: 'Request identifier',
|
|
657
|
+
},
|
|
658
|
+
method: {
|
|
659
|
+
type: 'string',
|
|
660
|
+
description: 'Method name (e.g., initialize, tools/call, tools/list)',
|
|
661
|
+
},
|
|
662
|
+
params: { type: 'object', description: 'Method parameters' },
|
|
441
663
|
},
|
|
442
|
-
required: ['jsonrpc', 'method']
|
|
664
|
+
required: ['jsonrpc', 'method'],
|
|
443
665
|
};
|
|
444
666
|
schemas.McpJsonRpcResponse = {
|
|
445
667
|
type: 'object',
|
|
446
668
|
description: 'JSON-RPC 2.0 response message',
|
|
447
669
|
properties: {
|
|
448
|
-
jsonrpc: {
|
|
449
|
-
|
|
670
|
+
jsonrpc: {
|
|
671
|
+
type: 'string',
|
|
672
|
+
enum: ['2.0'],
|
|
673
|
+
description: 'JSON-RPC version',
|
|
674
|
+
},
|
|
675
|
+
id: {
|
|
676
|
+
type: ['number', 'string', 'null'],
|
|
677
|
+
description: 'Request identifier',
|
|
678
|
+
},
|
|
450
679
|
result: { type: 'object', description: 'Method result' },
|
|
451
680
|
error: {
|
|
452
681
|
type: 'object',
|
|
453
682
|
properties: {
|
|
454
683
|
code: { type: 'number', description: 'Error code' },
|
|
455
684
|
message: { type: 'string', description: 'Error message' },
|
|
456
|
-
data: { type: 'object', description: 'Additional error data' }
|
|
457
|
-
}
|
|
458
|
-
}
|
|
685
|
+
data: { type: 'object', description: 'Additional error data' },
|
|
686
|
+
},
|
|
687
|
+
},
|
|
459
688
|
},
|
|
460
|
-
required: ['jsonrpc', 'id']
|
|
689
|
+
required: ['jsonrpc', 'id'],
|
|
461
690
|
};
|
|
462
691
|
schemas.McpJsonRpcError = {
|
|
463
692
|
type: 'object',
|
|
464
693
|
description: 'JSON-RPC 2.0 error response',
|
|
465
694
|
properties: {
|
|
466
|
-
jsonrpc: {
|
|
467
|
-
|
|
695
|
+
jsonrpc: {
|
|
696
|
+
type: 'string',
|
|
697
|
+
enum: ['2.0'],
|
|
698
|
+
description: 'JSON-RPC version',
|
|
699
|
+
},
|
|
700
|
+
id: {
|
|
701
|
+
type: ['number', 'string', 'null'],
|
|
702
|
+
description: 'Request identifier',
|
|
703
|
+
},
|
|
468
704
|
error: {
|
|
469
705
|
type: 'object',
|
|
470
706
|
properties: {
|
|
471
707
|
code: { type: 'number', description: 'Error code' },
|
|
472
708
|
message: { type: 'string', description: 'Error message' },
|
|
473
|
-
data: { type: 'object', description: 'Additional error data' }
|
|
709
|
+
data: { type: 'object', description: 'Additional error data' },
|
|
474
710
|
},
|
|
475
|
-
required: ['code', 'message']
|
|
476
|
-
}
|
|
711
|
+
required: ['code', 'message'],
|
|
712
|
+
},
|
|
477
713
|
},
|
|
478
|
-
required: ['jsonrpc', 'id', 'error']
|
|
714
|
+
required: ['jsonrpc', 'id', 'error'],
|
|
479
715
|
};
|
|
716
|
+
return schemas;
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Generate schemas for MCP tool endpoints
|
|
720
|
+
*/
|
|
721
|
+
generateToolSchemas(tools) {
|
|
722
|
+
const schemas = {};
|
|
480
723
|
// Individual tool request schemas
|
|
481
724
|
for (const tool of tools) {
|
|
482
725
|
schemas[`${tool.name}Request`] = tool.schema;
|
|
483
726
|
}
|
|
484
|
-
return
|
|
485
|
-
|
|
486
|
-
|
|
727
|
+
return schemas;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Generate schemas from REST route registry
|
|
731
|
+
* PRD #354: Auto-generates OpenAPI schemas from route Zod schemas
|
|
732
|
+
*/
|
|
733
|
+
generateRouteSchemas() {
|
|
734
|
+
if (!this.routeRegistry) {
|
|
735
|
+
return {};
|
|
736
|
+
}
|
|
737
|
+
const schemas = {};
|
|
738
|
+
const routes = this.routeRegistry.getAllRoutes();
|
|
739
|
+
for (const route of routes) {
|
|
740
|
+
// Add response schema
|
|
741
|
+
const responseSchemaName = this.getSchemaName(route, 'Response');
|
|
742
|
+
schemas[responseSchemaName] = this.zodSchemaToJsonSchema(route.response);
|
|
743
|
+
// Add request body schema if present
|
|
744
|
+
if (route.body) {
|
|
745
|
+
const requestSchemaName = this.getSchemaName(route, 'Request');
|
|
746
|
+
schemas[requestSchemaName] = this.zodSchemaToJsonSchema(route.body);
|
|
747
|
+
}
|
|
748
|
+
// Add error response schemas
|
|
749
|
+
if (route.errorResponses) {
|
|
750
|
+
for (const [statusCode, errorSchema] of Object.entries(route.errorResponses)) {
|
|
751
|
+
const errorSchemaName = this.getSchemaName(route, `Error${statusCode}`);
|
|
752
|
+
schemas[errorSchemaName] = this.zodSchemaToJsonSchema(errorSchema);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
return schemas;
|
|
487
757
|
}
|
|
488
758
|
/**
|
|
489
759
|
* Generate tags for grouping endpoints
|
|
@@ -492,30 +762,51 @@ class OpenApiGenerator {
|
|
|
492
762
|
const tags = [
|
|
493
763
|
{
|
|
494
764
|
name: 'MCP Protocol',
|
|
495
|
-
description: 'Model Context Protocol endpoints for AI assistant integration via JSON-RPC and Server-Sent Events'
|
|
765
|
+
description: 'Model Context Protocol endpoints for AI assistant integration via JSON-RPC and Server-Sent Events',
|
|
496
766
|
},
|
|
497
767
|
{
|
|
498
768
|
name: 'Tool Discovery',
|
|
499
|
-
description: 'Endpoints for discovering available tools and their capabilities'
|
|
769
|
+
description: 'Endpoints for discovering available tools and their capabilities',
|
|
500
770
|
},
|
|
501
771
|
{
|
|
502
772
|
name: 'Documentation',
|
|
503
|
-
description: 'API documentation and specification endpoints'
|
|
504
|
-
}
|
|
773
|
+
description: 'API documentation and specification endpoints',
|
|
774
|
+
},
|
|
505
775
|
];
|
|
506
|
-
//
|
|
776
|
+
// Track tag names to avoid duplicates
|
|
777
|
+
const tagNames = new Set(tags.map((t) => t.name));
|
|
778
|
+
// Add category-based tags from tool registry
|
|
507
779
|
for (const category of categories) {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
780
|
+
if (!tagNames.has(category)) {
|
|
781
|
+
tags.push({
|
|
782
|
+
name: category,
|
|
783
|
+
description: `${category} tools and operations`,
|
|
784
|
+
});
|
|
785
|
+
tagNames.add(category);
|
|
786
|
+
}
|
|
512
787
|
}
|
|
513
788
|
// Add generic tools tag for uncategorized tools
|
|
514
|
-
if (this.
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
789
|
+
if (this.toolRegistry.getAllTools().some((tool) => !tool.category)) {
|
|
790
|
+
if (!tagNames.has('Tools')) {
|
|
791
|
+
tags.push({
|
|
792
|
+
name: 'Tools',
|
|
793
|
+
description: 'General purpose tools and utilities',
|
|
794
|
+
});
|
|
795
|
+
tagNames.add('Tools');
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
// PRD #354: Add tags from route registry
|
|
799
|
+
if (this.routeRegistry) {
|
|
800
|
+
const routeTags = this.routeRegistry.getTags();
|
|
801
|
+
for (const routeTag of routeTags) {
|
|
802
|
+
if (!tagNames.has(routeTag)) {
|
|
803
|
+
tags.push({
|
|
804
|
+
name: routeTag,
|
|
805
|
+
description: `${routeTag} endpoints`,
|
|
806
|
+
});
|
|
807
|
+
tagNames.add(routeTag);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
519
810
|
}
|
|
520
811
|
return tags;
|
|
521
812
|
}
|