@gokiteam/goki-dev 0.2.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 +478 -0
- package/bin/goki-dev.js +452 -0
- package/bin/mcp-server.js +16 -0
- package/bin/secrets-cli.js +302 -0
- package/cli/ComposeOverrideGenerator.js +226 -0
- package/cli/ComposeParser.js +73 -0
- package/cli/ConfigGenerator.js +304 -0
- package/cli/ConfigManager.js +46 -0
- package/cli/DatabaseManager.js +94 -0
- package/cli/DevToolsChecker.js +21 -0
- package/cli/DevToolsDir.js +66 -0
- package/cli/DevToolsManager.js +451 -0
- package/cli/DockerManager.js +138 -0
- package/cli/FunctionManager.js +95 -0
- package/cli/HttpProxyRewriter.js +91 -0
- package/cli/Logger.js +10 -0
- package/cli/McpConfigManager.js +123 -0
- package/cli/NgrokManager.js +431 -0
- package/cli/ProjectCLI.js +2322 -0
- package/cli/PubSubManager.js +129 -0
- package/cli/SnapshotManager.js +88 -0
- package/cli/UiFormatter.js +292 -0
- package/cli/WebhookUrlRewriter.js +32 -0
- package/cli/secrets/BiometricAuth.js +125 -0
- package/cli/secrets/SecretInjector.js +47 -0
- package/cli/secrets/SecretsConfig.js +141 -0
- package/cli/secrets/SecretsDoctor.js +384 -0
- package/cli/secrets/SecretsManager.js +255 -0
- package/client/dist/client.d.ts +332 -0
- package/client/dist/client.js +507 -0
- package/client/dist/helpers.d.ts +62 -0
- package/client/dist/helpers.js +122 -0
- package/client/dist/index.d.ts +59 -0
- package/client/dist/index.js +78 -0
- package/client/dist/package.json +1 -0
- package/client/dist/types.d.ts +280 -0
- package/client/dist/types.js +7 -0
- package/config.development +46 -0
- package/config.test +18 -0
- package/guidelines/CodingStyleGuideline.md +148 -0
- package/guidelines/CommentingGuideline.md +10 -0
- package/guidelines/HttpApiImplementationGuideline.md +137 -0
- package/guidelines/NamingGuideline.md +182 -0
- package/package.json +138 -0
- package/patterns/api/[collectionName]/Controllers.md +62 -0
- package/patterns/api/[collectionName]/Logic.md +154 -0
- package/patterns/api/[collectionName]/Permissions.md +81 -0
- package/patterns/api/[collectionName]/Router.md +83 -0
- package/patterns/api/[collectionName]/Schemas.md +197 -0
- package/patterns/configs/Patterns.md +7 -0
- package/patterns/enums/Patterns.md +24 -0
- package/patterns/errorHandling/Patterns.md +185 -0
- package/patterns/testing/Patterns.md +232 -0
- package/src/Server.js +238 -0
- package/src/api/dashboard/Controllers.js +9 -0
- package/src/api/dashboard/Logic.js +76 -0
- package/src/api/dashboard/Router.js +11 -0
- package/src/api/dashboard/Schemas.js +47 -0
- package/src/api/data/Controllers.js +26 -0
- package/src/api/data/Logic.js +188 -0
- package/src/api/data/Router.js +16 -0
- package/src/api/docker/Controllers.js +33 -0
- package/src/api/docker/Logic.js +268 -0
- package/src/api/docker/Router.js +15 -0
- package/src/api/docker/Schemas.js +80 -0
- package/src/api/docs/Controllers.js +15 -0
- package/src/api/docs/Logic.js +85 -0
- package/src/api/docs/Router.js +12 -0
- package/src/api/export/Controllers.js +30 -0
- package/src/api/export/Logic.js +143 -0
- package/src/api/export/Router.js +18 -0
- package/src/api/export/Schemas.js +104 -0
- package/src/api/firestore/Controllers.js +152 -0
- package/src/api/firestore/Logic.js +474 -0
- package/src/api/firestore/Router.js +23 -0
- package/src/api/functions/Controllers.js +261 -0
- package/src/api/functions/Logic.js +710 -0
- package/src/api/functions/Router.js +50 -0
- package/src/api/functions/Schemas.js +193 -0
- package/src/api/gateway/Controllers.js +72 -0
- package/src/api/gateway/Logic.js +74 -0
- package/src/api/gateway/Router.js +10 -0
- package/src/api/gateway/Schemas.js +19 -0
- package/src/api/health/Controllers.js +14 -0
- package/src/api/health/Logic.js +24 -0
- package/src/api/health/Router.js +12 -0
- package/src/api/httpTraffic/Controllers.js +29 -0
- package/src/api/httpTraffic/Logic.js +33 -0
- package/src/api/httpTraffic/Router.js +9 -0
- package/src/api/httpTraffic/Schemas.js +23 -0
- package/src/api/logging/Controllers.js +80 -0
- package/src/api/logging/Logic.js +461 -0
- package/src/api/logging/Router.js +24 -0
- package/src/api/logging/Schemas.js +43 -0
- package/src/api/mqtt/Controllers.js +17 -0
- package/src/api/mqtt/Logic.js +66 -0
- package/src/api/mqtt/Router.js +12 -0
- package/src/api/postgres/Controllers.js +97 -0
- package/src/api/postgres/Logic.js +221 -0
- package/src/api/postgres/Router.js +21 -0
- package/src/api/pubsub/Controllers.js +236 -0
- package/src/api/pubsub/Logic.js +732 -0
- package/src/api/pubsub/Router.js +41 -0
- package/src/api/pubsub/Schemas.js +355 -0
- package/src/api/redis/Controllers.js +63 -0
- package/src/api/redis/Logic.js +239 -0
- package/src/api/redis/Router.js +21 -0
- package/src/api/scheduler/Controllers.js +27 -0
- package/src/api/scheduler/Logic.js +49 -0
- package/src/api/scheduler/Router.js +16 -0
- package/src/api/services/Controllers.js +26 -0
- package/src/api/services/Logic.js +205 -0
- package/src/api/services/Router.js +14 -0
- package/src/api/services/Schemas.js +66 -0
- package/src/api/snapshots/Controllers.js +37 -0
- package/src/api/snapshots/Logic.js +797 -0
- package/src/api/snapshots/Router.js +15 -0
- package/src/api/snapshots/Schemas.js +23 -0
- package/src/api/webhooks/Controllers.js +49 -0
- package/src/api/webhooks/Logic.js +137 -0
- package/src/api/webhooks/Router.js +12 -0
- package/src/api/webhooks/Schemas.js +31 -0
- package/src/configs/Application.js +147 -0
- package/src/configs/Default.js +13 -0
- package/src/consumers/BlackboxLogsConsumer.js +235 -0
- package/src/consumers/DockerLogsConsumer.js +687 -0
- package/src/db/Tables.js +66 -0
- package/src/db/schemas/firestore.js +18 -0
- package/src/db/schemas/functions.js +65 -0
- package/src/db/schemas/httpTraffic.js +43 -0
- package/src/db/schemas/logging.js +74 -0
- package/src/db/schemas/migrations.js +64 -0
- package/src/db/schemas/mqtt.js +56 -0
- package/src/db/schemas/pubsub.js +90 -0
- package/src/db/schemas/pubsubRegistry.js +22 -0
- package/src/db/schemas/webhooks.js +28 -0
- package/src/emulation/awsiot/Controllers.js +91 -0
- package/src/emulation/awsiot/Logic.js +70 -0
- package/src/emulation/awsiot/Router.js +19 -0
- package/src/emulation/awsiot/Server.js +100 -0
- package/src/emulation/firestore/Server.js +136 -0
- package/src/emulation/logging/Controllers.js +212 -0
- package/src/emulation/logging/Logic.js +416 -0
- package/src/emulation/logging/Router.js +36 -0
- package/src/emulation/logging/Schemas.js +82 -0
- package/src/emulation/logging/Server.js +108 -0
- package/src/emulation/pubsub/Controllers.js +279 -0
- package/src/emulation/pubsub/DefaultTopics.js +162 -0
- package/src/emulation/pubsub/Logic.js +427 -0
- package/src/emulation/pubsub/README.md +309 -0
- package/src/emulation/pubsub/Router.js +33 -0
- package/src/emulation/pubsub/Server.js +104 -0
- package/src/emulation/pubsub/ShadowPoller.js +276 -0
- package/src/emulation/pubsub/ShadowSubscriptionManager.js +199 -0
- package/src/enums/ContainerNames.js +106 -0
- package/src/enums/ErrorReason.js +28 -0
- package/src/enums/FunctionStatuses.js +15 -0
- package/src/enums/FunctionTriggerTypes.js +15 -0
- package/src/enums/GatewayState.js +7 -0
- package/src/enums/ServiceNames.js +68 -0
- package/src/jobs/DatabaseMaintenance.js +184 -0
- package/src/jobs/MessageHistoryCleanup.js +152 -0
- package/src/mcp/ApiClient.js +25 -0
- package/src/mcp/Server.js +52 -0
- package/src/mcp/prompts/debugging.js +104 -0
- package/src/mcp/resources/platform.js +118 -0
- package/src/mcp/tools/data.js +84 -0
- package/src/mcp/tools/docker.js +166 -0
- package/src/mcp/tools/firestore.js +162 -0
- package/src/mcp/tools/functions.js +380 -0
- package/src/mcp/tools/httpTraffic.js +69 -0
- package/src/mcp/tools/logging.js +174 -0
- package/src/mcp/tools/mqtt.js +37 -0
- package/src/mcp/tools/postgres.js +130 -0
- package/src/mcp/tools/pubsub.js +316 -0
- package/src/mcp/tools/redis.js +146 -0
- package/src/mcp/tools/services.js +169 -0
- package/src/mcp/tools/snapshots.js +88 -0
- package/src/mcp/tools/webhooks.js +115 -0
- package/src/middleware/DevProxy.js +67 -0
- package/src/middleware/ErrorCatcher.js +35 -0
- package/src/middleware/HttpProxy.js +215 -0
- package/src/middleware/Reply.js +24 -0
- package/src/middleware/TraceId.js +9 -0
- package/src/middleware/WebhookProxy.js +234 -0
- package/src/protocols/mqtt/Broker.js +92 -0
- package/src/protocols/mqtt/Handlers.js +175 -0
- package/src/protocols/mqtt/PubSubBridge.js +162 -0
- package/src/protocols/mqtt/Server.js +116 -0
- package/src/runtime/FunctionRunner.js +179 -0
- package/src/services/AppGatewayService.js +582 -0
- package/src/singletons/FirestoreBroadcaster.js +367 -0
- package/src/singletons/FunctionTriggerDispatcher.js +456 -0
- package/src/singletons/FunctionsService.js +418 -0
- package/src/singletons/HttpProxy.js +224 -0
- package/src/singletons/LogBroadcaster.js +159 -0
- package/src/singletons/Logger.js +49 -0
- package/src/singletons/MemoryJsonStore.js +175 -0
- package/src/singletons/MessageBroadcaster.js +190 -0
- package/src/singletons/PostgresBroadcaster.js +367 -0
- package/src/singletons/PostgresClient.js +180 -0
- package/src/singletons/RedisClient.js +184 -0
- package/src/singletons/SqliteStore.js +480 -0
- package/src/singletons/TickService.js +151 -0
- package/src/singletons/WebhookProxy.js +223 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export function registerFunctionsTools (server, apiClient) {
|
|
4
|
+
server.tool(
|
|
5
|
+
'functions_create',
|
|
6
|
+
'Register and deploy a Cloud Function in the dev-tools emulator',
|
|
7
|
+
{
|
|
8
|
+
name: z.string().describe('Unique function name (alphanumeric, hyphens, underscores)'),
|
|
9
|
+
source: z.string().optional().describe('Inline function source code'),
|
|
10
|
+
sourcePath: z.string().optional().describe('Absolute path to the function source directory'),
|
|
11
|
+
entryPoint: z.string().describe('Name of the exported function to invoke'),
|
|
12
|
+
triggerType: z.enum(['http', 'pubsub', 'firestore', 'scheduler']).describe('How the function is triggered'),
|
|
13
|
+
triggerConfig: z.record(z.any()).optional().describe('Trigger-specific config (e.g. { topic: "myTopic" } for pubsub)'),
|
|
14
|
+
signatureType: z.enum(['cloudevent', 'http']).optional().describe('Function signature type'),
|
|
15
|
+
runtime: z.string().optional().describe('Runtime identifier (default: nodejs20)'),
|
|
16
|
+
environmentVariables: z.record(z.string()).optional().describe('Environment variables for the function process'),
|
|
17
|
+
timeoutSeconds: z.number().optional().describe('Maximum execution time in seconds (1-540)'),
|
|
18
|
+
description: z.string().optional().describe('Human-readable description')
|
|
19
|
+
},
|
|
20
|
+
async ({ name, source, sourcePath, entryPoint, triggerType, triggerConfig, signatureType, runtime, environmentVariables, timeoutSeconds, description }) => {
|
|
21
|
+
try {
|
|
22
|
+
const body = { name, entryPoint, triggerType }
|
|
23
|
+
if (source !== undefined) body.source = source
|
|
24
|
+
if (sourcePath !== undefined) body.sourcePath = sourcePath
|
|
25
|
+
if (triggerConfig !== undefined) body.triggerConfig = triggerConfig
|
|
26
|
+
if (signatureType !== undefined) body.signatureType = signatureType
|
|
27
|
+
if (runtime !== undefined) body.runtime = runtime
|
|
28
|
+
if (environmentVariables !== undefined) body.environmentVariables = environmentVariables
|
|
29
|
+
if (timeoutSeconds !== undefined) body.timeoutSeconds = timeoutSeconds
|
|
30
|
+
if (description !== undefined) body.description = description
|
|
31
|
+
const data = await apiClient.post('/v1/functions/create', body)
|
|
32
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
33
|
+
} catch (error) {
|
|
34
|
+
return { content: [{ type: 'text', text: `Failed to create function: ${error.message}` }], isError: true }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
server.tool(
|
|
40
|
+
'functions_list',
|
|
41
|
+
'List all registered Cloud Functions in the dev-tools emulator',
|
|
42
|
+
{
|
|
43
|
+
triggerType: z.enum(['http', 'pubsub', 'firestore', 'scheduler']).optional().describe('Filter by trigger type'),
|
|
44
|
+
status: z.enum(['stopped', 'starting', 'running', 'error']).optional().describe('Filter by status'),
|
|
45
|
+
limit: z.number().optional().describe('Maximum number of results'),
|
|
46
|
+
offset: z.number().optional().describe('Offset for pagination')
|
|
47
|
+
},
|
|
48
|
+
async ({ triggerType, status, limit, offset }) => {
|
|
49
|
+
try {
|
|
50
|
+
const body = {}
|
|
51
|
+
const filter = {}
|
|
52
|
+
if (triggerType !== undefined) filter.triggerType = triggerType
|
|
53
|
+
if (status !== undefined) filter.status = status
|
|
54
|
+
if (Object.keys(filter).length > 0) body.filter = filter
|
|
55
|
+
if (limit !== undefined) body.limit = limit
|
|
56
|
+
if (offset !== undefined) body.offset = offset
|
|
57
|
+
const data = await apiClient.post('/v1/functions/list', body)
|
|
58
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return { content: [{ type: 'text', text: `Failed to list functions: ${error.message}` }], isError: true }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
server.tool(
|
|
66
|
+
'functions_details',
|
|
67
|
+
'Get details of a specific Cloud Function by id or name',
|
|
68
|
+
{
|
|
69
|
+
id: z.string().optional().describe('Function ID'),
|
|
70
|
+
name: z.string().optional().describe('Function name')
|
|
71
|
+
},
|
|
72
|
+
async ({ id, name }) => {
|
|
73
|
+
try {
|
|
74
|
+
const body = {}
|
|
75
|
+
if (id !== undefined) body.id = id
|
|
76
|
+
if (name !== undefined) body.name = name
|
|
77
|
+
const data = await apiClient.post('/v1/functions/details', body)
|
|
78
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
79
|
+
} catch (error) {
|
|
80
|
+
return { content: [{ type: 'text', text: `Failed to get function details: ${error.message}` }], isError: true }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
server.tool(
|
|
86
|
+
'functions_update',
|
|
87
|
+
'Update configuration of a Cloud Function',
|
|
88
|
+
{
|
|
89
|
+
id: z.string().optional().describe('Function ID'),
|
|
90
|
+
name: z.string().optional().describe('Function name'),
|
|
91
|
+
description: z.string().optional().describe('Updated description'),
|
|
92
|
+
triggerConfig: z.record(z.any()).optional().describe('Updated trigger configuration'),
|
|
93
|
+
enabled: z.boolean().optional().describe('Enable or disable the function'),
|
|
94
|
+
environmentVariables: z.record(z.string()).optional().describe('Updated environment variables'),
|
|
95
|
+
timeoutSeconds: z.number().optional().describe('Updated timeout in seconds'),
|
|
96
|
+
entryPoint: z.string().optional().describe('Updated entry point'),
|
|
97
|
+
signatureType: z.enum(['cloudevent', 'http']).optional().describe('Updated signature type')
|
|
98
|
+
},
|
|
99
|
+
async ({ id, name, description, triggerConfig, enabled, environmentVariables, timeoutSeconds, entryPoint, signatureType }) => {
|
|
100
|
+
try {
|
|
101
|
+
const body = {}
|
|
102
|
+
if (id !== undefined) body.id = id
|
|
103
|
+
if (name !== undefined) body.name = name
|
|
104
|
+
if (description !== undefined) body.description = description
|
|
105
|
+
if (triggerConfig !== undefined) body.triggerConfig = triggerConfig
|
|
106
|
+
if (enabled !== undefined) body.enabled = enabled
|
|
107
|
+
if (environmentVariables !== undefined) body.environmentVariables = environmentVariables
|
|
108
|
+
if (timeoutSeconds !== undefined) body.timeoutSeconds = timeoutSeconds
|
|
109
|
+
if (entryPoint !== undefined) body.entryPoint = entryPoint
|
|
110
|
+
if (signatureType !== undefined) body.signatureType = signatureType
|
|
111
|
+
const data = await apiClient.post('/v1/functions/update', body)
|
|
112
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
113
|
+
} catch (error) {
|
|
114
|
+
return { content: [{ type: 'text', text: `Failed to update function: ${error.message}` }], isError: true }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
server.tool(
|
|
120
|
+
'functions_delete',
|
|
121
|
+
'Delete a Cloud Function from the dev-tools emulator',
|
|
122
|
+
{
|
|
123
|
+
id: z.string().optional().describe('Function ID'),
|
|
124
|
+
name: z.string().optional().describe('Function name')
|
|
125
|
+
},
|
|
126
|
+
async ({ id, name }) => {
|
|
127
|
+
try {
|
|
128
|
+
const body = {}
|
|
129
|
+
if (id !== undefined) body.id = id
|
|
130
|
+
if (name !== undefined) body.name = name
|
|
131
|
+
const data = await apiClient.post('/v1/functions/delete', body)
|
|
132
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
133
|
+
} catch (error) {
|
|
134
|
+
return { content: [{ type: 'text', text: `Failed to delete function: ${error.message}` }], isError: true }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
server.tool(
|
|
140
|
+
'functions_start',
|
|
141
|
+
'Start a stopped Cloud Function',
|
|
142
|
+
{
|
|
143
|
+
id: z.string().optional().describe('Function ID'),
|
|
144
|
+
name: z.string().optional().describe('Function name')
|
|
145
|
+
},
|
|
146
|
+
async ({ id, name }) => {
|
|
147
|
+
try {
|
|
148
|
+
const body = {}
|
|
149
|
+
if (id !== undefined) body.id = id
|
|
150
|
+
if (name !== undefined) body.name = name
|
|
151
|
+
const data = await apiClient.post('/v1/functions/start', body)
|
|
152
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
153
|
+
} catch (error) {
|
|
154
|
+
return { content: [{ type: 'text', text: `Failed to start function: ${error.message}` }], isError: true }
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
server.tool(
|
|
160
|
+
'functions_stop',
|
|
161
|
+
'Stop a running Cloud Function',
|
|
162
|
+
{
|
|
163
|
+
id: z.string().optional().describe('Function ID'),
|
|
164
|
+
name: z.string().optional().describe('Function name')
|
|
165
|
+
},
|
|
166
|
+
async ({ id, name }) => {
|
|
167
|
+
try {
|
|
168
|
+
const body = {}
|
|
169
|
+
if (id !== undefined) body.id = id
|
|
170
|
+
if (name !== undefined) body.name = name
|
|
171
|
+
const data = await apiClient.post('/v1/functions/stop', body)
|
|
172
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
173
|
+
} catch (error) {
|
|
174
|
+
return { content: [{ type: 'text', text: `Failed to stop function: ${error.message}` }], isError: true }
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
server.tool(
|
|
180
|
+
'functions_restart',
|
|
181
|
+
'Restart a Cloud Function (stop then start)',
|
|
182
|
+
{
|
|
183
|
+
id: z.string().optional().describe('Function ID'),
|
|
184
|
+
name: z.string().optional().describe('Function name')
|
|
185
|
+
},
|
|
186
|
+
async ({ id, name }) => {
|
|
187
|
+
try {
|
|
188
|
+
const body = {}
|
|
189
|
+
if (id !== undefined) body.id = id
|
|
190
|
+
if (name !== undefined) body.name = name
|
|
191
|
+
const data = await apiClient.post('/v1/functions/restart', body)
|
|
192
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
193
|
+
} catch (error) {
|
|
194
|
+
return { content: [{ type: 'text', text: `Failed to restart function: ${error.message}` }], isError: true }
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
server.tool(
|
|
200
|
+
'functions_invoke',
|
|
201
|
+
'Manually invoke a Cloud Function with a custom payload',
|
|
202
|
+
{
|
|
203
|
+
id: z.string().optional().describe('Function ID'),
|
|
204
|
+
name: z.string().optional().describe('Function name'),
|
|
205
|
+
payload: z.any().optional().describe('Payload to pass as CloudEvent data')
|
|
206
|
+
},
|
|
207
|
+
async ({ id, name, payload }) => {
|
|
208
|
+
try {
|
|
209
|
+
const body = {}
|
|
210
|
+
if (id !== undefined) body.id = id
|
|
211
|
+
if (name !== undefined) body.name = name
|
|
212
|
+
if (payload !== undefined) body.payload = payload
|
|
213
|
+
const data = await apiClient.post('/v1/functions/invoke', body)
|
|
214
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
215
|
+
} catch (error) {
|
|
216
|
+
return { content: [{ type: 'text', text: `Failed to invoke function: ${error.message}` }], isError: true }
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
server.tool(
|
|
222
|
+
'functions_invocations_list',
|
|
223
|
+
'List invocation history for Cloud Functions',
|
|
224
|
+
{
|
|
225
|
+
functionId: z.string().optional().describe('Filter by function ID'),
|
|
226
|
+
functionName: z.string().optional().describe('Filter by function name'),
|
|
227
|
+
triggerType: z.string().optional().describe('Filter by trigger type'),
|
|
228
|
+
limit: z.number().optional().describe('Maximum number of results (default: 50)'),
|
|
229
|
+
offset: z.number().optional().describe('Offset for pagination')
|
|
230
|
+
},
|
|
231
|
+
async ({ functionId, functionName, triggerType, limit, offset }) => {
|
|
232
|
+
try {
|
|
233
|
+
const body = {}
|
|
234
|
+
if (functionId !== undefined) body.functionId = functionId
|
|
235
|
+
if (functionName !== undefined) body.functionName = functionName
|
|
236
|
+
if (triggerType !== undefined) body.triggerType = triggerType
|
|
237
|
+
if (limit !== undefined) body.limit = limit
|
|
238
|
+
if (offset !== undefined) body.offset = offset
|
|
239
|
+
const data = await apiClient.post('/v1/functions/invocations/list', body)
|
|
240
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
241
|
+
} catch (error) {
|
|
242
|
+
return { content: [{ type: 'text', text: `Failed to list invocations: ${error.message}` }], isError: true }
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
server.tool(
|
|
248
|
+
'functions_stats',
|
|
249
|
+
'Get aggregate statistics for Cloud Functions (counts by trigger type, status, invocations)',
|
|
250
|
+
{},
|
|
251
|
+
async () => {
|
|
252
|
+
try {
|
|
253
|
+
const data = await apiClient.post('/v1/functions/stats')
|
|
254
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
255
|
+
} catch (error) {
|
|
256
|
+
return { content: [{ type: 'text', text: `Failed to get functions stats: ${error.message}` }], isError: true }
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
server.tool(
|
|
262
|
+
'functions_dependencies_read',
|
|
263
|
+
'Read the package.json for a Cloud Function to see its npm dependencies',
|
|
264
|
+
{
|
|
265
|
+
name: z.string().describe('Function name')
|
|
266
|
+
},
|
|
267
|
+
async ({ name }) => {
|
|
268
|
+
try {
|
|
269
|
+
const data = await apiClient.post('/v1/functions/dependencies/read', { name })
|
|
270
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
271
|
+
} catch (error) {
|
|
272
|
+
return { content: [{ type: 'text', text: `Failed to read dependencies: ${error.message}` }], isError: true }
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
server.tool(
|
|
278
|
+
'functions_dependencies_update',
|
|
279
|
+
'Update the package.json for a Cloud Function and optionally run npm install',
|
|
280
|
+
{
|
|
281
|
+
name: z.string().describe('Function name'),
|
|
282
|
+
packageJson: z.string().describe('Full package.json content as a JSON string'),
|
|
283
|
+
install: z.boolean().optional().describe('Whether to run npm install after writing (default: true)')
|
|
284
|
+
},
|
|
285
|
+
async ({ name, packageJson, install }) => {
|
|
286
|
+
try {
|
|
287
|
+
const body = { name, packageJson }
|
|
288
|
+
if (install !== undefined) body.install = install
|
|
289
|
+
const data = await apiClient.post('/v1/functions/dependencies/update', body)
|
|
290
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
291
|
+
} catch (error) {
|
|
292
|
+
return { content: [{ type: 'text', text: `Failed to update dependencies: ${error.message}` }], isError: true }
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
server.tool(
|
|
298
|
+
'functions_files_list',
|
|
299
|
+
'List all files in a Cloud Function source directory (excludes node_modules)',
|
|
300
|
+
{
|
|
301
|
+
id: z.string().optional().describe('Function ID'),
|
|
302
|
+
name: z.string().optional().describe('Function name')
|
|
303
|
+
},
|
|
304
|
+
async ({ id, name }) => {
|
|
305
|
+
try {
|
|
306
|
+
const body = {}
|
|
307
|
+
if (id !== undefined) body.id = id
|
|
308
|
+
if (name !== undefined) body.name = name
|
|
309
|
+
const data = await apiClient.post('/v1/functions/files/list', body)
|
|
310
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
311
|
+
} catch (error) {
|
|
312
|
+
return { content: [{ type: 'text', text: `Failed to list files: ${error.message}` }], isError: true }
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
server.tool(
|
|
318
|
+
'functions_files_read',
|
|
319
|
+
'Read a file from a Cloud Function source directory',
|
|
320
|
+
{
|
|
321
|
+
id: z.string().optional().describe('Function ID'),
|
|
322
|
+
name: z.string().optional().describe('Function name'),
|
|
323
|
+
filePath: z.string().describe('Relative file path within the function source directory')
|
|
324
|
+
},
|
|
325
|
+
async ({ id, name, filePath }) => {
|
|
326
|
+
try {
|
|
327
|
+
const body = { filePath }
|
|
328
|
+
if (id !== undefined) body.id = id
|
|
329
|
+
if (name !== undefined) body.name = name
|
|
330
|
+
const data = await apiClient.post('/v1/functions/files/read', body)
|
|
331
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
332
|
+
} catch (error) {
|
|
333
|
+
return { content: [{ type: 'text', text: `Failed to read file: ${error.message}` }], isError: true }
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
server.tool(
|
|
339
|
+
'functions_files_write',
|
|
340
|
+
'Write a file in a Cloud Function source directory',
|
|
341
|
+
{
|
|
342
|
+
id: z.string().optional().describe('Function ID'),
|
|
343
|
+
name: z.string().optional().describe('Function name'),
|
|
344
|
+
filePath: z.string().describe('Relative file path within the function source directory'),
|
|
345
|
+
content: z.string().describe('File content to write')
|
|
346
|
+
},
|
|
347
|
+
async ({ id, name, filePath, content }) => {
|
|
348
|
+
try {
|
|
349
|
+
const body = { filePath, content }
|
|
350
|
+
if (id !== undefined) body.id = id
|
|
351
|
+
if (name !== undefined) body.name = name
|
|
352
|
+
const data = await apiClient.post('/v1/functions/files/write', body)
|
|
353
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
354
|
+
} catch (error) {
|
|
355
|
+
return { content: [{ type: 'text', text: `Failed to write file: ${error.message}` }], isError: true }
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
server.tool(
|
|
361
|
+
'functions_files_delete',
|
|
362
|
+
'Delete a file from a Cloud Function source directory',
|
|
363
|
+
{
|
|
364
|
+
id: z.string().optional().describe('Function ID'),
|
|
365
|
+
name: z.string().optional().describe('Function name'),
|
|
366
|
+
filePath: z.string().describe('Relative file path within the function source directory')
|
|
367
|
+
},
|
|
368
|
+
async ({ id, name, filePath }) => {
|
|
369
|
+
try {
|
|
370
|
+
const body = { filePath }
|
|
371
|
+
if (id !== undefined) body.id = id
|
|
372
|
+
if (name !== undefined) body.name = name
|
|
373
|
+
const data = await apiClient.post('/v1/functions/files/delete', body)
|
|
374
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
375
|
+
} catch (error) {
|
|
376
|
+
return { content: [{ type: 'text', text: `Failed to delete file: ${error.message}` }], isError: true }
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
)
|
|
380
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export function registerHttpTrafficTools (server, apiClient) {
|
|
4
|
+
server.tool(
|
|
5
|
+
'http_traffic_list',
|
|
6
|
+
'List recorded HTTP traffic between microservices (captured by the dev-tools proxy)',
|
|
7
|
+
{
|
|
8
|
+
filter: z.record(z.any()).optional().describe('Optional filter criteria (method, targetHost, sourceService, statusCode, traceId)'),
|
|
9
|
+
limit: z.number().optional().describe('Maximum number of records to return'),
|
|
10
|
+
offset: z.number().optional().describe('Number of records to skip for pagination')
|
|
11
|
+
},
|
|
12
|
+
async ({ filter, limit, offset }) => {
|
|
13
|
+
try {
|
|
14
|
+
const body = {}
|
|
15
|
+
if (filter !== undefined) body.filter = filter
|
|
16
|
+
if (limit !== undefined) body.limit = limit
|
|
17
|
+
if (offset !== undefined) body.offset = offset
|
|
18
|
+
const data = await apiClient.post('/v1/http-traffic/list', body)
|
|
19
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
20
|
+
} catch (error) {
|
|
21
|
+
return { content: [{ type: 'text', text: `Failed to list HTTP traffic: ${error.message}` }], isError: true }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
server.tool(
|
|
27
|
+
'http_traffic_details',
|
|
28
|
+
'Get full request/response details of an HTTP traffic entry including headers and body',
|
|
29
|
+
{
|
|
30
|
+
id: z.string().describe('ID of the HTTP traffic entry to retrieve')
|
|
31
|
+
},
|
|
32
|
+
async ({ id }) => {
|
|
33
|
+
try {
|
|
34
|
+
const data = await apiClient.post('/v1/http-traffic/details', { id })
|
|
35
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
36
|
+
} catch (error) {
|
|
37
|
+
return { content: [{ type: 'text', text: `Failed to get HTTP traffic details: ${error.message}` }], isError: true }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
server.tool(
|
|
43
|
+
'http_traffic_clear',
|
|
44
|
+
'Clear all recorded HTTP traffic',
|
|
45
|
+
{},
|
|
46
|
+
async () => {
|
|
47
|
+
try {
|
|
48
|
+
const data = await apiClient.post('/v1/http-traffic/clear')
|
|
49
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return { content: [{ type: 'text', text: `Failed to clear HTTP traffic: ${error.message}` }], isError: true }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
server.tool(
|
|
57
|
+
'http_traffic_stats',
|
|
58
|
+
'Get HTTP traffic statistics grouped by host, method, and error rates',
|
|
59
|
+
{},
|
|
60
|
+
async () => {
|
|
61
|
+
try {
|
|
62
|
+
const data = await apiClient.post('/v1/http-traffic/stats')
|
|
63
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
64
|
+
} catch (error) {
|
|
65
|
+
return { content: [{ type: 'text', text: `Failed to get HTTP traffic stats: ${error.message}` }], isError: true }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export function registerLoggingTools (server, apiClient) {
|
|
4
|
+
server.tool(
|
|
5
|
+
'logging_list_services',
|
|
6
|
+
'List all services that have sent log entries to the dev-tools logging emulator',
|
|
7
|
+
{},
|
|
8
|
+
async () => {
|
|
9
|
+
try {
|
|
10
|
+
const data = await apiClient.post('/v1/logging/services/list')
|
|
11
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
12
|
+
} catch (error) {
|
|
13
|
+
return { content: [{ type: 'text', text: `Failed to list services: ${error.message}` }], isError: true }
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
server.tool(
|
|
19
|
+
'logging_list_entries',
|
|
20
|
+
'List log entries with optional filters for service name, severity level, and search text. Supports pagination. Use compact=true (default) for an overview with just id, timestamp, severity, service, message, and error — then call logging_get_entries with specific IDs to get full details.',
|
|
21
|
+
{
|
|
22
|
+
serviceName: z.string().optional().describe('Filter by service name (e.g., "core-pms", "integration-apaleo")'),
|
|
23
|
+
severity: z.string().optional().describe('Filter by severity level: DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY'),
|
|
24
|
+
textContains: z.string().optional().describe('Search for text in log messages (case-sensitive substring match)'),
|
|
25
|
+
traceId: z.string().optional().describe('Filter by trace ID to see all logs for a specific request'),
|
|
26
|
+
sinceTimestamp: z.string().optional().describe('ISO timestamp - only show logs after this time (e.g., "2024-01-01T00:00:00Z")'),
|
|
27
|
+
untilTimestamp: z.string().optional().describe('ISO timestamp - only show logs before this time'),
|
|
28
|
+
compact: z.boolean().optional().describe('Return compact entries with only key fields. Default: true. Set to false for full entries.'),
|
|
29
|
+
limit: z.number().optional().describe('Max entries to return (default: 100, max: 1000)'),
|
|
30
|
+
offset: z.number().optional().describe('Skip this many entries for pagination (default: 0)')
|
|
31
|
+
},
|
|
32
|
+
async ({ serviceName, severity, textContains, traceId, sinceTimestamp, untilTimestamp, compact, limit, offset }) => {
|
|
33
|
+
try {
|
|
34
|
+
const filter = {}
|
|
35
|
+
if (serviceName) filter.serviceName = serviceName
|
|
36
|
+
if (severity) filter.severity = severity
|
|
37
|
+
if (textContains) filter.textPayload = { $regex: textContains }
|
|
38
|
+
if (traceId) filter.trace = traceId
|
|
39
|
+
if (sinceTimestamp || untilTimestamp) {
|
|
40
|
+
filter.timestamp = {}
|
|
41
|
+
if (sinceTimestamp) filter.timestamp.$gte = sinceTimestamp
|
|
42
|
+
if (untilTimestamp) filter.timestamp.$lte = untilTimestamp
|
|
43
|
+
}
|
|
44
|
+
const page = {}
|
|
45
|
+
if (limit !== undefined) page.limit = Math.min(limit, 1000)
|
|
46
|
+
if (offset !== undefined) page.offset = offset
|
|
47
|
+
const body = { compact: compact !== false }
|
|
48
|
+
if (Object.keys(filter).length > 0) body.filter = filter
|
|
49
|
+
if (Object.keys(page).length > 0) body.page = page
|
|
50
|
+
const data = await apiClient.post('/v1/logging/entries/list', body)
|
|
51
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
52
|
+
} catch (error) {
|
|
53
|
+
return { content: [{ type: 'text', text: `Failed to list log entries: ${error.message}` }], isError: true }
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
server.tool(
|
|
59
|
+
'logging_get_entries',
|
|
60
|
+
'Get full details of one or more log entries by their IDs. Use this after logging_list_entries (compact mode) to fetch complete details for specific entries you want to inspect.',
|
|
61
|
+
{
|
|
62
|
+
ids: z.array(z.string()).describe('Array of log entry IDs to retrieve (from the _id field in compact list results)')
|
|
63
|
+
},
|
|
64
|
+
async ({ ids }) => {
|
|
65
|
+
try {
|
|
66
|
+
const data = await apiClient.post('/v1/logging/entries/get', { ids })
|
|
67
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
68
|
+
} catch (error) {
|
|
69
|
+
return { content: [{ type: 'text', text: `Failed to get log entries: ${error.message}` }], isError: true }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
server.tool(
|
|
75
|
+
'logging_clear',
|
|
76
|
+
'Clear all log entries from the dev-tools logging emulator',
|
|
77
|
+
{},
|
|
78
|
+
async () => {
|
|
79
|
+
try {
|
|
80
|
+
const data = await apiClient.post('/v1/logging/entries/clear')
|
|
81
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
82
|
+
} catch (error) {
|
|
83
|
+
return { content: [{ type: 'text', text: `Failed to clear log entries: ${error.message}` }], isError: true }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
server.tool(
|
|
89
|
+
'logging_export',
|
|
90
|
+
'Export log entries from the dev-tools logging emulator, optionally filtered by criteria',
|
|
91
|
+
{
|
|
92
|
+
filter: z.record(z.any()).optional().describe('Optional filter criteria to scope the export')
|
|
93
|
+
},
|
|
94
|
+
async ({ filter }) => {
|
|
95
|
+
try {
|
|
96
|
+
const body = {}
|
|
97
|
+
if (filter !== undefined) body.filter = filter
|
|
98
|
+
const data = await apiClient.post('/v1/logging/entries/export', body)
|
|
99
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return { content: [{ type: 'text', text: `Failed to export log entries: ${error.message}` }], isError: true }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
server.tool(
|
|
107
|
+
'logging_get_trace',
|
|
108
|
+
'Get all log entries for a specific trace ID, useful for following a request across services',
|
|
109
|
+
{
|
|
110
|
+
traceId: z.string().describe('The trace ID to look up')
|
|
111
|
+
},
|
|
112
|
+
async ({ traceId }) => {
|
|
113
|
+
try {
|
|
114
|
+
const data = await apiClient.post(`/v1/logging/trace/${traceId}`)
|
|
115
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
116
|
+
} catch (error) {
|
|
117
|
+
return { content: [{ type: 'text', text: `Failed to get trace: ${error.message}` }], isError: true }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
server.tool(
|
|
123
|
+
'logging_wait_for',
|
|
124
|
+
'Wait for a log entry matching the filter criteria to appear. Blocks up to timeout seconds. Useful for verifying async operations completed.',
|
|
125
|
+
{
|
|
126
|
+
filter: z.record(z.any()).describe('Filter criteria the log entry must match'),
|
|
127
|
+
timeout: z.number().optional().describe('Maximum seconds to wait before timing out')
|
|
128
|
+
},
|
|
129
|
+
async ({ filter, timeout }) => {
|
|
130
|
+
try {
|
|
131
|
+
const body = { filter }
|
|
132
|
+
if (timeout !== undefined) body.timeout = timeout
|
|
133
|
+
const data = await apiClient.post('/v1/logging/entries/wait-for', body)
|
|
134
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
135
|
+
} catch (error) {
|
|
136
|
+
return { content: [{ type: 'text', text: `Failed to wait for log entry: ${error.message}` }], isError: true }
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
server.tool(
|
|
142
|
+
'logging_assert_no_errors',
|
|
143
|
+
'Assert that no error-level log entries exist. Optionally scope to a specific traceId or time window. Returns errors if any are found.',
|
|
144
|
+
{
|
|
145
|
+
traceId: z.string().optional().describe('Optional trace ID to scope the assertion to'),
|
|
146
|
+
sinceTimestamp: z.string().optional().describe('Optional ISO timestamp — only check logs after this time')
|
|
147
|
+
},
|
|
148
|
+
async ({ traceId, sinceTimestamp }) => {
|
|
149
|
+
try {
|
|
150
|
+
const body = {}
|
|
151
|
+
if (traceId !== undefined) body.traceId = traceId
|
|
152
|
+
if (sinceTimestamp !== undefined) body.sinceTimestamp = sinceTimestamp
|
|
153
|
+
const data = await apiClient.post('/v1/logging/entries/assert-no-errors', body)
|
|
154
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
155
|
+
} catch (error) {
|
|
156
|
+
return { content: [{ type: 'text', text: `Failed to assert no errors: ${error.message}` }], isError: true }
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
server.tool(
|
|
162
|
+
'logging_get_queue_stats',
|
|
163
|
+
'Get Bull queue statistics including job counts and health status for the blackbox logs consumer',
|
|
164
|
+
{},
|
|
165
|
+
async () => {
|
|
166
|
+
try {
|
|
167
|
+
const data = await apiClient.post('/v1/logging/queue-stats', {})
|
|
168
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
169
|
+
} catch (error) {
|
|
170
|
+
return { content: [{ type: 'text', text: `Failed to get queue stats: ${error.message}` }], isError: true }
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export function registerMqttTools (server, apiClient) {
|
|
4
|
+
server.tool(
|
|
5
|
+
'mqtt_list_clients',
|
|
6
|
+
'List all connected MQTT clients with their connection info',
|
|
7
|
+
{},
|
|
8
|
+
async () => {
|
|
9
|
+
try {
|
|
10
|
+
const data = await apiClient.post('/v1/mqtt/clients/list')
|
|
11
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
12
|
+
} catch (error) {
|
|
13
|
+
return { content: [{ type: 'text', text: `Failed to list MQTT clients: ${error.message}` }], isError: true }
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
server.tool(
|
|
19
|
+
'mqtt_list_messages',
|
|
20
|
+
'List recent MQTT messages with optional filtering',
|
|
21
|
+
{
|
|
22
|
+
filter: z.record(z.any()).optional().describe('Optional filter criteria for MQTT messages'),
|
|
23
|
+
page: z.object({ limit: z.number().optional(), offset: z.number().optional() }).optional().describe('Optional pagination with limit and offset')
|
|
24
|
+
},
|
|
25
|
+
async ({ filter, page }) => {
|
|
26
|
+
try {
|
|
27
|
+
const body = {}
|
|
28
|
+
if (filter !== undefined) body.filter = filter
|
|
29
|
+
if (page !== undefined) body.page = page
|
|
30
|
+
const data = await apiClient.post('/v1/mqtt/messages/list', body)
|
|
31
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return { content: [{ type: 'text', text: `Failed to list MQTT messages: ${error.message}` }], isError: true }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
}
|