@gxp-dev/tools 2.0.71 → 2.0.73

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.
@@ -18,130 +18,12 @@
18
18
  */
19
19
 
20
20
  const readline = require("readline")
21
- const fs = require("fs")
22
- const path = require("path")
23
-
24
- // Environment URL configuration (matches constants.js)
25
- const ENVIRONMENT_URLS = {
26
- production: {
27
- apiBaseUrl: "https://api.gramercy.cloud",
28
- openApiSpec: "https://api.gramercy.cloud/api-specs/openapi.json",
29
- asyncApiSpec: "https://api.gramercy.cloud/api-specs/asyncapi.json",
30
- webhookSpec: "https://api.gramercy.cloud/api-specs/webhooks.json",
31
- },
32
- staging: {
33
- apiBaseUrl: "https://api.efz-staging.env.eventfinity.app",
34
- openApiSpec:
35
- "https://api.efz-staging.env.eventfinity.app/api-specs/openapi.json",
36
- asyncApiSpec:
37
- "https://api.efz-staging.env.eventfinity.app/api-specs/asyncapi.json",
38
- webhookSpec:
39
- "https://api.efz-staging.env.eventfinity.app/api-specs/webhooks.json",
40
- },
41
- testing: {
42
- apiBaseUrl: "https://api.zenith-develop-testing.env.eventfinity.app",
43
- openApiSpec:
44
- "https://api.zenith-develop-testing.env.eventfinity.app/api-specs/openapi.json",
45
- asyncApiSpec:
46
- "https://api.zenith-develop-testing.env.eventfinity.app/api-specs/asyncapi.json",
47
- webhookSpec:
48
- "https://api.zenith-develop-testing.env.eventfinity.app/api-specs/webhooks.json",
49
- },
50
- develop: {
51
- apiBaseUrl: "https://api.zenith-develop.env.eventfinity.app",
52
- openApiSpec:
53
- "https://api.zenith-develop.env.eventfinity.app/api-specs/openapi.json",
54
- asyncApiSpec:
55
- "https://api.zenith-develop.env.eventfinity.app/api-specs/asyncapi.json",
56
- webhookSpec:
57
- "https://api.zenith-develop.env.eventfinity.app/api-specs/webhooks.json",
58
- },
59
- local: {
60
- apiBaseUrl: "https://dashboard.eventfinity.test",
61
- openApiSpec: "https://api.eventfinity.test/api-specs/openapi.json",
62
- asyncApiSpec: "https://api.eventfinity.test/api-specs/asyncapi.json",
63
- webhookSpec: "https://api.eventfinity.test/api-specs/webhooks.json",
64
- },
65
- }
66
-
67
- // Cache for fetched specs
68
- const specCache = {
69
- openapi: null,
70
- asyncapi: null,
71
- webhooks: null,
72
- lastFetch: null,
73
- }
74
-
75
- const CACHE_TTL = 5 * 60 * 1000 // 5 minutes
76
-
77
- /**
78
- * Get current environment from .env file or default
79
- */
80
- function getEnvironment() {
81
- // Try to read from .env file in current directory
82
- const envPath = path.join(process.cwd(), ".env")
83
- if (fs.existsSync(envPath)) {
84
- const envContent = fs.readFileSync(envPath, "utf-8")
85
- const match = envContent.match(/VITE_API_ENV=(\w+)/)
86
- if (match) {
87
- return match[1]
88
- }
89
- }
90
-
91
- // Fall back to environment variable or default
92
- return process.env.VITE_API_ENV || process.env.API_ENV || "develop"
93
- }
94
-
95
- /**
96
- * Get URLs for current environment
97
- */
98
- function getEnvUrls() {
99
- const env = getEnvironment()
100
- return ENVIRONMENT_URLS[env] || ENVIRONMENT_URLS.develop
101
- }
102
-
103
- /**
104
- * Fetch a spec with caching
105
- */
106
- async function fetchSpec(specType) {
107
- const urls = getEnvUrls()
108
- const urlMap = {
109
- openapi: urls.openApiSpec,
110
- asyncapi: urls.asyncApiSpec,
111
- webhooks: urls.webhookSpec,
112
- }
113
-
114
- const url = urlMap[specType]
115
- if (!url) {
116
- throw new Error(`Unknown spec type: ${specType}`)
117
- }
118
-
119
- // Check cache
120
- const now = Date.now()
121
- if (
122
- specCache[specType] &&
123
- specCache.lastFetch &&
124
- now - specCache.lastFetch < CACHE_TTL
125
- ) {
126
- return specCache[specType]
127
- }
128
-
129
- // Fetch fresh
130
- try {
131
- const response = await fetch(url)
132
- if (!response.ok) {
133
- throw new Error(`HTTP ${response.status}: ${response.statusText}`)
134
- }
135
- const data = await response.json()
136
- specCache[specType] = data
137
- specCache.lastFetch = now
138
- return data
139
- } catch (error) {
140
- throw new Error(
141
- `Failed to fetch ${specType} spec from ${url}: ${error.message}`,
142
- )
143
- }
144
- }
21
+ const {
22
+ ENVIRONMENT_URLS,
23
+ getEnvironment,
24
+ getEnvUrls,
25
+ fetchSpec,
26
+ } = require("./lib/specs")
145
27
 
