@eventcatalog/core 3.3.1 → 3.4.1
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/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-IFELNUKH.js → chunk-56E6QDHD.js} +1 -1
- package/dist/{chunk-AJ7F2ASU.js → chunk-6AW5YJSJ.js} +1 -1
- package/dist/{chunk-B5CNGEHG.js → chunk-7CV7NFRY.js} +1 -1
- package/dist/{chunk-LZMHPUTE.js → chunk-IVLW66F7.js} +1 -1
- package/dist/{chunk-DXXGEMLA.js → chunk-SPL7HGIZ.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +5 -5
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/integrations/eventcatalog-features.ts +9 -0
- package/eventcatalog/src/content.config.ts +1 -0
- package/eventcatalog/src/enterprise/ai/chat-api.ts +27 -83
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +21 -142
- package/eventcatalog/src/enterprise/mcp/mcp-server.ts +512 -0
- package/eventcatalog/src/enterprise/tools/catalog-tools.ts +690 -0
- package/eventcatalog/src/enterprise/tools/index.ts +5 -0
- package/eventcatalog/src/env.d.ts +11 -0
- package/eventcatalog/src/pages/diagrams/[id]/[version]/embed.astro +433 -10
- package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +21 -100
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +26 -141
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].mdx.ts +0 -4
- package/eventcatalog/src/types/mcp-modules.d.ts +66 -0
- package/eventcatalog/src/utils/feature.ts +2 -0
- package/eventcatalog/src/utils/mermaid-zoom.ts +751 -0
- package/eventcatalog/tsconfig.json +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
import type { APIRoute } from 'astro';
|
|
2
|
+
import { Hono, type Context } from 'hono';
|
|
3
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { isEventCatalogScaleEnabled } from '@utils/feature';
|
|
8
|
+
import {
|
|
9
|
+
getResources,
|
|
10
|
+
getResource,
|
|
11
|
+
getMessagesProducedOrConsumedByResource,
|
|
12
|
+
getSchemaForResource,
|
|
13
|
+
findResourcesByOwner,
|
|
14
|
+
getProducersOfMessage,
|
|
15
|
+
getConsumersOfMessage,
|
|
16
|
+
analyzeChangeImpact,
|
|
17
|
+
explainBusinessFlow,
|
|
18
|
+
getTeams,
|
|
19
|
+
getTeam,
|
|
20
|
+
getUsers,
|
|
21
|
+
getUser,
|
|
22
|
+
findMessageBySchemaId,
|
|
23
|
+
explainUbiquitousLanguageTerms,
|
|
24
|
+
collectionSchema,
|
|
25
|
+
resourceCollectionSchema,
|
|
26
|
+
messageCollectionSchema,
|
|
27
|
+
toolDescriptions,
|
|
28
|
+
} from '@enterprise/tools/catalog-tools';
|
|
29
|
+
import { getCollection } from 'astro:content';
|
|
30
|
+
|
|
31
|
+
const catalogDirectory = process.env.PROJECT_DIR || process.cwd();
|
|
32
|
+
|
|
33
|
+
// Helper to create consistent MCP tool handlers with error handling
|
|
34
|
+
function createToolHandler<T>(fn: (params: T) => Promise<any>, errorMessage: string) {
|
|
35
|
+
return async (params: T) => {
|
|
36
|
+
try {
|
|
37
|
+
const result = await fn(params);
|
|
38
|
+
|
|
39
|
+
if (result && 'error' in result) {
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: 'text' as const, text: JSON.stringify(result) }],
|
|
42
|
+
isError: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
48
|
+
};
|
|
49
|
+
} catch (error) {
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: 'text' as const, text: JSON.stringify({ error: `${errorMessage}: ${error}` }) }],
|
|
52
|
+
isError: true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Load extended tools from user configuration
|
|
59
|
+
let extendedTools: Record<string, any> = {};
|
|
60
|
+
let extendedToolNames: string[] = [];
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const providerConfiguration = await import(/* @vite-ignore */ join(catalogDirectory, 'eventcatalog.chat.js'));
|
|
64
|
+
|
|
65
|
+
if (isEventCatalogScaleEnabled() && providerConfiguration.tools) {
|
|
66
|
+
extendedTools = providerConfiguration.tools;
|
|
67
|
+
extendedToolNames = Object.keys(extendedTools);
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
// No chat configuration or tools defined - this is fine
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Create MCP Server with tools that access Astro collections
|
|
74
|
+
function createMcpServer() {
|
|
75
|
+
const server = new McpServer({
|
|
76
|
+
name: 'EventCatalog MCP Server',
|
|
77
|
+
version: '1.0.0',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Register all built-in tools using the helper
|
|
81
|
+
server.registerTool(
|
|
82
|
+
'getResources',
|
|
83
|
+
{
|
|
84
|
+
description: toolDescriptions.getResources,
|
|
85
|
+
inputSchema: z.object({
|
|
86
|
+
collection: collectionSchema.describe('The collection to get the resources from'),
|
|
87
|
+
cursor: z.string().optional().describe('Pagination cursor from previous response'),
|
|
88
|
+
search: z.string().optional().describe('Search term to filter resources by name, id, or summary (case-insensitive)'),
|
|
89
|
+
}),
|
|
90
|
+
},
|
|
91
|
+
createToolHandler(getResources, 'Failed to get resources')
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
server.registerTool(
|
|
95
|
+
'getResource',
|
|
96
|
+
{
|
|
97
|
+
description: toolDescriptions.getResource,
|
|
98
|
+
inputSchema: z.object({
|
|
99
|
+
collection: collectionSchema.describe('The collection to get the resource from'),
|
|
100
|
+
id: z.string().describe('The id of the resource to get'),
|
|
101
|
+
version: z.string().describe('The version of the resource to get'),
|
|
102
|
+
}),
|
|
103
|
+
},
|
|
104
|
+
createToolHandler(getResource, 'Failed to get resource')
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
server.registerTool(
|
|
108
|
+
'getMessagesProducedOrConsumedByResource',
|
|
109
|
+
{
|
|
110
|
+
description: toolDescriptions.getMessagesProducedOrConsumedByResource,
|
|
111
|
+
inputSchema: z.object({
|
|
112
|
+
resourceId: z.string().describe('The id of the resource to get the messages produced or consumed for'),
|
|
113
|
+
resourceVersion: z.string().describe('The version of the resource to get the messages produced or consumed for'),
|
|
114
|
+
resourceCollection: resourceCollectionSchema
|
|
115
|
+
.describe('The collection of the resource to get the messages produced or consumed for')
|
|
116
|
+
.default('services'),
|
|
117
|
+
}),
|
|
118
|
+
},
|
|
119
|
+
createToolHandler(getMessagesProducedOrConsumedByResource, 'Failed to get messages')
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
server.registerTool(
|
|
123
|
+
'getSchemaForResource',
|
|
124
|
+
{
|
|
125
|
+
description: toolDescriptions.getSchemaForResource,
|
|
126
|
+
inputSchema: z.object({
|
|
127
|
+
resourceId: z.string().describe('The id of the resource to get the schema for'),
|
|
128
|
+
resourceVersion: z.string().describe('The version of the resource to get the schema for'),
|
|
129
|
+
resourceCollection: resourceCollectionSchema
|
|
130
|
+
.describe('The collection of the resource to get the schema for')
|
|
131
|
+
.default('services'),
|
|
132
|
+
}),
|
|
133
|
+
},
|
|
134
|
+
createToolHandler(getSchemaForResource, 'Failed to get schema')
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
server.registerTool(
|
|
138
|
+
'findResourcesByOwner',
|
|
139
|
+
{
|
|
140
|
+
description: toolDescriptions.findResourcesByOwner,
|
|
141
|
+
inputSchema: z.object({
|
|
142
|
+
ownerId: z.string().describe('The id of the owner (team or user) to find resources for'),
|
|
143
|
+
}),
|
|
144
|
+
},
|
|
145
|
+
createToolHandler(findResourcesByOwner, 'Failed to find resources')
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
server.registerTool(
|
|
149
|
+
'getProducersOfMessage',
|
|
150
|
+
{
|
|
151
|
+
description: toolDescriptions.getProducersOfMessage,
|
|
152
|
+
inputSchema: z.object({
|
|
153
|
+
messageId: z.string().describe('The id of the message to find producers for'),
|
|
154
|
+
messageVersion: z.string().describe('The version of the message'),
|
|
155
|
+
messageCollection: messageCollectionSchema
|
|
156
|
+
.describe('The collection type of the message (events, commands, or queries)')
|
|
157
|
+
.default('events'),
|
|
158
|
+
}),
|
|
159
|
+
},
|
|
160
|
+
createToolHandler(getProducersOfMessage, 'Failed to get producers')
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
server.registerTool(
|
|
164
|
+
'getConsumersOfMessage',
|
|
165
|
+
{
|
|
166
|
+
description: toolDescriptions.getConsumersOfMessage,
|
|
167
|
+
inputSchema: z.object({
|
|
168
|
+
messageId: z.string().describe('The id of the message to find consumers for'),
|
|
169
|
+
messageVersion: z.string().describe('The version of the message'),
|
|
170
|
+
messageCollection: messageCollectionSchema
|
|
171
|
+
.describe('The collection type of the message (events, commands, or queries)')
|
|
172
|
+
.default('events'),
|
|
173
|
+
}),
|
|
174
|
+
},
|
|
175
|
+
createToolHandler(getConsumersOfMessage, 'Failed to get consumers')
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
server.registerTool(
|
|
179
|
+
'analyzeChangeImpact',
|
|
180
|
+
{
|
|
181
|
+
description: toolDescriptions.analyzeChangeImpact,
|
|
182
|
+
inputSchema: z.object({
|
|
183
|
+
messageId: z.string().describe('The id of the message to analyze impact for'),
|
|
184
|
+
messageVersion: z.string().describe('The version of the message'),
|
|
185
|
+
messageCollection: messageCollectionSchema
|
|
186
|
+
.describe('The collection type of the message (events, commands, or queries)')
|
|
187
|
+
.default('events'),
|
|
188
|
+
}),
|
|
189
|
+
},
|
|
190
|
+
createToolHandler(analyzeChangeImpact, 'Failed to analyze impact')
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
server.registerTool(
|
|
194
|
+
'explainBusinessFlow',
|
|
195
|
+
{
|
|
196
|
+
description: toolDescriptions.explainBusinessFlow,
|
|
197
|
+
inputSchema: z.object({
|
|
198
|
+
flowId: z.string().describe('The id of the flow to explain'),
|
|
199
|
+
flowVersion: z.string().describe('The version of the flow'),
|
|
200
|
+
}),
|
|
201
|
+
},
|
|
202
|
+
createToolHandler(explainBusinessFlow, 'Failed to explain flow')
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
server.registerTool(
|
|
206
|
+
'getTeams',
|
|
207
|
+
{
|
|
208
|
+
description: toolDescriptions.getTeams,
|
|
209
|
+
inputSchema: z.object({
|
|
210
|
+
cursor: z.string().optional().describe('Pagination cursor from previous response'),
|
|
211
|
+
}),
|
|
212
|
+
},
|
|
213
|
+
createToolHandler(getTeams, 'Failed to get teams')
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
server.registerTool(
|
|
217
|
+
'getTeam',
|
|
218
|
+
{
|
|
219
|
+
description: toolDescriptions.getTeam,
|
|
220
|
+
inputSchema: z.object({
|
|
221
|
+
id: z.string().describe('The id of the team to get'),
|
|
222
|
+
}),
|
|
223
|
+
},
|
|
224
|
+
createToolHandler(getTeam, 'Failed to get team')
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
server.registerTool(
|
|
228
|
+
'getUsers',
|
|
229
|
+
{
|
|
230
|
+
description: toolDescriptions.getUsers,
|
|
231
|
+
inputSchema: z.object({
|
|
232
|
+
cursor: z.string().optional().describe('Pagination cursor from previous response'),
|
|
233
|
+
}),
|
|
234
|
+
},
|
|
235
|
+
createToolHandler(getUsers, 'Failed to get users')
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
server.registerTool(
|
|
239
|
+
'getUser',
|
|
240
|
+
{
|
|
241
|
+
description: toolDescriptions.getUser,
|
|
242
|
+
inputSchema: z.object({
|
|
243
|
+
id: z.string().describe('The id of the user to get'),
|
|
244
|
+
}),
|
|
245
|
+
},
|
|
246
|
+
createToolHandler(getUser, 'Failed to get user')
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
server.registerTool(
|
|
250
|
+
'findMessageBySchemaId',
|
|
251
|
+
{
|
|
252
|
+
description: toolDescriptions.findMessageBySchemaId,
|
|
253
|
+
inputSchema: z.object({
|
|
254
|
+
messageId: z.string().describe('The message id (from x-eventcatalog-id in the schema)'),
|
|
255
|
+
messageVersion: z
|
|
256
|
+
.string()
|
|
257
|
+
.optional()
|
|
258
|
+
.describe(
|
|
259
|
+
'The message version (from x-eventcatalog-version in the schema). If not provided, returns the latest version.'
|
|
260
|
+
),
|
|
261
|
+
collection: messageCollectionSchema
|
|
262
|
+
.optional()
|
|
263
|
+
.describe('Optional hint for which collection to search (events, commands, or queries)'),
|
|
264
|
+
}),
|
|
265
|
+
},
|
|
266
|
+
createToolHandler(findMessageBySchemaId, 'Failed to find message')
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
server.registerTool(
|
|
270
|
+
'explainUbiquitousLanguageTerms',
|
|
271
|
+
{
|
|
272
|
+
description: toolDescriptions.explainUbiquitousLanguageTerms,
|
|
273
|
+
inputSchema: z.object({
|
|
274
|
+
domainId: z.string().describe('The id of the domain to get ubiquitous language terms for'),
|
|
275
|
+
domainVersion: z.string().optional().describe('The version of the domain. If not provided, uses the latest version.'),
|
|
276
|
+
}),
|
|
277
|
+
},
|
|
278
|
+
createToolHandler(explainUbiquitousLanguageTerms, 'Failed to get ubiquitous language terms')
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
// Register extended tools from user configuration
|
|
282
|
+
for (const [toolName, toolConfig] of Object.entries(extendedTools)) {
|
|
283
|
+
if (!toolConfig || typeof toolConfig !== 'object') continue;
|
|
284
|
+
|
|
285
|
+
// Extract tool properties (Vercel AI SDK format)
|
|
286
|
+
const { description, parameters, execute } = toolConfig;
|
|
287
|
+
|
|
288
|
+
if (!description || !execute) {
|
|
289
|
+
console.warn(`[MCP] Skipping invalid extended tool: ${toolName}`);
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
server.registerTool(
|
|
294
|
+
toolName,
|
|
295
|
+
{
|
|
296
|
+
description: description || `Custom tool: ${toolName}`,
|
|
297
|
+
inputSchema: parameters || z.object({}),
|
|
298
|
+
},
|
|
299
|
+
async (params: any) => {
|
|
300
|
+
try {
|
|
301
|
+
const result = await execute(params);
|
|
302
|
+
return {
|
|
303
|
+
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
304
|
+
};
|
|
305
|
+
} catch (error) {
|
|
306
|
+
return {
|
|
307
|
+
content: [{ type: 'text' as const, text: JSON.stringify({ error: `Failed to execute ${toolName}: ${error}` }) }],
|
|
308
|
+
isError: true,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// ============================================
|
|
316
|
+
// Register MCP Resources
|
|
317
|
+
// ============================================
|
|
318
|
+
|
|
319
|
+
const resourceDefinitions = [
|
|
320
|
+
{
|
|
321
|
+
name: 'All Resources in EventCatalog',
|
|
322
|
+
uri: 'eventcatalog://all',
|
|
323
|
+
description: 'All messages, domains and services in EventCatalog',
|
|
324
|
+
collections: ['events', 'commands', 'queries', 'services', 'domains', 'flows', 'channels', 'entities'] as const,
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
name: 'All Events in EventCatalog',
|
|
328
|
+
uri: 'eventcatalog://events',
|
|
329
|
+
description: 'All events in EventCatalog',
|
|
330
|
+
collections: ['events'] as const,
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
name: 'All Commands in EventCatalog',
|
|
334
|
+
uri: 'eventcatalog://commands',
|
|
335
|
+
description: 'All commands in EventCatalog',
|
|
336
|
+
collections: ['commands'] as const,
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
name: 'All Queries in EventCatalog',
|
|
340
|
+
uri: 'eventcatalog://queries',
|
|
341
|
+
description: 'All queries in EventCatalog',
|
|
342
|
+
collections: ['queries'] as const,
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
name: 'All Services in EventCatalog',
|
|
346
|
+
uri: 'eventcatalog://services',
|
|
347
|
+
description: 'All services in EventCatalog',
|
|
348
|
+
collections: ['services'] as const,
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
name: 'All Domains in EventCatalog',
|
|
352
|
+
uri: 'eventcatalog://domains',
|
|
353
|
+
description: 'All domains in EventCatalog',
|
|
354
|
+
collections: ['domains'] as const,
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
name: 'All Diagrams in EventCatalog',
|
|
358
|
+
uri: 'eventcatalog://diagrams',
|
|
359
|
+
description: 'All diagrams in EventCatalog',
|
|
360
|
+
collections: ['diagrams'] as const,
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
name: 'All Channels in EventCatalog',
|
|
364
|
+
uri: 'eventcatalog://channels',
|
|
365
|
+
description: 'All channels in EventCatalog',
|
|
366
|
+
collections: ['channels'] as const,
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
name: 'All Containers in EventCatalog',
|
|
370
|
+
uri: 'eventcatalog://containers',
|
|
371
|
+
description: 'All containers in EventCatalog',
|
|
372
|
+
collections: ['containers'] as const,
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
name: 'All Flows in EventCatalog',
|
|
376
|
+
uri: 'eventcatalog://flows',
|
|
377
|
+
description: 'All flows in EventCatalog',
|
|
378
|
+
collections: ['flows'] as const,
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
name: 'All Teams in EventCatalog',
|
|
382
|
+
uri: 'eventcatalog://teams',
|
|
383
|
+
description: 'All teams in EventCatalog',
|
|
384
|
+
collections: ['teams'] as const,
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
name: 'All Users in EventCatalog',
|
|
388
|
+
uri: 'eventcatalog://users',
|
|
389
|
+
description: 'All users in EventCatalog',
|
|
390
|
+
collections: ['users'] as const,
|
|
391
|
+
},
|
|
392
|
+
];
|
|
393
|
+
|
|
394
|
+
for (const resource of resourceDefinitions) {
|
|
395
|
+
server.registerResource(
|
|
396
|
+
resource.name,
|
|
397
|
+
resource.uri,
|
|
398
|
+
{ description: resource.description, mimeType: 'application/json' },
|
|
399
|
+
async (uri: URL) => {
|
|
400
|
+
const allResources: any[] = [];
|
|
401
|
+
|
|
402
|
+
for (const collectionName of resource.collections) {
|
|
403
|
+
try {
|
|
404
|
+
const items = await getCollection(collectionName as any);
|
|
405
|
+
for (const item of items) {
|
|
406
|
+
allResources.push({
|
|
407
|
+
type: collectionName,
|
|
408
|
+
id: (item as any).data.id,
|
|
409
|
+
version: (item as any).data.version,
|
|
410
|
+
name: (item as any).data.name || (item as any).data.id,
|
|
411
|
+
summary: (item as any).data.summary,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
} catch {
|
|
415
|
+
// Collection might not exist, skip it
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return {
|
|
420
|
+
contents: [
|
|
421
|
+
{
|
|
422
|
+
uri: uri.href,
|
|
423
|
+
text: JSON.stringify({ resources: allResources }, null, 2),
|
|
424
|
+
mimeType: 'application/json',
|
|
425
|
+
},
|
|
426
|
+
],
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return server;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Create a single MCP server instance
|
|
436
|
+
const mcpServer = createMcpServer();
|
|
437
|
+
|
|
438
|
+
// Create transport for handling requests
|
|
439
|
+
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
440
|
+
sessionIdGenerator: undefined, // Stateless mode
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
// Connect the server to the transport
|
|
444
|
+
let isConnected = false;
|
|
445
|
+
|
|
446
|
+
// Create Hono app for MCP routes
|
|
447
|
+
const app = new Hono().basePath('/docs/mcp');
|
|
448
|
+
|
|
449
|
+
// Built-in tool names derived from toolDescriptions
|
|
450
|
+
const builtInTools = Object.keys(toolDescriptions);
|
|
451
|
+
|
|
452
|
+
// MCP Resource URIs
|
|
453
|
+
const mcpResources = [
|
|
454
|
+
'eventcatalog://all',
|
|
455
|
+
'eventcatalog://events',
|
|
456
|
+
'eventcatalog://commands',
|
|
457
|
+
'eventcatalog://queries',
|
|
458
|
+
'eventcatalog://services',
|
|
459
|
+
'eventcatalog://domains',
|
|
460
|
+
'eventcatalog://flows',
|
|
461
|
+
'eventcatalog://teams',
|
|
462
|
+
'eventcatalog://users',
|
|
463
|
+
];
|
|
464
|
+
|
|
465
|
+
// Health check endpoint
|
|
466
|
+
app.get('/', async (c: Context) => {
|
|
467
|
+
return c.json({
|
|
468
|
+
name: 'EventCatalog MCP Server',
|
|
469
|
+
version: '1.0.0',
|
|
470
|
+
status: 'running',
|
|
471
|
+
tools: [...builtInTools, ...extendedToolNames],
|
|
472
|
+
extendedTools: extendedToolNames.length > 0 ? extendedToolNames : undefined,
|
|
473
|
+
resources: mcpResources,
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
// MCP protocol endpoint - handles POST requests for MCP protocol
|
|
478
|
+
app.post('/', async (c: Context) => {
|
|
479
|
+
try {
|
|
480
|
+
// Connect server to transport if not already connected
|
|
481
|
+
if (!isConnected) {
|
|
482
|
+
await mcpServer.connect(transport);
|
|
483
|
+
isConnected = true;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Handle the MCP request using the web standard transport
|
|
487
|
+
return await transport.handleRequest(c.req.raw);
|
|
488
|
+
} catch (error) {
|
|
489
|
+
console.error('MCP request error:', error);
|
|
490
|
+
return c.json(
|
|
491
|
+
{
|
|
492
|
+
jsonrpc: '2.0',
|
|
493
|
+
error: {
|
|
494
|
+
code: -32603,
|
|
495
|
+
message: 'Internal server error',
|
|
496
|
+
},
|
|
497
|
+
id: null,
|
|
498
|
+
},
|
|
499
|
+
500
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
// Astro API route handler - delegates all requests to Hono
|
|
505
|
+
// Note: SSR and Scale plan checks are handled at build time by the integration
|
|
506
|
+
// This route is only injected when isEventCatalogMCPEnabled() returns true
|
|
507
|
+
export const ALL: APIRoute = async ({ request }) => {
|
|
508
|
+
return app.fetch(request);
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
// Disable prerendering for SSR
|
|
512
|
+
export const prerender = false;
|