@burdenoff/mcp-libs 2026.511.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/README.md +76 -0
- package/dist/chunk-4GBVJ4OY.js +847 -0
- package/dist/chunk-4GBVJ4OY.js.map +1 -0
- package/dist/chunk-H2OYWLOA.js +919 -0
- package/dist/chunk-H2OYWLOA.js.map +1 -0
- package/dist/chunk-JFEQYSWM.js +174 -0
- package/dist/chunk-JFEQYSWM.js.map +1 -0
- package/dist/chunk-WWFVD7BO.js +273 -0
- package/dist/chunk-WWFVD7BO.js.map +1 -0
- package/dist/context-1jV4NsLv.d.cts +138 -0
- package/dist/context-1jV4NsLv.d.ts +138 -0
- package/dist/core/index.cjs +953 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/core/index.d.cts +59 -0
- package/dist/core/index.d.ts +59 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -0
- package/dist/http-BP4c721D.d.cts +22 -0
- package/dist/http-DXTeCD5r.d.ts +22 -0
- package/dist/index.cjs +1013 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/module-DBcfA-i3.d.ts +67 -0
- package/dist/module-DFQBZNK6.d.cts +67 -0
- package/dist/modules/auth/index.cjs +533 -0
- package/dist/modules/auth/index.cjs.map +1 -0
- package/dist/modules/auth/index.d.cts +51 -0
- package/dist/modules/auth/index.d.ts +51 -0
- package/dist/modules/auth/index.js +159 -0
- package/dist/modules/auth/index.js.map +1 -0
- package/dist/modules/billing/index.cjs +655 -0
- package/dist/modules/billing/index.cjs.map +1 -0
- package/dist/modules/billing/index.d.cts +8 -0
- package/dist/modules/billing/index.d.ts +8 -0
- package/dist/modules/billing/index.js +606 -0
- package/dist/modules/billing/index.js.map +1 -0
- package/dist/modules/channels/index.cjs +443 -0
- package/dist/modules/channels/index.cjs.map +1 -0
- package/dist/modules/channels/index.d.cts +8 -0
- package/dist/modules/channels/index.d.ts +8 -0
- package/dist/modules/channels/index.js +394 -0
- package/dist/modules/channels/index.js.map +1 -0
- package/dist/modules/conversations/index.cjs +288 -0
- package/dist/modules/conversations/index.cjs.map +1 -0
- package/dist/modules/conversations/index.d.cts +8 -0
- package/dist/modules/conversations/index.d.ts +8 -0
- package/dist/modules/conversations/index.js +239 -0
- package/dist/modules/conversations/index.js.map +1 -0
- package/dist/modules/devportal/index.cjs +796 -0
- package/dist/modules/devportal/index.cjs.map +1 -0
- package/dist/modules/devportal/index.d.cts +8 -0
- package/dist/modules/devportal/index.d.ts +8 -0
- package/dist/modules/devportal/index.js +747 -0
- package/dist/modules/devportal/index.js.map +1 -0
- package/dist/modules/export/index.cjs +333 -0
- package/dist/modules/export/index.cjs.map +1 -0
- package/dist/modules/export/index.d.cts +8 -0
- package/dist/modules/export/index.d.ts +8 -0
- package/dist/modules/export/index.js +284 -0
- package/dist/modules/export/index.js.map +1 -0
- package/dist/modules/files/index.cjs +278 -0
- package/dist/modules/files/index.cjs.map +1 -0
- package/dist/modules/files/index.d.cts +8 -0
- package/dist/modules/files/index.d.ts +8 -0
- package/dist/modules/files/index.js +229 -0
- package/dist/modules/files/index.js.map +1 -0
- package/dist/modules/groups/index.cjs +451 -0
- package/dist/modules/groups/index.cjs.map +1 -0
- package/dist/modules/groups/index.d.cts +8 -0
- package/dist/modules/groups/index.d.ts +8 -0
- package/dist/modules/groups/index.js +402 -0
- package/dist/modules/groups/index.js.map +1 -0
- package/dist/modules/health/index.cjs +159 -0
- package/dist/modules/health/index.cjs.map +1 -0
- package/dist/modules/health/index.d.cts +8 -0
- package/dist/modules/health/index.d.ts +8 -0
- package/dist/modules/health/index.js +36 -0
- package/dist/modules/health/index.js.map +1 -0
- package/dist/modules/integrations/index.cjs +316 -0
- package/dist/modules/integrations/index.cjs.map +1 -0
- package/dist/modules/integrations/index.d.cts +8 -0
- package/dist/modules/integrations/index.d.ts +8 -0
- package/dist/modules/integrations/index.js +267 -0
- package/dist/modules/integrations/index.js.map +1 -0
- package/dist/modules/notifications/index.cjs +222 -0
- package/dist/modules/notifications/index.cjs.map +1 -0
- package/dist/modules/notifications/index.d.cts +8 -0
- package/dist/modules/notifications/index.d.ts +8 -0
- package/dist/modules/notifications/index.js +173 -0
- package/dist/modules/notifications/index.js.map +1 -0
- package/dist/modules/organizations/index.cjs +267 -0
- package/dist/modules/organizations/index.cjs.map +1 -0
- package/dist/modules/organizations/index.d.cts +8 -0
- package/dist/modules/organizations/index.d.ts +8 -0
- package/dist/modules/organizations/index.js +218 -0
- package/dist/modules/organizations/index.js.map +1 -0
- package/dist/modules/products/index.cjs +736 -0
- package/dist/modules/products/index.cjs.map +1 -0
- package/dist/modules/products/index.d.cts +8 -0
- package/dist/modules/products/index.d.ts +8 -0
- package/dist/modules/products/index.js +687 -0
- package/dist/modules/products/index.js.map +1 -0
- package/dist/modules/rbac/index.cjs +378 -0
- package/dist/modules/rbac/index.cjs.map +1 -0
- package/dist/modules/rbac/index.d.cts +8 -0
- package/dist/modules/rbac/index.d.ts +8 -0
- package/dist/modules/rbac/index.js +329 -0
- package/dist/modules/rbac/index.js.map +1 -0
- package/dist/modules/sandbox/index.cjs +318 -0
- package/dist/modules/sandbox/index.cjs.map +1 -0
- package/dist/modules/sandbox/index.d.cts +8 -0
- package/dist/modules/sandbox/index.d.ts +8 -0
- package/dist/modules/sandbox/index.js +225 -0
- package/dist/modules/sandbox/index.js.map +1 -0
- package/dist/modules/scheduler/index.cjs +267 -0
- package/dist/modules/scheduler/index.cjs.map +1 -0
- package/dist/modules/scheduler/index.d.cts +8 -0
- package/dist/modules/scheduler/index.d.ts +8 -0
- package/dist/modules/scheduler/index.js +218 -0
- package/dist/modules/scheduler/index.js.map +1 -0
- package/dist/modules/security/index.cjs +529 -0
- package/dist/modules/security/index.cjs.map +1 -0
- package/dist/modules/security/index.d.cts +8 -0
- package/dist/modules/security/index.d.ts +8 -0
- package/dist/modules/security/index.js +480 -0
- package/dist/modules/security/index.js.map +1 -0
- package/dist/modules/store/index.cjs +450 -0
- package/dist/modules/store/index.cjs.map +1 -0
- package/dist/modules/store/index.d.cts +8 -0
- package/dist/modules/store/index.d.ts +8 -0
- package/dist/modules/store/index.js +401 -0
- package/dist/modules/store/index.js.map +1 -0
- package/dist/modules/support/index.cjs +285 -0
- package/dist/modules/support/index.cjs.map +1 -0
- package/dist/modules/support/index.d.cts +8 -0
- package/dist/modules/support/index.d.ts +8 -0
- package/dist/modules/support/index.js +236 -0
- package/dist/modules/support/index.js.map +1 -0
- package/dist/modules/tags/index.cjs +421 -0
- package/dist/modules/tags/index.cjs.map +1 -0
- package/dist/modules/tags/index.d.cts +8 -0
- package/dist/modules/tags/index.d.ts +8 -0
- package/dist/modules/tags/index.js +372 -0
- package/dist/modules/tags/index.js.map +1 -0
- package/dist/modules/tours/index.cjs +225 -0
- package/dist/modules/tours/index.cjs.map +1 -0
- package/dist/modules/tours/index.d.cts +8 -0
- package/dist/modules/tours/index.d.ts +8 -0
- package/dist/modules/tours/index.js +176 -0
- package/dist/modules/tours/index.js.map +1 -0
- package/dist/modules/vibecontrols/index.cjs +5551 -0
- package/dist/modules/vibecontrols/index.cjs.map +1 -0
- package/dist/modules/vibecontrols/index.d.cts +8 -0
- package/dist/modules/vibecontrols/index.d.ts +8 -0
- package/dist/modules/vibecontrols/index.js +4380 -0
- package/dist/modules/vibecontrols/index.js.map +1 -0
- package/dist/modules/workspaces/index.cjs +552 -0
- package/dist/modules/workspaces/index.cjs.map +1 -0
- package/dist/modules/workspaces/index.d.cts +8 -0
- package/dist/modules/workspaces/index.d.ts +8 -0
- package/dist/modules/workspaces/index.js +503 -0
- package/dist/modules/workspaces/index.js.map +1 -0
- package/dist/tool-name-CQf_IqAj.d.cts +47 -0
- package/dist/tool-name-DlnrBsZ6.d.ts +47 -0
- package/dist/transports/index.cjs +183 -0
- package/dist/transports/index.cjs.map +1 -0
- package/dist/transports/index.d.cts +13 -0
- package/dist/transports/index.d.ts +13 -0
- package/dist/transports/index.js +3 -0
- package/dist/transports/index.js.map +1 -0
- package/package.json +125 -0
|
@@ -0,0 +1,4380 @@
|
|
|
1
|
+
import { LIST_AGENTS, GET_AGENT, CREATE_AGENT, UPDATE_AGENT, DELETE_AGENT, PROBE_AGENT_CONNECTION, AGENT_HEALTH_PROBES, AGENT_PLUGINS, INSTALL_AGENT_PLUGIN, REMOVE_AGENT_PLUGIN, LIST_VIBES, GET_VIBE, CREATE_VIBE, UPDATE_VIBE, DELETE_VIBE, UPDATE_VIBE_STATUS, ARCHIVE_VIBE, RESTORE_VIBE, VIBE_HIERARCHY, SEARCH_VIBES, LIST_SESSIONS, GET_SESSION, CREATE_SESSION, START_SESSION, STOP_SESSION, RESTART_SESSION, TERMINATE_SESSION, SEND_SESSION_INPUT, START_SESSION_TERMINAL, SESSION_OUTPUT, ACTIVE_SESSIONS, CHECK_SESSION_HEALTH, BULK_RESTART_SESSIONS, BULK_STOP_SESSIONS, BULK_TERMINATE_SESSIONS, LIST_NOTES, GET_NOTE, CREATE_NOTE, UPDATE_NOTE, DELETE_NOTE, SEARCH_NOTES, PIN_NOTE, UNPIN_NOTE, LIST_CONFIGURATIONS, GET_CONFIGURATION, SET_CONFIGURATION, DELETE_CONFIGURATION, CONFIGURATIONS_BY_SCOPE, LIST_WEBHOOKS, GET_WEBHOOK, CREATE_WEBHOOK, UPDATE_WEBHOOK, DELETE_WEBHOOK, TEST_WEBHOOK, TRIGGER_WEBHOOK, LIST_TUNNELS, CREATE_TUNNEL, STOP_TUNNEL, DELETE_TUNNEL, GET_UI_SESSION, SAVE_UI_SESSION, CLEAR_UI_SESSION, LIST_AI_TOOL_EVENTS, CREATE_AI_TOOL_EVENT, RECENT_AI_TOOL_EVENTS, LIST_TARGETS, GET_TARGET, CREATE_TARGET, UPDATE_TARGET, DELETE_TARGET, TEST_TARGET, IMPORT_TARGETS_FROM_CONFIG, SCAN_SSH_CONFIG, INSTALL_AGENT_ON_TARGET, LIST_VIBEDECKS, GET_VIBEDECK, CREATE_VIBEDECK, UPDATE_VIBEDECK, DELETE_VIBEDECK, DUPLICATE_VIBEDECK, SET_DEFAULT_VIBEDECK, LIST_VIBEDECK_BUTTONS, CREATE_VIBEDECK_BUTTON, UPDATE_VIBEDECK_BUTTON, DELETE_VIBEDECK_BUTTON, EXECUTE_VIBEDECK_BUTTON, LIST_DOCS_SITES, GET_DOCS_SITE, CREATE_DOCS_SITE, UPDATE_DOCS_SITE, DELETE_DOCS_SITE, LIST_DOCS_PAGES, GET_DOCS_PAGE, CREATE_DOCS_PAGE, UPDATE_DOCS_PAGE, DELETE_DOCS_PAGE, COMPILE_DOCS_SITE, PUBLISH_DOCS_REVISION, ROLLBACK_DOCS_REVISION, SHARE_SESSION, CREATE_SESSION_SHARE_LINK, REVOKE_SESSION_SHARE, REVOKE_SESSION_SHARE_LINK, SESSION_SHARES, SESSION_SHARE_LINKS, SESSION_COLLABORATORS, SESSIONS_SHARED_WITH_ME, LIST_AUDIT_LOGS, GET_AUDIT_LOG, AUDIT_LOG_STATS, EXPORT_AUDIT_LOGS, DELETE_AUDIT_LOG, LIST_ACTIONS, GET_ACTION, CREATE_ACTION, UPDATE_ACTION, DELETE_ACTION, EXECUTE_ACTION, LIST_ACTION_EXECUTIONS, DUPLICATE_ACTION, INSTALL_ACTION_FROM_STORE, CANCEL_ACTION_EXECUTION, CREATE_SCHEDULED_JOB, DELETE_SCHEDULED_JOB, LIST_SCHEDULED_JOBS, VIBECONTROLS_ANALYTICS, PINNED_NOTES } from '../../chunk-4GBVJ4OY.js';
|
|
2
|
+
import { getAuth } from '../../chunk-WWFVD7BO.js';
|
|
3
|
+
import { mcpToolName, jsonResult, errorResult } from '../../chunk-H2OYWLOA.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
|
|
6
|
+
function registerActionTools(server, ctx, track) {
|
|
7
|
+
server.registerTool(
|
|
8
|
+
track(mcpToolName(ctx.productName, "actions_list")),
|
|
9
|
+
{
|
|
10
|
+
title: "List Actions",
|
|
11
|
+
description: "List all Vibe Actions with optional filters and pagination.",
|
|
12
|
+
inputSchema: {
|
|
13
|
+
name: z.string().optional().describe("Filter by action name"),
|
|
14
|
+
actionType: z.string().optional().describe("Filter by action type (COMMAND, SCRIPT, WEBHOOK, WORKFLOW)"),
|
|
15
|
+
sourceType: z.string().optional().describe("Filter by source type (USER_CREATED, STORE_INSTALLED)"),
|
|
16
|
+
triggerType: z.string().optional().describe("Filter by trigger type (MANUAL, SCHEDULED, EVENT, ON_DEMAND)"),
|
|
17
|
+
isActive: z.boolean().optional().describe("Filter by active status"),
|
|
18
|
+
limit: z.number().optional().describe("Max results to return"),
|
|
19
|
+
offset: z.number().optional().describe("Number of results to skip")
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
async ({ name, actionType, sourceType, triggerType, isActive, limit, offset }) => {
|
|
23
|
+
try {
|
|
24
|
+
const filter = {};
|
|
25
|
+
if (name !== void 0) filter.name = name;
|
|
26
|
+
if (actionType !== void 0) filter.actionType = actionType;
|
|
27
|
+
if (sourceType !== void 0) filter.sourceType = sourceType;
|
|
28
|
+
if (triggerType !== void 0) filter.triggerType = triggerType;
|
|
29
|
+
if (isActive !== void 0) filter.isActive = isActive;
|
|
30
|
+
const pagination = {};
|
|
31
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
32
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
33
|
+
const data = await ctx.gql.workspace.request(LIST_ACTIONS, {
|
|
34
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
35
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
36
|
+
});
|
|
37
|
+
return jsonResult(data.actions);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
ctx.logger.error("vibecontrols_actions_list failed", { error });
|
|
40
|
+
return errorResult(
|
|
41
|
+
`Failed to list Actions: ${error instanceof Error ? error.message : String(error)}`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
server.registerTool(
|
|
47
|
+
track(mcpToolName(ctx.productName, "actions_get")),
|
|
48
|
+
{
|
|
49
|
+
title: "Get Action",
|
|
50
|
+
description: "Get a Vibe Action by its ID.",
|
|
51
|
+
inputSchema: { id: z.string().describe("Action ID") }
|
|
52
|
+
},
|
|
53
|
+
async ({ id }) => {
|
|
54
|
+
try {
|
|
55
|
+
const data = await ctx.gql.workspace.request(GET_ACTION, { id });
|
|
56
|
+
return jsonResult(data.action);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
ctx.logger.error("vibecontrols_actions_get failed", { error });
|
|
59
|
+
return errorResult(
|
|
60
|
+
`Failed to get Action: ${error instanceof Error ? error.message : String(error)}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
server.registerTool(
|
|
66
|
+
track(mcpToolName(ctx.productName, "actions_create")),
|
|
67
|
+
{
|
|
68
|
+
title: "Create Action",
|
|
69
|
+
description: "Create a new Vibe Action.",
|
|
70
|
+
inputSchema: {
|
|
71
|
+
name: z.string().describe("Action name"),
|
|
72
|
+
description: z.string().optional().describe("Action description"),
|
|
73
|
+
actionType: z.string().describe("Action type (COMMAND, SCRIPT, WEBHOOK, WORKFLOW)"),
|
|
74
|
+
triggerType: z.string().optional().describe("Trigger type (MANUAL, SCHEDULED, EVENT, ON_DEMAND)"),
|
|
75
|
+
command: z.string().optional().describe("Command to execute (for COMMAND type)"),
|
|
76
|
+
script: z.string().optional().describe("Script to execute (for SCRIPT type)"),
|
|
77
|
+
webhookUrl: z.string().optional().describe("Webhook URL (for WEBHOOK type)"),
|
|
78
|
+
tags: z.array(z.string()).optional().describe("Tags for categorization"),
|
|
79
|
+
isActive: z.boolean().optional().describe("Whether the action is active")
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
async ({
|
|
83
|
+
name,
|
|
84
|
+
description,
|
|
85
|
+
actionType,
|
|
86
|
+
triggerType,
|
|
87
|
+
command,
|
|
88
|
+
script,
|
|
89
|
+
webhookUrl,
|
|
90
|
+
tags,
|
|
91
|
+
isActive
|
|
92
|
+
}) => {
|
|
93
|
+
try {
|
|
94
|
+
const input = { name, actionType };
|
|
95
|
+
if (description !== void 0) input.description = description;
|
|
96
|
+
if (triggerType !== void 0) input.triggerType = triggerType;
|
|
97
|
+
if (command !== void 0) input.command = command;
|
|
98
|
+
if (script !== void 0) input.script = script;
|
|
99
|
+
if (webhookUrl !== void 0) input.webhookUrl = webhookUrl;
|
|
100
|
+
if (tags !== void 0) input.tags = tags;
|
|
101
|
+
if (isActive !== void 0) input.isActive = isActive;
|
|
102
|
+
const data = await ctx.gql.workspace.request(CREATE_ACTION, {
|
|
103
|
+
input
|
|
104
|
+
});
|
|
105
|
+
return jsonResult(data.createAction);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
ctx.logger.error("vibecontrols_actions_create failed", { error });
|
|
108
|
+
return errorResult(
|
|
109
|
+
`Failed to create Action: ${error instanceof Error ? error.message : String(error)}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
server.registerTool(
|
|
115
|
+
track(mcpToolName(ctx.productName, "actions_update")),
|
|
116
|
+
{
|
|
117
|
+
title: "Update Action",
|
|
118
|
+
description: "Update an existing Vibe Action.",
|
|
119
|
+
inputSchema: {
|
|
120
|
+
id: z.string().describe("Action ID"),
|
|
121
|
+
name: z.string().optional().describe("Updated name"),
|
|
122
|
+
description: z.string().optional().describe("Updated description"),
|
|
123
|
+
actionType: z.string().optional().describe("Updated action type (COMMAND, SCRIPT, WEBHOOK, WORKFLOW)"),
|
|
124
|
+
triggerType: z.string().optional().describe("Updated trigger type (MANUAL, SCHEDULED, EVENT, ON_DEMAND)"),
|
|
125
|
+
command: z.string().optional().describe("Updated command"),
|
|
126
|
+
script: z.string().optional().describe("Updated script"),
|
|
127
|
+
webhookUrl: z.string().optional().describe("Updated webhook URL"),
|
|
128
|
+
tags: z.array(z.string()).optional().describe("Updated tags"),
|
|
129
|
+
isActive: z.boolean().optional().describe("Updated active status")
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
async ({
|
|
133
|
+
id,
|
|
134
|
+
name,
|
|
135
|
+
description,
|
|
136
|
+
actionType,
|
|
137
|
+
triggerType,
|
|
138
|
+
command,
|
|
139
|
+
script,
|
|
140
|
+
webhookUrl,
|
|
141
|
+
tags,
|
|
142
|
+
isActive
|
|
143
|
+
}) => {
|
|
144
|
+
try {
|
|
145
|
+
const input = {};
|
|
146
|
+
if (name !== void 0) input.name = name;
|
|
147
|
+
if (description !== void 0) input.description = description;
|
|
148
|
+
if (actionType !== void 0) input.actionType = actionType;
|
|
149
|
+
if (triggerType !== void 0) input.triggerType = triggerType;
|
|
150
|
+
if (command !== void 0) input.command = command;
|
|
151
|
+
if (script !== void 0) input.script = script;
|
|
152
|
+
if (webhookUrl !== void 0) input.webhookUrl = webhookUrl;
|
|
153
|
+
if (tags !== void 0) input.tags = tags;
|
|
154
|
+
if (isActive !== void 0) input.isActive = isActive;
|
|
155
|
+
const data = await ctx.gql.workspace.request(UPDATE_ACTION, {
|
|
156
|
+
id,
|
|
157
|
+
input
|
|
158
|
+
});
|
|
159
|
+
return jsonResult(data.updateAction);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
ctx.logger.error("vibecontrols_actions_update failed", { error });
|
|
162
|
+
return errorResult(
|
|
163
|
+
`Failed to update Action: ${error instanceof Error ? error.message : String(error)}`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
server.registerTool(
|
|
169
|
+
track(mcpToolName(ctx.productName, "actions_delete")),
|
|
170
|
+
{
|
|
171
|
+
title: "Delete Action",
|
|
172
|
+
description: "Permanently delete a Vibe Action.",
|
|
173
|
+
inputSchema: { id: z.string().describe("Action ID to delete") }
|
|
174
|
+
},
|
|
175
|
+
async ({ id }) => {
|
|
176
|
+
try {
|
|
177
|
+
const data = await ctx.gql.workspace.request(DELETE_ACTION, {
|
|
178
|
+
id
|
|
179
|
+
});
|
|
180
|
+
return jsonResult({ deleted: data.deleteAction, actionId: id });
|
|
181
|
+
} catch (error) {
|
|
182
|
+
ctx.logger.error("vibecontrols_actions_delete failed", { error });
|
|
183
|
+
return errorResult(
|
|
184
|
+
`Failed to delete Action: ${error instanceof Error ? error.message : String(error)}`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
server.registerTool(
|
|
190
|
+
track(mcpToolName(ctx.productName, "actions_execute")),
|
|
191
|
+
{
|
|
192
|
+
title: "Execute Action",
|
|
193
|
+
description: "Execute a Vibe Action and return the execution result.",
|
|
194
|
+
inputSchema: {
|
|
195
|
+
id: z.string().describe("Action ID to execute"),
|
|
196
|
+
parameters: z.string().optional().describe("JSON string of execution parameters"),
|
|
197
|
+
triggeredBy: z.string().optional().describe("Identifier of who triggered the execution")
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
async ({ id, parameters, triggeredBy }) => {
|
|
201
|
+
try {
|
|
202
|
+
const input = {};
|
|
203
|
+
if (parameters !== void 0) {
|
|
204
|
+
try {
|
|
205
|
+
input.parameters = JSON.parse(parameters);
|
|
206
|
+
} catch {
|
|
207
|
+
input.parameters = parameters;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (triggeredBy !== void 0) input.triggeredBy = triggeredBy;
|
|
211
|
+
const data = await ctx.gql.workspace.request(EXECUTE_ACTION, {
|
|
212
|
+
id,
|
|
213
|
+
input: Object.keys(input).length > 0 ? input : void 0
|
|
214
|
+
});
|
|
215
|
+
return jsonResult(data.executeAction);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
ctx.logger.error("vibecontrols_actions_execute failed", { error });
|
|
218
|
+
return errorResult(
|
|
219
|
+
`Failed to execute Action: ${error instanceof Error ? error.message : String(error)}`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
server.registerTool(
|
|
225
|
+
track(mcpToolName(ctx.productName, "actions_executions_list")),
|
|
226
|
+
{
|
|
227
|
+
title: "List Action Executions",
|
|
228
|
+
description: "List action execution history with optional filters and pagination.",
|
|
229
|
+
inputSchema: {
|
|
230
|
+
actionId: z.string().optional().describe("Filter by action ID"),
|
|
231
|
+
status: z.string().optional().describe("Filter by status (PENDING, RUNNING, SUCCESS, FAILURE, TIMEOUT, CANCELLED)"),
|
|
232
|
+
triggeredBy: z.string().optional().describe("Filter by who triggered the execution"),
|
|
233
|
+
limit: z.number().optional().describe("Max results to return"),
|
|
234
|
+
offset: z.number().optional().describe("Number of results to skip")
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
async ({ actionId, status, triggeredBy, limit, offset }) => {
|
|
238
|
+
try {
|
|
239
|
+
const filter = {};
|
|
240
|
+
if (actionId !== void 0) filter.actionId = actionId;
|
|
241
|
+
if (status !== void 0) filter.status = status;
|
|
242
|
+
if (triggeredBy !== void 0) filter.triggeredBy = triggeredBy;
|
|
243
|
+
const pagination = {};
|
|
244
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
245
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
246
|
+
const data = await ctx.gql.workspace.request(
|
|
247
|
+
LIST_ACTION_EXECUTIONS,
|
|
248
|
+
{
|
|
249
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
250
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
251
|
+
}
|
|
252
|
+
);
|
|
253
|
+
return jsonResult(data.actionExecutions);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
ctx.logger.error("vibecontrols_actions_executions_list failed", { error });
|
|
256
|
+
return errorResult(
|
|
257
|
+
`Failed to list Action Executions: ${error instanceof Error ? error.message : String(error)}`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
server.registerTool(
|
|
263
|
+
track(mcpToolName(ctx.productName, "actions_duplicate")),
|
|
264
|
+
{
|
|
265
|
+
title: "Duplicate Action",
|
|
266
|
+
description: "Create a copy of an existing Vibe Action.",
|
|
267
|
+
inputSchema: {
|
|
268
|
+
id: z.string().describe("Action ID to duplicate"),
|
|
269
|
+
name: z.string().optional().describe("Name for the duplicated action")
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
async ({ id, name }) => {
|
|
273
|
+
try {
|
|
274
|
+
const variables = { id };
|
|
275
|
+
if (name !== void 0) variables.name = name;
|
|
276
|
+
const data = await ctx.gql.workspace.request(
|
|
277
|
+
DUPLICATE_ACTION,
|
|
278
|
+
variables
|
|
279
|
+
);
|
|
280
|
+
return jsonResult(data.duplicateAction);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
ctx.logger.error("vibecontrols_actions_duplicate failed", { error });
|
|
283
|
+
return errorResult(
|
|
284
|
+
`Failed to duplicate Action: ${error instanceof Error ? error.message : String(error)}`
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
server.registerTool(
|
|
290
|
+
track(mcpToolName(ctx.productName, "actions_install")),
|
|
291
|
+
{
|
|
292
|
+
title: "Install Action from Store",
|
|
293
|
+
description: "Install a Vibe Action from the action store.",
|
|
294
|
+
inputSchema: {
|
|
295
|
+
storeItemId: z.string().describe("Store item ID to install"),
|
|
296
|
+
version: z.string().optional().describe("Version to install"),
|
|
297
|
+
name: z.string().optional().describe("Custom name for the installed action")
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
async ({ storeItemId, version, name }) => {
|
|
301
|
+
try {
|
|
302
|
+
const variables = { storeItemId };
|
|
303
|
+
if (version !== void 0) variables.version = version;
|
|
304
|
+
if (name !== void 0) variables.name = name;
|
|
305
|
+
const data = await ctx.gql.workspace.request(
|
|
306
|
+
INSTALL_ACTION_FROM_STORE,
|
|
307
|
+
variables
|
|
308
|
+
);
|
|
309
|
+
return jsonResult(data.installActionFromStore);
|
|
310
|
+
} catch (error) {
|
|
311
|
+
ctx.logger.error("vibecontrols_actions_install failed", { error });
|
|
312
|
+
return errorResult(
|
|
313
|
+
`Failed to install Action from store: ${error instanceof Error ? error.message : String(error)}`
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
);
|
|
318
|
+
server.registerTool(
|
|
319
|
+
track(mcpToolName(ctx.productName, "actions_cancel_execution")),
|
|
320
|
+
{
|
|
321
|
+
title: "Cancel Action Execution",
|
|
322
|
+
description: "Cancel a running Vibe Action execution.",
|
|
323
|
+
inputSchema: {
|
|
324
|
+
id: z.string().describe("Action execution ID to cancel")
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
async ({ id }) => {
|
|
328
|
+
try {
|
|
329
|
+
const data = await ctx.gql.workspace.request(
|
|
330
|
+
CANCEL_ACTION_EXECUTION,
|
|
331
|
+
{ id }
|
|
332
|
+
);
|
|
333
|
+
return jsonResult(data.cancelActionExecution);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
ctx.logger.error("vibecontrols_actions_cancel_execution failed", { error });
|
|
336
|
+
return errorResult(
|
|
337
|
+
`Failed to cancel Action Execution: ${error instanceof Error ? error.message : String(error)}`
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
server.registerTool(
|
|
343
|
+
track(mcpToolName(ctx.productName, "actions_schedule")),
|
|
344
|
+
{
|
|
345
|
+
title: "Schedule Action",
|
|
346
|
+
description: "Create a scheduled job for a Vibe Action via the scheduler service.",
|
|
347
|
+
inputSchema: {
|
|
348
|
+
actionId: z.string().describe("Action ID to schedule"),
|
|
349
|
+
scheduleType: z.string().describe("Schedule type (CRON, ONE_TIME, FIXED_INTERVAL)"),
|
|
350
|
+
cronExpression: z.string().optional().describe("Cron expression (for CRON type)"),
|
|
351
|
+
timezone: z.string().optional().describe("Timezone (default UTC)"),
|
|
352
|
+
scheduledAt: z.string().optional().describe("ISO date for ONE_TIME schedule"),
|
|
353
|
+
interval: z.number().optional().describe("Interval value (for FIXED_INTERVAL)"),
|
|
354
|
+
intervalUnit: z.string().optional().describe("Interval unit (MINUTES, HOURS, DAYS)"),
|
|
355
|
+
startDate: z.string().optional().describe("Schedule start date (ISO)"),
|
|
356
|
+
endDate: z.string().optional().describe("Schedule end date (ISO)"),
|
|
357
|
+
name: z.string().optional().describe("Name for the scheduled job")
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
async ({
|
|
361
|
+
actionId,
|
|
362
|
+
scheduleType,
|
|
363
|
+
cronExpression,
|
|
364
|
+
timezone,
|
|
365
|
+
scheduledAt,
|
|
366
|
+
interval,
|
|
367
|
+
intervalUnit,
|
|
368
|
+
startDate,
|
|
369
|
+
endDate,
|
|
370
|
+
name
|
|
371
|
+
}) => {
|
|
372
|
+
try {
|
|
373
|
+
const input = { actionId, scheduleType };
|
|
374
|
+
if (cronExpression !== void 0) input.cronExpression = cronExpression;
|
|
375
|
+
if (timezone !== void 0) input.timezone = timezone;
|
|
376
|
+
if (scheduledAt !== void 0) input.scheduledAt = scheduledAt;
|
|
377
|
+
if (interval !== void 0) input.interval = interval;
|
|
378
|
+
if (intervalUnit !== void 0) input.intervalUnit = intervalUnit;
|
|
379
|
+
if (startDate !== void 0) input.startDate = startDate;
|
|
380
|
+
if (endDate !== void 0) input.endDate = endDate;
|
|
381
|
+
if (name !== void 0) input.name = name;
|
|
382
|
+
const data = await ctx.gql.workspace.request(
|
|
383
|
+
CREATE_SCHEDULED_JOB,
|
|
384
|
+
{
|
|
385
|
+
input
|
|
386
|
+
}
|
|
387
|
+
);
|
|
388
|
+
return jsonResult(data.createScheduledJob);
|
|
389
|
+
} catch (error) {
|
|
390
|
+
ctx.logger.error("vibecontrols_actions_schedule failed", { error });
|
|
391
|
+
return errorResult(
|
|
392
|
+
`Failed to schedule Action: ${error instanceof Error ? error.message : String(error)}`
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
);
|
|
397
|
+
server.registerTool(
|
|
398
|
+
track(mcpToolName(ctx.productName, "actions_unschedule")),
|
|
399
|
+
{
|
|
400
|
+
title: "Unschedule Action",
|
|
401
|
+
description: "Delete a scheduled job for a Vibe Action.",
|
|
402
|
+
inputSchema: {
|
|
403
|
+
scheduledJobId: z.string().describe("Scheduled job ID to delete")
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
async ({ scheduledJobId }) => {
|
|
407
|
+
try {
|
|
408
|
+
const data = await ctx.gql.workspace.request(
|
|
409
|
+
DELETE_SCHEDULED_JOB,
|
|
410
|
+
{
|
|
411
|
+
id: scheduledJobId
|
|
412
|
+
}
|
|
413
|
+
);
|
|
414
|
+
return jsonResult({ deleted: data.deleteScheduledJob, scheduledJobId });
|
|
415
|
+
} catch (error) {
|
|
416
|
+
ctx.logger.error("vibecontrols_actions_unschedule failed", { error });
|
|
417
|
+
return errorResult(
|
|
418
|
+
`Failed to unschedule Action: ${error instanceof Error ? error.message : String(error)}`
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
);
|
|
423
|
+
server.registerTool(
|
|
424
|
+
track(mcpToolName(ctx.productName, "actions_schedules_list")),
|
|
425
|
+
{
|
|
426
|
+
title: "List Scheduled Jobs",
|
|
427
|
+
description: "List scheduled jobs for Vibe Actions, optionally filtered by action ID.",
|
|
428
|
+
inputSchema: {
|
|
429
|
+
actionId: z.string().optional().describe("Filter by action ID"),
|
|
430
|
+
limit: z.number().optional().describe("Max results to return"),
|
|
431
|
+
offset: z.number().optional().describe("Number of results to skip")
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
async ({ actionId, limit, offset }) => {
|
|
435
|
+
try {
|
|
436
|
+
const filter = {};
|
|
437
|
+
if (actionId !== void 0) filter.actionId = actionId;
|
|
438
|
+
const pagination = {};
|
|
439
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
440
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
441
|
+
const data = await ctx.gql.workspace.request(
|
|
442
|
+
LIST_SCHEDULED_JOBS,
|
|
443
|
+
{
|
|
444
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
445
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
446
|
+
}
|
|
447
|
+
);
|
|
448
|
+
return jsonResult(data.scheduledJobs);
|
|
449
|
+
} catch (error) {
|
|
450
|
+
ctx.logger.error("vibecontrols_actions_schedules_list failed", { error });
|
|
451
|
+
return errorResult(
|
|
452
|
+
`Failed to list scheduled jobs: ${error instanceof Error ? error.message : String(error)}`
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
function registerAgentTools(server, ctx, track) {
|
|
459
|
+
server.registerTool(
|
|
460
|
+
track(mcpToolName(ctx.productName, "agents_list")),
|
|
461
|
+
{
|
|
462
|
+
title: "List Agents",
|
|
463
|
+
description: "List all VibeControls agents with optional filters and pagination.",
|
|
464
|
+
inputSchema: {
|
|
465
|
+
name: z.string().optional().describe("Filter by agent name"),
|
|
466
|
+
hostname: z.string().optional().describe("Filter by hostname"),
|
|
467
|
+
platform: z.string().optional().describe("Filter by platform"),
|
|
468
|
+
isActive: z.boolean().optional().describe("Filter by active status"),
|
|
469
|
+
limit: z.number().optional().describe("Max results to return"),
|
|
470
|
+
offset: z.number().optional().describe("Number of results to skip")
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
async ({ name, hostname, platform, isActive, limit, offset }) => {
|
|
474
|
+
try {
|
|
475
|
+
const filter = {};
|
|
476
|
+
if (name !== void 0) filter.name = name;
|
|
477
|
+
if (hostname !== void 0) filter.hostname = hostname;
|
|
478
|
+
if (platform !== void 0) filter.platform = platform;
|
|
479
|
+
if (isActive !== void 0) filter.isActive = isActive;
|
|
480
|
+
const pagination = {};
|
|
481
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
482
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
483
|
+
const data = await ctx.gql.workspace.request(LIST_AGENTS, {
|
|
484
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
485
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
486
|
+
});
|
|
487
|
+
return jsonResult(data.vibecontrolsAgents);
|
|
488
|
+
} catch (error) {
|
|
489
|
+
ctx.logger.error("vibecontrols_agents_list failed", { error });
|
|
490
|
+
return errorResult(
|
|
491
|
+
`Failed to list agents: ${error instanceof Error ? error.message : String(error)}`
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
);
|
|
496
|
+
server.registerTool(
|
|
497
|
+
track(mcpToolName(ctx.productName, "agents_get")),
|
|
498
|
+
{
|
|
499
|
+
title: "Get Agent",
|
|
500
|
+
description: "Get a VibeControls agent by its ID.",
|
|
501
|
+
inputSchema: { id: z.string().describe("Agent ID") }
|
|
502
|
+
},
|
|
503
|
+
async ({ id }) => {
|
|
504
|
+
try {
|
|
505
|
+
const data = await ctx.gql.workspace.request(GET_AGENT, {
|
|
506
|
+
id
|
|
507
|
+
});
|
|
508
|
+
return jsonResult(data.vibecontrolsAgent);
|
|
509
|
+
} catch (error) {
|
|
510
|
+
ctx.logger.error("vibecontrols_agents_get failed", { error });
|
|
511
|
+
return errorResult(
|
|
512
|
+
`Failed to get agent: ${error instanceof Error ? error.message : String(error)}`
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
);
|
|
517
|
+
server.registerTool(
|
|
518
|
+
track(mcpToolName(ctx.productName, "agents_create")),
|
|
519
|
+
{
|
|
520
|
+
title: "Create Agent",
|
|
521
|
+
description: "Create a new VibeControls agent.",
|
|
522
|
+
inputSchema: {
|
|
523
|
+
name: z.string().describe("Agent name"),
|
|
524
|
+
hostname: z.string().describe("Agent hostname"),
|
|
525
|
+
platform: z.string().optional().describe("Operating system platform"),
|
|
526
|
+
architecture: z.string().optional().describe("CPU architecture"),
|
|
527
|
+
version: z.string().optional().describe("Agent version"),
|
|
528
|
+
tunnelUrl: z.string().optional().describe("Tunnel URL for remote access"),
|
|
529
|
+
apiUrl: z.string().optional().describe("Agent API URL"),
|
|
530
|
+
capabilities: z.array(z.string()).optional().describe("Agent capabilities")
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
async ({
|
|
534
|
+
name,
|
|
535
|
+
hostname,
|
|
536
|
+
platform,
|
|
537
|
+
architecture,
|
|
538
|
+
version,
|
|
539
|
+
tunnelUrl,
|
|
540
|
+
apiUrl,
|
|
541
|
+
capabilities
|
|
542
|
+
}) => {
|
|
543
|
+
try {
|
|
544
|
+
const input = { name, hostname };
|
|
545
|
+
if (platform !== void 0) input.platform = platform;
|
|
546
|
+
if (architecture !== void 0) input.architecture = architecture;
|
|
547
|
+
if (version !== void 0) input.version = version;
|
|
548
|
+
if (tunnelUrl !== void 0) input.tunnelUrl = tunnelUrl;
|
|
549
|
+
if (apiUrl !== void 0) input.apiUrl = apiUrl;
|
|
550
|
+
if (capabilities !== void 0) input.capabilities = capabilities;
|
|
551
|
+
const data = await ctx.gql.workspace.request(
|
|
552
|
+
CREATE_AGENT,
|
|
553
|
+
{
|
|
554
|
+
input
|
|
555
|
+
}
|
|
556
|
+
);
|
|
557
|
+
return jsonResult(data.createVibecontrolsAgent);
|
|
558
|
+
} catch (error) {
|
|
559
|
+
ctx.logger.error("vibecontrols_agents_create failed", { error });
|
|
560
|
+
return errorResult(
|
|
561
|
+
`Failed to create agent: ${error instanceof Error ? error.message : String(error)}`
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
);
|
|
566
|
+
server.registerTool(
|
|
567
|
+
track(mcpToolName(ctx.productName, "agents_update")),
|
|
568
|
+
{
|
|
569
|
+
title: "Update Agent",
|
|
570
|
+
description: "Update an existing VibeControls agent.",
|
|
571
|
+
inputSchema: {
|
|
572
|
+
id: z.string().describe("Agent ID"),
|
|
573
|
+
name: z.string().optional().describe("Updated name"),
|
|
574
|
+
hostname: z.string().optional().describe("Updated hostname"),
|
|
575
|
+
platform: z.string().optional().describe("Updated platform"),
|
|
576
|
+
architecture: z.string().optional().describe("Updated architecture"),
|
|
577
|
+
version: z.string().optional().describe("Updated version"),
|
|
578
|
+
tunnelUrl: z.string().optional().describe("Updated tunnel URL"),
|
|
579
|
+
apiUrl: z.string().optional().describe("Updated API URL"),
|
|
580
|
+
capabilities: z.array(z.string()).optional().describe("Updated capabilities"),
|
|
581
|
+
isActive: z.boolean().optional().describe("Active status")
|
|
582
|
+
}
|
|
583
|
+
},
|
|
584
|
+
async ({
|
|
585
|
+
id,
|
|
586
|
+
name,
|
|
587
|
+
hostname,
|
|
588
|
+
platform,
|
|
589
|
+
architecture,
|
|
590
|
+
version,
|
|
591
|
+
tunnelUrl,
|
|
592
|
+
apiUrl,
|
|
593
|
+
capabilities,
|
|
594
|
+
isActive
|
|
595
|
+
}) => {
|
|
596
|
+
try {
|
|
597
|
+
const input = {};
|
|
598
|
+
if (name !== void 0) input.name = name;
|
|
599
|
+
if (hostname !== void 0) input.hostname = hostname;
|
|
600
|
+
if (platform !== void 0) input.platform = platform;
|
|
601
|
+
if (architecture !== void 0) input.architecture = architecture;
|
|
602
|
+
if (version !== void 0) input.version = version;
|
|
603
|
+
if (tunnelUrl !== void 0) input.tunnelUrl = tunnelUrl;
|
|
604
|
+
if (apiUrl !== void 0) input.apiUrl = apiUrl;
|
|
605
|
+
if (capabilities !== void 0) input.capabilities = capabilities;
|
|
606
|
+
if (isActive !== void 0) input.isActive = isActive;
|
|
607
|
+
const data = await ctx.gql.workspace.request(
|
|
608
|
+
UPDATE_AGENT,
|
|
609
|
+
{
|
|
610
|
+
id,
|
|
611
|
+
input
|
|
612
|
+
}
|
|
613
|
+
);
|
|
614
|
+
return jsonResult(data.updateVibecontrolsAgent);
|
|
615
|
+
} catch (error) {
|
|
616
|
+
ctx.logger.error("vibecontrols_agents_update failed", { error });
|
|
617
|
+
return errorResult(
|
|
618
|
+
`Failed to update agent: ${error instanceof Error ? error.message : String(error)}`
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
);
|
|
623
|
+
server.registerTool(
|
|
624
|
+
track(mcpToolName(ctx.productName, "agents_delete")),
|
|
625
|
+
{
|
|
626
|
+
title: "Delete Agent",
|
|
627
|
+
description: "Permanently delete a VibeControls agent.",
|
|
628
|
+
inputSchema: { id: z.string().describe("Agent ID to delete") }
|
|
629
|
+
},
|
|
630
|
+
async ({ id }) => {
|
|
631
|
+
try {
|
|
632
|
+
const data = await ctx.gql.workspace.request(
|
|
633
|
+
DELETE_AGENT,
|
|
634
|
+
{
|
|
635
|
+
id
|
|
636
|
+
}
|
|
637
|
+
);
|
|
638
|
+
return jsonResult({ deleted: data.deleteVibecontrolsAgent, agentId: id });
|
|
639
|
+
} catch (error) {
|
|
640
|
+
ctx.logger.error("vibecontrols_agents_delete failed", { error });
|
|
641
|
+
return errorResult(
|
|
642
|
+
`Failed to delete agent: ${error instanceof Error ? error.message : String(error)}`
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
);
|
|
647
|
+
server.registerTool(
|
|
648
|
+
track(mcpToolName(ctx.productName, "agents_probe")),
|
|
649
|
+
{
|
|
650
|
+
title: "Probe Agent Connection",
|
|
651
|
+
description: "Probe the connectivity of a specific agent to check if it is reachable.",
|
|
652
|
+
inputSchema: { id: z.string().describe("Agent ID to probe") }
|
|
653
|
+
},
|
|
654
|
+
async ({ id }) => {
|
|
655
|
+
try {
|
|
656
|
+
const data = await ctx.gql.workspace.request(
|
|
657
|
+
PROBE_AGENT_CONNECTION,
|
|
658
|
+
{ id }
|
|
659
|
+
);
|
|
660
|
+
return jsonResult(data.probeAgentConnection);
|
|
661
|
+
} catch (error) {
|
|
662
|
+
ctx.logger.error("vibecontrols_agents_probe failed", { error });
|
|
663
|
+
return errorResult(
|
|
664
|
+
`Failed to probe agent: ${error instanceof Error ? error.message : String(error)}`
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
);
|
|
669
|
+
server.registerTool(
|
|
670
|
+
track(mcpToolName(ctx.productName, "agents_health")),
|
|
671
|
+
{
|
|
672
|
+
title: "Agent Health Probes",
|
|
673
|
+
description: "Run health probes against all registered agents. Returns health status for each agent.",
|
|
674
|
+
inputSchema: {}
|
|
675
|
+
},
|
|
676
|
+
async () => {
|
|
677
|
+
try {
|
|
678
|
+
const data = await ctx.gql.workspace.request(
|
|
679
|
+
AGENT_HEALTH_PROBES
|
|
680
|
+
);
|
|
681
|
+
return jsonResult(data.vibecontrolsAgentHealthProbes);
|
|
682
|
+
} catch (error) {
|
|
683
|
+
ctx.logger.error("vibecontrols_agents_health failed", { error });
|
|
684
|
+
return errorResult(
|
|
685
|
+
`Failed to get agent health: ${error instanceof Error ? error.message : String(error)}`
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
);
|
|
690
|
+
server.registerTool(
|
|
691
|
+
track(mcpToolName(ctx.productName, "agents_plugins")),
|
|
692
|
+
{
|
|
693
|
+
title: "List Agent Plugins",
|
|
694
|
+
description: "List all plugins installed on a specific agent.",
|
|
695
|
+
inputSchema: { agentId: z.string().describe("Agent ID") }
|
|
696
|
+
},
|
|
697
|
+
async ({ agentId }) => {
|
|
698
|
+
try {
|
|
699
|
+
const data = await ctx.gql.workspace.request(AGENT_PLUGINS, {
|
|
700
|
+
agentId
|
|
701
|
+
});
|
|
702
|
+
return jsonResult(data.agentPlugins);
|
|
703
|
+
} catch (error) {
|
|
704
|
+
ctx.logger.error("vibecontrols_agents_plugins failed", { error });
|
|
705
|
+
return errorResult(
|
|
706
|
+
`Failed to list agent plugins: ${error instanceof Error ? error.message : String(error)}`
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
);
|
|
711
|
+
server.registerTool(
|
|
712
|
+
track(mcpToolName(ctx.productName, "agents_install_plugin")),
|
|
713
|
+
{
|
|
714
|
+
title: "Install Agent Plugin",
|
|
715
|
+
description: "Install a plugin on a specific agent by package name.",
|
|
716
|
+
inputSchema: {
|
|
717
|
+
agentId: z.string().describe("Agent ID"),
|
|
718
|
+
packageName: z.string().describe("NPM package name of the plugin to install")
|
|
719
|
+
}
|
|
720
|
+
},
|
|
721
|
+
async ({ agentId, packageName }) => {
|
|
722
|
+
try {
|
|
723
|
+
const data = await ctx.gql.workspace.request(
|
|
724
|
+
INSTALL_AGENT_PLUGIN,
|
|
725
|
+
{
|
|
726
|
+
agentId,
|
|
727
|
+
packageName
|
|
728
|
+
}
|
|
729
|
+
);
|
|
730
|
+
return jsonResult(data.installAgentPlugin);
|
|
731
|
+
} catch (error) {
|
|
732
|
+
ctx.logger.error("vibecontrols_agents_install_plugin failed", { error });
|
|
733
|
+
return errorResult(
|
|
734
|
+
`Failed to install plugin: ${error instanceof Error ? error.message : String(error)}`
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
);
|
|
739
|
+
server.registerTool(
|
|
740
|
+
track(mcpToolName(ctx.productName, "agents_remove_plugin")),
|
|
741
|
+
{
|
|
742
|
+
title: "Remove Agent Plugin",
|
|
743
|
+
description: "Remove a plugin from a specific agent.",
|
|
744
|
+
inputSchema: {
|
|
745
|
+
agentId: z.string().describe("Agent ID"),
|
|
746
|
+
packageName: z.string().describe("NPM package name of the plugin to remove")
|
|
747
|
+
}
|
|
748
|
+
},
|
|
749
|
+
async ({ agentId, packageName }) => {
|
|
750
|
+
try {
|
|
751
|
+
const data = await ctx.gql.workspace.request(
|
|
752
|
+
REMOVE_AGENT_PLUGIN,
|
|
753
|
+
{
|
|
754
|
+
agentId,
|
|
755
|
+
packageName
|
|
756
|
+
}
|
|
757
|
+
);
|
|
758
|
+
return jsonResult(data.removeAgentPlugin);
|
|
759
|
+
} catch (error) {
|
|
760
|
+
ctx.logger.error("vibecontrols_agents_remove_plugin failed", { error });
|
|
761
|
+
return errorResult(
|
|
762
|
+
`Failed to remove plugin: ${error instanceof Error ? error.message : String(error)}`
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
function registerAiEventTools(server, ctx, track) {
|
|
769
|
+
server.registerTool(
|
|
770
|
+
track(mcpToolName(ctx.productName, "ai_events_list")),
|
|
771
|
+
{
|
|
772
|
+
title: "List AI Tool Events",
|
|
773
|
+
description: "List AI tool events with optional filters and pagination.",
|
|
774
|
+
inputSchema: {
|
|
775
|
+
source: z.string().optional().describe("Filter by event source"),
|
|
776
|
+
eventType: z.string().optional().describe("Filter by event type"),
|
|
777
|
+
agentId: z.string().optional().describe("Filter by agent ID"),
|
|
778
|
+
limit: z.number().optional().describe("Max results"),
|
|
779
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
780
|
+
}
|
|
781
|
+
},
|
|
782
|
+
async ({ source, eventType, agentId, limit, offset }) => {
|
|
783
|
+
try {
|
|
784
|
+
const filter = {};
|
|
785
|
+
if (source !== void 0) filter.source = source;
|
|
786
|
+
if (eventType !== void 0) filter.eventType = eventType;
|
|
787
|
+
if (agentId !== void 0) filter.agentId = agentId;
|
|
788
|
+
const pagination = {};
|
|
789
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
790
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
791
|
+
const data = await ctx.gql.workspace.request(
|
|
792
|
+
LIST_AI_TOOL_EVENTS,
|
|
793
|
+
{
|
|
794
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
795
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
796
|
+
}
|
|
797
|
+
);
|
|
798
|
+
return jsonResult(data.aiToolEvents);
|
|
799
|
+
} catch (error) {
|
|
800
|
+
ctx.logger.error("vibecontrols_ai_events_list failed", { error });
|
|
801
|
+
return errorResult(
|
|
802
|
+
`Failed to list AI events: ${error instanceof Error ? error.message : String(error)}`
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
);
|
|
807
|
+
server.registerTool(
|
|
808
|
+
track(mcpToolName(ctx.productName, "ai_events_create")),
|
|
809
|
+
{
|
|
810
|
+
title: "Create AI Tool Event",
|
|
811
|
+
description: "Record a new AI tool event.",
|
|
812
|
+
inputSchema: {
|
|
813
|
+
source: z.string().describe("Event source (e.g., mcp, cli, sdk)"),
|
|
814
|
+
eventType: z.string().describe("Event type (e.g., tool_call, completion)"),
|
|
815
|
+
payload: z.string().describe("Event payload as JSON string"),
|
|
816
|
+
agentId: z.string().optional().describe("Associated agent ID")
|
|
817
|
+
}
|
|
818
|
+
},
|
|
819
|
+
async ({ source, eventType, payload, agentId }) => {
|
|
820
|
+
try {
|
|
821
|
+
const input = { source, eventType };
|
|
822
|
+
input.payload = JSON.parse(payload);
|
|
823
|
+
if (agentId !== void 0) input.agentId = agentId;
|
|
824
|
+
const data = await ctx.gql.workspace.request(
|
|
825
|
+
CREATE_AI_TOOL_EVENT,
|
|
826
|
+
{
|
|
827
|
+
input
|
|
828
|
+
}
|
|
829
|
+
);
|
|
830
|
+
return jsonResult(data.createAiToolEvent);
|
|
831
|
+
} catch (error) {
|
|
832
|
+
ctx.logger.error("vibecontrols_ai_events_create failed", { error });
|
|
833
|
+
return errorResult(
|
|
834
|
+
`Failed to create AI event: ${error instanceof Error ? error.message : String(error)}`
|
|
835
|
+
);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
);
|
|
839
|
+
server.registerTool(
|
|
840
|
+
track(mcpToolName(ctx.productName, "ai_events_recent")),
|
|
841
|
+
{
|
|
842
|
+
title: "Recent AI Tool Events",
|
|
843
|
+
description: "Get recent AI tool events for a specific agent.",
|
|
844
|
+
inputSchema: {
|
|
845
|
+
agentId: z.string().describe("Agent ID"),
|
|
846
|
+
limit: z.number().optional().describe("Maximum events to return")
|
|
847
|
+
}
|
|
848
|
+
},
|
|
849
|
+
async ({ agentId, limit }) => {
|
|
850
|
+
try {
|
|
851
|
+
const data = await ctx.gql.workspace.request(
|
|
852
|
+
RECENT_AI_TOOL_EVENTS,
|
|
853
|
+
{ agentId, limit }
|
|
854
|
+
);
|
|
855
|
+
return jsonResult(data.recentAiToolEvents);
|
|
856
|
+
} catch (error) {
|
|
857
|
+
ctx.logger.error("vibecontrols_ai_events_recent failed", { error });
|
|
858
|
+
return errorResult(
|
|
859
|
+
`Failed to get recent AI events: ${error instanceof Error ? error.message : String(error)}`
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
function registerAnalyticsTools(server, ctx, track) {
|
|
866
|
+
server.registerTool(
|
|
867
|
+
track(mcpToolName(ctx.productName, "analytics_overview")),
|
|
868
|
+
{
|
|
869
|
+
title: "VibeControls Analytics Overview",
|
|
870
|
+
description: "Get consolidated analytics overview with KPIs, time series, and breakdowns for all VibeControls entities (agents, sessions, vibes, actions, webhooks, AI events, vibe decks, audit, docs, notes, config).",
|
|
871
|
+
inputSchema: {
|
|
872
|
+
startDate: z.string().optional().describe("Start date (ISO format). Defaults to 7 days ago."),
|
|
873
|
+
endDate: z.string().optional().describe("End date (ISO format). Defaults to now."),
|
|
874
|
+
granularity: z.enum(["HOUR", "DAY", "WEEK", "MONTH"]).optional().default("DAY").describe("Time series granularity"),
|
|
875
|
+
entityTypes: z.array(
|
|
876
|
+
z.enum([
|
|
877
|
+
"AGENT",
|
|
878
|
+
"TARGET",
|
|
879
|
+
"SESSION",
|
|
880
|
+
"VIBE",
|
|
881
|
+
"ACTION",
|
|
882
|
+
"WEBHOOK",
|
|
883
|
+
"AI_EVENT",
|
|
884
|
+
"VIBE_DECK",
|
|
885
|
+
"AUDIT",
|
|
886
|
+
"DOCS",
|
|
887
|
+
"NOTE",
|
|
888
|
+
"CONFIGURATION"
|
|
889
|
+
])
|
|
890
|
+
).optional().describe("Filter to specific entity types (null = all)"),
|
|
891
|
+
agentId: z.string().optional().describe("Filter analytics by agent ID"),
|
|
892
|
+
vibeId: z.string().optional().describe("Filter analytics by vibe ID")
|
|
893
|
+
}
|
|
894
|
+
},
|
|
895
|
+
async ({ startDate, endDate, granularity, entityTypes, agentId, vibeId }) => {
|
|
896
|
+
try {
|
|
897
|
+
const input = {
|
|
898
|
+
startDate: startDate || new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3).toISOString(),
|
|
899
|
+
endDate: endDate || (/* @__PURE__ */ new Date()).toISOString(),
|
|
900
|
+
granularity: granularity || "DAY"
|
|
901
|
+
};
|
|
902
|
+
if (entityTypes && entityTypes.length > 0) input.entityTypes = entityTypes;
|
|
903
|
+
if (agentId) input.agentId = agentId;
|
|
904
|
+
if (vibeId) input.vibeId = vibeId;
|
|
905
|
+
const data = await ctx.gql.workspace.request(
|
|
906
|
+
VIBECONTROLS_ANALYTICS,
|
|
907
|
+
{ input }
|
|
908
|
+
);
|
|
909
|
+
return jsonResult(data.vibecontrolsAnalytics);
|
|
910
|
+
} catch (error) {
|
|
911
|
+
ctx.logger.error("vibecontrols_analytics_overview failed", { error });
|
|
912
|
+
return errorResult(
|
|
913
|
+
`Failed to get analytics: ${error instanceof Error ? error.message : String(error)}`
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
);
|
|
918
|
+
server.registerTool(
|
|
919
|
+
track(mcpToolName(ctx.productName, "analytics_summary")),
|
|
920
|
+
{
|
|
921
|
+
title: "VibeControls Analytics Summary",
|
|
922
|
+
description: "Get a quick KPI summary of all VibeControls entity counts (agents, sessions, vibes, actions, etc.). Lighter-weight than the full overview.",
|
|
923
|
+
inputSchema: {
|
|
924
|
+
startDate: z.string().optional().describe("Start date (ISO format). Defaults to 7 days ago."),
|
|
925
|
+
endDate: z.string().optional().describe("End date (ISO format). Defaults to now.")
|
|
926
|
+
}
|
|
927
|
+
},
|
|
928
|
+
async ({ startDate, endDate }) => {
|
|
929
|
+
try {
|
|
930
|
+
const input = {
|
|
931
|
+
startDate: startDate || new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3).toISOString(),
|
|
932
|
+
endDate: endDate || (/* @__PURE__ */ new Date()).toISOString(),
|
|
933
|
+
granularity: "DAY"
|
|
934
|
+
};
|
|
935
|
+
const data = await ctx.gql.workspace.request(VIBECONTROLS_ANALYTICS, { input });
|
|
936
|
+
const a = data.vibecontrolsAnalytics;
|
|
937
|
+
const summary = {
|
|
938
|
+
agents: { total: a.agents?.total, active: a.agents?.active },
|
|
939
|
+
targets: { total: a.targets?.total },
|
|
940
|
+
sessions: { total: a.sessions?.total, active: a.sessions?.active },
|
|
941
|
+
vibes: { total: a.vibes?.total },
|
|
942
|
+
actions: {
|
|
943
|
+
total: a.actions?.total,
|
|
944
|
+
executions: a.actions?.totalExecutions,
|
|
945
|
+
successRate: a.actions?.successRate
|
|
946
|
+
},
|
|
947
|
+
webhooks: { total: a.webhooks?.total, active: a.webhooks?.active },
|
|
948
|
+
aiEvents: { total: a.aiEvents?.total },
|
|
949
|
+
vibeDecks: {
|
|
950
|
+
totalDecks: a.vibeDecks?.totalDecks,
|
|
951
|
+
totalButtons: a.vibeDecks?.totalButtons
|
|
952
|
+
},
|
|
953
|
+
audit: { total: a.audit?.total },
|
|
954
|
+
docs: { sites: a.docs?.totalSites, pages: a.docs?.totalPages },
|
|
955
|
+
notes: { total: a.notes?.total, pinned: a.notes?.pinned },
|
|
956
|
+
configurations: { total: a.configurations?.total },
|
|
957
|
+
executionTimeMs: a.executionTimeMs
|
|
958
|
+
};
|
|
959
|
+
return jsonResult(summary);
|
|
960
|
+
} catch (error) {
|
|
961
|
+
ctx.logger.error("vibecontrols_analytics_summary failed", { error });
|
|
962
|
+
return errorResult(
|
|
963
|
+
`Failed to get analytics summary: ${error instanceof Error ? error.message : String(error)}`
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
);
|
|
968
|
+
}
|
|
969
|
+
function registerAuditTools(server, ctx, track) {
|
|
970
|
+
server.registerTool(
|
|
971
|
+
track(mcpToolName(ctx.productName, "audit_list")),
|
|
972
|
+
{
|
|
973
|
+
title: "List Audit Logs",
|
|
974
|
+
description: "List audit logs with optional filters and pagination.",
|
|
975
|
+
inputSchema: {
|
|
976
|
+
action: z.string().optional().describe("Filter by action type"),
|
|
977
|
+
resourceType: z.string().optional().describe("Filter by resource type"),
|
|
978
|
+
resourceId: z.string().optional().describe("Filter by resource ID"),
|
|
979
|
+
actorId: z.string().optional().describe("Filter by actor ID"),
|
|
980
|
+
status: z.string().optional().describe("Filter by status"),
|
|
981
|
+
limit: z.number().optional().describe("Max results"),
|
|
982
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
983
|
+
}
|
|
984
|
+
},
|
|
985
|
+
async ({ action, resourceType, resourceId, actorId, status, limit, offset }) => {
|
|
986
|
+
try {
|
|
987
|
+
const filter = {};
|
|
988
|
+
if (action !== void 0) filter.action = action;
|
|
989
|
+
if (resourceType !== void 0) filter.resourceType = resourceType;
|
|
990
|
+
if (resourceId !== void 0) filter.resourceId = resourceId;
|
|
991
|
+
if (actorId !== void 0) filter.actorId = actorId;
|
|
992
|
+
if (status !== void 0) filter.status = status;
|
|
993
|
+
const pagination = {};
|
|
994
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
995
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
996
|
+
const data = await ctx.gql.workspace.request(LIST_AUDIT_LOGS, {
|
|
997
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
998
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
999
|
+
});
|
|
1000
|
+
return jsonResult(data.vibeAuditLogs);
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
ctx.logger.error("vibecontrols_audit_list failed", { error });
|
|
1003
|
+
return errorResult(
|
|
1004
|
+
`Failed to list audit logs: ${error instanceof Error ? error.message : String(error)}`
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
);
|
|
1009
|
+
server.registerTool(
|
|
1010
|
+
track(mcpToolName(ctx.productName, "audit_get")),
|
|
1011
|
+
{
|
|
1012
|
+
title: "Get Audit Log",
|
|
1013
|
+
description: "Get an audit log entry by its ID.",
|
|
1014
|
+
inputSchema: { id: z.string().describe("Audit log ID") }
|
|
1015
|
+
},
|
|
1016
|
+
async ({ id }) => {
|
|
1017
|
+
try {
|
|
1018
|
+
const data = await ctx.gql.workspace.request(GET_AUDIT_LOG, {
|
|
1019
|
+
id
|
|
1020
|
+
});
|
|
1021
|
+
return jsonResult(data.vibeAuditLog);
|
|
1022
|
+
} catch (error) {
|
|
1023
|
+
ctx.logger.error("vibecontrols_audit_get failed", { error });
|
|
1024
|
+
return errorResult(
|
|
1025
|
+
`Failed to get audit log: ${error instanceof Error ? error.message : String(error)}`
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
);
|
|
1030
|
+
server.registerTool(
|
|
1031
|
+
track(mcpToolName(ctx.productName, "audit_stats")),
|
|
1032
|
+
{
|
|
1033
|
+
title: "Audit Log Stats",
|
|
1034
|
+
description: "Get aggregated statistics for audit logs.",
|
|
1035
|
+
inputSchema: {
|
|
1036
|
+
action: z.string().optional().describe("Filter stats by action type"),
|
|
1037
|
+
resourceType: z.string().optional().describe("Filter stats by resource type"),
|
|
1038
|
+
status: z.string().optional().describe("Filter stats by status")
|
|
1039
|
+
}
|
|
1040
|
+
},
|
|
1041
|
+
async ({ action, resourceType, status }) => {
|
|
1042
|
+
try {
|
|
1043
|
+
const filter = {};
|
|
1044
|
+
if (action !== void 0) filter.action = action;
|
|
1045
|
+
if (resourceType !== void 0) filter.resourceType = resourceType;
|
|
1046
|
+
if (status !== void 0) filter.status = status;
|
|
1047
|
+
const data = await ctx.gql.workspace.request(
|
|
1048
|
+
AUDIT_LOG_STATS,
|
|
1049
|
+
{
|
|
1050
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0
|
|
1051
|
+
}
|
|
1052
|
+
);
|
|
1053
|
+
return jsonResult(data.vibeAuditLogStats);
|
|
1054
|
+
} catch (error) {
|
|
1055
|
+
ctx.logger.error("vibecontrols_audit_stats failed", { error });
|
|
1056
|
+
return errorResult(
|
|
1057
|
+
`Failed to get audit log stats: ${error instanceof Error ? error.message : String(error)}`
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
);
|
|
1062
|
+
server.registerTool(
|
|
1063
|
+
track(mcpToolName(ctx.productName, "audit_export")),
|
|
1064
|
+
{
|
|
1065
|
+
title: "Export Audit Logs",
|
|
1066
|
+
description: "Export audit logs in a specified format.",
|
|
1067
|
+
inputSchema: {
|
|
1068
|
+
action: z.string().optional().describe("Filter by action type"),
|
|
1069
|
+
resourceType: z.string().optional().describe("Filter by resource type"),
|
|
1070
|
+
status: z.string().optional().describe("Filter by status"),
|
|
1071
|
+
format: z.string().optional().describe("Export format: json or csv")
|
|
1072
|
+
}
|
|
1073
|
+
},
|
|
1074
|
+
async ({ action, resourceType, status, format }) => {
|
|
1075
|
+
try {
|
|
1076
|
+
const filter = {};
|
|
1077
|
+
if (action !== void 0) filter.action = action;
|
|
1078
|
+
if (resourceType !== void 0) filter.resourceType = resourceType;
|
|
1079
|
+
if (status !== void 0) filter.status = status;
|
|
1080
|
+
const variables = {
|
|
1081
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0
|
|
1082
|
+
};
|
|
1083
|
+
if (format !== void 0) variables.format = format;
|
|
1084
|
+
const data = await ctx.gql.workspace.request(
|
|
1085
|
+
EXPORT_AUDIT_LOGS,
|
|
1086
|
+
variables
|
|
1087
|
+
);
|
|
1088
|
+
return jsonResult(data.exportVibeAuditLogs);
|
|
1089
|
+
} catch (error) {
|
|
1090
|
+
ctx.logger.error("vibecontrols_audit_export failed", { error });
|
|
1091
|
+
return errorResult(
|
|
1092
|
+
`Failed to export audit logs: ${error instanceof Error ? error.message : String(error)}`
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
);
|
|
1097
|
+
server.registerTool(
|
|
1098
|
+
track(mcpToolName(ctx.productName, "audit_delete")),
|
|
1099
|
+
{
|
|
1100
|
+
title: "Delete Audit Log",
|
|
1101
|
+
description: "Delete an audit log entry.",
|
|
1102
|
+
inputSchema: {
|
|
1103
|
+
id: z.string().describe("Audit log ID to delete"),
|
|
1104
|
+
reason: z.string().optional().describe("Reason for deletion")
|
|
1105
|
+
}
|
|
1106
|
+
},
|
|
1107
|
+
async ({ id, reason }) => {
|
|
1108
|
+
try {
|
|
1109
|
+
const variables = { id };
|
|
1110
|
+
if (reason !== void 0) variables.reason = reason;
|
|
1111
|
+
const data = await ctx.gql.workspace.request(
|
|
1112
|
+
DELETE_AUDIT_LOG,
|
|
1113
|
+
variables
|
|
1114
|
+
);
|
|
1115
|
+
return jsonResult(data.deleteVibeAuditLog);
|
|
1116
|
+
} catch (error) {
|
|
1117
|
+
ctx.logger.error("vibecontrols_audit_delete failed", { error });
|
|
1118
|
+
return errorResult(
|
|
1119
|
+
`Failed to delete audit log: ${error instanceof Error ? error.message : String(error)}`
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
var ConfigScopeEnum = z.enum(["WORKSPACE", "VIBE", "SESSION", "AGENT", "USER", "GLOBAL"]);
|
|
1126
|
+
function registerConfigurationTools(server, ctx, track) {
|
|
1127
|
+
server.registerTool(
|
|
1128
|
+
track(mcpToolName(ctx.productName, "config_list")),
|
|
1129
|
+
{
|
|
1130
|
+
title: "List Configurations",
|
|
1131
|
+
description: "List configuration key-value pairs with required filter.",
|
|
1132
|
+
inputSchema: {
|
|
1133
|
+
key: z.string().optional().describe("Filter by key pattern"),
|
|
1134
|
+
scope: ConfigScopeEnum.describe("Configuration scope"),
|
|
1135
|
+
scopeId: z.string().optional().describe("Filter by scope entity ID"),
|
|
1136
|
+
isSecret: z.boolean().optional().describe("Filter by secret status"),
|
|
1137
|
+
limit: z.number().optional().describe("Max results"),
|
|
1138
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
1139
|
+
}
|
|
1140
|
+
},
|
|
1141
|
+
async ({ key, scope, scopeId, isSecret, limit, offset }) => {
|
|
1142
|
+
try {
|
|
1143
|
+
const filter = { scope };
|
|
1144
|
+
if (key !== void 0) filter.key = key;
|
|
1145
|
+
if (scopeId !== void 0) filter.scopeId = scopeId;
|
|
1146
|
+
if (isSecret !== void 0) filter.isSecret = isSecret;
|
|
1147
|
+
const pagination = {};
|
|
1148
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
1149
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
1150
|
+
const data = await ctx.gql.workspace.request(
|
|
1151
|
+
LIST_CONFIGURATIONS,
|
|
1152
|
+
{
|
|
1153
|
+
filter,
|
|
1154
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
1155
|
+
}
|
|
1156
|
+
);
|
|
1157
|
+
return jsonResult(data.configurations);
|
|
1158
|
+
} catch (error) {
|
|
1159
|
+
ctx.logger.error("vibecontrols_config_list failed", { error });
|
|
1160
|
+
return errorResult(
|
|
1161
|
+
`Failed to list configurations: ${error instanceof Error ? error.message : String(error)}`
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
);
|
|
1166
|
+
server.registerTool(
|
|
1167
|
+
track(mcpToolName(ctx.productName, "config_get")),
|
|
1168
|
+
{
|
|
1169
|
+
title: "Get Configuration",
|
|
1170
|
+
description: "Get a configuration value by key and scope.",
|
|
1171
|
+
inputSchema: {
|
|
1172
|
+
key: z.string().describe("Configuration key"),
|
|
1173
|
+
scope: ConfigScopeEnum.describe("Configuration scope"),
|
|
1174
|
+
scopeId: z.string().optional().describe("Scope entity ID")
|
|
1175
|
+
}
|
|
1176
|
+
},
|
|
1177
|
+
async ({ key, scope, scopeId }) => {
|
|
1178
|
+
try {
|
|
1179
|
+
const data = await ctx.gql.workspace.request(
|
|
1180
|
+
GET_CONFIGURATION,
|
|
1181
|
+
{
|
|
1182
|
+
key,
|
|
1183
|
+
scope,
|
|
1184
|
+
scopeId
|
|
1185
|
+
}
|
|
1186
|
+
);
|
|
1187
|
+
return jsonResult(data.configuration);
|
|
1188
|
+
} catch (error) {
|
|
1189
|
+
ctx.logger.error("vibecontrols_config_get failed", { error });
|
|
1190
|
+
return errorResult(
|
|
1191
|
+
`Failed to get configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
1192
|
+
);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
);
|
|
1196
|
+
server.registerTool(
|
|
1197
|
+
track(mcpToolName(ctx.productName, "config_set")),
|
|
1198
|
+
{
|
|
1199
|
+
title: "Set Configuration",
|
|
1200
|
+
description: "Set (create or update) a configuration value.",
|
|
1201
|
+
inputSchema: {
|
|
1202
|
+
key: z.string().describe("Configuration key"),
|
|
1203
|
+
scope: ConfigScopeEnum.describe("Configuration scope"),
|
|
1204
|
+
scopeId: z.string().optional().describe("Scope entity ID"),
|
|
1205
|
+
value: z.string().describe("Configuration value as a JSON string"),
|
|
1206
|
+
isSecret: z.boolean().optional().describe("Mark as secret (value will be masked in reads)")
|
|
1207
|
+
}
|
|
1208
|
+
},
|
|
1209
|
+
async ({ key, scope, scopeId, value, isSecret }) => {
|
|
1210
|
+
try {
|
|
1211
|
+
const parsedValue = JSON.parse(value);
|
|
1212
|
+
const variables = { key, scope, value: parsedValue };
|
|
1213
|
+
if (scopeId !== void 0) variables.scopeId = scopeId;
|
|
1214
|
+
if (isSecret !== void 0) variables.isSecret = isSecret;
|
|
1215
|
+
const data = await ctx.gql.workspace.request(
|
|
1216
|
+
SET_CONFIGURATION,
|
|
1217
|
+
variables
|
|
1218
|
+
);
|
|
1219
|
+
return jsonResult(data.setConfiguration);
|
|
1220
|
+
} catch (error) {
|
|
1221
|
+
ctx.logger.error("vibecontrols_config_set failed", { error });
|
|
1222
|
+
return errorResult(
|
|
1223
|
+
`Failed to set configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
);
|
|
1228
|
+
server.registerTool(
|
|
1229
|
+
track(mcpToolName(ctx.productName, "config_delete")),
|
|
1230
|
+
{
|
|
1231
|
+
title: "Delete Configuration",
|
|
1232
|
+
description: "Delete a configuration by key and scope.",
|
|
1233
|
+
inputSchema: {
|
|
1234
|
+
key: z.string().describe("Configuration key to delete"),
|
|
1235
|
+
scope: ConfigScopeEnum.describe("Configuration scope"),
|
|
1236
|
+
scopeId: z.string().optional().describe("Scope entity ID")
|
|
1237
|
+
}
|
|
1238
|
+
},
|
|
1239
|
+
async ({ key, scope, scopeId }) => {
|
|
1240
|
+
try {
|
|
1241
|
+
const data = await ctx.gql.workspace.request(
|
|
1242
|
+
DELETE_CONFIGURATION,
|
|
1243
|
+
{ key, scope, scopeId }
|
|
1244
|
+
);
|
|
1245
|
+
return jsonResult({ deleted: data.deleteConfiguration, key, scope });
|
|
1246
|
+
} catch (error) {
|
|
1247
|
+
ctx.logger.error("vibecontrols_config_delete failed", { error });
|
|
1248
|
+
return errorResult(
|
|
1249
|
+
`Failed to delete configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
);
|
|
1254
|
+
server.registerTool(
|
|
1255
|
+
track(mcpToolName(ctx.productName, "config_by_scope")),
|
|
1256
|
+
{
|
|
1257
|
+
title: "Configurations by Scope",
|
|
1258
|
+
description: "Get all configuration values for a given scope.",
|
|
1259
|
+
inputSchema: {
|
|
1260
|
+
scope: ConfigScopeEnum.describe("Configuration scope"),
|
|
1261
|
+
scopeId: z.string().optional().describe("Scope entity ID")
|
|
1262
|
+
}
|
|
1263
|
+
},
|
|
1264
|
+
async ({ scope, scopeId }) => {
|
|
1265
|
+
try {
|
|
1266
|
+
const data = await ctx.gql.workspace.request(
|
|
1267
|
+
CONFIGURATIONS_BY_SCOPE,
|
|
1268
|
+
{ scope, scopeId }
|
|
1269
|
+
);
|
|
1270
|
+
return jsonResult(data.configurationsByScope);
|
|
1271
|
+
} catch (error) {
|
|
1272
|
+
ctx.logger.error("vibecontrols_config_by_scope failed", { error });
|
|
1273
|
+
return errorResult(
|
|
1274
|
+
`Failed to get configurations by scope: ${error instanceof Error ? error.message : String(error)}`
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1280
|
+
function registerDocsTools(server, ctx, track) {
|
|
1281
|
+
server.registerTool(
|
|
1282
|
+
track(mcpToolName(ctx.productName, "docs_sites_list")),
|
|
1283
|
+
{
|
|
1284
|
+
title: "List Docs Sites",
|
|
1285
|
+
description: "List documentation sites with optional filtering by vibe and pagination.",
|
|
1286
|
+
inputSchema: {
|
|
1287
|
+
vibeId: z.string().optional().describe("Filter by vibe ID"),
|
|
1288
|
+
limit: z.number().optional().describe("Max results"),
|
|
1289
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
1290
|
+
}
|
|
1291
|
+
},
|
|
1292
|
+
async ({ vibeId, limit, offset }) => {
|
|
1293
|
+
try {
|
|
1294
|
+
const variables = {};
|
|
1295
|
+
if (vibeId !== void 0) variables.vibeId = vibeId;
|
|
1296
|
+
if (limit !== void 0) variables.limit = limit;
|
|
1297
|
+
if (offset !== void 0) variables.offset = offset;
|
|
1298
|
+
const data = await ctx.gql.workspace.request(
|
|
1299
|
+
LIST_DOCS_SITES,
|
|
1300
|
+
variables
|
|
1301
|
+
);
|
|
1302
|
+
return jsonResult(data.docsSites);
|
|
1303
|
+
} catch (error) {
|
|
1304
|
+
ctx.logger.error("vibecontrols_docs_sites_list failed", { error });
|
|
1305
|
+
return errorResult(
|
|
1306
|
+
`Failed to list docs sites: ${error instanceof Error ? error.message : String(error)}`
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
);
|
|
1311
|
+
server.registerTool(
|
|
1312
|
+
track(mcpToolName(ctx.productName, "docs_sites_get")),
|
|
1313
|
+
{
|
|
1314
|
+
title: "Get Docs Site",
|
|
1315
|
+
description: "Get a documentation site by its vibe ID.",
|
|
1316
|
+
inputSchema: { vibeId: z.string().describe("Vibe ID") }
|
|
1317
|
+
},
|
|
1318
|
+
async ({ vibeId }) => {
|
|
1319
|
+
try {
|
|
1320
|
+
const data = await ctx.gql.workspace.request(GET_DOCS_SITE, {
|
|
1321
|
+
vibeId
|
|
1322
|
+
});
|
|
1323
|
+
return jsonResult(data.docsSite);
|
|
1324
|
+
} catch (error) {
|
|
1325
|
+
ctx.logger.error("vibecontrols_docs_sites_get failed", { error });
|
|
1326
|
+
return errorResult(
|
|
1327
|
+
`Failed to get docs site: ${error instanceof Error ? error.message : String(error)}`
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
);
|
|
1332
|
+
server.registerTool(
|
|
1333
|
+
track(mcpToolName(ctx.productName, "docs_sites_create")),
|
|
1334
|
+
{
|
|
1335
|
+
title: "Create Docs Site",
|
|
1336
|
+
description: "Create a new documentation site.",
|
|
1337
|
+
inputSchema: {
|
|
1338
|
+
vibeId: z.string().describe("Vibe ID to associate the docs site with"),
|
|
1339
|
+
name: z.string().describe("Docs site name"),
|
|
1340
|
+
visibility: z.string().optional().describe("PRIVATE or PUBLIC"),
|
|
1341
|
+
runtime: z.string().optional().describe("Docs runtime/framework")
|
|
1342
|
+
}
|
|
1343
|
+
},
|
|
1344
|
+
async ({ vibeId, name, visibility, runtime }) => {
|
|
1345
|
+
try {
|
|
1346
|
+
const input = { vibeId, name };
|
|
1347
|
+
if (visibility !== void 0) input.visibility = visibility;
|
|
1348
|
+
if (runtime !== void 0) input.runtime = runtime;
|
|
1349
|
+
const data = await ctx.gql.workspace.request(
|
|
1350
|
+
CREATE_DOCS_SITE,
|
|
1351
|
+
{
|
|
1352
|
+
input
|
|
1353
|
+
}
|
|
1354
|
+
);
|
|
1355
|
+
return jsonResult(data.createDocsSite);
|
|
1356
|
+
} catch (error) {
|
|
1357
|
+
ctx.logger.error("vibecontrols_docs_sites_create failed", { error });
|
|
1358
|
+
return errorResult(
|
|
1359
|
+
`Failed to create docs site: ${error instanceof Error ? error.message : String(error)}`
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
);
|
|
1364
|
+
server.registerTool(
|
|
1365
|
+
track(mcpToolName(ctx.productName, "docs_sites_update")),
|
|
1366
|
+
{
|
|
1367
|
+
title: "Update Docs Site",
|
|
1368
|
+
description: "Update an existing documentation site.",
|
|
1369
|
+
inputSchema: {
|
|
1370
|
+
id: z.string().describe("Docs site ID"),
|
|
1371
|
+
name: z.string().optional().describe("Updated name"),
|
|
1372
|
+
visibility: z.string().optional().describe("PRIVATE or PUBLIC"),
|
|
1373
|
+
runtime: z.string().optional().describe("Updated runtime/framework")
|
|
1374
|
+
}
|
|
1375
|
+
},
|
|
1376
|
+
async ({ id, name, visibility, runtime }) => {
|
|
1377
|
+
try {
|
|
1378
|
+
const input = {};
|
|
1379
|
+
if (name !== void 0) input.name = name;
|
|
1380
|
+
if (visibility !== void 0) input.visibility = visibility;
|
|
1381
|
+
if (runtime !== void 0) input.runtime = runtime;
|
|
1382
|
+
const data = await ctx.gql.workspace.request(
|
|
1383
|
+
UPDATE_DOCS_SITE,
|
|
1384
|
+
{
|
|
1385
|
+
id,
|
|
1386
|
+
input
|
|
1387
|
+
}
|
|
1388
|
+
);
|
|
1389
|
+
return jsonResult(data.updateDocsSite);
|
|
1390
|
+
} catch (error) {
|
|
1391
|
+
ctx.logger.error("vibecontrols_docs_sites_update failed", { error });
|
|
1392
|
+
return errorResult(
|
|
1393
|
+
`Failed to update docs site: ${error instanceof Error ? error.message : String(error)}`
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
);
|
|
1398
|
+
server.registerTool(
|
|
1399
|
+
track(mcpToolName(ctx.productName, "docs_sites_delete")),
|
|
1400
|
+
{
|
|
1401
|
+
title: "Delete Docs Site",
|
|
1402
|
+
description: "Delete a documentation site.",
|
|
1403
|
+
inputSchema: { id: z.string().describe("Docs site ID to delete") }
|
|
1404
|
+
},
|
|
1405
|
+
async ({ id }) => {
|
|
1406
|
+
try {
|
|
1407
|
+
const data = await ctx.gql.workspace.request(
|
|
1408
|
+
DELETE_DOCS_SITE,
|
|
1409
|
+
{ id }
|
|
1410
|
+
);
|
|
1411
|
+
return jsonResult({ deleted: data.deleteDocsSite, docsSiteId: id });
|
|
1412
|
+
} catch (error) {
|
|
1413
|
+
ctx.logger.error("vibecontrols_docs_sites_delete failed", { error });
|
|
1414
|
+
return errorResult(
|
|
1415
|
+
`Failed to delete docs site: ${error instanceof Error ? error.message : String(error)}`
|
|
1416
|
+
);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
);
|
|
1420
|
+
server.registerTool(
|
|
1421
|
+
track(mcpToolName(ctx.productName, "docs_pages_list")),
|
|
1422
|
+
{
|
|
1423
|
+
title: "List Docs Pages",
|
|
1424
|
+
description: "List pages in a documentation site with optional status filter.",
|
|
1425
|
+
inputSchema: {
|
|
1426
|
+
siteId: z.string().describe("Docs site ID"),
|
|
1427
|
+
status: z.string().optional().describe("Filter by page status")
|
|
1428
|
+
}
|
|
1429
|
+
},
|
|
1430
|
+
async ({ siteId, status }) => {
|
|
1431
|
+
try {
|
|
1432
|
+
const filter = {};
|
|
1433
|
+
if (status !== void 0) filter.status = status;
|
|
1434
|
+
const data = await ctx.gql.workspace.request(LIST_DOCS_PAGES, {
|
|
1435
|
+
siteId,
|
|
1436
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0
|
|
1437
|
+
});
|
|
1438
|
+
return jsonResult(data.docsPages);
|
|
1439
|
+
} catch (error) {
|
|
1440
|
+
ctx.logger.error("vibecontrols_docs_pages_list failed", { error });
|
|
1441
|
+
return errorResult(
|
|
1442
|
+
`Failed to list docs pages: ${error instanceof Error ? error.message : String(error)}`
|
|
1443
|
+
);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
);
|
|
1447
|
+
server.registerTool(
|
|
1448
|
+
track(mcpToolName(ctx.productName, "docs_pages_get")),
|
|
1449
|
+
{
|
|
1450
|
+
title: "Get Docs Page",
|
|
1451
|
+
description: "Get a documentation page by its ID.",
|
|
1452
|
+
inputSchema: { id: z.string().describe("Docs page ID") }
|
|
1453
|
+
},
|
|
1454
|
+
async ({ id }) => {
|
|
1455
|
+
try {
|
|
1456
|
+
const data = await ctx.gql.workspace.request(GET_DOCS_PAGE, { id });
|
|
1457
|
+
return jsonResult(data.docsPage);
|
|
1458
|
+
} catch (error) {
|
|
1459
|
+
ctx.logger.error("vibecontrols_docs_pages_get failed", { error });
|
|
1460
|
+
return errorResult(
|
|
1461
|
+
`Failed to get docs page: ${error instanceof Error ? error.message : String(error)}`
|
|
1462
|
+
);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
);
|
|
1466
|
+
server.registerTool(
|
|
1467
|
+
track(mcpToolName(ctx.productName, "docs_pages_create")),
|
|
1468
|
+
{
|
|
1469
|
+
title: "Create Docs Page",
|
|
1470
|
+
description: "Create a new documentation page.",
|
|
1471
|
+
inputSchema: {
|
|
1472
|
+
siteId: z.string().describe("Docs site ID"),
|
|
1473
|
+
title: z.string().describe("Page title"),
|
|
1474
|
+
slug: z.string().optional().describe("URL slug for the page"),
|
|
1475
|
+
content: z.string().optional().describe("Page content (markdown supported)"),
|
|
1476
|
+
parentId: z.string().optional().describe("Parent page ID for nesting"),
|
|
1477
|
+
sidebarPosition: z.number().optional().describe("Position in the sidebar")
|
|
1478
|
+
}
|
|
1479
|
+
},
|
|
1480
|
+
async ({ siteId, title, slug, content, parentId, sidebarPosition }) => {
|
|
1481
|
+
try {
|
|
1482
|
+
const input = { siteId, title };
|
|
1483
|
+
if (slug !== void 0) input.slug = slug;
|
|
1484
|
+
if (content !== void 0) input.content = content;
|
|
1485
|
+
if (parentId !== void 0) input.parentId = parentId;
|
|
1486
|
+
if (sidebarPosition !== void 0) input.sidebarPosition = sidebarPosition;
|
|
1487
|
+
const data = await ctx.gql.workspace.request(
|
|
1488
|
+
CREATE_DOCS_PAGE,
|
|
1489
|
+
{
|
|
1490
|
+
input
|
|
1491
|
+
}
|
|
1492
|
+
);
|
|
1493
|
+
return jsonResult(data.createDocsPage);
|
|
1494
|
+
} catch (error) {
|
|
1495
|
+
ctx.logger.error("vibecontrols_docs_pages_create failed", { error });
|
|
1496
|
+
return errorResult(
|
|
1497
|
+
`Failed to create docs page: ${error instanceof Error ? error.message : String(error)}`
|
|
1498
|
+
);
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
);
|
|
1502
|
+
server.registerTool(
|
|
1503
|
+
track(mcpToolName(ctx.productName, "docs_pages_update")),
|
|
1504
|
+
{
|
|
1505
|
+
title: "Update Docs Page",
|
|
1506
|
+
description: "Update an existing documentation page.",
|
|
1507
|
+
inputSchema: {
|
|
1508
|
+
id: z.string().describe("Docs page ID"),
|
|
1509
|
+
title: z.string().optional().describe("Updated title"),
|
|
1510
|
+
slug: z.string().optional().describe("Updated slug"),
|
|
1511
|
+
content: z.string().optional().describe("Updated content"),
|
|
1512
|
+
parentId: z.string().optional().describe("Updated parent page ID"),
|
|
1513
|
+
sidebarPosition: z.number().optional().describe("Updated sidebar position")
|
|
1514
|
+
}
|
|
1515
|
+
},
|
|
1516
|
+
async ({ id, title, slug, content, parentId, sidebarPosition }) => {
|
|
1517
|
+
try {
|
|
1518
|
+
const input = {};
|
|
1519
|
+
if (title !== void 0) input.title = title;
|
|
1520
|
+
if (slug !== void 0) input.slug = slug;
|
|
1521
|
+
if (content !== void 0) input.content = content;
|
|
1522
|
+
if (parentId !== void 0) input.parentId = parentId;
|
|
1523
|
+
if (sidebarPosition !== void 0) input.sidebarPosition = sidebarPosition;
|
|
1524
|
+
const data = await ctx.gql.workspace.request(
|
|
1525
|
+
UPDATE_DOCS_PAGE,
|
|
1526
|
+
{
|
|
1527
|
+
id,
|
|
1528
|
+
input
|
|
1529
|
+
}
|
|
1530
|
+
);
|
|
1531
|
+
return jsonResult(data.updateDocsPage);
|
|
1532
|
+
} catch (error) {
|
|
1533
|
+
ctx.logger.error("vibecontrols_docs_pages_update failed", { error });
|
|
1534
|
+
return errorResult(
|
|
1535
|
+
`Failed to update docs page: ${error instanceof Error ? error.message : String(error)}`
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
);
|
|
1540
|
+
server.registerTool(
|
|
1541
|
+
track(mcpToolName(ctx.productName, "docs_pages_delete")),
|
|
1542
|
+
{
|
|
1543
|
+
title: "Delete Docs Page",
|
|
1544
|
+
description: "Delete a documentation page.",
|
|
1545
|
+
inputSchema: { id: z.string().describe("Docs page ID to delete") }
|
|
1546
|
+
},
|
|
1547
|
+
async ({ id }) => {
|
|
1548
|
+
try {
|
|
1549
|
+
const data = await ctx.gql.workspace.request(
|
|
1550
|
+
DELETE_DOCS_PAGE,
|
|
1551
|
+
{ id }
|
|
1552
|
+
);
|
|
1553
|
+
return jsonResult({ deleted: data.deleteDocsPage, docsPageId: id });
|
|
1554
|
+
} catch (error) {
|
|
1555
|
+
ctx.logger.error("vibecontrols_docs_pages_delete failed", { error });
|
|
1556
|
+
return errorResult(
|
|
1557
|
+
`Failed to delete docs page: ${error instanceof Error ? error.message : String(error)}`
|
|
1558
|
+
);
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
);
|
|
1562
|
+
server.registerTool(
|
|
1563
|
+
track(mcpToolName(ctx.productName, "docs_compile")),
|
|
1564
|
+
{
|
|
1565
|
+
title: "Compile Docs Site",
|
|
1566
|
+
description: "Compile a documentation site, optionally publishing it.",
|
|
1567
|
+
inputSchema: {
|
|
1568
|
+
siteId: z.string().describe("Docs site ID to compile"),
|
|
1569
|
+
publish: z.boolean().optional().describe("Publish after compilation")
|
|
1570
|
+
}
|
|
1571
|
+
},
|
|
1572
|
+
async ({ siteId, publish }) => {
|
|
1573
|
+
try {
|
|
1574
|
+
const variables = { siteId };
|
|
1575
|
+
if (publish !== void 0) variables.publish = publish;
|
|
1576
|
+
const data = await ctx.gql.workspace.request(
|
|
1577
|
+
COMPILE_DOCS_SITE,
|
|
1578
|
+
variables
|
|
1579
|
+
);
|
|
1580
|
+
return jsonResult(data.compileDocsSite);
|
|
1581
|
+
} catch (error) {
|
|
1582
|
+
ctx.logger.error("vibecontrols_docs_compile failed", { error });
|
|
1583
|
+
return errorResult(
|
|
1584
|
+
`Failed to compile docs site: ${error instanceof Error ? error.message : String(error)}`
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
);
|
|
1589
|
+
server.registerTool(
|
|
1590
|
+
track(mcpToolName(ctx.productName, "docs_publish")),
|
|
1591
|
+
{
|
|
1592
|
+
title: "Publish Docs Revision",
|
|
1593
|
+
description: "Publish a specific docs revision.",
|
|
1594
|
+
inputSchema: { revisionId: z.string().describe("Revision ID to publish") }
|
|
1595
|
+
},
|
|
1596
|
+
async ({ revisionId }) => {
|
|
1597
|
+
try {
|
|
1598
|
+
const data = await ctx.gql.workspace.request(
|
|
1599
|
+
PUBLISH_DOCS_REVISION,
|
|
1600
|
+
{ revisionId }
|
|
1601
|
+
);
|
|
1602
|
+
return jsonResult(data.publishDocsRevision);
|
|
1603
|
+
} catch (error) {
|
|
1604
|
+
ctx.logger.error("vibecontrols_docs_publish failed", { error });
|
|
1605
|
+
return errorResult(
|
|
1606
|
+
`Failed to publish docs revision: ${error instanceof Error ? error.message : String(error)}`
|
|
1607
|
+
);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
);
|
|
1611
|
+
server.registerTool(
|
|
1612
|
+
track(mcpToolName(ctx.productName, "docs_rollback")),
|
|
1613
|
+
{
|
|
1614
|
+
title: "Rollback Docs Revision",
|
|
1615
|
+
description: "Rollback a documentation site to a previous revision.",
|
|
1616
|
+
inputSchema: {
|
|
1617
|
+
siteId: z.string().describe("Docs site ID"),
|
|
1618
|
+
revisionId: z.string().describe("Revision ID to rollback to")
|
|
1619
|
+
}
|
|
1620
|
+
},
|
|
1621
|
+
async ({ siteId, revisionId }) => {
|
|
1622
|
+
try {
|
|
1623
|
+
const data = await ctx.gql.workspace.request(
|
|
1624
|
+
ROLLBACK_DOCS_REVISION,
|
|
1625
|
+
{
|
|
1626
|
+
siteId,
|
|
1627
|
+
revisionId
|
|
1628
|
+
}
|
|
1629
|
+
);
|
|
1630
|
+
return jsonResult(data.rollbackDocsRevision);
|
|
1631
|
+
} catch (error) {
|
|
1632
|
+
ctx.logger.error("vibecontrols_docs_rollback failed", { error });
|
|
1633
|
+
return errorResult(
|
|
1634
|
+
`Failed to rollback docs revision: ${error instanceof Error ? error.message : String(error)}`
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1640
|
+
function registerNoteTools(server, ctx, track) {
|
|
1641
|
+
server.registerTool(
|
|
1642
|
+
track(mcpToolName(ctx.productName, "notes_list")),
|
|
1643
|
+
{
|
|
1644
|
+
title: "List Notes",
|
|
1645
|
+
description: "List notes with optional filters and pagination.",
|
|
1646
|
+
inputSchema: {
|
|
1647
|
+
title: z.string().optional().describe("Filter by title"),
|
|
1648
|
+
vibeId: z.string().optional().describe("Filter by vibe ID"),
|
|
1649
|
+
tags: z.array(z.string()).optional().describe("Filter by tags"),
|
|
1650
|
+
isPinned: z.boolean().optional().describe("Filter by pinned status"),
|
|
1651
|
+
limit: z.number().optional().describe("Max results"),
|
|
1652
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
1653
|
+
}
|
|
1654
|
+
},
|
|
1655
|
+
async ({ title, vibeId, tags, isPinned, limit, offset }) => {
|
|
1656
|
+
try {
|
|
1657
|
+
const filter = {};
|
|
1658
|
+
if (title !== void 0) filter.title = title;
|
|
1659
|
+
if (vibeId !== void 0) filter.vibeId = vibeId;
|
|
1660
|
+
if (tags !== void 0) filter.tags = tags;
|
|
1661
|
+
if (isPinned !== void 0) filter.isPinned = isPinned;
|
|
1662
|
+
const pagination = {};
|
|
1663
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
1664
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
1665
|
+
const data = await ctx.gql.workspace.request(LIST_NOTES, {
|
|
1666
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
1667
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
1668
|
+
});
|
|
1669
|
+
return jsonResult(data.notes);
|
|
1670
|
+
} catch (error) {
|
|
1671
|
+
ctx.logger.error("vibecontrols_notes_list failed", { error });
|
|
1672
|
+
return errorResult(
|
|
1673
|
+
`Failed to list notes: ${error instanceof Error ? error.message : String(error)}`
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
);
|
|
1678
|
+
server.registerTool(
|
|
1679
|
+
track(mcpToolName(ctx.productName, "notes_get")),
|
|
1680
|
+
{
|
|
1681
|
+
title: "Get Note",
|
|
1682
|
+
description: "Get a note by its ID.",
|
|
1683
|
+
inputSchema: { id: z.string().describe("Note ID") }
|
|
1684
|
+
},
|
|
1685
|
+
async ({ id }) => {
|
|
1686
|
+
try {
|
|
1687
|
+
const data = await ctx.gql.workspace.request(GET_NOTE, { id });
|
|
1688
|
+
return jsonResult(data.note);
|
|
1689
|
+
} catch (error) {
|
|
1690
|
+
ctx.logger.error("vibecontrols_notes_get failed", { error });
|
|
1691
|
+
return errorResult(
|
|
1692
|
+
`Failed to get note: ${error instanceof Error ? error.message : String(error)}`
|
|
1693
|
+
);
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
);
|
|
1697
|
+
server.registerTool(
|
|
1698
|
+
track(mcpToolName(ctx.productName, "notes_create")),
|
|
1699
|
+
{
|
|
1700
|
+
title: "Create Note",
|
|
1701
|
+
description: "Create a new note.",
|
|
1702
|
+
inputSchema: {
|
|
1703
|
+
title: z.string().describe("Note title"),
|
|
1704
|
+
content: z.string().optional().describe("Note content (markdown supported)"),
|
|
1705
|
+
tags: z.array(z.string()).optional().describe("Tags for categorization"),
|
|
1706
|
+
isPinned: z.boolean().optional().describe("Pin the note"),
|
|
1707
|
+
vibeId: z.string().optional().describe("Associated vibe ID")
|
|
1708
|
+
}
|
|
1709
|
+
},
|
|
1710
|
+
async ({ title, content, tags, isPinned, vibeId }) => {
|
|
1711
|
+
try {
|
|
1712
|
+
const input = { title };
|
|
1713
|
+
if (content !== void 0) input.content = content;
|
|
1714
|
+
if (tags !== void 0) input.tags = tags;
|
|
1715
|
+
if (isPinned !== void 0) input.isPinned = isPinned;
|
|
1716
|
+
if (vibeId !== void 0) input.vibeId = vibeId;
|
|
1717
|
+
const data = await ctx.gql.workspace.request(CREATE_NOTE, {
|
|
1718
|
+
input
|
|
1719
|
+
});
|
|
1720
|
+
return jsonResult(data.createNote);
|
|
1721
|
+
} catch (error) {
|
|
1722
|
+
ctx.logger.error("vibecontrols_notes_create failed", { error });
|
|
1723
|
+
return errorResult(
|
|
1724
|
+
`Failed to create note: ${error instanceof Error ? error.message : String(error)}`
|
|
1725
|
+
);
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
);
|
|
1729
|
+
server.registerTool(
|
|
1730
|
+
track(mcpToolName(ctx.productName, "notes_update")),
|
|
1731
|
+
{
|
|
1732
|
+
title: "Update Note",
|
|
1733
|
+
description: "Update an existing note.",
|
|
1734
|
+
inputSchema: {
|
|
1735
|
+
id: z.string().describe("Note ID"),
|
|
1736
|
+
title: z.string().optional().describe("Updated title"),
|
|
1737
|
+
content: z.string().optional().describe("Updated content"),
|
|
1738
|
+
tags: z.array(z.string()).optional().describe("Updated tags"),
|
|
1739
|
+
isPinned: z.boolean().optional().describe("Updated pin status")
|
|
1740
|
+
}
|
|
1741
|
+
},
|
|
1742
|
+
async ({ id, title, content, tags, isPinned }) => {
|
|
1743
|
+
try {
|
|
1744
|
+
const input = {};
|
|
1745
|
+
if (title !== void 0) input.title = title;
|
|
1746
|
+
if (content !== void 0) input.content = content;
|
|
1747
|
+
if (tags !== void 0) input.tags = tags;
|
|
1748
|
+
if (isPinned !== void 0) input.isPinned = isPinned;
|
|
1749
|
+
const data = await ctx.gql.workspace.request(UPDATE_NOTE, {
|
|
1750
|
+
id,
|
|
1751
|
+
input
|
|
1752
|
+
});
|
|
1753
|
+
return jsonResult(data.updateNote);
|
|
1754
|
+
} catch (error) {
|
|
1755
|
+
ctx.logger.error("vibecontrols_notes_update failed", { error });
|
|
1756
|
+
return errorResult(
|
|
1757
|
+
`Failed to update note: ${error instanceof Error ? error.message : String(error)}`
|
|
1758
|
+
);
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
);
|
|
1762
|
+
server.registerTool(
|
|
1763
|
+
track(mcpToolName(ctx.productName, "notes_delete")),
|
|
1764
|
+
{
|
|
1765
|
+
title: "Delete Note",
|
|
1766
|
+
description: "Delete a note.",
|
|
1767
|
+
inputSchema: { id: z.string().describe("Note ID to delete") }
|
|
1768
|
+
},
|
|
1769
|
+
async ({ id }) => {
|
|
1770
|
+
try {
|
|
1771
|
+
const data = await ctx.gql.workspace.request(DELETE_NOTE, { id });
|
|
1772
|
+
return jsonResult({ deleted: data.deleteNote, noteId: id });
|
|
1773
|
+
} catch (error) {
|
|
1774
|
+
ctx.logger.error("vibecontrols_notes_delete failed", { error });
|
|
1775
|
+
return errorResult(
|
|
1776
|
+
`Failed to delete note: ${error instanceof Error ? error.message : String(error)}`
|
|
1777
|
+
);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
);
|
|
1781
|
+
server.registerTool(
|
|
1782
|
+
track(mcpToolName(ctx.productName, "notes_search")),
|
|
1783
|
+
{
|
|
1784
|
+
title: "Search Notes",
|
|
1785
|
+
description: "Full-text search across notes.",
|
|
1786
|
+
inputSchema: {
|
|
1787
|
+
query: z.string().describe("Search query string"),
|
|
1788
|
+
vibeId: z.string().optional().describe("Scope search to a specific vibe"),
|
|
1789
|
+
limit: z.number().optional().describe("Maximum results")
|
|
1790
|
+
}
|
|
1791
|
+
},
|
|
1792
|
+
async ({ query, vibeId, limit }) => {
|
|
1793
|
+
try {
|
|
1794
|
+
const data = await ctx.gql.workspace.request(SEARCH_NOTES, {
|
|
1795
|
+
query,
|
|
1796
|
+
vibeId,
|
|
1797
|
+
limit
|
|
1798
|
+
});
|
|
1799
|
+
return jsonResult(data.searchNotes);
|
|
1800
|
+
} catch (error) {
|
|
1801
|
+
ctx.logger.error("vibecontrols_notes_search failed", { error });
|
|
1802
|
+
return errorResult(
|
|
1803
|
+
`Failed to search notes: ${error instanceof Error ? error.message : String(error)}`
|
|
1804
|
+
);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
);
|
|
1808
|
+
server.registerTool(
|
|
1809
|
+
track(mcpToolName(ctx.productName, "notes_pin")),
|
|
1810
|
+
{
|
|
1811
|
+
title: "Pin Note",
|
|
1812
|
+
description: "Pin a note so it appears at the top of lists.",
|
|
1813
|
+
inputSchema: { id: z.string().describe("Note ID to pin") }
|
|
1814
|
+
},
|
|
1815
|
+
async ({ id }) => {
|
|
1816
|
+
try {
|
|
1817
|
+
const data = await ctx.gql.workspace.request(PIN_NOTE, { id });
|
|
1818
|
+
return jsonResult(data.pinNote);
|
|
1819
|
+
} catch (error) {
|
|
1820
|
+
ctx.logger.error("vibecontrols_notes_pin failed", { error });
|
|
1821
|
+
return errorResult(
|
|
1822
|
+
`Failed to pin note: ${error instanceof Error ? error.message : String(error)}`
|
|
1823
|
+
);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
);
|
|
1827
|
+
server.registerTool(
|
|
1828
|
+
track(mcpToolName(ctx.productName, "notes_unpin")),
|
|
1829
|
+
{
|
|
1830
|
+
title: "Unpin Note",
|
|
1831
|
+
description: "Unpin a previously pinned note.",
|
|
1832
|
+
inputSchema: { id: z.string().describe("Note ID to unpin") }
|
|
1833
|
+
},
|
|
1834
|
+
async ({ id }) => {
|
|
1835
|
+
try {
|
|
1836
|
+
const data = await ctx.gql.workspace.request(UNPIN_NOTE, { id });
|
|
1837
|
+
return jsonResult(data.unpinNote);
|
|
1838
|
+
} catch (error) {
|
|
1839
|
+
ctx.logger.error("vibecontrols_notes_unpin failed", { error });
|
|
1840
|
+
return errorResult(
|
|
1841
|
+
`Failed to unpin note: ${error instanceof Error ? error.message : String(error)}`
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
);
|
|
1846
|
+
}
|
|
1847
|
+
function registerSessionSharingTools(server, ctx, track) {
|
|
1848
|
+
server.registerTool(
|
|
1849
|
+
track(mcpToolName(ctx.productName, "sessions_share")),
|
|
1850
|
+
{
|
|
1851
|
+
title: "Share Session",
|
|
1852
|
+
description: "Share a session with another user.",
|
|
1853
|
+
inputSchema: {
|
|
1854
|
+
sessionId: z.string().describe("Session ID to share"),
|
|
1855
|
+
sharedWithId: z.string().describe("User ID to share with"),
|
|
1856
|
+
permission: z.string().describe("Permission level: VIEW or CONTROL")
|
|
1857
|
+
}
|
|
1858
|
+
},
|
|
1859
|
+
async ({ sessionId, sharedWithId, permission }) => {
|
|
1860
|
+
try {
|
|
1861
|
+
const input = { sessionId, sharedWithId, permission };
|
|
1862
|
+
const data = await ctx.gql.workspace.request(SHARE_SESSION, {
|
|
1863
|
+
input
|
|
1864
|
+
});
|
|
1865
|
+
return jsonResult(data.shareSession);
|
|
1866
|
+
} catch (error) {
|
|
1867
|
+
ctx.logger.error("vibecontrols_sessions_share failed", { error });
|
|
1868
|
+
return errorResult(
|
|
1869
|
+
`Failed to share session: ${error instanceof Error ? error.message : String(error)}`
|
|
1870
|
+
);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
);
|
|
1874
|
+
server.registerTool(
|
|
1875
|
+
track(mcpToolName(ctx.productName, "sessions_share_link_create")),
|
|
1876
|
+
{
|
|
1877
|
+
title: "Create Session Share Link",
|
|
1878
|
+
description: "Create a shareable link for a session.",
|
|
1879
|
+
inputSchema: {
|
|
1880
|
+
sessionId: z.string().describe("Session ID"),
|
|
1881
|
+
permission: z.string().describe("Permission level: VIEW or CONTROL"),
|
|
1882
|
+
expiresAt: z.string().optional().describe("Expiration date in ISO format")
|
|
1883
|
+
}
|
|
1884
|
+
},
|
|
1885
|
+
async ({ sessionId, permission, expiresAt }) => {
|
|
1886
|
+
try {
|
|
1887
|
+
const input = { sessionId, permission };
|
|
1888
|
+
if (expiresAt !== void 0) input.expiresAt = expiresAt;
|
|
1889
|
+
const data = await ctx.gql.workspace.request(
|
|
1890
|
+
CREATE_SESSION_SHARE_LINK,
|
|
1891
|
+
{ input }
|
|
1892
|
+
);
|
|
1893
|
+
return jsonResult(data.createSessionShareLink);
|
|
1894
|
+
} catch (error) {
|
|
1895
|
+
ctx.logger.error("vibecontrols_sessions_share_link_create failed", { error });
|
|
1896
|
+
return errorResult(
|
|
1897
|
+
`Failed to create session share link: ${error instanceof Error ? error.message : String(error)}`
|
|
1898
|
+
);
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
);
|
|
1902
|
+
server.registerTool(
|
|
1903
|
+
track(mcpToolName(ctx.productName, "sessions_share_revoke")),
|
|
1904
|
+
{
|
|
1905
|
+
title: "Revoke Session Share",
|
|
1906
|
+
description: "Revoke a session share.",
|
|
1907
|
+
inputSchema: { id: z.string().describe("Session share ID to revoke") }
|
|
1908
|
+
},
|
|
1909
|
+
async ({ id }) => {
|
|
1910
|
+
try {
|
|
1911
|
+
const data = await ctx.gql.workspace.request(
|
|
1912
|
+
REVOKE_SESSION_SHARE,
|
|
1913
|
+
{
|
|
1914
|
+
id
|
|
1915
|
+
}
|
|
1916
|
+
);
|
|
1917
|
+
return jsonResult(data.revokeSessionShare);
|
|
1918
|
+
} catch (error) {
|
|
1919
|
+
ctx.logger.error("vibecontrols_sessions_share_revoke failed", { error });
|
|
1920
|
+
return errorResult(
|
|
1921
|
+
`Failed to revoke session share: ${error instanceof Error ? error.message : String(error)}`
|
|
1922
|
+
);
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
);
|
|
1926
|
+
server.registerTool(
|
|
1927
|
+
track(mcpToolName(ctx.productName, "sessions_share_link_revoke")),
|
|
1928
|
+
{
|
|
1929
|
+
title: "Revoke Session Share Link",
|
|
1930
|
+
description: "Revoke a session share link.",
|
|
1931
|
+
inputSchema: { id: z.string().describe("Session share link ID to revoke") }
|
|
1932
|
+
},
|
|
1933
|
+
async ({ id }) => {
|
|
1934
|
+
try {
|
|
1935
|
+
const data = await ctx.gql.workspace.request(
|
|
1936
|
+
REVOKE_SESSION_SHARE_LINK,
|
|
1937
|
+
{ id }
|
|
1938
|
+
);
|
|
1939
|
+
return jsonResult(data.revokeSessionShareLink);
|
|
1940
|
+
} catch (error) {
|
|
1941
|
+
ctx.logger.error("vibecontrols_sessions_share_link_revoke failed", { error });
|
|
1942
|
+
return errorResult(
|
|
1943
|
+
`Failed to revoke session share link: ${error instanceof Error ? error.message : String(error)}`
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
);
|
|
1948
|
+
server.registerTool(
|
|
1949
|
+
track(mcpToolName(ctx.productName, "sessions_shares")),
|
|
1950
|
+
{
|
|
1951
|
+
title: "List Session Shares",
|
|
1952
|
+
description: "List all shares for a session.",
|
|
1953
|
+
inputSchema: { sessionId: z.string().describe("Session ID") }
|
|
1954
|
+
},
|
|
1955
|
+
async ({ sessionId }) => {
|
|
1956
|
+
try {
|
|
1957
|
+
const data = await ctx.gql.workspace.request(SESSION_SHARES, {
|
|
1958
|
+
sessionId
|
|
1959
|
+
});
|
|
1960
|
+
return jsonResult(data.sessionShares);
|
|
1961
|
+
} catch (error) {
|
|
1962
|
+
ctx.logger.error("vibecontrols_sessions_shares failed", { error });
|
|
1963
|
+
return errorResult(
|
|
1964
|
+
`Failed to list session shares: ${error instanceof Error ? error.message : String(error)}`
|
|
1965
|
+
);
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
);
|
|
1969
|
+
server.registerTool(
|
|
1970
|
+
track(mcpToolName(ctx.productName, "sessions_share_links")),
|
|
1971
|
+
{
|
|
1972
|
+
title: "List Session Share Links",
|
|
1973
|
+
description: "List all share links for a session.",
|
|
1974
|
+
inputSchema: { sessionId: z.string().describe("Session ID") }
|
|
1975
|
+
},
|
|
1976
|
+
async ({ sessionId }) => {
|
|
1977
|
+
try {
|
|
1978
|
+
const data = await ctx.gql.workspace.request(
|
|
1979
|
+
SESSION_SHARE_LINKS,
|
|
1980
|
+
{
|
|
1981
|
+
sessionId
|
|
1982
|
+
}
|
|
1983
|
+
);
|
|
1984
|
+
return jsonResult(data.sessionShareLinks);
|
|
1985
|
+
} catch (error) {
|
|
1986
|
+
ctx.logger.error("vibecontrols_sessions_share_links failed", { error });
|
|
1987
|
+
return errorResult(
|
|
1988
|
+
`Failed to list session share links: ${error instanceof Error ? error.message : String(error)}`
|
|
1989
|
+
);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
);
|
|
1993
|
+
server.registerTool(
|
|
1994
|
+
track(mcpToolName(ctx.productName, "sessions_collaborators")),
|
|
1995
|
+
{
|
|
1996
|
+
title: "List Session Collaborators",
|
|
1997
|
+
description: "List all collaborators for a session.",
|
|
1998
|
+
inputSchema: { sessionId: z.string().describe("Session ID") }
|
|
1999
|
+
},
|
|
2000
|
+
async ({ sessionId }) => {
|
|
2001
|
+
try {
|
|
2002
|
+
const data = await ctx.gql.workspace.request(
|
|
2003
|
+
SESSION_COLLABORATORS,
|
|
2004
|
+
{ sessionId }
|
|
2005
|
+
);
|
|
2006
|
+
return jsonResult(data.sessionCollaborators);
|
|
2007
|
+
} catch (error) {
|
|
2008
|
+
ctx.logger.error("vibecontrols_sessions_collaborators failed", { error });
|
|
2009
|
+
return errorResult(
|
|
2010
|
+
`Failed to list session collaborators: ${error instanceof Error ? error.message : String(error)}`
|
|
2011
|
+
);
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
);
|
|
2015
|
+
server.registerTool(
|
|
2016
|
+
track(mcpToolName(ctx.productName, "sessions_shared_with_me")),
|
|
2017
|
+
{
|
|
2018
|
+
title: "Sessions Shared With Me",
|
|
2019
|
+
description: "List sessions that have been shared with the current user.",
|
|
2020
|
+
inputSchema: {
|
|
2021
|
+
permission: z.string().optional().describe("Filter by permission level"),
|
|
2022
|
+
limit: z.number().optional().describe("Max results"),
|
|
2023
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
2024
|
+
}
|
|
2025
|
+
},
|
|
2026
|
+
async ({ permission, limit, offset }) => {
|
|
2027
|
+
try {
|
|
2028
|
+
const filter = {};
|
|
2029
|
+
if (permission !== void 0) filter.permission = permission;
|
|
2030
|
+
const pagination = {};
|
|
2031
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
2032
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
2033
|
+
const data = await ctx.gql.workspace.request(SESSIONS_SHARED_WITH_ME, {
|
|
2034
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
2035
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
2036
|
+
});
|
|
2037
|
+
const edges = data.sessionsSharedWithMe?.edges ?? [];
|
|
2038
|
+
return jsonResult({
|
|
2039
|
+
totalCount: data.sessionsSharedWithMe?.totalCount ?? edges.length,
|
|
2040
|
+
items: edges.map((edge) => edge.node),
|
|
2041
|
+
edges
|
|
2042
|
+
});
|
|
2043
|
+
} catch (error) {
|
|
2044
|
+
ctx.logger.error("vibecontrols_sessions_shared_with_me failed", { error });
|
|
2045
|
+
return errorResult(
|
|
2046
|
+
`Failed to list shared sessions: ${error instanceof Error ? error.message : String(error)}`
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
);
|
|
2051
|
+
}
|
|
2052
|
+
function registerSessionTools(server, ctx, track) {
|
|
2053
|
+
server.registerTool(
|
|
2054
|
+
track(mcpToolName(ctx.productName, "sessions_list")),
|
|
2055
|
+
{
|
|
2056
|
+
title: "List Sessions",
|
|
2057
|
+
description: "List terminal sessions with optional filters and pagination.",
|
|
2058
|
+
inputSchema: {
|
|
2059
|
+
name: z.string().optional().describe("Filter by session name"),
|
|
2060
|
+
type: z.string().optional().describe("Filter by type (TMUX, SSH, TERMINAL, SCRIPT, CUSTOM)"),
|
|
2061
|
+
status: z.string().optional().describe("Filter by status (PENDING, STARTING, RUNNING, STOPPED, ERROR, TERMINATED)"),
|
|
2062
|
+
agentId: z.string().optional().describe("Filter by agent ID"),
|
|
2063
|
+
vibeId: z.string().optional().describe("Filter by vibe ID"),
|
|
2064
|
+
limit: z.number().optional().describe("Max results"),
|
|
2065
|
+
offset: z.number().optional().describe("Skip results")
|
|
2066
|
+
}
|
|
2067
|
+
},
|
|
2068
|
+
async ({ name, type, status, agentId, vibeId, limit, offset }) => {
|
|
2069
|
+
try {
|
|
2070
|
+
const filter = {};
|
|
2071
|
+
if (name !== void 0) filter.name = name;
|
|
2072
|
+
if (type !== void 0) filter.type = type;
|
|
2073
|
+
if (status !== void 0) filter.status = status;
|
|
2074
|
+
if (agentId !== void 0) filter.agentId = agentId;
|
|
2075
|
+
if (vibeId !== void 0) filter.vibeId = vibeId;
|
|
2076
|
+
const pagination = {};
|
|
2077
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
2078
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
2079
|
+
const data = await ctx.gql.workspace.request(LIST_SESSIONS, {
|
|
2080
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
2081
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
2082
|
+
});
|
|
2083
|
+
return jsonResult(data.sessions);
|
|
2084
|
+
} catch (error) {
|
|
2085
|
+
ctx.logger.error("vibecontrols_sessions_list failed", { error });
|
|
2086
|
+
return errorResult(
|
|
2087
|
+
`Failed to list sessions: ${error instanceof Error ? error.message : String(error)}`
|
|
2088
|
+
);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
);
|
|
2092
|
+
server.registerTool(
|
|
2093
|
+
track(mcpToolName(ctx.productName, "sessions_get")),
|
|
2094
|
+
{
|
|
2095
|
+
title: "Get Session",
|
|
2096
|
+
description: "Get a terminal session by its ID.",
|
|
2097
|
+
inputSchema: { id: z.string().describe("Session ID") }
|
|
2098
|
+
},
|
|
2099
|
+
async ({ id }) => {
|
|
2100
|
+
try {
|
|
2101
|
+
const data = await ctx.gql.workspace.request(GET_SESSION, { id });
|
|
2102
|
+
return jsonResult(data.session);
|
|
2103
|
+
} catch (error) {
|
|
2104
|
+
ctx.logger.error("vibecontrols_sessions_get failed", { error });
|
|
2105
|
+
return errorResult(
|
|
2106
|
+
`Failed to get session: ${error instanceof Error ? error.message : String(error)}`
|
|
2107
|
+
);
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
);
|
|
2111
|
+
server.registerTool(
|
|
2112
|
+
track(mcpToolName(ctx.productName, "sessions_create")),
|
|
2113
|
+
{
|
|
2114
|
+
title: "Create Session",
|
|
2115
|
+
description: "Create a new terminal session.",
|
|
2116
|
+
inputSchema: {
|
|
2117
|
+
name: z.string().describe("Session name"),
|
|
2118
|
+
command: z.string().optional().describe("Command to run"),
|
|
2119
|
+
workingDirectory: z.string().optional().describe("Working directory"),
|
|
2120
|
+
type: z.string().optional().describe("Session type (TMUX, SSH, TERMINAL, SCRIPT, CUSTOM)"),
|
|
2121
|
+
agentId: z.string().optional().describe("Agent ID"),
|
|
2122
|
+
vibeId: z.string().optional().describe("Vibe ID"),
|
|
2123
|
+
tmuxSessionName: z.string().optional().describe("Tmux session name"),
|
|
2124
|
+
autoStart: z.boolean().optional().describe("Auto-start on creation")
|
|
2125
|
+
}
|
|
2126
|
+
},
|
|
2127
|
+
async ({
|
|
2128
|
+
name,
|
|
2129
|
+
command,
|
|
2130
|
+
workingDirectory,
|
|
2131
|
+
type,
|
|
2132
|
+
agentId,
|
|
2133
|
+
vibeId,
|
|
2134
|
+
tmuxSessionName,
|
|
2135
|
+
autoStart
|
|
2136
|
+
}) => {
|
|
2137
|
+
try {
|
|
2138
|
+
const input = { name };
|
|
2139
|
+
if (command !== void 0) input.command = command;
|
|
2140
|
+
if (workingDirectory !== void 0) input.workingDirectory = workingDirectory;
|
|
2141
|
+
if (type !== void 0) input.type = type;
|
|
2142
|
+
if (agentId !== void 0) input.agentId = agentId;
|
|
2143
|
+
if (vibeId !== void 0) input.vibeId = vibeId;
|
|
2144
|
+
if (tmuxSessionName !== void 0) input.tmuxSessionName = tmuxSessionName;
|
|
2145
|
+
if (autoStart !== void 0) input.autoStart = autoStart;
|
|
2146
|
+
const data = await ctx.gql.workspace.request(CREATE_SESSION, {
|
|
2147
|
+
input
|
|
2148
|
+
});
|
|
2149
|
+
return jsonResult(data.createSession);
|
|
2150
|
+
} catch (error) {
|
|
2151
|
+
ctx.logger.error("vibecontrols_sessions_create failed", { error });
|
|
2152
|
+
return errorResult(
|
|
2153
|
+
`Failed to create session: ${error instanceof Error ? error.message : String(error)}`
|
|
2154
|
+
);
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
);
|
|
2158
|
+
server.registerTool(
|
|
2159
|
+
track(mcpToolName(ctx.productName, "sessions_start")),
|
|
2160
|
+
{
|
|
2161
|
+
title: "Start Session",
|
|
2162
|
+
description: "Start a terminal session.",
|
|
2163
|
+
inputSchema: { id: z.string().describe("Session ID") }
|
|
2164
|
+
},
|
|
2165
|
+
async ({ id }) => {
|
|
2166
|
+
try {
|
|
2167
|
+
const data = await ctx.gql.workspace.request(START_SESSION, {
|
|
2168
|
+
id
|
|
2169
|
+
});
|
|
2170
|
+
return jsonResult(data.startSession);
|
|
2171
|
+
} catch (error) {
|
|
2172
|
+
ctx.logger.error("vibecontrols_sessions_start failed", { error });
|
|
2173
|
+
return errorResult(
|
|
2174
|
+
`Failed to start session: ${error instanceof Error ? error.message : String(error)}`
|
|
2175
|
+
);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
);
|
|
2179
|
+
server.registerTool(
|
|
2180
|
+
track(mcpToolName(ctx.productName, "sessions_stop")),
|
|
2181
|
+
{
|
|
2182
|
+
title: "Stop Session",
|
|
2183
|
+
description: "Stop a running terminal session.",
|
|
2184
|
+
inputSchema: { id: z.string().describe("Session ID") }
|
|
2185
|
+
},
|
|
2186
|
+
async ({ id }) => {
|
|
2187
|
+
try {
|
|
2188
|
+
const data = await ctx.gql.workspace.request(STOP_SESSION, {
|
|
2189
|
+
id
|
|
2190
|
+
});
|
|
2191
|
+
return jsonResult(data.stopSession);
|
|
2192
|
+
} catch (error) {
|
|
2193
|
+
ctx.logger.error("vibecontrols_sessions_stop failed", { error });
|
|
2194
|
+
return errorResult(
|
|
2195
|
+
`Failed to stop session: ${error instanceof Error ? error.message : String(error)}`
|
|
2196
|
+
);
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
);
|
|
2200
|
+
server.registerTool(
|
|
2201
|
+
track(mcpToolName(ctx.productName, "sessions_restart")),
|
|
2202
|
+
{
|
|
2203
|
+
title: "Restart Session",
|
|
2204
|
+
description: "Restart a terminal session (stop then start).",
|
|
2205
|
+
inputSchema: { id: z.string().describe("Session ID") }
|
|
2206
|
+
},
|
|
2207
|
+
async ({ id }) => {
|
|
2208
|
+
try {
|
|
2209
|
+
const data = await ctx.gql.workspace.request(RESTART_SESSION, {
|
|
2210
|
+
id
|
|
2211
|
+
});
|
|
2212
|
+
return jsonResult(data.restartSession);
|
|
2213
|
+
} catch (error) {
|
|
2214
|
+
ctx.logger.error("vibecontrols_sessions_restart failed", { error });
|
|
2215
|
+
return errorResult(
|
|
2216
|
+
`Failed to restart session: ${error instanceof Error ? error.message : String(error)}`
|
|
2217
|
+
);
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
);
|
|
2221
|
+
server.registerTool(
|
|
2222
|
+
track(mcpToolName(ctx.productName, "sessions_terminate")),
|
|
2223
|
+
{
|
|
2224
|
+
title: "Terminate Session",
|
|
2225
|
+
description: "Forcefully terminate a terminal session.",
|
|
2226
|
+
inputSchema: { id: z.string().describe("Session ID") }
|
|
2227
|
+
},
|
|
2228
|
+
async ({ id }) => {
|
|
2229
|
+
try {
|
|
2230
|
+
const data = await ctx.gql.workspace.request(
|
|
2231
|
+
TERMINATE_SESSION,
|
|
2232
|
+
{
|
|
2233
|
+
id
|
|
2234
|
+
}
|
|
2235
|
+
);
|
|
2236
|
+
return jsonResult({ terminated: data.terminateSession, sessionId: id });
|
|
2237
|
+
} catch (error) {
|
|
2238
|
+
ctx.logger.error("vibecontrols_sessions_terminate failed", { error });
|
|
2239
|
+
return errorResult(
|
|
2240
|
+
`Failed to terminate session: ${error instanceof Error ? error.message : String(error)}`
|
|
2241
|
+
);
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
);
|
|
2245
|
+
server.registerTool(
|
|
2246
|
+
track(mcpToolName(ctx.productName, "sessions_send_input")),
|
|
2247
|
+
{
|
|
2248
|
+
title: "Send Session Input",
|
|
2249
|
+
description: "Send keystrokes or text to a running terminal session.",
|
|
2250
|
+
inputSchema: {
|
|
2251
|
+
id: z.string().describe("Session ID"),
|
|
2252
|
+
input: z.string().describe("Text/keystrokes to send")
|
|
2253
|
+
}
|
|
2254
|
+
},
|
|
2255
|
+
async ({ id, input }) => {
|
|
2256
|
+
try {
|
|
2257
|
+
const data = await ctx.gql.workspace.request(
|
|
2258
|
+
SEND_SESSION_INPUT,
|
|
2259
|
+
{
|
|
2260
|
+
id,
|
|
2261
|
+
input
|
|
2262
|
+
}
|
|
2263
|
+
);
|
|
2264
|
+
return jsonResult({ sent: data.sendSessionInput, sessionId: id });
|
|
2265
|
+
} catch (error) {
|
|
2266
|
+
ctx.logger.error("vibecontrols_sessions_send_input failed", { error });
|
|
2267
|
+
return errorResult(
|
|
2268
|
+
`Failed to send input: ${error instanceof Error ? error.message : String(error)}`
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
);
|
|
2273
|
+
server.registerTool(
|
|
2274
|
+
track(mcpToolName(ctx.productName, "sessions_start_terminal")),
|
|
2275
|
+
{
|
|
2276
|
+
title: "Start Web Terminal",
|
|
2277
|
+
description: "Start a web terminal (ttyd) for browser-based access to a session.",
|
|
2278
|
+
inputSchema: { id: z.string().describe("Session ID") }
|
|
2279
|
+
},
|
|
2280
|
+
async ({ id }) => {
|
|
2281
|
+
try {
|
|
2282
|
+
const data = await ctx.gql.workspace.request(
|
|
2283
|
+
START_SESSION_TERMINAL,
|
|
2284
|
+
{ id }
|
|
2285
|
+
);
|
|
2286
|
+
return jsonResult(data.startSessionTerminal);
|
|
2287
|
+
} catch (error) {
|
|
2288
|
+
ctx.logger.error("vibecontrols_sessions_start_terminal failed", { error });
|
|
2289
|
+
return errorResult(
|
|
2290
|
+
`Failed to start terminal: ${error instanceof Error ? error.message : String(error)}`
|
|
2291
|
+
);
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
);
|
|
2295
|
+
server.registerTool(
|
|
2296
|
+
track(mcpToolName(ctx.productName, "sessions_output")),
|
|
2297
|
+
{
|
|
2298
|
+
title: "Get Session Output",
|
|
2299
|
+
description: "Get recent output from a terminal session.",
|
|
2300
|
+
inputSchema: {
|
|
2301
|
+
id: z.string().describe("Session ID"),
|
|
2302
|
+
lines: z.number().optional().describe("Number of lines to return (default: 50)")
|
|
2303
|
+
}
|
|
2304
|
+
},
|
|
2305
|
+
async ({ id, lines }) => {
|
|
2306
|
+
try {
|
|
2307
|
+
const data = await ctx.gql.workspace.request(SESSION_OUTPUT, {
|
|
2308
|
+
id,
|
|
2309
|
+
lines
|
|
2310
|
+
});
|
|
2311
|
+
return jsonResult(data.sessionOutput);
|
|
2312
|
+
} catch (error) {
|
|
2313
|
+
ctx.logger.error("vibecontrols_sessions_output failed", { error });
|
|
2314
|
+
return errorResult(
|
|
2315
|
+
`Failed to get output: ${error instanceof Error ? error.message : String(error)}`
|
|
2316
|
+
);
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
);
|
|
2320
|
+
server.registerTool(
|
|
2321
|
+
track(mcpToolName(ctx.productName, "sessions_active")),
|
|
2322
|
+
{
|
|
2323
|
+
title: "Active Sessions",
|
|
2324
|
+
description: "Get all currently active/running sessions, optionally filtered by vibe.",
|
|
2325
|
+
inputSchema: { vibeId: z.string().optional().describe("Filter by vibe ID") }
|
|
2326
|
+
},
|
|
2327
|
+
async ({ vibeId }) => {
|
|
2328
|
+
try {
|
|
2329
|
+
const data = await ctx.gql.workspace.request(ACTIVE_SESSIONS, {
|
|
2330
|
+
vibeId
|
|
2331
|
+
});
|
|
2332
|
+
return jsonResult(data.activeSessions);
|
|
2333
|
+
} catch (error) {
|
|
2334
|
+
ctx.logger.error("vibecontrols_sessions_active failed", { error });
|
|
2335
|
+
return errorResult(
|
|
2336
|
+
`Failed to get active sessions: ${error instanceof Error ? error.message : String(error)}`
|
|
2337
|
+
);
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
);
|
|
2341
|
+
server.registerTool(
|
|
2342
|
+
track(mcpToolName(ctx.productName, "sessions_check_health")),
|
|
2343
|
+
{
|
|
2344
|
+
title: "Check Session Health",
|
|
2345
|
+
description: "Run health checks on all sessions.",
|
|
2346
|
+
inputSchema: {}
|
|
2347
|
+
},
|
|
2348
|
+
async () => {
|
|
2349
|
+
try {
|
|
2350
|
+
const data = await ctx.gql.workspace.request(
|
|
2351
|
+
CHECK_SESSION_HEALTH
|
|
2352
|
+
);
|
|
2353
|
+
return jsonResult(data.checkSessionHealth);
|
|
2354
|
+
} catch (error) {
|
|
2355
|
+
ctx.logger.error("vibecontrols_sessions_check_health failed", { error });
|
|
2356
|
+
return errorResult(
|
|
2357
|
+
`Failed to check health: ${error instanceof Error ? error.message : String(error)}`
|
|
2358
|
+
);
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
);
|
|
2362
|
+
server.registerTool(
|
|
2363
|
+
track(mcpToolName(ctx.productName, "sessions_bulk_restart")),
|
|
2364
|
+
{
|
|
2365
|
+
title: "Bulk Restart Sessions",
|
|
2366
|
+
description: "Restart multiple sessions at once.",
|
|
2367
|
+
inputSchema: { ids: z.array(z.string()).describe("Array of session IDs to restart") }
|
|
2368
|
+
},
|
|
2369
|
+
async ({ ids }) => {
|
|
2370
|
+
try {
|
|
2371
|
+
const data = await ctx.gql.workspace.request(
|
|
2372
|
+
BULK_RESTART_SESSIONS,
|
|
2373
|
+
{ ids }
|
|
2374
|
+
);
|
|
2375
|
+
return jsonResult(data.bulkRestartSessions);
|
|
2376
|
+
} catch (error) {
|
|
2377
|
+
ctx.logger.error("vibecontrols_sessions_bulk_restart failed", { error });
|
|
2378
|
+
return errorResult(
|
|
2379
|
+
`Failed to bulk restart: ${error instanceof Error ? error.message : String(error)}`
|
|
2380
|
+
);
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
);
|
|
2384
|
+
server.registerTool(
|
|
2385
|
+
track(mcpToolName(ctx.productName, "sessions_bulk_stop")),
|
|
2386
|
+
{
|
|
2387
|
+
title: "Bulk Stop Sessions",
|
|
2388
|
+
description: "Stop multiple sessions at once.",
|
|
2389
|
+
inputSchema: { ids: z.array(z.string()).describe("Array of session IDs to stop") }
|
|
2390
|
+
},
|
|
2391
|
+
async ({ ids }) => {
|
|
2392
|
+
try {
|
|
2393
|
+
const data = await ctx.gql.workspace.request(
|
|
2394
|
+
BULK_STOP_SESSIONS,
|
|
2395
|
+
{
|
|
2396
|
+
ids
|
|
2397
|
+
}
|
|
2398
|
+
);
|
|
2399
|
+
return jsonResult(data.bulkStopSessions);
|
|
2400
|
+
} catch (error) {
|
|
2401
|
+
ctx.logger.error("vibecontrols_sessions_bulk_stop failed", { error });
|
|
2402
|
+
return errorResult(
|
|
2403
|
+
`Failed to bulk stop: ${error instanceof Error ? error.message : String(error)}`
|
|
2404
|
+
);
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
);
|
|
2408
|
+
server.registerTool(
|
|
2409
|
+
track(mcpToolName(ctx.productName, "sessions_bulk_terminate")),
|
|
2410
|
+
{
|
|
2411
|
+
title: "Bulk Terminate Sessions",
|
|
2412
|
+
description: "Forcefully terminate multiple sessions at once.",
|
|
2413
|
+
inputSchema: { ids: z.array(z.string()).describe("Array of session IDs to terminate") }
|
|
2414
|
+
},
|
|
2415
|
+
async ({ ids }) => {
|
|
2416
|
+
try {
|
|
2417
|
+
const data = await ctx.gql.workspace.request(
|
|
2418
|
+
BULK_TERMINATE_SESSIONS,
|
|
2419
|
+
{ ids }
|
|
2420
|
+
);
|
|
2421
|
+
return jsonResult(data.bulkTerminateSessions);
|
|
2422
|
+
} catch (error) {
|
|
2423
|
+
ctx.logger.error("vibecontrols_sessions_bulk_terminate failed", { error });
|
|
2424
|
+
return errorResult(
|
|
2425
|
+
`Failed to bulk terminate: ${error instanceof Error ? error.message : String(error)}`
|
|
2426
|
+
);
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
);
|
|
2430
|
+
}
|
|
2431
|
+
function registerTargetTools(server, ctx, track) {
|
|
2432
|
+
server.registerTool(
|
|
2433
|
+
track(mcpToolName(ctx.productName, "targets_list")),
|
|
2434
|
+
{
|
|
2435
|
+
title: "List Targets",
|
|
2436
|
+
description: "List all VibeControls targets with optional filters and pagination.",
|
|
2437
|
+
inputSchema: {
|
|
2438
|
+
workspaceId: z.string().describe("Workspace ID (required by the GraphQL schema)"),
|
|
2439
|
+
type: z.string().optional().describe("Filter by target type"),
|
|
2440
|
+
status: z.string().optional().describe("Filter by target status"),
|
|
2441
|
+
limit: z.number().optional().describe("Max results to return"),
|
|
2442
|
+
offset: z.number().optional().describe("Number of results to skip")
|
|
2443
|
+
}
|
|
2444
|
+
},
|
|
2445
|
+
async ({ workspaceId, type, status, limit, offset }) => {
|
|
2446
|
+
try {
|
|
2447
|
+
const filter = {};
|
|
2448
|
+
if (type !== void 0) filter.type = type;
|
|
2449
|
+
if (status !== void 0) filter.status = status;
|
|
2450
|
+
const pagination = {};
|
|
2451
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
2452
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
2453
|
+
const data = await ctx.gql.workspace.request(LIST_TARGETS, {
|
|
2454
|
+
workspaceId,
|
|
2455
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
2456
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
2457
|
+
});
|
|
2458
|
+
return jsonResult(data.targets);
|
|
2459
|
+
} catch (error) {
|
|
2460
|
+
ctx.logger.error("vibecontrols_targets_list failed", { error });
|
|
2461
|
+
return errorResult(
|
|
2462
|
+
`Failed to list targets: ${error instanceof Error ? error.message : String(error)}`
|
|
2463
|
+
);
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
);
|
|
2467
|
+
server.registerTool(
|
|
2468
|
+
track(mcpToolName(ctx.productName, "targets_get")),
|
|
2469
|
+
{
|
|
2470
|
+
title: "Get Target",
|
|
2471
|
+
description: "Get a VibeControls target by its ID.",
|
|
2472
|
+
inputSchema: { id: z.string().describe("Target ID") }
|
|
2473
|
+
},
|
|
2474
|
+
async ({ id }) => {
|
|
2475
|
+
try {
|
|
2476
|
+
const data = await ctx.gql.workspace.request(GET_TARGET, { id });
|
|
2477
|
+
return jsonResult(data.target);
|
|
2478
|
+
} catch (error) {
|
|
2479
|
+
ctx.logger.error("vibecontrols_targets_get failed", { error });
|
|
2480
|
+
return errorResult(
|
|
2481
|
+
`Failed to get target: ${error instanceof Error ? error.message : String(error)}`
|
|
2482
|
+
);
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
);
|
|
2486
|
+
server.registerTool(
|
|
2487
|
+
track(mcpToolName(ctx.productName, "targets_create")),
|
|
2488
|
+
{
|
|
2489
|
+
title: "Create Target",
|
|
2490
|
+
description: "Create a new VibeControls target.",
|
|
2491
|
+
inputSchema: {
|
|
2492
|
+
workspaceId: z.string().describe("Workspace ID"),
|
|
2493
|
+
name: z.string().describe("Target name"),
|
|
2494
|
+
type: z.string().describe("Target type (DIRECT, SSH, RDP, VNC)"),
|
|
2495
|
+
host: z.string().describe("Target host address"),
|
|
2496
|
+
port: z.number().optional().describe("Target port"),
|
|
2497
|
+
username: z.string().optional().describe("Username for authentication")
|
|
2498
|
+
}
|
|
2499
|
+
},
|
|
2500
|
+
async ({ workspaceId, name, type, host, port, username }) => {
|
|
2501
|
+
try {
|
|
2502
|
+
const input = { name, type, host };
|
|
2503
|
+
if (port !== void 0) input.port = port;
|
|
2504
|
+
if (username !== void 0) input.username = username;
|
|
2505
|
+
const data = await ctx.gql.workspace.request(CREATE_TARGET, {
|
|
2506
|
+
workspaceId,
|
|
2507
|
+
input
|
|
2508
|
+
});
|
|
2509
|
+
return jsonResult(data.createTarget);
|
|
2510
|
+
} catch (error) {
|
|
2511
|
+
ctx.logger.error("vibecontrols_targets_create failed", { error });
|
|
2512
|
+
return errorResult(
|
|
2513
|
+
`Failed to create target: ${error instanceof Error ? error.message : String(error)}`
|
|
2514
|
+
);
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
);
|
|
2518
|
+
server.registerTool(
|
|
2519
|
+
track(mcpToolName(ctx.productName, "targets_update")),
|
|
2520
|
+
{
|
|
2521
|
+
title: "Update Target",
|
|
2522
|
+
description: "Update an existing VibeControls target.",
|
|
2523
|
+
inputSchema: {
|
|
2524
|
+
id: z.string().describe("Target ID"),
|
|
2525
|
+
name: z.string().optional().describe("Updated name"),
|
|
2526
|
+
type: z.string().optional().describe("Updated type (DIRECT, SSH, RDP, VNC)"),
|
|
2527
|
+
host: z.string().optional().describe("Updated host address"),
|
|
2528
|
+
port: z.number().optional().describe("Updated port"),
|
|
2529
|
+
username: z.string().optional().describe("Updated username")
|
|
2530
|
+
}
|
|
2531
|
+
},
|
|
2532
|
+
async ({ id, name, type, host, port, username }) => {
|
|
2533
|
+
try {
|
|
2534
|
+
const input = {};
|
|
2535
|
+
if (name !== void 0) input.name = name;
|
|
2536
|
+
if (type !== void 0) input.type = type;
|
|
2537
|
+
if (host !== void 0) input.host = host;
|
|
2538
|
+
if (port !== void 0) input.port = port;
|
|
2539
|
+
if (username !== void 0) input.username = username;
|
|
2540
|
+
const data = await ctx.gql.workspace.request(UPDATE_TARGET, {
|
|
2541
|
+
id,
|
|
2542
|
+
input
|
|
2543
|
+
});
|
|
2544
|
+
return jsonResult(data.updateTarget);
|
|
2545
|
+
} catch (error) {
|
|
2546
|
+
ctx.logger.error("vibecontrols_targets_update failed", { error });
|
|
2547
|
+
return errorResult(
|
|
2548
|
+
`Failed to update target: ${error instanceof Error ? error.message : String(error)}`
|
|
2549
|
+
);
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
);
|
|
2553
|
+
server.registerTool(
|
|
2554
|
+
track(mcpToolName(ctx.productName, "targets_delete")),
|
|
2555
|
+
{
|
|
2556
|
+
title: "Delete Target",
|
|
2557
|
+
description: "Permanently delete a VibeControls target.",
|
|
2558
|
+
inputSchema: { id: z.string().describe("Target ID to delete") }
|
|
2559
|
+
},
|
|
2560
|
+
async ({ id }) => {
|
|
2561
|
+
try {
|
|
2562
|
+
const data = await ctx.gql.workspace.request(DELETE_TARGET, {
|
|
2563
|
+
id
|
|
2564
|
+
});
|
|
2565
|
+
return jsonResult({ deleted: data.deleteTarget, targetId: id });
|
|
2566
|
+
} catch (error) {
|
|
2567
|
+
ctx.logger.error("vibecontrols_targets_delete failed", { error });
|
|
2568
|
+
return errorResult(
|
|
2569
|
+
`Failed to delete target: ${error instanceof Error ? error.message : String(error)}`
|
|
2570
|
+
);
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
);
|
|
2574
|
+
server.registerTool(
|
|
2575
|
+
track(mcpToolName(ctx.productName, "targets_test")),
|
|
2576
|
+
{
|
|
2577
|
+
title: "Test Target",
|
|
2578
|
+
description: "Test the connectivity of a specific target.",
|
|
2579
|
+
inputSchema: { id: z.string().describe("Target ID to test") }
|
|
2580
|
+
},
|
|
2581
|
+
async ({ id }) => {
|
|
2582
|
+
try {
|
|
2583
|
+
const data = await ctx.gql.workspace.request(TEST_TARGET, { id });
|
|
2584
|
+
return jsonResult(data.testTarget);
|
|
2585
|
+
} catch (error) {
|
|
2586
|
+
ctx.logger.error("vibecontrols_targets_test failed", { error });
|
|
2587
|
+
return errorResult(
|
|
2588
|
+
`Failed to test target: ${error instanceof Error ? error.message : String(error)}`
|
|
2589
|
+
);
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
);
|
|
2593
|
+
server.registerTool(
|
|
2594
|
+
track(mcpToolName(ctx.productName, "targets_import")),
|
|
2595
|
+
{
|
|
2596
|
+
title: "Import Targets from Config",
|
|
2597
|
+
description: "Import multiple targets from a configuration. Provide hosts as a JSON array of objects with name, host, port (optional), and username (optional).",
|
|
2598
|
+
inputSchema: {
|
|
2599
|
+
agentId: z.string().describe("Agent ID to use for import"),
|
|
2600
|
+
workspaceId: z.string().describe("Workspace ID"),
|
|
2601
|
+
hosts: z.string().describe("JSON array of host objects: [{name, host, port?, username?}]")
|
|
2602
|
+
}
|
|
2603
|
+
},
|
|
2604
|
+
async ({ agentId, workspaceId, hosts }) => {
|
|
2605
|
+
try {
|
|
2606
|
+
const parsedHosts = JSON.parse(hosts);
|
|
2607
|
+
const data = await ctx.gql.workspace.request(
|
|
2608
|
+
IMPORT_TARGETS_FROM_CONFIG,
|
|
2609
|
+
{
|
|
2610
|
+
agentId,
|
|
2611
|
+
workspaceId,
|
|
2612
|
+
hosts: parsedHosts
|
|
2613
|
+
}
|
|
2614
|
+
);
|
|
2615
|
+
return jsonResult(data.importTargetsFromConfig);
|
|
2616
|
+
} catch (error) {
|
|
2617
|
+
ctx.logger.error("vibecontrols_targets_import failed", { error });
|
|
2618
|
+
return errorResult(
|
|
2619
|
+
`Failed to import targets: ${error instanceof Error ? error.message : String(error)}`
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
);
|
|
2624
|
+
server.registerTool(
|
|
2625
|
+
track(mcpToolName(ctx.productName, "targets_scan_ssh")),
|
|
2626
|
+
{
|
|
2627
|
+
title: "Scan SSH Config",
|
|
2628
|
+
description: "Scan an SSH config file on the agent to discover targets.",
|
|
2629
|
+
inputSchema: {
|
|
2630
|
+
agentId: z.string().describe("Agent ID to scan SSH config on"),
|
|
2631
|
+
configPath: z.string().optional().describe("Path to SSH config file (defaults to ~/.ssh/config)")
|
|
2632
|
+
}
|
|
2633
|
+
},
|
|
2634
|
+
async ({ agentId, configPath }) => {
|
|
2635
|
+
try {
|
|
2636
|
+
const variables = { agentId };
|
|
2637
|
+
if (configPath !== void 0) variables.configPath = configPath;
|
|
2638
|
+
const data = await ctx.gql.workspace.request(
|
|
2639
|
+
SCAN_SSH_CONFIG,
|
|
2640
|
+
variables
|
|
2641
|
+
);
|
|
2642
|
+
return jsonResult(data.scanSSHConfig);
|
|
2643
|
+
} catch (error) {
|
|
2644
|
+
ctx.logger.error("vibecontrols_targets_scan_ssh failed", { error });
|
|
2645
|
+
return errorResult(
|
|
2646
|
+
`Failed to scan SSH config: ${error instanceof Error ? error.message : String(error)}`
|
|
2647
|
+
);
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
);
|
|
2651
|
+
server.registerTool(
|
|
2652
|
+
track(mcpToolName(ctx.productName, "targets_install_agent")),
|
|
2653
|
+
{
|
|
2654
|
+
title: "Install Agent on Target",
|
|
2655
|
+
description: "Install a VibeControls agent on a remote target machine.",
|
|
2656
|
+
inputSchema: {
|
|
2657
|
+
sourceAgentId: z.string().describe("Source agent ID to initiate the install from"),
|
|
2658
|
+
targetId: z.string().describe("Target ID to install the agent on"),
|
|
2659
|
+
agentPort: z.number().optional().describe("Port for the new agent to listen on")
|
|
2660
|
+
}
|
|
2661
|
+
},
|
|
2662
|
+
async ({ sourceAgentId, targetId, agentPort }) => {
|
|
2663
|
+
try {
|
|
2664
|
+
const variables = { sourceAgentId, targetId };
|
|
2665
|
+
if (agentPort !== void 0) variables.agentPort = agentPort;
|
|
2666
|
+
const data = await ctx.gql.workspace.request(
|
|
2667
|
+
INSTALL_AGENT_ON_TARGET,
|
|
2668
|
+
variables
|
|
2669
|
+
);
|
|
2670
|
+
return jsonResult(data.installAgentOnTarget);
|
|
2671
|
+
} catch (error) {
|
|
2672
|
+
ctx.logger.error("vibecontrols_targets_install_agent failed", { error });
|
|
2673
|
+
return errorResult(
|
|
2674
|
+
`Failed to install agent on target: ${error instanceof Error ? error.message : String(error)}`
|
|
2675
|
+
);
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
);
|
|
2679
|
+
}
|
|
2680
|
+
function registerTunnelTools(server, ctx, track) {
|
|
2681
|
+
server.registerTool(
|
|
2682
|
+
track(mcpToolName(ctx.productName, "tunnels_list")),
|
|
2683
|
+
{
|
|
2684
|
+
title: "List Tunnels",
|
|
2685
|
+
description: "List all agent tunnels.",
|
|
2686
|
+
inputSchema: {}
|
|
2687
|
+
},
|
|
2688
|
+
async () => {
|
|
2689
|
+
try {
|
|
2690
|
+
const data = await ctx.gql.workspace.request(
|
|
2691
|
+
LIST_TUNNELS
|
|
2692
|
+
);
|
|
2693
|
+
return jsonResult(data.vibecontrolsAgentTunnels);
|
|
2694
|
+
} catch (error) {
|
|
2695
|
+
ctx.logger.error("vibecontrols_tunnels_list failed", { error });
|
|
2696
|
+
return errorResult(
|
|
2697
|
+
`Failed to list tunnels: ${error instanceof Error ? error.message : String(error)}`
|
|
2698
|
+
);
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
);
|
|
2702
|
+
server.registerTool(
|
|
2703
|
+
track(mcpToolName(ctx.productName, "tunnels_create")),
|
|
2704
|
+
{
|
|
2705
|
+
title: "Create Tunnel",
|
|
2706
|
+
description: "Create a new agent tunnel for remote access.",
|
|
2707
|
+
inputSchema: {
|
|
2708
|
+
agentId: z.string().describe("Agent ID to create the tunnel for"),
|
|
2709
|
+
provider: z.string().optional().describe("Tunnel provider (e.g., cloudflare)")
|
|
2710
|
+
}
|
|
2711
|
+
},
|
|
2712
|
+
async ({ agentId, provider }) => {
|
|
2713
|
+
try {
|
|
2714
|
+
const input = { agentId };
|
|
2715
|
+
if (provider !== void 0) input.provider = provider;
|
|
2716
|
+
const data = await ctx.gql.workspace.request(
|
|
2717
|
+
CREATE_TUNNEL,
|
|
2718
|
+
{
|
|
2719
|
+
input
|
|
2720
|
+
}
|
|
2721
|
+
);
|
|
2722
|
+
return jsonResult(data.createAgentTunnel);
|
|
2723
|
+
} catch (error) {
|
|
2724
|
+
ctx.logger.error("vibecontrols_tunnels_create failed", { error });
|
|
2725
|
+
return errorResult(
|
|
2726
|
+
`Failed to create tunnel: ${error instanceof Error ? error.message : String(error)}`
|
|
2727
|
+
);
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
);
|
|
2731
|
+
server.registerTool(
|
|
2732
|
+
track(mcpToolName(ctx.productName, "tunnels_stop")),
|
|
2733
|
+
{
|
|
2734
|
+
title: "Stop Tunnel",
|
|
2735
|
+
description: "Stop a running tunnel.",
|
|
2736
|
+
inputSchema: {
|
|
2737
|
+
agentId: z.string().describe("Agent ID that owns the tunnel"),
|
|
2738
|
+
tunnelId: z.string().describe("Tunnel ID to stop")
|
|
2739
|
+
}
|
|
2740
|
+
},
|
|
2741
|
+
async ({ agentId, tunnelId }) => {
|
|
2742
|
+
try {
|
|
2743
|
+
const data = await ctx.gql.workspace.request(STOP_TUNNEL, {
|
|
2744
|
+
agentId,
|
|
2745
|
+
tunnelId
|
|
2746
|
+
});
|
|
2747
|
+
return jsonResult({ stopped: data.stopAgentTunnel, agentId, tunnelId });
|
|
2748
|
+
} catch (error) {
|
|
2749
|
+
ctx.logger.error("vibecontrols_tunnels_stop failed", { error });
|
|
2750
|
+
return errorResult(
|
|
2751
|
+
`Failed to stop tunnel: ${error instanceof Error ? error.message : String(error)}`
|
|
2752
|
+
);
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
);
|
|
2756
|
+
server.registerTool(
|
|
2757
|
+
track(mcpToolName(ctx.productName, "tunnels_delete")),
|
|
2758
|
+
{
|
|
2759
|
+
title: "Delete Tunnel",
|
|
2760
|
+
description: "Permanently delete a tunnel.",
|
|
2761
|
+
inputSchema: {
|
|
2762
|
+
agentId: z.string().describe("Agent ID that owns the tunnel"),
|
|
2763
|
+
tunnelId: z.string().describe("Tunnel ID to delete")
|
|
2764
|
+
}
|
|
2765
|
+
},
|
|
2766
|
+
async ({ agentId, tunnelId }) => {
|
|
2767
|
+
try {
|
|
2768
|
+
const data = await ctx.gql.workspace.request(
|
|
2769
|
+
DELETE_TUNNEL,
|
|
2770
|
+
{
|
|
2771
|
+
agentId,
|
|
2772
|
+
tunnelId
|
|
2773
|
+
}
|
|
2774
|
+
);
|
|
2775
|
+
return jsonResult({ deleted: data.deleteAgentTunnel, agentId, tunnelId });
|
|
2776
|
+
} catch (error) {
|
|
2777
|
+
ctx.logger.error("vibecontrols_tunnels_delete failed", { error });
|
|
2778
|
+
return errorResult(
|
|
2779
|
+
`Failed to delete tunnel: ${error instanceof Error ? error.message : String(error)}`
|
|
2780
|
+
);
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
);
|
|
2784
|
+
}
|
|
2785
|
+
function registerUISessionTools(server, ctx, track) {
|
|
2786
|
+
server.registerTool(
|
|
2787
|
+
track(mcpToolName(ctx.productName, "ui_session_get")),
|
|
2788
|
+
{
|
|
2789
|
+
title: "Get UI Session",
|
|
2790
|
+
description: "Get the current user's UI session state (active vibe, active session, recent items).",
|
|
2791
|
+
inputSchema: {}
|
|
2792
|
+
},
|
|
2793
|
+
async () => {
|
|
2794
|
+
try {
|
|
2795
|
+
const data = await ctx.gql.workspace.request(GET_UI_SESSION);
|
|
2796
|
+
return jsonResult(data.uiSession);
|
|
2797
|
+
} catch (error) {
|
|
2798
|
+
ctx.logger.error("vibecontrols_ui_session_get failed", { error });
|
|
2799
|
+
return errorResult(
|
|
2800
|
+
`Failed to get UI session: ${error instanceof Error ? error.message : String(error)}`
|
|
2801
|
+
);
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
);
|
|
2805
|
+
server.registerTool(
|
|
2806
|
+
track(mcpToolName(ctx.productName, "ui_session_save")),
|
|
2807
|
+
{
|
|
2808
|
+
title: "Save UI Session",
|
|
2809
|
+
description: "Save the current user's UI session state.",
|
|
2810
|
+
inputSchema: {
|
|
2811
|
+
activeVibeId: z.string().optional().describe("Active vibe ID"),
|
|
2812
|
+
activeSessionId: z.string().optional().describe("Active session ID"),
|
|
2813
|
+
recentVibes: z.array(z.string()).optional().describe("Recent vibe IDs"),
|
|
2814
|
+
recentSessions: z.array(z.string()).optional().describe("Recent session IDs"),
|
|
2815
|
+
state: z.string().optional().describe("Custom state as JSON string")
|
|
2816
|
+
}
|
|
2817
|
+
},
|
|
2818
|
+
async ({ activeVibeId, activeSessionId, recentVibes, recentSessions, state }) => {
|
|
2819
|
+
try {
|
|
2820
|
+
const input = {};
|
|
2821
|
+
if (activeVibeId !== void 0) input.activeVibeId = activeVibeId;
|
|
2822
|
+
if (activeSessionId !== void 0) input.activeSessionId = activeSessionId;
|
|
2823
|
+
if (recentVibes !== void 0) input.recentVibes = recentVibes;
|
|
2824
|
+
if (recentSessions !== void 0) input.recentSessions = recentSessions;
|
|
2825
|
+
if (state !== void 0) input.state = JSON.parse(state);
|
|
2826
|
+
const data = await ctx.gql.workspace.request(SAVE_UI_SESSION, {
|
|
2827
|
+
input
|
|
2828
|
+
});
|
|
2829
|
+
return jsonResult(data.saveUISession);
|
|
2830
|
+
} catch (error) {
|
|
2831
|
+
ctx.logger.error("vibecontrols_ui_session_save failed", { error });
|
|
2832
|
+
return errorResult(
|
|
2833
|
+
`Failed to save UI session: ${error instanceof Error ? error.message : String(error)}`
|
|
2834
|
+
);
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
);
|
|
2838
|
+
server.registerTool(
|
|
2839
|
+
track(mcpToolName(ctx.productName, "ui_session_clear")),
|
|
2840
|
+
{
|
|
2841
|
+
title: "Clear UI Session",
|
|
2842
|
+
description: "Clear the current user's UI session state.",
|
|
2843
|
+
inputSchema: {}
|
|
2844
|
+
},
|
|
2845
|
+
async () => {
|
|
2846
|
+
try {
|
|
2847
|
+
const data = await ctx.gql.workspace.request(CLEAR_UI_SESSION);
|
|
2848
|
+
return jsonResult({ cleared: data.clearUISession });
|
|
2849
|
+
} catch (error) {
|
|
2850
|
+
ctx.logger.error("vibecontrols_ui_session_clear failed", { error });
|
|
2851
|
+
return errorResult(
|
|
2852
|
+
`Failed to clear UI session: ${error instanceof Error ? error.message : String(error)}`
|
|
2853
|
+
);
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
);
|
|
2857
|
+
}
|
|
2858
|
+
function registerVibeDeckTools(server, ctx, track) {
|
|
2859
|
+
server.registerTool(
|
|
2860
|
+
track(mcpToolName(ctx.productName, "decks_list")),
|
|
2861
|
+
{
|
|
2862
|
+
title: "List VibeDecks",
|
|
2863
|
+
description: "List all VibeDecks with optional filters and pagination.",
|
|
2864
|
+
inputSchema: {
|
|
2865
|
+
name: z.string().optional().describe("Filter by deck name"),
|
|
2866
|
+
limit: z.number().optional().describe("Max results to return"),
|
|
2867
|
+
offset: z.number().optional().describe("Number of results to skip")
|
|
2868
|
+
}
|
|
2869
|
+
},
|
|
2870
|
+
async ({ name, limit, offset }) => {
|
|
2871
|
+
try {
|
|
2872
|
+
const filter = {};
|
|
2873
|
+
if (name !== void 0) filter.name = name;
|
|
2874
|
+
const pagination = {};
|
|
2875
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
2876
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
2877
|
+
const data = await ctx.gql.workspace.request(LIST_VIBEDECKS, {
|
|
2878
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
2879
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
2880
|
+
});
|
|
2881
|
+
return jsonResult(data.vibeDecks);
|
|
2882
|
+
} catch (error) {
|
|
2883
|
+
ctx.logger.error("vibecontrols_decks_list failed", { error });
|
|
2884
|
+
return errorResult(
|
|
2885
|
+
`Failed to list VibeDecks: ${error instanceof Error ? error.message : String(error)}`
|
|
2886
|
+
);
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
);
|
|
2890
|
+
server.registerTool(
|
|
2891
|
+
track(mcpToolName(ctx.productName, "decks_get")),
|
|
2892
|
+
{
|
|
2893
|
+
title: "Get VibeDeck",
|
|
2894
|
+
description: "Get a VibeDeck by its ID.",
|
|
2895
|
+
inputSchema: { id: z.string().describe("VibeDeck ID") }
|
|
2896
|
+
},
|
|
2897
|
+
async ({ id }) => {
|
|
2898
|
+
try {
|
|
2899
|
+
const data = await ctx.gql.workspace.request(GET_VIBEDECK, { id });
|
|
2900
|
+
return jsonResult(data.vibeDeck);
|
|
2901
|
+
} catch (error) {
|
|
2902
|
+
ctx.logger.error("vibecontrols_decks_get failed", { error });
|
|
2903
|
+
return errorResult(
|
|
2904
|
+
`Failed to get VibeDeck: ${error instanceof Error ? error.message : String(error)}`
|
|
2905
|
+
);
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
);
|
|
2909
|
+
server.registerTool(
|
|
2910
|
+
track(mcpToolName(ctx.productName, "decks_create")),
|
|
2911
|
+
{
|
|
2912
|
+
title: "Create VibeDeck",
|
|
2913
|
+
description: "Create a new VibeDeck.",
|
|
2914
|
+
inputSchema: {
|
|
2915
|
+
name: z.string().describe("Deck name"),
|
|
2916
|
+
description: z.string().optional().describe("Deck description"),
|
|
2917
|
+
isDefault: z.boolean().optional().describe("Set as default deck")
|
|
2918
|
+
}
|
|
2919
|
+
},
|
|
2920
|
+
async ({ name, description, isDefault }) => {
|
|
2921
|
+
try {
|
|
2922
|
+
const input = { name };
|
|
2923
|
+
if (description !== void 0) input.description = description;
|
|
2924
|
+
if (isDefault !== void 0) input.isDefault = isDefault;
|
|
2925
|
+
const data = await ctx.gql.workspace.request(CREATE_VIBEDECK, {
|
|
2926
|
+
input
|
|
2927
|
+
});
|
|
2928
|
+
return jsonResult(data.createVibeDeck);
|
|
2929
|
+
} catch (error) {
|
|
2930
|
+
ctx.logger.error("vibecontrols_decks_create failed", { error });
|
|
2931
|
+
return errorResult(
|
|
2932
|
+
`Failed to create VibeDeck: ${error instanceof Error ? error.message : String(error)}`
|
|
2933
|
+
);
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
);
|
|
2937
|
+
server.registerTool(
|
|
2938
|
+
track(mcpToolName(ctx.productName, "decks_update")),
|
|
2939
|
+
{
|
|
2940
|
+
title: "Update VibeDeck",
|
|
2941
|
+
description: "Update an existing VibeDeck.",
|
|
2942
|
+
inputSchema: {
|
|
2943
|
+
id: z.string().describe("VibeDeck ID"),
|
|
2944
|
+
name: z.string().optional().describe("Updated name"),
|
|
2945
|
+
description: z.string().optional().describe("Updated description"),
|
|
2946
|
+
isDefault: z.boolean().optional().describe("Set as default deck")
|
|
2947
|
+
}
|
|
2948
|
+
},
|
|
2949
|
+
async ({ id, name, description, isDefault }) => {
|
|
2950
|
+
try {
|
|
2951
|
+
const input = {};
|
|
2952
|
+
if (name !== void 0) input.name = name;
|
|
2953
|
+
if (description !== void 0) input.description = description;
|
|
2954
|
+
if (isDefault !== void 0) input.isDefault = isDefault;
|
|
2955
|
+
const data = await ctx.gql.workspace.request(UPDATE_VIBEDECK, {
|
|
2956
|
+
id,
|
|
2957
|
+
input
|
|
2958
|
+
});
|
|
2959
|
+
return jsonResult(data.updateVibeDeck);
|
|
2960
|
+
} catch (error) {
|
|
2961
|
+
ctx.logger.error("vibecontrols_decks_update failed", { error });
|
|
2962
|
+
return errorResult(
|
|
2963
|
+
`Failed to update VibeDeck: ${error instanceof Error ? error.message : String(error)}`
|
|
2964
|
+
);
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
);
|
|
2968
|
+
server.registerTool(
|
|
2969
|
+
track(mcpToolName(ctx.productName, "decks_delete")),
|
|
2970
|
+
{
|
|
2971
|
+
title: "Delete VibeDeck",
|
|
2972
|
+
description: "Permanently delete a VibeDeck.",
|
|
2973
|
+
inputSchema: { id: z.string().describe("VibeDeck ID to delete") }
|
|
2974
|
+
},
|
|
2975
|
+
async ({ id }) => {
|
|
2976
|
+
try {
|
|
2977
|
+
const data = await ctx.gql.workspace.request(DELETE_VIBEDECK, {
|
|
2978
|
+
id
|
|
2979
|
+
});
|
|
2980
|
+
return jsonResult({ deleted: data.deleteVibeDeck, vibeDeckId: id });
|
|
2981
|
+
} catch (error) {
|
|
2982
|
+
ctx.logger.error("vibecontrols_decks_delete failed", { error });
|
|
2983
|
+
return errorResult(
|
|
2984
|
+
`Failed to delete VibeDeck: ${error instanceof Error ? error.message : String(error)}`
|
|
2985
|
+
);
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
);
|
|
2989
|
+
server.registerTool(
|
|
2990
|
+
track(mcpToolName(ctx.productName, "decks_duplicate")),
|
|
2991
|
+
{
|
|
2992
|
+
title: "Duplicate VibeDeck",
|
|
2993
|
+
description: "Create a copy of an existing VibeDeck.",
|
|
2994
|
+
inputSchema: {
|
|
2995
|
+
id: z.string().describe("VibeDeck ID to duplicate"),
|
|
2996
|
+
name: z.string().optional().describe("Name for the duplicated deck")
|
|
2997
|
+
}
|
|
2998
|
+
},
|
|
2999
|
+
async ({ id, name }) => {
|
|
3000
|
+
try {
|
|
3001
|
+
const variables = { id };
|
|
3002
|
+
if (name !== void 0) variables.name = name;
|
|
3003
|
+
const data = await ctx.gql.workspace.request(
|
|
3004
|
+
DUPLICATE_VIBEDECK,
|
|
3005
|
+
variables
|
|
3006
|
+
);
|
|
3007
|
+
return jsonResult(data.duplicateVibeDeck);
|
|
3008
|
+
} catch (error) {
|
|
3009
|
+
ctx.logger.error("vibecontrols_decks_duplicate failed", { error });
|
|
3010
|
+
return errorResult(
|
|
3011
|
+
`Failed to duplicate VibeDeck: ${error instanceof Error ? error.message : String(error)}`
|
|
3012
|
+
);
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
);
|
|
3016
|
+
server.registerTool(
|
|
3017
|
+
track(mcpToolName(ctx.productName, "decks_set_default")),
|
|
3018
|
+
{
|
|
3019
|
+
title: "Set Default VibeDeck",
|
|
3020
|
+
description: "Set a VibeDeck as the default deck.",
|
|
3021
|
+
inputSchema: { id: z.string().describe("VibeDeck ID to set as default") }
|
|
3022
|
+
},
|
|
3023
|
+
async ({ id }) => {
|
|
3024
|
+
try {
|
|
3025
|
+
const data = await ctx.gql.workspace.request(
|
|
3026
|
+
SET_DEFAULT_VIBEDECK,
|
|
3027
|
+
{
|
|
3028
|
+
id
|
|
3029
|
+
}
|
|
3030
|
+
);
|
|
3031
|
+
return jsonResult(data.setDefaultVibeDeck);
|
|
3032
|
+
} catch (error) {
|
|
3033
|
+
ctx.logger.error("vibecontrols_decks_set_default failed", { error });
|
|
3034
|
+
return errorResult(
|
|
3035
|
+
`Failed to set default VibeDeck: ${error instanceof Error ? error.message : String(error)}`
|
|
3036
|
+
);
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
);
|
|
3040
|
+
server.registerTool(
|
|
3041
|
+
track(mcpToolName(ctx.productName, "decks_buttons_list")),
|
|
3042
|
+
{
|
|
3043
|
+
title: "List VibeDeck Buttons",
|
|
3044
|
+
description: "List all buttons in a VibeDeck with optional pagination.",
|
|
3045
|
+
inputSchema: {
|
|
3046
|
+
vibeDeckId: z.string().optional().describe("Filter by VibeDeck ID"),
|
|
3047
|
+
limit: z.number().optional().describe("Max results to return"),
|
|
3048
|
+
offset: z.number().optional().describe("Number of results to skip")
|
|
3049
|
+
}
|
|
3050
|
+
},
|
|
3051
|
+
async ({ vibeDeckId, limit, offset }) => {
|
|
3052
|
+
try {
|
|
3053
|
+
const filter = {};
|
|
3054
|
+
if (vibeDeckId !== void 0) filter.vibeDeckId = vibeDeckId;
|
|
3055
|
+
const pagination = {};
|
|
3056
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
3057
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
3058
|
+
const data = await ctx.gql.workspace.request(
|
|
3059
|
+
LIST_VIBEDECK_BUTTONS,
|
|
3060
|
+
{
|
|
3061
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
3062
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
3063
|
+
}
|
|
3064
|
+
);
|
|
3065
|
+
return jsonResult(data.vibeDeckButtons);
|
|
3066
|
+
} catch (error) {
|
|
3067
|
+
ctx.logger.error("vibecontrols_decks_buttons_list failed", { error });
|
|
3068
|
+
return errorResult(
|
|
3069
|
+
`Failed to list VibeDeck buttons: ${error instanceof Error ? error.message : String(error)}`
|
|
3070
|
+
);
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
);
|
|
3074
|
+
server.registerTool(
|
|
3075
|
+
track(mcpToolName(ctx.productName, "decks_buttons_create")),
|
|
3076
|
+
{
|
|
3077
|
+
title: "Create VibeDeck Button",
|
|
3078
|
+
description: "Create a new button in a VibeDeck.",
|
|
3079
|
+
inputSchema: {
|
|
3080
|
+
vibeDeckId: z.string().describe("VibeDeck ID to add the button to"),
|
|
3081
|
+
label: z.string().describe("Button label"),
|
|
3082
|
+
actionType: z.string().optional().describe("Action type for the button"),
|
|
3083
|
+
actionId: z.string().optional().describe("Action ID to link to this button"),
|
|
3084
|
+
command: z.string().optional().describe("Command to execute"),
|
|
3085
|
+
script: z.string().optional().describe("Script to execute"),
|
|
3086
|
+
webhookUrl: z.string().optional().describe("Webhook URL to call"),
|
|
3087
|
+
row: z.number().optional().describe("Row position in the deck grid"),
|
|
3088
|
+
column: z.number().optional().describe("Column position in the deck grid"),
|
|
3089
|
+
color: z.string().optional().describe("Button color"),
|
|
3090
|
+
icon: z.string().optional().describe("Button icon")
|
|
3091
|
+
}
|
|
3092
|
+
},
|
|
3093
|
+
async ({
|
|
3094
|
+
vibeDeckId,
|
|
3095
|
+
label,
|
|
3096
|
+
actionType,
|
|
3097
|
+
actionId,
|
|
3098
|
+
command,
|
|
3099
|
+
script,
|
|
3100
|
+
webhookUrl,
|
|
3101
|
+
row,
|
|
3102
|
+
column,
|
|
3103
|
+
color,
|
|
3104
|
+
icon
|
|
3105
|
+
}) => {
|
|
3106
|
+
try {
|
|
3107
|
+
const input = { vibeDeckId, label };
|
|
3108
|
+
if (actionType !== void 0) input.actionType = actionType;
|
|
3109
|
+
if (actionId !== void 0) input.actionId = actionId;
|
|
3110
|
+
if (command !== void 0) input.command = command;
|
|
3111
|
+
if (script !== void 0) input.script = script;
|
|
3112
|
+
if (webhookUrl !== void 0) input.webhookUrl = webhookUrl;
|
|
3113
|
+
if (row !== void 0) input.row = row;
|
|
3114
|
+
if (column !== void 0) input.column = column;
|
|
3115
|
+
if (color !== void 0) input.color = color;
|
|
3116
|
+
if (icon !== void 0) input.icon = icon;
|
|
3117
|
+
const data = await ctx.gql.workspace.request(
|
|
3118
|
+
CREATE_VIBEDECK_BUTTON,
|
|
3119
|
+
{ input }
|
|
3120
|
+
);
|
|
3121
|
+
return jsonResult(data.createVibeDeckButton);
|
|
3122
|
+
} catch (error) {
|
|
3123
|
+
ctx.logger.error("vibecontrols_decks_buttons_create failed", { error });
|
|
3124
|
+
return errorResult(
|
|
3125
|
+
`Failed to create VibeDeck button: ${error instanceof Error ? error.message : String(error)}`
|
|
3126
|
+
);
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3129
|
+
);
|
|
3130
|
+
server.registerTool(
|
|
3131
|
+
track(mcpToolName(ctx.productName, "decks_buttons_update")),
|
|
3132
|
+
{
|
|
3133
|
+
title: "Update VibeDeck Button",
|
|
3134
|
+
description: "Update an existing VibeDeck button.",
|
|
3135
|
+
inputSchema: {
|
|
3136
|
+
id: z.string().describe("Button ID"),
|
|
3137
|
+
label: z.string().optional().describe("Updated label"),
|
|
3138
|
+
actionType: z.string().optional().describe("Updated action type"),
|
|
3139
|
+
actionId: z.string().optional().describe("Updated action ID to link to this button"),
|
|
3140
|
+
command: z.string().optional().describe("Updated command"),
|
|
3141
|
+
script: z.string().optional().describe("Updated script"),
|
|
3142
|
+
webhookUrl: z.string().optional().describe("Updated webhook URL"),
|
|
3143
|
+
row: z.number().optional().describe("Updated row position"),
|
|
3144
|
+
column: z.number().optional().describe("Updated column position"),
|
|
3145
|
+
color: z.string().optional().describe("Updated color"),
|
|
3146
|
+
icon: z.string().optional().describe("Updated icon")
|
|
3147
|
+
}
|
|
3148
|
+
},
|
|
3149
|
+
async ({
|
|
3150
|
+
id,
|
|
3151
|
+
label,
|
|
3152
|
+
actionType,
|
|
3153
|
+
actionId,
|
|
3154
|
+
command,
|
|
3155
|
+
script,
|
|
3156
|
+
webhookUrl,
|
|
3157
|
+
row,
|
|
3158
|
+
column,
|
|
3159
|
+
color,
|
|
3160
|
+
icon
|
|
3161
|
+
}) => {
|
|
3162
|
+
try {
|
|
3163
|
+
const input = {};
|
|
3164
|
+
if (label !== void 0) input.label = label;
|
|
3165
|
+
if (actionType !== void 0) input.actionType = actionType;
|
|
3166
|
+
if (actionId !== void 0) input.actionId = actionId;
|
|
3167
|
+
if (command !== void 0) input.command = command;
|
|
3168
|
+
if (script !== void 0) input.script = script;
|
|
3169
|
+
if (webhookUrl !== void 0) input.webhookUrl = webhookUrl;
|
|
3170
|
+
if (row !== void 0) input.row = row;
|
|
3171
|
+
if (column !== void 0) input.column = column;
|
|
3172
|
+
if (color !== void 0) input.color = color;
|
|
3173
|
+
if (icon !== void 0) input.icon = icon;
|
|
3174
|
+
const data = await ctx.gql.workspace.request(
|
|
3175
|
+
UPDATE_VIBEDECK_BUTTON,
|
|
3176
|
+
{ id, input }
|
|
3177
|
+
);
|
|
3178
|
+
return jsonResult(data.updateVibeDeckButton);
|
|
3179
|
+
} catch (error) {
|
|
3180
|
+
ctx.logger.error("vibecontrols_decks_buttons_update failed", { error });
|
|
3181
|
+
return errorResult(
|
|
3182
|
+
`Failed to update VibeDeck button: ${error instanceof Error ? error.message : String(error)}`
|
|
3183
|
+
);
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
3186
|
+
);
|
|
3187
|
+
server.registerTool(
|
|
3188
|
+
track(mcpToolName(ctx.productName, "decks_buttons_delete")),
|
|
3189
|
+
{
|
|
3190
|
+
title: "Delete VibeDeck Button",
|
|
3191
|
+
description: "Permanently delete a VibeDeck button.",
|
|
3192
|
+
inputSchema: { id: z.string().describe("Button ID to delete") }
|
|
3193
|
+
},
|
|
3194
|
+
async ({ id }) => {
|
|
3195
|
+
try {
|
|
3196
|
+
const data = await ctx.gql.workspace.request(
|
|
3197
|
+
DELETE_VIBEDECK_BUTTON,
|
|
3198
|
+
{ id }
|
|
3199
|
+
);
|
|
3200
|
+
return jsonResult({ deleted: data.deleteVibeDeckButton, buttonId: id });
|
|
3201
|
+
} catch (error) {
|
|
3202
|
+
ctx.logger.error("vibecontrols_decks_buttons_delete failed", { error });
|
|
3203
|
+
return errorResult(
|
|
3204
|
+
`Failed to delete VibeDeck button: ${error instanceof Error ? error.message : String(error)}`
|
|
3205
|
+
);
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
);
|
|
3209
|
+
server.registerTool(
|
|
3210
|
+
track(mcpToolName(ctx.productName, "decks_buttons_execute")),
|
|
3211
|
+
{
|
|
3212
|
+
title: "Execute VibeDeck Button",
|
|
3213
|
+
description: "Execute the action associated with a VibeDeck button on a specific agent.",
|
|
3214
|
+
inputSchema: {
|
|
3215
|
+
id: z.string().describe("Button ID to execute"),
|
|
3216
|
+
agentId: z.string().describe("Agent ID to execute the button action on")
|
|
3217
|
+
}
|
|
3218
|
+
},
|
|
3219
|
+
async ({ id, agentId }) => {
|
|
3220
|
+
try {
|
|
3221
|
+
const data = await ctx.gql.workspace.request(
|
|
3222
|
+
EXECUTE_VIBEDECK_BUTTON,
|
|
3223
|
+
{ id, agentId }
|
|
3224
|
+
);
|
|
3225
|
+
return jsonResult(data.executeVibeDeckButton);
|
|
3226
|
+
} catch (error) {
|
|
3227
|
+
ctx.logger.error("vibecontrols_decks_buttons_execute failed", { error });
|
|
3228
|
+
return errorResult(
|
|
3229
|
+
`Failed to execute VibeDeck button: ${error instanceof Error ? error.message : String(error)}`
|
|
3230
|
+
);
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
);
|
|
3234
|
+
}
|
|
3235
|
+
var VibeTypeEnum = z.enum([
|
|
3236
|
+
"PROJECT",
|
|
3237
|
+
"WORKSPACE",
|
|
3238
|
+
"REPOSITORY",
|
|
3239
|
+
"MONOREPO",
|
|
3240
|
+
"PACKAGE",
|
|
3241
|
+
"CUSTOM"
|
|
3242
|
+
]);
|
|
3243
|
+
var VibeStatusEnum = z.enum(["ACTIVE", "INACTIVE", "ARCHIVED", "ERROR"]);
|
|
3244
|
+
function registerVibeTools(server, ctx, track) {
|
|
3245
|
+
server.registerTool(
|
|
3246
|
+
track(mcpToolName(ctx.productName, "vibes_list")),
|
|
3247
|
+
{
|
|
3248
|
+
title: "List Vibes",
|
|
3249
|
+
description: "List all vibes (projects/workspaces) with optional filters and pagination.",
|
|
3250
|
+
inputSchema: {
|
|
3251
|
+
name: z.string().optional().describe("Filter by vibe name"),
|
|
3252
|
+
type: VibeTypeEnum.optional().describe("Filter by vibe type"),
|
|
3253
|
+
status: VibeStatusEnum.optional().describe("Filter by status"),
|
|
3254
|
+
agentId: z.string().optional().describe("Filter by agent ID"),
|
|
3255
|
+
parentId: z.string().optional().describe("Filter by parent vibe ID"),
|
|
3256
|
+
tags: z.array(z.string()).optional().describe("Filter by tags"),
|
|
3257
|
+
limit: z.number().optional().describe("Max results"),
|
|
3258
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
3259
|
+
}
|
|
3260
|
+
},
|
|
3261
|
+
async ({ name, type, status, agentId, parentId, tags, limit, offset }) => {
|
|
3262
|
+
try {
|
|
3263
|
+
const filter = {};
|
|
3264
|
+
if (name !== void 0) filter.name = name;
|
|
3265
|
+
if (type !== void 0) filter.type = type;
|
|
3266
|
+
if (status !== void 0) filter.status = status;
|
|
3267
|
+
if (agentId !== void 0) filter.agentId = agentId;
|
|
3268
|
+
if (parentId !== void 0) filter.parentId = parentId;
|
|
3269
|
+
if (tags !== void 0) filter.tags = tags;
|
|
3270
|
+
const pagination = {};
|
|
3271
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
3272
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
3273
|
+
const data = await ctx.gql.workspace.request(LIST_VIBES, {
|
|
3274
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
3275
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
3276
|
+
});
|
|
3277
|
+
return jsonResult(data.vibes);
|
|
3278
|
+
} catch (error) {
|
|
3279
|
+
ctx.logger.error("vibecontrols_vibes_list failed", { error });
|
|
3280
|
+
return errorResult(
|
|
3281
|
+
`Failed to list vibes: ${error instanceof Error ? error.message : String(error)}`
|
|
3282
|
+
);
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
);
|
|
3286
|
+
server.registerTool(
|
|
3287
|
+
track(mcpToolName(ctx.productName, "vibes_get")),
|
|
3288
|
+
{
|
|
3289
|
+
title: "Get Vibe",
|
|
3290
|
+
description: "Get a vibe by its ID.",
|
|
3291
|
+
inputSchema: { id: z.string().describe("Vibe ID") }
|
|
3292
|
+
},
|
|
3293
|
+
async ({ id }) => {
|
|
3294
|
+
try {
|
|
3295
|
+
const data = await ctx.gql.workspace.request(GET_VIBE, { id });
|
|
3296
|
+
return jsonResult(data.vibe);
|
|
3297
|
+
} catch (error) {
|
|
3298
|
+
ctx.logger.error("vibecontrols_vibes_get failed", { error });
|
|
3299
|
+
return errorResult(
|
|
3300
|
+
`Failed to get vibe: ${error instanceof Error ? error.message : String(error)}`
|
|
3301
|
+
);
|
|
3302
|
+
}
|
|
3303
|
+
}
|
|
3304
|
+
);
|
|
3305
|
+
server.registerTool(
|
|
3306
|
+
track(mcpToolName(ctx.productName, "vibes_create")),
|
|
3307
|
+
{
|
|
3308
|
+
title: "Create Vibe",
|
|
3309
|
+
description: "Create a new vibe (project/workspace).",
|
|
3310
|
+
inputSchema: {
|
|
3311
|
+
name: z.string().describe("Vibe name"),
|
|
3312
|
+
description: z.string().optional().describe("Vibe description"),
|
|
3313
|
+
path: z.string().optional().describe("Local filesystem path"),
|
|
3314
|
+
type: VibeTypeEnum.optional().describe("Vibe type (default: PROJECT)"),
|
|
3315
|
+
status: VibeStatusEnum.optional().describe("Initial status"),
|
|
3316
|
+
agentId: z.string().optional().describe("Agent ID to associate with"),
|
|
3317
|
+
parentId: z.string().optional().describe("Parent vibe ID"),
|
|
3318
|
+
gitBranch: z.string().optional().describe("Git branch"),
|
|
3319
|
+
gitRemote: z.string().optional().describe("Git remote URL"),
|
|
3320
|
+
tags: z.array(z.string()).optional().describe("Tags")
|
|
3321
|
+
}
|
|
3322
|
+
},
|
|
3323
|
+
async ({
|
|
3324
|
+
name,
|
|
3325
|
+
description,
|
|
3326
|
+
path,
|
|
3327
|
+
type,
|
|
3328
|
+
status,
|
|
3329
|
+
agentId,
|
|
3330
|
+
parentId,
|
|
3331
|
+
gitBranch,
|
|
3332
|
+
gitRemote,
|
|
3333
|
+
tags
|
|
3334
|
+
}) => {
|
|
3335
|
+
try {
|
|
3336
|
+
const input = { name };
|
|
3337
|
+
if (description !== void 0) input.description = description;
|
|
3338
|
+
if (path !== void 0) input.path = path;
|
|
3339
|
+
if (type !== void 0) input.type = type;
|
|
3340
|
+
if (status !== void 0) input.status = status;
|
|
3341
|
+
if (agentId !== void 0) input.agentId = agentId;
|
|
3342
|
+
if (parentId !== void 0) input.parentId = parentId;
|
|
3343
|
+
if (gitBranch !== void 0) input.gitBranch = gitBranch;
|
|
3344
|
+
if (gitRemote !== void 0) input.gitRemote = gitRemote;
|
|
3345
|
+
if (tags !== void 0) input.tags = tags;
|
|
3346
|
+
const data = await ctx.gql.workspace.request(CREATE_VIBE, {
|
|
3347
|
+
input
|
|
3348
|
+
});
|
|
3349
|
+
return jsonResult(data.createVibe);
|
|
3350
|
+
} catch (error) {
|
|
3351
|
+
ctx.logger.error("vibecontrols_vibes_create failed", { error });
|
|
3352
|
+
return errorResult(
|
|
3353
|
+
`Failed to create vibe: ${error instanceof Error ? error.message : String(error)}`
|
|
3354
|
+
);
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
);
|
|
3358
|
+
server.registerTool(
|
|
3359
|
+
track(mcpToolName(ctx.productName, "vibes_update")),
|
|
3360
|
+
{
|
|
3361
|
+
title: "Update Vibe",
|
|
3362
|
+
description: "Update an existing vibe.",
|
|
3363
|
+
inputSchema: {
|
|
3364
|
+
id: z.string().describe("Vibe ID"),
|
|
3365
|
+
name: z.string().optional().describe("Updated name"),
|
|
3366
|
+
description: z.string().optional().describe("Updated description"),
|
|
3367
|
+
path: z.string().optional().describe("Updated path"),
|
|
3368
|
+
type: VibeTypeEnum.optional().describe("Updated type"),
|
|
3369
|
+
status: VibeStatusEnum.optional().describe("Updated status"),
|
|
3370
|
+
agentId: z.string().optional().describe("Updated agent ID"),
|
|
3371
|
+
parentId: z.string().optional().describe("Updated parent vibe ID"),
|
|
3372
|
+
gitBranch: z.string().optional().describe("Updated git branch"),
|
|
3373
|
+
gitRemote: z.string().optional().describe("Updated git remote"),
|
|
3374
|
+
tags: z.array(z.string()).optional().describe("Updated tags")
|
|
3375
|
+
}
|
|
3376
|
+
},
|
|
3377
|
+
async ({
|
|
3378
|
+
id,
|
|
3379
|
+
name,
|
|
3380
|
+
description,
|
|
3381
|
+
path,
|
|
3382
|
+
type,
|
|
3383
|
+
status,
|
|
3384
|
+
agentId,
|
|
3385
|
+
parentId,
|
|
3386
|
+
gitBranch,
|
|
3387
|
+
gitRemote,
|
|
3388
|
+
tags
|
|
3389
|
+
}) => {
|
|
3390
|
+
try {
|
|
3391
|
+
const input = {};
|
|
3392
|
+
if (name !== void 0) input.name = name;
|
|
3393
|
+
if (description !== void 0) input.description = description;
|
|
3394
|
+
if (path !== void 0) input.path = path;
|
|
3395
|
+
if (type !== void 0) input.type = type;
|
|
3396
|
+
if (status !== void 0) input.status = status;
|
|
3397
|
+
if (agentId !== void 0) input.agentId = agentId;
|
|
3398
|
+
if (parentId !== void 0) input.parentId = parentId;
|
|
3399
|
+
if (gitBranch !== void 0) input.gitBranch = gitBranch;
|
|
3400
|
+
if (gitRemote !== void 0) input.gitRemote = gitRemote;
|
|
3401
|
+
if (tags !== void 0) input.tags = tags;
|
|
3402
|
+
const data = await ctx.gql.workspace.request(UPDATE_VIBE, {
|
|
3403
|
+
id,
|
|
3404
|
+
input
|
|
3405
|
+
});
|
|
3406
|
+
return jsonResult(data.updateVibe);
|
|
3407
|
+
} catch (error) {
|
|
3408
|
+
ctx.logger.error("vibecontrols_vibes_update failed", { error });
|
|
3409
|
+
return errorResult(
|
|
3410
|
+
`Failed to update vibe: ${error instanceof Error ? error.message : String(error)}`
|
|
3411
|
+
);
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
);
|
|
3415
|
+
server.registerTool(
|
|
3416
|
+
track(mcpToolName(ctx.productName, "vibes_delete")),
|
|
3417
|
+
{
|
|
3418
|
+
title: "Delete Vibe",
|
|
3419
|
+
description: "Permanently delete a vibe.",
|
|
3420
|
+
inputSchema: { id: z.string().describe("Vibe ID to delete") }
|
|
3421
|
+
},
|
|
3422
|
+
async ({ id }) => {
|
|
3423
|
+
try {
|
|
3424
|
+
const data = await ctx.gql.workspace.request(DELETE_VIBE, { id });
|
|
3425
|
+
return jsonResult({ deleted: data.deleteVibe, vibeId: id });
|
|
3426
|
+
} catch (error) {
|
|
3427
|
+
ctx.logger.error("vibecontrols_vibes_delete failed", { error });
|
|
3428
|
+
return errorResult(
|
|
3429
|
+
`Failed to delete vibe: ${error instanceof Error ? error.message : String(error)}`
|
|
3430
|
+
);
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
);
|
|
3434
|
+
server.registerTool(
|
|
3435
|
+
track(mcpToolName(ctx.productName, "vibes_update_status")),
|
|
3436
|
+
{
|
|
3437
|
+
title: "Update Vibe Status",
|
|
3438
|
+
description: "Change the status of a vibe (ACTIVE, INACTIVE, ARCHIVED, ERROR).",
|
|
3439
|
+
inputSchema: {
|
|
3440
|
+
id: z.string().describe("Vibe ID"),
|
|
3441
|
+
status: VibeStatusEnum.describe("New status")
|
|
3442
|
+
}
|
|
3443
|
+
},
|
|
3444
|
+
async ({ id, status }) => {
|
|
3445
|
+
try {
|
|
3446
|
+
const data = await ctx.gql.workspace.request(
|
|
3447
|
+
UPDATE_VIBE_STATUS,
|
|
3448
|
+
{
|
|
3449
|
+
id,
|
|
3450
|
+
status
|
|
3451
|
+
}
|
|
3452
|
+
);
|
|
3453
|
+
return jsonResult(data.updateVibeStatus);
|
|
3454
|
+
} catch (error) {
|
|
3455
|
+
ctx.logger.error("vibecontrols_vibes_update_status failed", { error });
|
|
3456
|
+
return errorResult(
|
|
3457
|
+
`Failed to update vibe status: ${error instanceof Error ? error.message : String(error)}`
|
|
3458
|
+
);
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3461
|
+
);
|
|
3462
|
+
server.registerTool(
|
|
3463
|
+
track(mcpToolName(ctx.productName, "vibes_archive")),
|
|
3464
|
+
{
|
|
3465
|
+
title: "Archive Vibe",
|
|
3466
|
+
description: "Archive a vibe (soft-delete with archivedAt timestamp).",
|
|
3467
|
+
inputSchema: { id: z.string().describe("Vibe ID to archive") }
|
|
3468
|
+
},
|
|
3469
|
+
async ({ id }) => {
|
|
3470
|
+
try {
|
|
3471
|
+
const data = await ctx.gql.workspace.request(ARCHIVE_VIBE, {
|
|
3472
|
+
id
|
|
3473
|
+
});
|
|
3474
|
+
return jsonResult(data.archiveVibe);
|
|
3475
|
+
} catch (error) {
|
|
3476
|
+
ctx.logger.error("vibecontrols_vibes_archive failed", { error });
|
|
3477
|
+
return errorResult(
|
|
3478
|
+
`Failed to archive vibe: ${error instanceof Error ? error.message : String(error)}`
|
|
3479
|
+
);
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
);
|
|
3483
|
+
server.registerTool(
|
|
3484
|
+
track(mcpToolName(ctx.productName, "vibes_restore")),
|
|
3485
|
+
{
|
|
3486
|
+
title: "Restore Vibe",
|
|
3487
|
+
description: "Restore a previously archived vibe.",
|
|
3488
|
+
inputSchema: { id: z.string().describe("Vibe ID to restore") }
|
|
3489
|
+
},
|
|
3490
|
+
async ({ id }) => {
|
|
3491
|
+
try {
|
|
3492
|
+
const data = await ctx.gql.workspace.request(RESTORE_VIBE, {
|
|
3493
|
+
id
|
|
3494
|
+
});
|
|
3495
|
+
return jsonResult(data.restoreVibe);
|
|
3496
|
+
} catch (error) {
|
|
3497
|
+
ctx.logger.error("vibecontrols_vibes_restore failed", { error });
|
|
3498
|
+
return errorResult(
|
|
3499
|
+
`Failed to restore vibe: ${error instanceof Error ? error.message : String(error)}`
|
|
3500
|
+
);
|
|
3501
|
+
}
|
|
3502
|
+
}
|
|
3503
|
+
);
|
|
3504
|
+
server.registerTool(
|
|
3505
|
+
track(mcpToolName(ctx.productName, "vibes_hierarchy")),
|
|
3506
|
+
{
|
|
3507
|
+
title: "Vibe Hierarchy",
|
|
3508
|
+
description: "Get the vibe hierarchy tree starting from an optional root vibe.",
|
|
3509
|
+
inputSchema: {
|
|
3510
|
+
rootId: z.string().optional().describe("Root vibe ID (omit for all top-level vibes)")
|
|
3511
|
+
}
|
|
3512
|
+
},
|
|
3513
|
+
async ({ rootId }) => {
|
|
3514
|
+
try {
|
|
3515
|
+
const data = await ctx.gql.workspace.request(VIBE_HIERARCHY, {
|
|
3516
|
+
rootId
|
|
3517
|
+
});
|
|
3518
|
+
return jsonResult(data.vibeHierarchy);
|
|
3519
|
+
} catch (error) {
|
|
3520
|
+
ctx.logger.error("vibecontrols_vibes_hierarchy failed", { error });
|
|
3521
|
+
return errorResult(
|
|
3522
|
+
`Failed to get vibe hierarchy: ${error instanceof Error ? error.message : String(error)}`
|
|
3523
|
+
);
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
);
|
|
3527
|
+
server.registerTool(
|
|
3528
|
+
track(mcpToolName(ctx.productName, "vibes_search")),
|
|
3529
|
+
{
|
|
3530
|
+
title: "Search Vibes",
|
|
3531
|
+
description: "Full-text search across vibes by name, description, path, or tags.",
|
|
3532
|
+
inputSchema: {
|
|
3533
|
+
query: z.string().describe("Search query string"),
|
|
3534
|
+
limit: z.number().optional().describe("Maximum results to return")
|
|
3535
|
+
}
|
|
3536
|
+
},
|
|
3537
|
+
async ({ query, limit }) => {
|
|
3538
|
+
try {
|
|
3539
|
+
const data = await ctx.gql.workspace.request(SEARCH_VIBES, {
|
|
3540
|
+
query,
|
|
3541
|
+
limit
|
|
3542
|
+
});
|
|
3543
|
+
return jsonResult(data.searchVibes);
|
|
3544
|
+
} catch (error) {
|
|
3545
|
+
ctx.logger.error("vibecontrols_vibes_search failed", { error });
|
|
3546
|
+
return errorResult(
|
|
3547
|
+
`Failed to search vibes: ${error instanceof Error ? error.message : String(error)}`
|
|
3548
|
+
);
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
);
|
|
3552
|
+
}
|
|
3553
|
+
function registerWebhookTools(server, ctx, track) {
|
|
3554
|
+
server.registerTool(
|
|
3555
|
+
track(mcpToolName(ctx.productName, "webhooks_list")),
|
|
3556
|
+
{
|
|
3557
|
+
title: "List Webhooks",
|
|
3558
|
+
description: "List all webhooks with optional filters.",
|
|
3559
|
+
inputSchema: {
|
|
3560
|
+
name: z.string().optional().describe("Filter by webhook name"),
|
|
3561
|
+
event: z.string().optional().describe("Filter by event type"),
|
|
3562
|
+
isActive: z.boolean().optional().describe("Filter by active status"),
|
|
3563
|
+
limit: z.number().optional().describe("Max results"),
|
|
3564
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
3565
|
+
}
|
|
3566
|
+
},
|
|
3567
|
+
async ({ name, event, isActive, limit, offset }) => {
|
|
3568
|
+
try {
|
|
3569
|
+
const filter = {};
|
|
3570
|
+
if (name !== void 0) filter.name = name;
|
|
3571
|
+
if (event !== void 0) filter.event = event;
|
|
3572
|
+
if (isActive !== void 0) filter.isActive = isActive;
|
|
3573
|
+
const pagination = {};
|
|
3574
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
3575
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
3576
|
+
const data = await ctx.gql.workspace.request(LIST_WEBHOOKS, {
|
|
3577
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
3578
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
3579
|
+
});
|
|
3580
|
+
return jsonResult(data.webhooks);
|
|
3581
|
+
} catch (error) {
|
|
3582
|
+
ctx.logger.error("vibecontrols_webhooks_list failed", { error });
|
|
3583
|
+
return errorResult(
|
|
3584
|
+
`Failed to list webhooks: ${error instanceof Error ? error.message : String(error)}`
|
|
3585
|
+
);
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
);
|
|
3589
|
+
server.registerTool(
|
|
3590
|
+
track(mcpToolName(ctx.productName, "webhooks_get")),
|
|
3591
|
+
{
|
|
3592
|
+
title: "Get Webhook",
|
|
3593
|
+
description: "Get a webhook by its ID.",
|
|
3594
|
+
inputSchema: { id: z.string().describe("Webhook ID") }
|
|
3595
|
+
},
|
|
3596
|
+
async ({ id }) => {
|
|
3597
|
+
try {
|
|
3598
|
+
const data = await ctx.gql.workspace.request(GET_WEBHOOK, { id });
|
|
3599
|
+
return jsonResult(data.webhook);
|
|
3600
|
+
} catch (error) {
|
|
3601
|
+
ctx.logger.error("vibecontrols_webhooks_get failed", { error });
|
|
3602
|
+
return errorResult(
|
|
3603
|
+
`Failed to get webhook: ${error instanceof Error ? error.message : String(error)}`
|
|
3604
|
+
);
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
);
|
|
3608
|
+
server.registerTool(
|
|
3609
|
+
track(mcpToolName(ctx.productName, "webhooks_create")),
|
|
3610
|
+
{
|
|
3611
|
+
title: "Create Webhook",
|
|
3612
|
+
description: "Create a new webhook.",
|
|
3613
|
+
inputSchema: {
|
|
3614
|
+
name: z.string().describe("Webhook name"),
|
|
3615
|
+
url: z.string().describe("Webhook endpoint URL"),
|
|
3616
|
+
events: z.array(z.string()).describe("Events to subscribe to"),
|
|
3617
|
+
agentIds: z.array(z.string()).optional().describe("Agent IDs to scope to"),
|
|
3618
|
+
isActive: z.boolean().optional().describe("Active status (default: true)"),
|
|
3619
|
+
signingKey: z.string().optional().describe("Signing key for payload verification")
|
|
3620
|
+
}
|
|
3621
|
+
},
|
|
3622
|
+
async ({ name, url, events, agentIds, isActive, signingKey }) => {
|
|
3623
|
+
try {
|
|
3624
|
+
const input = { name, url, events };
|
|
3625
|
+
if (agentIds !== void 0) input.agentIds = agentIds;
|
|
3626
|
+
if (isActive !== void 0) input.isActive = isActive;
|
|
3627
|
+
if (signingKey !== void 0) input.signingKey = signingKey;
|
|
3628
|
+
const data = await ctx.gql.workspace.request(CREATE_WEBHOOK, {
|
|
3629
|
+
input
|
|
3630
|
+
});
|
|
3631
|
+
return jsonResult(data.createWebhook);
|
|
3632
|
+
} catch (error) {
|
|
3633
|
+
ctx.logger.error("vibecontrols_webhooks_create failed", { error });
|
|
3634
|
+
return errorResult(
|
|
3635
|
+
`Failed to create webhook: ${error instanceof Error ? error.message : String(error)}`
|
|
3636
|
+
);
|
|
3637
|
+
}
|
|
3638
|
+
}
|
|
3639
|
+
);
|
|
3640
|
+
server.registerTool(
|
|
3641
|
+
track(mcpToolName(ctx.productName, "webhooks_update")),
|
|
3642
|
+
{
|
|
3643
|
+
title: "Update Webhook",
|
|
3644
|
+
description: "Update an existing webhook.",
|
|
3645
|
+
inputSchema: {
|
|
3646
|
+
id: z.string().describe("Webhook ID"),
|
|
3647
|
+
name: z.string().optional().describe("Updated name"),
|
|
3648
|
+
url: z.string().optional().describe("Updated endpoint URL"),
|
|
3649
|
+
events: z.array(z.string()).optional().describe("Updated events"),
|
|
3650
|
+
agentIds: z.array(z.string()).optional().describe("Updated agent IDs"),
|
|
3651
|
+
isActive: z.boolean().optional().describe("Updated active status"),
|
|
3652
|
+
signingKey: z.string().optional().describe("Updated signing key")
|
|
3653
|
+
}
|
|
3654
|
+
},
|
|
3655
|
+
async ({ id, name, url, events, agentIds, isActive, signingKey }) => {
|
|
3656
|
+
try {
|
|
3657
|
+
const input = {};
|
|
3658
|
+
if (name !== void 0) input.name = name;
|
|
3659
|
+
if (url !== void 0) input.url = url;
|
|
3660
|
+
if (events !== void 0) input.events = events;
|
|
3661
|
+
if (agentIds !== void 0) input.agentIds = agentIds;
|
|
3662
|
+
if (isActive !== void 0) input.isActive = isActive;
|
|
3663
|
+
if (signingKey !== void 0) input.signingKey = signingKey;
|
|
3664
|
+
const data = await ctx.gql.workspace.request(UPDATE_WEBHOOK, {
|
|
3665
|
+
id,
|
|
3666
|
+
input
|
|
3667
|
+
});
|
|
3668
|
+
return jsonResult(data.updateWebhook);
|
|
3669
|
+
} catch (error) {
|
|
3670
|
+
ctx.logger.error("vibecontrols_webhooks_update failed", { error });
|
|
3671
|
+
return errorResult(
|
|
3672
|
+
`Failed to update webhook: ${error instanceof Error ? error.message : String(error)}`
|
|
3673
|
+
);
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
);
|
|
3677
|
+
server.registerTool(
|
|
3678
|
+
track(mcpToolName(ctx.productName, "webhooks_delete")),
|
|
3679
|
+
{
|
|
3680
|
+
title: "Delete Webhook",
|
|
3681
|
+
description: "Delete a webhook.",
|
|
3682
|
+
inputSchema: { id: z.string().describe("Webhook ID to delete") }
|
|
3683
|
+
},
|
|
3684
|
+
async ({ id }) => {
|
|
3685
|
+
try {
|
|
3686
|
+
const data = await ctx.gql.workspace.request(DELETE_WEBHOOK, {
|
|
3687
|
+
id
|
|
3688
|
+
});
|
|
3689
|
+
return jsonResult({ deleted: data.deleteWebhook, webhookId: id });
|
|
3690
|
+
} catch (error) {
|
|
3691
|
+
ctx.logger.error("vibecontrols_webhooks_delete failed", { error });
|
|
3692
|
+
return errorResult(
|
|
3693
|
+
`Failed to delete webhook: ${error instanceof Error ? error.message : String(error)}`
|
|
3694
|
+
);
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
);
|
|
3698
|
+
server.registerTool(
|
|
3699
|
+
track(mcpToolName(ctx.productName, "webhooks_test")),
|
|
3700
|
+
{
|
|
3701
|
+
title: "Test Webhook",
|
|
3702
|
+
description: "Send a test delivery to a webhook to verify its endpoint.",
|
|
3703
|
+
inputSchema: { id: z.string().describe("Webhook ID to test") }
|
|
3704
|
+
},
|
|
3705
|
+
async ({ id }) => {
|
|
3706
|
+
try {
|
|
3707
|
+
const data = await ctx.gql.workspace.request(TEST_WEBHOOK, {
|
|
3708
|
+
id
|
|
3709
|
+
});
|
|
3710
|
+
return jsonResult(data.testWebhook);
|
|
3711
|
+
} catch (error) {
|
|
3712
|
+
ctx.logger.error("vibecontrols_webhooks_test failed", { error });
|
|
3713
|
+
return errorResult(
|
|
3714
|
+
`Failed to test webhook: ${error instanceof Error ? error.message : String(error)}`
|
|
3715
|
+
);
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
);
|
|
3719
|
+
server.registerTool(
|
|
3720
|
+
track(mcpToolName(ctx.productName, "webhooks_trigger")),
|
|
3721
|
+
{
|
|
3722
|
+
title: "Trigger Webhook",
|
|
3723
|
+
description: "Trigger a webhook with a custom JSON payload.",
|
|
3724
|
+
inputSchema: {
|
|
3725
|
+
id: z.string().describe("Webhook ID to trigger"),
|
|
3726
|
+
payload: z.string().describe("JSON payload to deliver")
|
|
3727
|
+
}
|
|
3728
|
+
},
|
|
3729
|
+
async ({ id, payload }) => {
|
|
3730
|
+
try {
|
|
3731
|
+
const parsedPayload = JSON.parse(payload);
|
|
3732
|
+
const data = await ctx.gql.workspace.request(TRIGGER_WEBHOOK, {
|
|
3733
|
+
id,
|
|
3734
|
+
payload: parsedPayload
|
|
3735
|
+
});
|
|
3736
|
+
return jsonResult(data.triggerWebhook);
|
|
3737
|
+
} catch (error) {
|
|
3738
|
+
ctx.logger.error("vibecontrols_webhooks_trigger failed", { error });
|
|
3739
|
+
return errorResult(
|
|
3740
|
+
`Failed to trigger webhook: ${error instanceof Error ? error.message : String(error)}`
|
|
3741
|
+
);
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3744
|
+
);
|
|
3745
|
+
}
|
|
3746
|
+
|
|
3747
|
+
// src/modules/vibecontrols/resources.ts
|
|
3748
|
+
var RESOURCE_URIS = [
|
|
3749
|
+
"vibecontrols://schema",
|
|
3750
|
+
"vibecontrols://config",
|
|
3751
|
+
"vibecontrols://topology",
|
|
3752
|
+
"vibecontrols://sessions/active",
|
|
3753
|
+
"vibecontrols://notes/pinned",
|
|
3754
|
+
"vibecontrols://audit/recent",
|
|
3755
|
+
"vibecontrols://plugins"
|
|
3756
|
+
];
|
|
3757
|
+
function registerVibecontrolsResources(server, ctx, track) {
|
|
3758
|
+
RESOURCE_URIS.forEach(track);
|
|
3759
|
+
server.registerResource(
|
|
3760
|
+
"vibecontrols-schema",
|
|
3761
|
+
"vibecontrols://schema",
|
|
3762
|
+
{
|
|
3763
|
+
title: "VibeControls GraphQL Schema",
|
|
3764
|
+
description: "Overview of the VibeControls GraphQL API schema \u2014 types, queries, mutations, and enums.",
|
|
3765
|
+
mimeType: "text/plain"
|
|
3766
|
+
},
|
|
3767
|
+
async () => {
|
|
3768
|
+
ctx.logger.debug("Resource vibecontrols://schema requested");
|
|
3769
|
+
const schema = `# VibeControls GraphQL Schema (Overview)
|
|
3770
|
+
|
|
3771
|
+
## Entity Types
|
|
3772
|
+
- VibecontrolsAgent \u2014 Development environment agent
|
|
3773
|
+
- Vibe \u2014 Project/workspace/repository
|
|
3774
|
+
- Session \u2014 Terminal session (tmux, SSH, terminal, script)
|
|
3775
|
+
- VibecontrolsNote \u2014 Notes attached to vibes
|
|
3776
|
+
- Configuration \u2014 Key-value settings (scoped)
|
|
3777
|
+
- UISession \u2014 UI state persistence
|
|
3778
|
+
- Webhook \u2014 Event-driven HTTP callbacks
|
|
3779
|
+
- AiToolEvent \u2014 AI tool usage tracking
|
|
3780
|
+
- AgentTunnel \u2014 Remote access tunnels
|
|
3781
|
+
- AgentPlugin \u2014 Plugins on agents
|
|
3782
|
+
- Target \u2014 Connection targets (SSH, RDP, VNC, DIRECT)
|
|
3783
|
+
- VibeDeck \u2014 Command button grids
|
|
3784
|
+
- VibeDeckButton \u2014 Individual buttons in decks
|
|
3785
|
+
- DocsSite \u2014 Documentation sites
|
|
3786
|
+
- DocsPage \u2014 Individual documentation pages
|
|
3787
|
+
- DocsRevision \u2014 Build revisions for docs
|
|
3788
|
+
- AuditLog \u2014 Audit trail entries
|
|
3789
|
+
- SessionShare \u2014 Direct user shares
|
|
3790
|
+
- SessionShareLink \u2014 Link-based shares
|
|
3791
|
+
|
|
3792
|
+
## Enums
|
|
3793
|
+
- VibeType: PROJECT, WORKSPACE, REPOSITORY, MONOREPO, PACKAGE, CUSTOM
|
|
3794
|
+
- VibeStatus: ACTIVE, INACTIVE, ARCHIVED, ERROR
|
|
3795
|
+
- SessionType: TMUX, SSH, TERMINAL, SCRIPT, CUSTOM
|
|
3796
|
+
- SessionStatus: PENDING, STARTING, RUNNING, STOPPED, ERROR, TERMINATED
|
|
3797
|
+
- ConfigScope: WORKSPACE, VIBE, SESSION, AGENT, USER, GLOBAL
|
|
3798
|
+
- TargetType: DIRECT, SSH, RDP, VNC
|
|
3799
|
+
- DocsVisibility: PRIVATE, PUBLIC
|
|
3800
|
+
`;
|
|
3801
|
+
return {
|
|
3802
|
+
contents: [
|
|
3803
|
+
{
|
|
3804
|
+
uri: "vibecontrols://schema",
|
|
3805
|
+
text: schema,
|
|
3806
|
+
mimeType: "text/plain"
|
|
3807
|
+
}
|
|
3808
|
+
]
|
|
3809
|
+
};
|
|
3810
|
+
}
|
|
3811
|
+
);
|
|
3812
|
+
server.registerResource(
|
|
3813
|
+
"vibecontrols-config",
|
|
3814
|
+
"vibecontrols://config",
|
|
3815
|
+
{
|
|
3816
|
+
title: "VibeControls MCP Configuration",
|
|
3817
|
+
description: "Current server configuration \u2014 endpoints, auth status, and transport settings.",
|
|
3818
|
+
mimeType: "application/json"
|
|
3819
|
+
},
|
|
3820
|
+
async () => {
|
|
3821
|
+
ctx.logger.debug("Resource vibecontrols://config requested");
|
|
3822
|
+
const auth = getAuth(ctx);
|
|
3823
|
+
const authStatus = await auth.getStatus();
|
|
3824
|
+
const configData = {
|
|
3825
|
+
server: {
|
|
3826
|
+
name: ctx.serverName,
|
|
3827
|
+
version: ctx.serverVersion,
|
|
3828
|
+
transport: "unknown"
|
|
3829
|
+
},
|
|
3830
|
+
endpoints: {
|
|
3831
|
+
workspace: ctx.config.read().workspaceEndpoint,
|
|
3832
|
+
global: ctx.config.read().globalEndpoint
|
|
3833
|
+
},
|
|
3834
|
+
auth: authStatus,
|
|
3835
|
+
environment: ctx.env
|
|
3836
|
+
};
|
|
3837
|
+
return {
|
|
3838
|
+
contents: [
|
|
3839
|
+
{
|
|
3840
|
+
uri: "vibecontrols://config",
|
|
3841
|
+
text: JSON.stringify(configData, null, 2),
|
|
3842
|
+
mimeType: "application/json"
|
|
3843
|
+
}
|
|
3844
|
+
]
|
|
3845
|
+
};
|
|
3846
|
+
}
|
|
3847
|
+
);
|
|
3848
|
+
server.registerResource(
|
|
3849
|
+
"vibecontrols-topology",
|
|
3850
|
+
"vibecontrols://topology",
|
|
3851
|
+
{
|
|
3852
|
+
title: "Workspace Topology",
|
|
3853
|
+
description: "Overview of agents, active sessions, and tunnels in the workspace.",
|
|
3854
|
+
mimeType: "application/json"
|
|
3855
|
+
},
|
|
3856
|
+
async () => {
|
|
3857
|
+
ctx.logger.debug("Resource vibecontrols://topology requested");
|
|
3858
|
+
try {
|
|
3859
|
+
const [agents, sessions, tunnels] = await Promise.all([
|
|
3860
|
+
ctx.gql.workspace.request(LIST_AGENTS, {}),
|
|
3861
|
+
ctx.gql.workspace.request(ACTIVE_SESSIONS, {}),
|
|
3862
|
+
ctx.gql.workspace.request(LIST_TUNNELS)
|
|
3863
|
+
]);
|
|
3864
|
+
const topology = {
|
|
3865
|
+
agents: agents.vibecontrolsAgents,
|
|
3866
|
+
activeSessions: sessions.activeSessions,
|
|
3867
|
+
tunnels: tunnels.vibecontrolsAgentTunnels
|
|
3868
|
+
};
|
|
3869
|
+
return {
|
|
3870
|
+
contents: [
|
|
3871
|
+
{
|
|
3872
|
+
uri: "vibecontrols://topology",
|
|
3873
|
+
text: JSON.stringify(topology, null, 2),
|
|
3874
|
+
mimeType: "application/json"
|
|
3875
|
+
}
|
|
3876
|
+
]
|
|
3877
|
+
};
|
|
3878
|
+
} catch (error) {
|
|
3879
|
+
return {
|
|
3880
|
+
contents: [
|
|
3881
|
+
{
|
|
3882
|
+
uri: "vibecontrols://topology",
|
|
3883
|
+
text: JSON.stringify({
|
|
3884
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3885
|
+
}),
|
|
3886
|
+
mimeType: "application/json"
|
|
3887
|
+
}
|
|
3888
|
+
]
|
|
3889
|
+
};
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
);
|
|
3893
|
+
server.registerResource(
|
|
3894
|
+
"vibecontrols-active-sessions",
|
|
3895
|
+
"vibecontrols://sessions/active",
|
|
3896
|
+
{
|
|
3897
|
+
title: "Active Sessions",
|
|
3898
|
+
description: "All currently running terminal sessions.",
|
|
3899
|
+
mimeType: "application/json"
|
|
3900
|
+
},
|
|
3901
|
+
async () => {
|
|
3902
|
+
ctx.logger.debug("Resource vibecontrols://sessions/active requested");
|
|
3903
|
+
try {
|
|
3904
|
+
const data = await ctx.gql.workspace.request(
|
|
3905
|
+
ACTIVE_SESSIONS,
|
|
3906
|
+
{}
|
|
3907
|
+
);
|
|
3908
|
+
return {
|
|
3909
|
+
contents: [
|
|
3910
|
+
{
|
|
3911
|
+
uri: "vibecontrols://sessions/active",
|
|
3912
|
+
text: JSON.stringify(data.activeSessions, null, 2),
|
|
3913
|
+
mimeType: "application/json"
|
|
3914
|
+
}
|
|
3915
|
+
]
|
|
3916
|
+
};
|
|
3917
|
+
} catch (error) {
|
|
3918
|
+
return {
|
|
3919
|
+
contents: [
|
|
3920
|
+
{
|
|
3921
|
+
uri: "vibecontrols://sessions/active",
|
|
3922
|
+
text: JSON.stringify({
|
|
3923
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3924
|
+
}),
|
|
3925
|
+
mimeType: "application/json"
|
|
3926
|
+
}
|
|
3927
|
+
]
|
|
3928
|
+
};
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
);
|
|
3932
|
+
server.registerResource(
|
|
3933
|
+
"vibecontrols-pinned-notes",
|
|
3934
|
+
"vibecontrols://notes/pinned",
|
|
3935
|
+
{
|
|
3936
|
+
title: "Pinned Notes",
|
|
3937
|
+
description: "All pinned notes across the workspace.",
|
|
3938
|
+
mimeType: "application/json"
|
|
3939
|
+
},
|
|
3940
|
+
async () => {
|
|
3941
|
+
ctx.logger.debug("Resource vibecontrols://notes/pinned requested");
|
|
3942
|
+
try {
|
|
3943
|
+
const data = await ctx.gql.workspace.request(PINNED_NOTES, {});
|
|
3944
|
+
return {
|
|
3945
|
+
contents: [
|
|
3946
|
+
{
|
|
3947
|
+
uri: "vibecontrols://notes/pinned",
|
|
3948
|
+
text: JSON.stringify(data.pinnedNotes, null, 2),
|
|
3949
|
+
mimeType: "application/json"
|
|
3950
|
+
}
|
|
3951
|
+
]
|
|
3952
|
+
};
|
|
3953
|
+
} catch (error) {
|
|
3954
|
+
return {
|
|
3955
|
+
contents: [
|
|
3956
|
+
{
|
|
3957
|
+
uri: "vibecontrols://notes/pinned",
|
|
3958
|
+
text: JSON.stringify({
|
|
3959
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3960
|
+
}),
|
|
3961
|
+
mimeType: "application/json"
|
|
3962
|
+
}
|
|
3963
|
+
]
|
|
3964
|
+
};
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3967
|
+
);
|
|
3968
|
+
server.registerResource(
|
|
3969
|
+
"vibecontrols-recent-audit",
|
|
3970
|
+
"vibecontrols://audit/recent",
|
|
3971
|
+
{
|
|
3972
|
+
title: "Recent Audit Logs",
|
|
3973
|
+
description: "The 20 most recent audit log entries.",
|
|
3974
|
+
mimeType: "application/json"
|
|
3975
|
+
},
|
|
3976
|
+
async () => {
|
|
3977
|
+
ctx.logger.debug("Resource vibecontrols://audit/recent requested");
|
|
3978
|
+
try {
|
|
3979
|
+
const data = await ctx.gql.workspace.request(LIST_AUDIT_LOGS, {
|
|
3980
|
+
filter: {},
|
|
3981
|
+
pagination: { limit: 20, offset: 0 }
|
|
3982
|
+
});
|
|
3983
|
+
return {
|
|
3984
|
+
contents: [
|
|
3985
|
+
{
|
|
3986
|
+
uri: "vibecontrols://audit/recent",
|
|
3987
|
+
text: JSON.stringify(data.vibeAuditLogs, null, 2),
|
|
3988
|
+
mimeType: "application/json"
|
|
3989
|
+
}
|
|
3990
|
+
]
|
|
3991
|
+
};
|
|
3992
|
+
} catch (error) {
|
|
3993
|
+
return {
|
|
3994
|
+
contents: [
|
|
3995
|
+
{
|
|
3996
|
+
uri: "vibecontrols://audit/recent",
|
|
3997
|
+
text: JSON.stringify({
|
|
3998
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3999
|
+
}),
|
|
4000
|
+
mimeType: "application/json"
|
|
4001
|
+
}
|
|
4002
|
+
]
|
|
4003
|
+
};
|
|
4004
|
+
}
|
|
4005
|
+
}
|
|
4006
|
+
);
|
|
4007
|
+
server.registerResource(
|
|
4008
|
+
"vibecontrols-plugins",
|
|
4009
|
+
"vibecontrols://plugins",
|
|
4010
|
+
{
|
|
4011
|
+
title: "Installed Plugins",
|
|
4012
|
+
description: "Plugins installed across all agents in the workspace.",
|
|
4013
|
+
mimeType: "application/json"
|
|
4014
|
+
},
|
|
4015
|
+
async () => {
|
|
4016
|
+
ctx.logger.debug("Resource vibecontrols://plugins requested");
|
|
4017
|
+
try {
|
|
4018
|
+
const agentData = await ctx.gql.workspace.request(LIST_AGENTS, {});
|
|
4019
|
+
const agents = agentData.vibecontrolsAgents?.items ?? [];
|
|
4020
|
+
const pluginResults = await Promise.all(
|
|
4021
|
+
agents.map(async (agent) => {
|
|
4022
|
+
try {
|
|
4023
|
+
const data = await ctx.gql.workspace.request(
|
|
4024
|
+
AGENT_PLUGINS,
|
|
4025
|
+
{
|
|
4026
|
+
agentId: agent.id
|
|
4027
|
+
}
|
|
4028
|
+
);
|
|
4029
|
+
return { agentId: agent.id, agentName: agent.name, ...data.agentPlugins };
|
|
4030
|
+
} catch {
|
|
4031
|
+
return { agentId: agent.id, agentName: agent.name, error: "Failed to fetch plugins" };
|
|
4032
|
+
}
|
|
4033
|
+
})
|
|
4034
|
+
);
|
|
4035
|
+
return {
|
|
4036
|
+
contents: [
|
|
4037
|
+
{
|
|
4038
|
+
uri: "vibecontrols://plugins",
|
|
4039
|
+
text: JSON.stringify(pluginResults, null, 2),
|
|
4040
|
+
mimeType: "application/json"
|
|
4041
|
+
}
|
|
4042
|
+
]
|
|
4043
|
+
};
|
|
4044
|
+
} catch (error) {
|
|
4045
|
+
return {
|
|
4046
|
+
contents: [
|
|
4047
|
+
{
|
|
4048
|
+
uri: "vibecontrols://plugins",
|
|
4049
|
+
text: JSON.stringify({
|
|
4050
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4051
|
+
}),
|
|
4052
|
+
mimeType: "application/json"
|
|
4053
|
+
}
|
|
4054
|
+
]
|
|
4055
|
+
};
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
4058
|
+
);
|
|
4059
|
+
}
|
|
4060
|
+
var PROMPT_NAMES = [
|
|
4061
|
+
"vibecontrols-setup",
|
|
4062
|
+
"vibecontrols-session-workflow",
|
|
4063
|
+
"vibecontrols-onboarding",
|
|
4064
|
+
"vibecontrols-incident-response",
|
|
4065
|
+
"vibecontrols-deploy",
|
|
4066
|
+
"vibecontrols-daily-standup",
|
|
4067
|
+
"vibecontrols-runbook"
|
|
4068
|
+
];
|
|
4069
|
+
function registerVibecontrolsPrompts(server, ctx, track) {
|
|
4070
|
+
PROMPT_NAMES.forEach(track);
|
|
4071
|
+
server.registerPrompt(
|
|
4072
|
+
"vibecontrols-setup",
|
|
4073
|
+
{
|
|
4074
|
+
title: "VibeControls Workspace Setup",
|
|
4075
|
+
description: "Step-by-step guide for setting up a VibeControls workspace with agents, vibes, and sessions.",
|
|
4076
|
+
argsSchema: {
|
|
4077
|
+
projectPath: z.string().optional().describe("Local project path to set up"),
|
|
4078
|
+
agentName: z.string().optional().describe("Name for the agent")
|
|
4079
|
+
}
|
|
4080
|
+
},
|
|
4081
|
+
({ projectPath, agentName }) => {
|
|
4082
|
+
ctx.logger.debug("Prompt vibecontrols-setup called", { projectPath, agentName });
|
|
4083
|
+
const agentNote = agentName ? `Use the agent name "${agentName}".` : "Choose a descriptive agent name based on the machine hostname.";
|
|
4084
|
+
const pathNote = projectPath ? `Set up the vibe for the project at "${projectPath}".` : "Ask the user for the project path.";
|
|
4085
|
+
return {
|
|
4086
|
+
messages: [
|
|
4087
|
+
{
|
|
4088
|
+
role: "user",
|
|
4089
|
+
content: {
|
|
4090
|
+
type: "text",
|
|
4091
|
+
text: `Help me set up a VibeControls workspace. Follow these steps:
|
|
4092
|
+
|
|
4093
|
+
1. **Check Auth**: Use vibecontrols_auth_status. If not authenticated, use vibecontrols_auth_login.
|
|
4094
|
+
2. **Create/Find Agent**: Use vibecontrols_agents_list. If none, use vibecontrols_agents_create. ${agentNote}
|
|
4095
|
+
3. **Create Vibe**: Use vibecontrols_vibes_create. ${pathNote} Set type=PROJECT.
|
|
4096
|
+
4. **Create Session**: Use vibecontrols_sessions_create linked to the vibe and agent.
|
|
4097
|
+
5. **Start Session**: Use vibecontrols_sessions_start.
|
|
4098
|
+
6. **Verify**: Use vibecontrols_sessions_active to confirm.
|
|
4099
|
+
|
|
4100
|
+
Show results at each step.`
|
|
4101
|
+
}
|
|
4102
|
+
}
|
|
4103
|
+
]
|
|
4104
|
+
};
|
|
4105
|
+
}
|
|
4106
|
+
);
|
|
4107
|
+
server.registerPrompt(
|
|
4108
|
+
"vibecontrols-session-workflow",
|
|
4109
|
+
{
|
|
4110
|
+
title: "VibeControls Session Workflow",
|
|
4111
|
+
description: "Guide for creating, managing, and monitoring terminal sessions.",
|
|
4112
|
+
argsSchema: {
|
|
4113
|
+
vibeId: z.string().optional().describe("Vibe ID to create sessions in"),
|
|
4114
|
+
command: z.string().optional().describe("Command to run")
|
|
4115
|
+
}
|
|
4116
|
+
},
|
|
4117
|
+
({ vibeId, command }) => {
|
|
4118
|
+
ctx.logger.debug("Prompt vibecontrols-session-workflow called", { vibeId, command });
|
|
4119
|
+
const vibeNote = vibeId ? `Use vibe ID "${vibeId}".` : "First list vibes with vibecontrols_vibes_list and let the user pick one.";
|
|
4120
|
+
const commandNote = command ? `Run: "${command}"` : "Ask the user what command to run.";
|
|
4121
|
+
return {
|
|
4122
|
+
messages: [
|
|
4123
|
+
{
|
|
4124
|
+
role: "user",
|
|
4125
|
+
content: {
|
|
4126
|
+
type: "text",
|
|
4127
|
+
text: `Help me manage terminal sessions. Workflow:
|
|
4128
|
+
|
|
4129
|
+
1. **Select Vibe**: ${vibeNote}
|
|
4130
|
+
2. **Check Active**: Use vibecontrols_sessions_active.
|
|
4131
|
+
3. **Create Session**: vibecontrols_sessions_create with name, ${commandNote}, vibe + agent IDs.
|
|
4132
|
+
4. **Start**: vibecontrols_sessions_start.
|
|
4133
|
+
5. **Monitor**: vibecontrols_sessions_output.
|
|
4134
|
+
6. **Send Input** (if needed): vibecontrols_sessions_send_input.
|
|
4135
|
+
7. **Web Terminal** (optional): vibecontrols_sessions_start_terminal.
|
|
4136
|
+
8. **Stop/Restart**: vibecontrols_sessions_stop or vibecontrols_sessions_restart.
|
|
4137
|
+
|
|
4138
|
+
Show results at each step.`
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
]
|
|
4142
|
+
};
|
|
4143
|
+
}
|
|
4144
|
+
);
|
|
4145
|
+
server.registerPrompt(
|
|
4146
|
+
"vibecontrols-onboarding",
|
|
4147
|
+
{
|
|
4148
|
+
title: "VibeControls Onboarding",
|
|
4149
|
+
description: "Complete onboarding guide: auth, workspace, agent, vibe, session, deck, and docs setup.",
|
|
4150
|
+
argsSchema: {
|
|
4151
|
+
projectPath: z.string().optional().describe("Project path")
|
|
4152
|
+
}
|
|
4153
|
+
},
|
|
4154
|
+
({ projectPath }) => {
|
|
4155
|
+
ctx.logger.debug("Prompt vibecontrols-onboarding called", { projectPath });
|
|
4156
|
+
const pathNote = projectPath ? `for "${projectPath}"` : "(ask for path)";
|
|
4157
|
+
return {
|
|
4158
|
+
messages: [
|
|
4159
|
+
{
|
|
4160
|
+
role: "user",
|
|
4161
|
+
content: {
|
|
4162
|
+
type: "text",
|
|
4163
|
+
text: `I'm new to VibeControls. Walk me through complete setup ${pathNote}:
|
|
4164
|
+
|
|
4165
|
+
1. **Authenticate**: vibecontrols_auth_login \u2192 vibecontrols_auth_select_workspace (if multiple).
|
|
4166
|
+
2. **Register Agent**: vibecontrols_agents_create for this machine.
|
|
4167
|
+
3. **Create Vibe**: vibecontrols_vibes_create with PROJECT type.
|
|
4168
|
+
4. **Create Sessions**: Create dev, test, and log sessions via vibecontrols_sessions_create.
|
|
4169
|
+
5. **Create Deck**: vibecontrols_decks_create with common command buttons (build, test, lint, dev).
|
|
4170
|
+
6. **Create Docs Site**: vibecontrols_docs_sites_create + vibecontrols_docs_pages_create for a getting-started page.
|
|
4171
|
+
7. **Pin a Note**: vibecontrols_notes_create with setup instructions, then vibecontrols_notes_pin.
|
|
4172
|
+
8. **Start Dev Session**: vibecontrols_sessions_start.
|
|
4173
|
+
|
|
4174
|
+
Guide me step by step, showing results and asking before each step.`
|
|
4175
|
+
}
|
|
4176
|
+
}
|
|
4177
|
+
]
|
|
4178
|
+
};
|
|
4179
|
+
}
|
|
4180
|
+
);
|
|
4181
|
+
server.registerPrompt(
|
|
4182
|
+
"vibecontrols-incident-response",
|
|
4183
|
+
{
|
|
4184
|
+
title: "Incident Response",
|
|
4185
|
+
description: "Guided incident investigation: health checks, logs, audit trail, and session sharing.",
|
|
4186
|
+
argsSchema: {
|
|
4187
|
+
agentId: z.string().optional().describe("Agent ID to investigate")
|
|
4188
|
+
}
|
|
4189
|
+
},
|
|
4190
|
+
({ agentId }) => {
|
|
4191
|
+
ctx.logger.debug("Prompt vibecontrols-incident-response called", { agentId });
|
|
4192
|
+
const agentNote = agentId ? `Focus on agent "${agentId}".` : "List agents with vibecontrols_agents_list and identify the affected one.";
|
|
4193
|
+
return {
|
|
4194
|
+
messages: [
|
|
4195
|
+
{
|
|
4196
|
+
role: "user",
|
|
4197
|
+
content: {
|
|
4198
|
+
type: "text",
|
|
4199
|
+
text: `Help me investigate an incident. ${agentNote}
|
|
4200
|
+
|
|
4201
|
+
1. **Agent Health**: vibecontrols_agents_probe to check connectivity.
|
|
4202
|
+
2. **All Agent Health**: vibecontrols_agents_health for full overview.
|
|
4203
|
+
3. **Active Sessions**: vibecontrols_sessions_active to see what's running.
|
|
4204
|
+
4. **Session Output**: vibecontrols_sessions_output for error logs.
|
|
4205
|
+
5. **Audit Trail**: vibecontrols_audit_list to see recent changes.
|
|
4206
|
+
6. **Audit Stats**: vibecontrols_audit_stats for activity summary.
|
|
4207
|
+
7. **Create Debug Session**: vibecontrols_sessions_create for investigation.
|
|
4208
|
+
8. **Share Session**: vibecontrols_sessions_share or vibecontrols_sessions_share_link_create for on-call.
|
|
4209
|
+
9. **Document Findings**: vibecontrols_notes_create with incident details.
|
|
4210
|
+
|
|
4211
|
+
Summarize findings after each step and suggest next actions.`
|
|
4212
|
+
}
|
|
4213
|
+
}
|
|
4214
|
+
]
|
|
4215
|
+
};
|
|
4216
|
+
}
|
|
4217
|
+
);
|
|
4218
|
+
server.registerPrompt(
|
|
4219
|
+
"vibecontrols-deploy",
|
|
4220
|
+
{
|
|
4221
|
+
title: "Deployment Workflow",
|
|
4222
|
+
description: "Guided deployment using vibe decks, sessions, and health checks.",
|
|
4223
|
+
argsSchema: {
|
|
4224
|
+
vibeId: z.string().optional().describe("Vibe ID to deploy"),
|
|
4225
|
+
environment: z.string().optional().describe("Target environment (alpha, prod)")
|
|
4226
|
+
}
|
|
4227
|
+
},
|
|
4228
|
+
({ vibeId, environment }) => {
|
|
4229
|
+
ctx.logger.debug("Prompt vibecontrols-deploy called", { vibeId, environment });
|
|
4230
|
+
const vibeNote = vibeId ? `Deploy vibe "${vibeId}".` : "List vibes with vibecontrols_vibes_list and select one.";
|
|
4231
|
+
const envNote = environment || "alpha";
|
|
4232
|
+
return {
|
|
4233
|
+
messages: [
|
|
4234
|
+
{
|
|
4235
|
+
role: "user",
|
|
4236
|
+
content: {
|
|
4237
|
+
type: "text",
|
|
4238
|
+
text: `Help me deploy to ${envNote}. ${vibeNote}
|
|
4239
|
+
|
|
4240
|
+
1. **Pre-flight**: vibecontrols_sessions_active to check running state.
|
|
4241
|
+
2. **Find Deck**: vibecontrols_decks_list to find the deploy deck.
|
|
4242
|
+
3. **Run Tests**: vibecontrols_decks_buttons_execute for the test button.
|
|
4243
|
+
4. **Build**: vibecontrols_decks_buttons_execute for the build button.
|
|
4244
|
+
5. **Deploy**: vibecontrols_decks_buttons_execute for the deploy-${envNote} button.
|
|
4245
|
+
6. **Verify Health**: vibecontrols_agents_probe + vibecontrols_sessions_check_health.
|
|
4246
|
+
7. **Check Logs**: vibecontrols_sessions_output for any errors.
|
|
4247
|
+
8. **Record**: vibecontrols_notes_create with deployment summary.
|
|
4248
|
+
|
|
4249
|
+
Stop and confirm with me before the deploy step.`
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
]
|
|
4253
|
+
};
|
|
4254
|
+
}
|
|
4255
|
+
);
|
|
4256
|
+
server.registerPrompt(
|
|
4257
|
+
"vibecontrols-daily-standup",
|
|
4258
|
+
{
|
|
4259
|
+
title: "Daily Standup Summary",
|
|
4260
|
+
description: "Generate a standup-ready summary of recent activity.",
|
|
4261
|
+
argsSchema: {
|
|
4262
|
+
since: z.string().optional().describe("Date to summarize from (ISO format, default: yesterday)")
|
|
4263
|
+
}
|
|
4264
|
+
},
|
|
4265
|
+
({ since }) => {
|
|
4266
|
+
ctx.logger.debug("Prompt vibecontrols-daily-standup called", { since });
|
|
4267
|
+
const sinceNote = since || "yesterday";
|
|
4268
|
+
return {
|
|
4269
|
+
messages: [
|
|
4270
|
+
{
|
|
4271
|
+
role: "user",
|
|
4272
|
+
content: {
|
|
4273
|
+
type: "text",
|
|
4274
|
+
text: `Generate a standup summary since ${sinceNote}:
|
|
4275
|
+
|
|
4276
|
+
1. **Audit Activity**: vibecontrols_audit_list with date filter for recent actions.
|
|
4277
|
+
2. **Audit Stats**: vibecontrols_audit_stats for activity breakdown.
|
|
4278
|
+
3. **Session Activity**: vibecontrols_sessions_list to see session activity.
|
|
4279
|
+
4. **AI Events**: vibecontrols_ai_events_list for AI tool usage.
|
|
4280
|
+
5. **Notes Created**: vibecontrols_notes_list for recently created notes.
|
|
4281
|
+
6. **Active State**: vibecontrols_sessions_active + vibecontrols_agents_health.
|
|
4282
|
+
|
|
4283
|
+
Compile into a concise standup format:
|
|
4284
|
+
- What I did
|
|
4285
|
+
- What I'm doing today
|
|
4286
|
+
- Any blockers`
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
]
|
|
4290
|
+
};
|
|
4291
|
+
}
|
|
4292
|
+
);
|
|
4293
|
+
server.registerPrompt(
|
|
4294
|
+
"vibecontrols-runbook",
|
|
4295
|
+
{
|
|
4296
|
+
title: "Runbook Authoring",
|
|
4297
|
+
description: "Create a documentation runbook for a service or project.",
|
|
4298
|
+
argsSchema: {
|
|
4299
|
+
vibeId: z.string().optional().describe("Vibe ID to create docs for"),
|
|
4300
|
+
topic: z.string().optional().describe("Runbook topic (e.g., deployment, incident-response)")
|
|
4301
|
+
}
|
|
4302
|
+
},
|
|
4303
|
+
({ vibeId, topic }) => {
|
|
4304
|
+
ctx.logger.debug("Prompt vibecontrols-runbook called", { vibeId, topic });
|
|
4305
|
+
const vibeNote = vibeId ? `for vibe "${vibeId}"` : "(select a vibe with vibecontrols_vibes_list first)";
|
|
4306
|
+
const topicNote = topic || "general operations";
|
|
4307
|
+
return {
|
|
4308
|
+
messages: [
|
|
4309
|
+
{
|
|
4310
|
+
role: "user",
|
|
4311
|
+
content: {
|
|
4312
|
+
type: "text",
|
|
4313
|
+
text: `Create a runbook ${vibeNote} about "${topicNote}":
|
|
4314
|
+
|
|
4315
|
+
1. **Create Docs Site**: vibecontrols_docs_sites_create linked to the vibe.
|
|
4316
|
+
2. **Create Overview Page**: vibecontrols_docs_pages_create with title "Overview" and a summary.
|
|
4317
|
+
3. **Create Prerequisites Page**: vibecontrols_docs_pages_create with requirements and setup.
|
|
4318
|
+
4. **Create Steps Page**: vibecontrols_docs_pages_create with step-by-step procedures.
|
|
4319
|
+
5. **Create Rollback Page**: vibecontrols_docs_pages_create with rollback procedures.
|
|
4320
|
+
6. **Create Troubleshooting Page**: vibecontrols_docs_pages_create with common issues.
|
|
4321
|
+
7. **Compile**: vibecontrols_docs_compile to build the docs.
|
|
4322
|
+
8. **Publish**: vibecontrols_docs_publish to make them live.
|
|
4323
|
+
|
|
4324
|
+
Generate appropriate content for each page based on the topic.`
|
|
4325
|
+
}
|
|
4326
|
+
}
|
|
4327
|
+
]
|
|
4328
|
+
};
|
|
4329
|
+
}
|
|
4330
|
+
);
|
|
4331
|
+
}
|
|
4332
|
+
|
|
4333
|
+
// src/modules/vibecontrols/index.ts
|
|
4334
|
+
var vibecontrolsModule = {
|
|
4335
|
+
id: "vibecontrols",
|
|
4336
|
+
version: "0.0.1",
|
|
4337
|
+
displayName: "VibeControls",
|
|
4338
|
+
capabilities: { tools: {}, resources: {}, prompts: {} },
|
|
4339
|
+
register(server, ctx) {
|
|
4340
|
+
const tools = [];
|
|
4341
|
+
const resources = [];
|
|
4342
|
+
const prompts = [];
|
|
4343
|
+
const trackTool = (n) => {
|
|
4344
|
+
tools.push(n);
|
|
4345
|
+
return n;
|
|
4346
|
+
};
|
|
4347
|
+
const trackResource = (uri) => {
|
|
4348
|
+
resources.push(uri);
|
|
4349
|
+
return uri;
|
|
4350
|
+
};
|
|
4351
|
+
const trackPrompt = (n) => {
|
|
4352
|
+
prompts.push(n);
|
|
4353
|
+
return n;
|
|
4354
|
+
};
|
|
4355
|
+
registerAgentTools(server, ctx, trackTool);
|
|
4356
|
+
registerVibeTools(server, ctx, trackTool);
|
|
4357
|
+
registerSessionTools(server, ctx, trackTool);
|
|
4358
|
+
registerNoteTools(server, ctx, trackTool);
|
|
4359
|
+
registerConfigurationTools(server, ctx, trackTool);
|
|
4360
|
+
registerWebhookTools(server, ctx, trackTool);
|
|
4361
|
+
registerTunnelTools(server, ctx, trackTool);
|
|
4362
|
+
registerUISessionTools(server, ctx, trackTool);
|
|
4363
|
+
registerAiEventTools(server, ctx, trackTool);
|
|
4364
|
+
registerTargetTools(server, ctx, trackTool);
|
|
4365
|
+
registerVibeDeckTools(server, ctx, trackTool);
|
|
4366
|
+
registerDocsTools(server, ctx, trackTool);
|
|
4367
|
+
registerSessionSharingTools(server, ctx, trackTool);
|
|
4368
|
+
registerAuditTools(server, ctx, trackTool);
|
|
4369
|
+
registerActionTools(server, ctx, trackTool);
|
|
4370
|
+
registerAnalyticsTools(server, ctx, trackTool);
|
|
4371
|
+
registerVibecontrolsResources(server, ctx, trackResource);
|
|
4372
|
+
registerVibecontrolsPrompts(server, ctx, trackPrompt);
|
|
4373
|
+
return { tools, resources, prompts };
|
|
4374
|
+
}
|
|
4375
|
+
};
|
|
4376
|
+
var vibecontrols_default = vibecontrolsModule;
|
|
4377
|
+
|
|
4378
|
+
export { vibecontrols_default as default };
|
|
4379
|
+
//# sourceMappingURL=index.js.map
|
|
4380
|
+
//# sourceMappingURL=index.js.map
|