146
28
  /**
147
29
  * Search OpenAPI spec for endpoints matching a query
@@ -181,12 +63,40 @@ function searchEndpoints(spec, query) {
181
63
  }
182
64
 
183
65
  /**
184
- * Search AsyncAPI spec for channels/events matching a query
66
+ * Search AsyncAPI spec for channels/events matching a query.
67
+ *
68
+ * Matches across:
69
+ * - components.messages (event name, summary, description, x-triggered-by)
70
+ * - channels (channel name, description)
71
+ *
72
+ * For messages, the returned `eventName` is what you pass to
73
+ * store.listen(eventName, permissionIdentifier, callback) on the client.
185
74
  */
186
75
  function searchEvents(spec, query) {
187
76
  const results = []
188
77
  const queryLower = query.toLowerCase()
189
78
 
79
+ const messages = spec?.components?.messages || {}
80
+ for (const [eventName, message] of Object.entries(messages)) {
81
+ if (typeof message !== "object" || message === null) continue
82
+ const trigger = message["x-triggered-by"] || ""
83
+ if (
84
+ eventName.toLowerCase().includes(queryLower) ||
85
+ message.summary?.toLowerCase().includes(queryLower) ||
86
+ message.description?.toLowerCase().includes(queryLower) ||
87
+ trigger.toLowerCase().includes(queryLower)
88
+ ) {
89
+ results.push({
90
+ kind: "event",
91
+ eventName,
92
+ summary: message.summary || "",
93
+ description: message.description || "",
94
+ triggeredBy: trigger || null,
95
+ payloadRef: message.payload?.$ref || null,
96
+ })
97
+ }
98
+ }
99
+
190
100
  if (spec.channels) {
191
101
  for (const [channel, details] of Object.entries(spec.channels)) {
192
102
  if (
@@ -210,6 +120,7 @@ function searchEvents(spec, query) {
210
120
  }
211
121
 
212
122
  results.push({
123
+ kind: "channel",
213
124
  channel,
214
125
  description: details.description || "",
215
126
  operations,
@@ -247,13 +158,38 @@ function getEndpointDetails(spec, path, method) {
247
158
  }
248
159
 
249
160
  // MCP Server Implementation
161
+ const {
162
+ CONFIG_TOOLS,
163
+ handleConfigToolCall,
164
+ isConfigTool,
165
+ } = require("./lib/config-tools")
166
+
167
+ const {
168
+ EXT_API_TOOLS,
169
+ handleExtApiToolCall,
170
+ isExtApiTool,
171
+ } = require("./lib/api-tools")
172
+
173
+ const {
174
+ DOCS_TOOLS,
175
+ handleDocsToolCall,
176
+ isDocsTool,
177
+ } = require("./lib/docs-tools")
178
+
179
+ const {
180
+ TEST_TOOLS,
181
+ handleTestToolCall,
182
+ isTestTool,
183
+ } = require("./lib/test-tools")
184
+
250
185
  const SERVER_INFO = {
251
186
  name: "gxp-api-server",
252
- version: "1.0.0",
253
- description: "GxP API documentation server for AI coding assistants",
187
+ version: "2.0.0",
188
+ description:
189
+ "GxP toolkit MCP server: API specs, config/manifest editing, documentation search, and plugin test helpers for AI coding assistants.",
254
190
  }
255
191
 
256
- const TOOLS = [
192
+ const API_TOOLS = [
257
193
  {
258
194
  name: "get_openapi_spec",
259
195
  description:
@@ -293,7 +229,7 @@ const TOOLS = [
293
229
  {
294
230
  name: "search_websocket_events",
295
231
  description:
296
- "Search for WebSocket channels/events matching a query. Searches channel names and descriptions.",
232
+ "Search AsyncAPI events matching a query. Searches components.messages (event name, summary, description, x-triggered-by) and channel definitions. The returned eventName is what you pass to store.listen(eventName, permissionIdentifier, callback).",
297
233
  inputSchema: {
298
234
  type: "object",
299
235
  properties: {
@@ -337,10 +273,32 @@ const TOOLS = [
337
273
  },
338
274
  ]
339
275
 
276
+ // Final tool set surfaced to MCP clients: API spec tools + extended API tools
277
+ // + config-editor tools + doc-search tools + test tools.
278
+ const TOOLS = [
279
+ ...API_TOOLS,
280
+ ...EXT_API_TOOLS,
281
+ ...CONFIG_TOOLS,
282
+ ...DOCS_TOOLS,
283
+ ...TEST_TOOLS,
284
+ ]
285
+
340
286
  /**
341
287
  * Handle MCP tool calls
342
288
  */
343
289
  async function handleToolCall(name, args) {
290
+ if (isConfigTool(name)) {
291
+ return handleConfigToolCall(name, args)
292
+ }
293
+ if (isExtApiTool(name)) {
294
+ return handleExtApiToolCall(name, args)
295
+ }
296
+ if (isDocsTool(name)) {
297
+ return handleDocsToolCall(name, args)
298
+ }
299
+ if (isTestTool(name)) {
300
+ return handleTestToolCall(name, args)
301
+ }
344
302
  switch (name) {
345
303
  case "get_openapi_spec": {
346
304
  const spec = await fetchSpec("openapi")