@burdenoff/mcp-libs 2026.523.1 → 2026.529.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-HRWIDQJE.js +1771 -0
- package/dist/chunk-HRWIDQJE.js.map +1 -0
- package/dist/modules/conversations/index.cjs +1174 -0
- package/dist/modules/conversations/index.cjs.map +1 -1
- package/dist/modules/conversations/index.js +1174 -0
- package/dist/modules/conversations/index.js.map +1 -1
- package/dist/modules/export/index.cjs +348 -0
- package/dist/modules/export/index.cjs.map +1 -1
- package/dist/modules/export/index.js +348 -0
- package/dist/modules/export/index.js.map +1 -1
- package/dist/modules/integrations/index.cjs +539 -0
- package/dist/modules/integrations/index.cjs.map +1 -1
- package/dist/modules/integrations/index.js +539 -0
- package/dist/modules/integrations/index.js.map +1 -1
- package/dist/modules/sandbox/index.cjs +864 -0
- package/dist/modules/sandbox/index.cjs.map +1 -1
- package/dist/modules/sandbox/index.js +699 -1
- package/dist/modules/sandbox/index.js.map +1 -1
- package/dist/modules/scheduler/index.cjs +736 -0
- package/dist/modules/scheduler/index.cjs.map +1 -1
- package/dist/modules/scheduler/index.js +736 -0
- package/dist/modules/scheduler/index.js.map +1 -1
- package/dist/modules/vibecontrols/index.cjs +4230 -477
- package/dist/modules/vibecontrols/index.cjs.map +1 -1
- package/dist/modules/vibecontrols/index.js +3424 -401
- package/dist/modules/vibecontrols/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-N2CZNPYC.js +0 -875
- package/dist/chunk-N2CZNPYC.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
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, MOVE_VIBE, UPDATE_VIBE_GIT, 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, UPDATE_SESSION, UPDATE_SESSION_STATUS, DELETE_SESSION, KILL_SESSION, 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,
|
|
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, MOVE_VIBE, UPDATE_VIBE_GIT, 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, UPDATE_SESSION, UPDATE_SESSION_STATUS, DELETE_SESSION, KILL_SESSION, STOP_SESSION_TERMINAL, RESTART_SESSION_TERMINAL, START_TARGET_TERMINAL, STOP_TARGET_TERMINAL, EXPORT_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, SECURITY_PROVIDERS_Q, SET_SECURITY_PROVIDER_M, MY_SECURITY_SCANS_Q, ALL_SECURITY_SCANS_Q, SECURITY_SCAN_Q, RUN_SECURITY_SCAN_M, CANCEL_SECURITY_SCAN_M, SECURITY_FINDINGS_Q, UPDATE_SECURITY_FINDING_STATUS_M, SECURITY_POLICY_DECISION_Q, SECURITY_STATUS_Q, REPOSITORY_SECURITY_CONFIG_Q, UPDATE_REPOSITORY_SECURITY_CONFIG_M, CREATE_SECURITY_EXCEPTION_M, REVOKE_SECURITY_EXCEPTION_M, PRESIGN_SECURITY_EVIDENCE_M, PUSH_SECURITY_SCAN_RUN_M, GET_CI_STATUS_Q, REFRESH_CI_STATUS_M, GET_CI_PIPELINE_RUNS_Q, GET_CI_PIPELINE_DETAILS_Q, GET_REPO_STATS_Q, REFRESH_REPO_STATS_M, LIST_GITOPS_PROVIDERS_Q, GET_GITOPS_PROVIDER_Q, CREATE_GITOPS_PROVIDER_M, UPDATE_GITOPS_PROVIDER_M, DELETE_GITOPS_PROVIDER_M, MY_SETTINGS_Q, MY_SETTINGS_BY_CATEGORY_Q, RESET_SETTINGS_M, UPDATE_PREFERENCES_M, UPDATE_NOTIFICATION_PREFERENCES_M, UPDATE_WORKSPACE_DEFAULTS_M, LIST_SETTINGS_SECRETS_Q, SET_SETTINGS_SECRET_M, DELETE_SETTINGS_SECRET_M, RESOLVE_INTEGRATION_TOKEN_M, LIST_WEBHOOKS, GET_WEBHOOK, CREATE_WEBHOOK, UPDATE_WEBHOOK, DELETE_WEBHOOK, TEST_WEBHOOK, TRIGGER_WEBHOOK, 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, UPDATE_SESSION_SHARE, JOIN_SHARED_SESSION, LEAVE_SHARED_SESSION, REQUEST_SESSION_CONTROL, RELEASE_SESSION_CONTROL, TRANSFER_SESSION_CONTROL, 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, LIST_AI_PROMPTS, GET_AI_PROMPT, CREATE_AI_PROMPT, UPDATE_AI_PROMPT, DELETE_AI_PROMPT, DUPLICATE_AI_PROMPT, RENDER_AI_PROMPT, RECORD_AI_PROMPT_USAGE, LIST_VIBE_DECK_SHARE_LINKS, CREATE_VIBE_DECK_SHARE_LINK, UPDATE_VIBE_DECK_SHARE_LINK, REVOKE_VIBE_DECK_SHARE_LINK, VALIDATE_VIBE_DECK_SHARE_LINK, SHARED_VIBE_DECK, EXECUTE_SHARED_VIBE_DECK_BUTTON, VIBECONTROLS_ANALYTICS, LIST_CATALOGS, GET_CATALOG, GET_CATALOG_DEPENDENCY_GRAPH, GET_CATALOG_SBOM, CREATE_CATALOG, UPDATE_CATALOG, DELETE_CATALOG, ADD_COMPONENT_TO_CATALOG, REMOVE_COMPONENT_FROM_CATALOG, ADD_VIBE_TO_CATALOG, REMOVE_VIBE_FROM_CATALOG, LIST_COMPONENTS, GET_COMPONENT, CREATE_COMPONENT, UPDATE_COMPONENT, DELETE_COMPONENT, FORK_GITHUB_REPO, PUBLISH_COMPONENT_AS_TEMPLATE, LIST_TEMPLATES, GET_TEMPLATE, UPDATE_TEMPLATE, DELETE_TEMPLATE, INSTANTIATE_TEMPLATE, GET_SCORECARD, UPSERT_SCORECARD, ADD_SCORECARD_METRIC, UPDATE_SCORECARD_METRIC, REMOVE_SCORECARD_METRIC, LIST_TUNNELS, PINNED_NOTES, GET_TUNNEL, GET_TUNNEL_BY_SLUG, CREATE_TUNNEL, UPDATE_TUNNEL, DELETE_TUNNEL, START_TUNNEL, STOP_TUNNEL, ROTATE_TUNNEL_CREDENTIALS, ISSUE_TUNNEL_SESSION, REVOKE_TUNNEL_SESSION, LIST_TUNNEL_SESSIONS, LIST_TUNNEL_PROVIDERS, GET_TUNNEL_PROVIDER, LIST_TUNNEL_SHARDS, TUNNEL_USAGE, TUNNEL_AUDIT, LIST_TUNNEL_DOMAINS, GET_TUNNEL_DOMAIN, RESERVE_TUNNEL_SUBDOMAIN, REGISTER_CUSTOM_TUNNEL_DOMAIN, VERIFY_TUNNEL_DOMAIN, ATTACH_TUNNEL_DOMAIN, DETACH_TUNNEL_DOMAIN, DELETE_TUNNEL_DOMAIN, PROBE_AGENT_TUNNEL, ADD_AGENT_FROM_TUNNEL } from '../../chunk-HRWIDQJE.js';
|
|
2
2
|
import { getAuth } from '../../chunk-WWFVD7BO.js';
|
|
3
3
|
import { mcpToolName, jsonResult, errorResult } from '../../chunk-H2OYWLOA.js';
|
|
4
4
|
import { z } from 'zod';
|
|
@@ -765,513 +765,2923 @@ function registerAgentTools(server, ctx, track) {
|
|
|
765
765
|
}
|
|
766
766
|
);
|
|
767
767
|
}
|
|
768
|
-
function
|
|
768
|
+
function registerAiPromptTools(server, ctx, track) {
|
|
769
769
|
server.registerTool(
|
|
770
|
-
track(mcpToolName(ctx.productName, "
|
|
770
|
+
track(mcpToolName(ctx.productName, "ai_prompts_list")),
|
|
771
771
|
{
|
|
772
|
-
title: "List AI
|
|
773
|
-
description: "List AI
|
|
772
|
+
title: "List AI Prompts",
|
|
773
|
+
description: "List AI prompt templates with optional filters.",
|
|
774
774
|
inputSchema: {
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
775
|
+
category: z.string().optional().describe("Filter by category"),
|
|
776
|
+
status: z.string().optional().describe("Filter by status (ACTIVE, ARCHIVED, DRAFT)"),
|
|
777
|
+
isShared: z.boolean().optional().describe("Only shared prompts"),
|
|
778
|
+
search: z.string().optional().describe("Search text"),
|
|
779
|
+
limit: z.number().optional(),
|
|
780
|
+
offset: z.number().optional()
|
|
780
781
|
}
|
|
781
782
|
},
|
|
782
|
-
async ({
|
|
783
|
+
async ({ category, status, isShared, search, limit, offset }) => {
|
|
783
784
|
try {
|
|
784
785
|
const filter = {};
|
|
785
|
-
if (
|
|
786
|
-
if (
|
|
787
|
-
if (
|
|
786
|
+
if (category !== void 0) filter.category = category;
|
|
787
|
+
if (status !== void 0) filter.status = status;
|
|
788
|
+
if (isShared !== void 0) filter.isShared = isShared;
|
|
789
|
+
if (search !== void 0) filter.search = search;
|
|
788
790
|
const pagination = {};
|
|
789
791
|
if (limit !== void 0) pagination.limit = limit;
|
|
790
792
|
if (offset !== void 0) pagination.offset = offset;
|
|
791
|
-
const data = await ctx.gql.workspace.request(
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
793
|
+
const data = await ctx.gql.workspace.request(LIST_AI_PROMPTS, {
|
|
794
|
+
filter: Object.keys(filter).length ? filter : void 0,
|
|
795
|
+
pagination: Object.keys(pagination).length ? pagination : void 0
|
|
796
|
+
});
|
|
797
|
+
return jsonResult(data.aiPrompts);
|
|
798
|
+
} catch (error) {
|
|
799
|
+
ctx.logger.error("vibecontrols_actions_ai_prompts_list failed", { error });
|
|
800
|
+
return errorResult(
|
|
801
|
+
`Failed to list AI prompts: ${error instanceof Error ? error.message : String(error)}`
|
|
797
802
|
);
|
|
798
|
-
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
);
|
|
806
|
+
server.registerTool(
|
|
807
|
+
track(mcpToolName(ctx.productName, "ai_prompts_get")),
|
|
808
|
+
{
|
|
809
|
+
title: "Get AI Prompt",
|
|
810
|
+
description: "Fetch a single AI prompt by ID.",
|
|
811
|
+
inputSchema: { id: z.string().describe("Prompt ID") }
|
|
812
|
+
},
|
|
813
|
+
async ({ id }) => {
|
|
814
|
+
try {
|
|
815
|
+
const data = await ctx.gql.workspace.request(GET_AI_PROMPT, { id });
|
|
816
|
+
return jsonResult(data.aiPrompt);
|
|
799
817
|
} catch (error) {
|
|
800
|
-
ctx.logger.error("
|
|
818
|
+
ctx.logger.error("vibecontrols_actions_ai_prompts_get failed", { error });
|
|
801
819
|
return errorResult(
|
|
802
|
-
`Failed to
|
|
820
|
+
`Failed to get AI prompt: ${error instanceof Error ? error.message : String(error)}`
|
|
803
821
|
);
|
|
804
822
|
}
|
|
805
823
|
}
|
|
806
824
|
);
|
|
807
825
|
server.registerTool(
|
|
808
|
-
track(mcpToolName(ctx.productName, "
|
|
826
|
+
track(mcpToolName(ctx.productName, "ai_prompts_create")),
|
|
809
827
|
{
|
|
810
|
-
title: "Create AI
|
|
811
|
-
description: "
|
|
828
|
+
title: "Create AI Prompt",
|
|
829
|
+
description: "Create a new AI prompt template.",
|
|
812
830
|
inputSchema: {
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
831
|
+
name: z.string().describe("Prompt name"),
|
|
832
|
+
content: z.string().describe("Prompt content/template"),
|
|
833
|
+
description: z.string().optional(),
|
|
834
|
+
category: z.string().optional(),
|
|
835
|
+
status: z.string().optional(),
|
|
836
|
+
isShared: z.boolean().optional(),
|
|
837
|
+
tags: z.array(z.string()).optional(),
|
|
838
|
+
variables: z.unknown().optional(),
|
|
839
|
+
metadata: z.unknown().optional()
|
|
817
840
|
}
|
|
818
841
|
},
|
|
819
|
-
async (
|
|
842
|
+
async (input) => {
|
|
820
843
|
try {
|
|
821
|
-
const input = { source, eventType };
|
|
822
|
-
input.payload = JSON.parse(payload);
|
|
823
|
-
if (agentId !== void 0) input.agentId = agentId;
|
|
824
844
|
const data = await ctx.gql.workspace.request(
|
|
825
|
-
|
|
826
|
-
{
|
|
827
|
-
input
|
|
828
|
-
}
|
|
845
|
+
CREATE_AI_PROMPT,
|
|
846
|
+
{ input }
|
|
829
847
|
);
|
|
830
|
-
return jsonResult(data.
|
|
848
|
+
return jsonResult(data.createAIPrompt);
|
|
831
849
|
} catch (error) {
|
|
832
|
-
ctx.logger.error("
|
|
850
|
+
ctx.logger.error("vibecontrols_actions_ai_prompts_create failed", { error });
|
|
833
851
|
return errorResult(
|
|
834
|
-
`Failed to create AI
|
|
852
|
+
`Failed to create AI prompt: ${error instanceof Error ? error.message : String(error)}`
|
|
835
853
|
);
|
|
836
854
|
}
|
|
837
855
|
}
|
|
838
856
|
);
|
|
839
857
|
server.registerTool(
|
|
840
|
-
track(mcpToolName(ctx.productName, "
|
|
858
|
+
track(mcpToolName(ctx.productName, "ai_prompts_update")),
|
|
841
859
|
{
|
|
842
|
-
title: "
|
|
843
|
-
description: "
|
|
860
|
+
title: "Update AI Prompt",
|
|
861
|
+
description: "Update an existing AI prompt.",
|
|
844
862
|
inputSchema: {
|
|
845
|
-
|
|
846
|
-
|
|
863
|
+
id: z.string().describe("Prompt ID"),
|
|
864
|
+
name: z.string().optional(),
|
|
865
|
+
content: z.string().optional(),
|
|
866
|
+
description: z.string().optional(),
|
|
867
|
+
category: z.string().optional(),
|
|
868
|
+
status: z.string().optional(),
|
|
869
|
+
isShared: z.boolean().optional(),
|
|
870
|
+
tags: z.array(z.string()).optional(),
|
|
871
|
+
variables: z.unknown().optional(),
|
|
872
|
+
metadata: z.unknown().optional()
|
|
847
873
|
}
|
|
848
874
|
},
|
|
849
|
-
async ({
|
|
875
|
+
async ({ id, ...rest }) => {
|
|
850
876
|
try {
|
|
877
|
+
const input = {};
|
|
878
|
+
for (const [k, v] of Object.entries(rest)) {
|
|
879
|
+
if (v !== void 0) input[k] = v;
|
|
880
|
+
}
|
|
851
881
|
const data = await ctx.gql.workspace.request(
|
|
852
|
-
|
|
853
|
-
{
|
|
882
|
+
UPDATE_AI_PROMPT,
|
|
883
|
+
{ id, input }
|
|
854
884
|
);
|
|
855
|
-
return jsonResult(data.
|
|
885
|
+
return jsonResult(data.updateAIPrompt);
|
|
856
886
|
} catch (error) {
|
|
857
|
-
ctx.logger.error("
|
|
887
|
+
ctx.logger.error("vibecontrols_actions_ai_prompts_update failed", { error });
|
|
858
888
|
return errorResult(
|
|
859
|
-
`Failed to
|
|
889
|
+
`Failed to update AI prompt: ${error instanceof Error ? error.message : String(error)}`
|
|
860
890
|
);
|
|
861
891
|
}
|
|
862
892
|
}
|
|
863
893
|
);
|
|
864
|
-
}
|
|
865
|
-
function registerAnalyticsTools(server, ctx, track) {
|
|
866
894
|
server.registerTool(
|
|
867
|
-
track(mcpToolName(ctx.productName, "
|
|
895
|
+
track(mcpToolName(ctx.productName, "ai_prompts_delete")),
|
|
868
896
|
{
|
|
869
|
-
title: "
|
|
870
|
-
description: "
|
|
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
|
-
}
|
|
897
|
+
title: "Delete AI Prompt",
|
|
898
|
+
description: "Delete an AI prompt.",
|
|
899
|
+
inputSchema: { id: z.string().describe("Prompt ID") }
|
|
894
900
|
},
|
|
895
|
-
async ({
|
|
901
|
+
async ({ id }) => {
|
|
896
902
|
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
903
|
const data = await ctx.gql.workspace.request(
|
|
906
|
-
|
|
907
|
-
{
|
|
904
|
+
DELETE_AI_PROMPT,
|
|
905
|
+
{ id }
|
|
908
906
|
);
|
|
909
|
-
return jsonResult(data.
|
|
907
|
+
return jsonResult({ deleted: data.deleteAIPrompt, id });
|
|
910
908
|
} catch (error) {
|
|
911
|
-
ctx.logger.error("
|
|
909
|
+
ctx.logger.error("vibecontrols_actions_ai_prompts_delete failed", { error });
|
|
912
910
|
return errorResult(
|
|
913
|
-
`Failed to
|
|
911
|
+
`Failed to delete AI prompt: ${error instanceof Error ? error.message : String(error)}`
|
|
914
912
|
);
|
|
915
913
|
}
|
|
916
914
|
}
|
|
917
915
|
);
|
|
918
916
|
server.registerTool(
|
|
919
|
-
track(mcpToolName(ctx.productName, "
|
|
917
|
+
track(mcpToolName(ctx.productName, "ai_prompts_duplicate")),
|
|
920
918
|
{
|
|
921
|
-
title: "
|
|
922
|
-
description: "
|
|
919
|
+
title: "Duplicate AI Prompt",
|
|
920
|
+
description: "Duplicate an AI prompt with a new name.",
|
|
923
921
|
inputSchema: {
|
|
924
|
-
|
|
925
|
-
|
|
922
|
+
id: z.string().describe("Source prompt ID"),
|
|
923
|
+
name: z.string().describe("Name for the duplicate")
|
|
926
924
|
}
|
|
927
925
|
},
|
|
928
|
-
async ({
|
|
926
|
+
async ({ id, name }) => {
|
|
929
927
|
try {
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
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);
|
|
928
|
+
const data = await ctx.gql.workspace.request(
|
|
929
|
+
DUPLICATE_AI_PROMPT,
|
|
930
|
+
{ id, name }
|
|
931
|
+
);
|
|
932
|
+
return jsonResult(data.duplicateAIPrompt);
|
|
960
933
|
} catch (error) {
|
|
961
|
-
ctx.logger.error("
|
|
934
|
+
ctx.logger.error("vibecontrols_actions_ai_prompts_duplicate failed", { error });
|
|
962
935
|
return errorResult(
|
|
963
|
-
`Failed to
|
|
936
|
+
`Failed to duplicate AI prompt: ${error instanceof Error ? error.message : String(error)}`
|
|
964
937
|
);
|
|
965
938
|
}
|
|
966
939
|
}
|
|
967
940
|
);
|
|
968
|
-
}
|
|
969
|
-
function registerAuditTools(server, ctx, track) {
|
|
970
941
|
server.registerTool(
|
|
971
|
-
track(mcpToolName(ctx.productName, "
|
|
942
|
+
track(mcpToolName(ctx.productName, "ai_prompts_render")),
|
|
972
943
|
{
|
|
973
|
-
title: "
|
|
974
|
-
description: "
|
|
944
|
+
title: "Render AI Prompt",
|
|
945
|
+
description: "Render an AI prompt template with variables substituted.",
|
|
975
946
|
inputSchema: {
|
|
976
|
-
|
|
977
|
-
|
|
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")
|
|
947
|
+
id: z.string().describe("Prompt ID"),
|
|
948
|
+
variables: z.unknown().optional().describe("Variables as JSON")
|
|
983
949
|
}
|
|
984
950
|
},
|
|
985
|
-
async ({
|
|
951
|
+
async ({ id, variables }) => {
|
|
986
952
|
try {
|
|
987
|
-
const
|
|
988
|
-
|
|
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);
|
|
953
|
+
const data = await ctx.gql.workspace.request(RENDER_AI_PROMPT, { id, variables });
|
|
954
|
+
return jsonResult(data.renderAIPrompt);
|
|
1001
955
|
} catch (error) {
|
|
1002
|
-
ctx.logger.error("
|
|
956
|
+
ctx.logger.error("vibecontrols_actions_ai_prompts_render failed", { error });
|
|
1003
957
|
return errorResult(
|
|
1004
|
-
`Failed to
|
|
958
|
+
`Failed to render AI prompt: ${error instanceof Error ? error.message : String(error)}`
|
|
1005
959
|
);
|
|
1006
960
|
}
|
|
1007
961
|
}
|
|
1008
962
|
);
|
|
1009
963
|
server.registerTool(
|
|
1010
|
-
track(mcpToolName(ctx.productName, "
|
|
964
|
+
track(mcpToolName(ctx.productName, "ai_prompts_record_usage")),
|
|
1011
965
|
{
|
|
1012
|
-
title: "
|
|
1013
|
-
description: "
|
|
1014
|
-
inputSchema: { id: z.string().describe("
|
|
966
|
+
title: "Record AI Prompt Usage",
|
|
967
|
+
description: "Increment the usage counter on an AI prompt.",
|
|
968
|
+
inputSchema: { id: z.string().describe("Prompt ID") }
|
|
1015
969
|
},
|
|
1016
970
|
async ({ id }) => {
|
|
1017
971
|
try {
|
|
1018
|
-
const data = await ctx.gql.workspace.request(
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
972
|
+
const data = await ctx.gql.workspace.request(
|
|
973
|
+
RECORD_AI_PROMPT_USAGE,
|
|
974
|
+
{ id }
|
|
975
|
+
);
|
|
976
|
+
return jsonResult(data.recordAIPromptUsage);
|
|
1022
977
|
} catch (error) {
|
|
1023
|
-
ctx.logger.error("
|
|
978
|
+
ctx.logger.error("vibecontrols_actions_ai_prompts_record_usage failed", { error });
|
|
1024
979
|
return errorResult(
|
|
1025
|
-
`Failed to
|
|
980
|
+
`Failed to record AI prompt usage: ${error instanceof Error ? error.message : String(error)}`
|
|
1026
981
|
);
|
|
1027
982
|
}
|
|
1028
983
|
}
|
|
1029
984
|
);
|
|
985
|
+
}
|
|
986
|
+
function registerVibeDeckShareLinkTools(server, ctx, track) {
|
|
1030
987
|
server.registerTool(
|
|
1031
|
-
track(mcpToolName(ctx.productName, "
|
|
988
|
+
track(mcpToolName(ctx.productName, "vibe_deck_share_links_list")),
|
|
1032
989
|
{
|
|
1033
|
-
title: "
|
|
1034
|
-
description: "
|
|
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
|
-
}
|
|
990
|
+
title: "List VibeDeck Share-Links",
|
|
991
|
+
description: "List share-links for a VibeDeck.",
|
|
992
|
+
inputSchema: { vibeDeckId: z.string().describe("VibeDeck ID") }
|
|
1040
993
|
},
|
|
1041
|
-
async ({
|
|
994
|
+
async ({ vibeDeckId }) => {
|
|
1042
995
|
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
996
|
const data = await ctx.gql.workspace.request(
|
|
1048
|
-
|
|
1049
|
-
{
|
|
1050
|
-
filter: Object.keys(filter).length > 0 ? filter : void 0
|
|
1051
|
-
}
|
|
997
|
+
LIST_VIBE_DECK_SHARE_LINKS,
|
|
998
|
+
{ vibeDeckId }
|
|
1052
999
|
);
|
|
1053
|
-
return jsonResult(data.
|
|
1000
|
+
return jsonResult(data.vibeDeckShareLinks);
|
|
1054
1001
|
} catch (error) {
|
|
1055
|
-
ctx.logger.error("
|
|
1002
|
+
ctx.logger.error("vibecontrols_vibedecks_share_links_list failed", { error });
|
|
1056
1003
|
return errorResult(
|
|
1057
|
-
`Failed to
|
|
1004
|
+
`Failed to list VibeDeck share-links: ${error instanceof Error ? error.message : String(error)}`
|
|
1058
1005
|
);
|
|
1059
1006
|
}
|
|
1060
1007
|
}
|
|
1061
1008
|
);
|
|
1062
1009
|
server.registerTool(
|
|
1063
|
-
track(mcpToolName(ctx.productName, "
|
|
1010
|
+
track(mcpToolName(ctx.productName, "vibe_deck_share_links_create")),
|
|
1064
1011
|
{
|
|
1065
|
-
title: "
|
|
1066
|
-
description: "
|
|
1012
|
+
title: "Create VibeDeck Share-Link",
|
|
1013
|
+
description: "Create a new share-link for a VibeDeck.",
|
|
1067
1014
|
inputSchema: {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1015
|
+
vibeDeckId: z.string().describe("VibeDeck ID"),
|
|
1016
|
+
permission: z.string().optional().describe("EXECUTE or VIEW"),
|
|
1017
|
+
visibility: z.string().optional().describe("PUBLIC | RESTRICTED | SIGNED_LINK"),
|
|
1018
|
+
name: z.string().optional(),
|
|
1019
|
+
password: z.string().optional(),
|
|
1020
|
+
maxUses: z.number().optional(),
|
|
1021
|
+
expiresInHours: z.number().optional(),
|
|
1022
|
+
allowIframe: z.boolean().optional()
|
|
1072
1023
|
}
|
|
1073
1024
|
},
|
|
1074
|
-
async (
|
|
1025
|
+
async (input) => {
|
|
1075
1026
|
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
1027
|
const data = await ctx.gql.workspace.request(
|
|
1085
|
-
|
|
1086
|
-
|
|
1028
|
+
CREATE_VIBE_DECK_SHARE_LINK,
|
|
1029
|
+
{ input }
|
|
1087
1030
|
);
|
|
1088
|
-
return jsonResult(data.
|
|
1031
|
+
return jsonResult(data.createVibeDeckShareLink);
|
|
1089
1032
|
} catch (error) {
|
|
1090
|
-
ctx.logger.error("
|
|
1033
|
+
ctx.logger.error("vibecontrols_vibedecks_share_links_create failed", { error });
|
|
1091
1034
|
return errorResult(
|
|
1092
|
-
`Failed to
|
|
1035
|
+
`Failed to create VibeDeck share-link: ${error instanceof Error ? error.message : String(error)}`
|
|
1093
1036
|
);
|
|
1094
1037
|
}
|
|
1095
1038
|
}
|
|
1096
1039
|
);
|
|
1097
1040
|
server.registerTool(
|
|
1098
|
-
track(mcpToolName(ctx.productName, "
|
|
1041
|
+
track(mcpToolName(ctx.productName, "vibe_deck_share_links_update")),
|
|
1099
1042
|
{
|
|
1100
|
-
title: "
|
|
1101
|
-
description: "
|
|
1043
|
+
title: "Update VibeDeck Share-Link",
|
|
1044
|
+
description: "Update an existing VibeDeck share-link.",
|
|
1102
1045
|
inputSchema: {
|
|
1103
|
-
id: z.string().describe("
|
|
1104
|
-
|
|
1046
|
+
id: z.string().describe("Share-link ID"),
|
|
1047
|
+
permission: z.string().optional(),
|
|
1048
|
+
visibility: z.string().optional(),
|
|
1049
|
+
name: z.string().optional(),
|
|
1050
|
+
password: z.string().optional(),
|
|
1051
|
+
maxUses: z.number().optional(),
|
|
1052
|
+
expiresAt: z.string().optional(),
|
|
1053
|
+
allowIframe: z.boolean().optional()
|
|
1105
1054
|
}
|
|
1106
1055
|
},
|
|
1107
|
-
async ({ id,
|
|
1056
|
+
async ({ id, ...rest }) => {
|
|
1108
1057
|
try {
|
|
1109
|
-
const
|
|
1110
|
-
|
|
1058
|
+
const input = {};
|
|
1059
|
+
for (const [k, v] of Object.entries(rest)) {
|
|
1060
|
+
if (v !== void 0) input[k] = v;
|
|
1061
|
+
}
|
|
1111
1062
|
const data = await ctx.gql.workspace.request(
|
|
1112
|
-
|
|
1113
|
-
|
|
1063
|
+
UPDATE_VIBE_DECK_SHARE_LINK,
|
|
1064
|
+
{ id, input }
|
|
1114
1065
|
);
|
|
1115
|
-
return jsonResult(data.
|
|
1066
|
+
return jsonResult(data.updateVibeDeckShareLink);
|
|
1116
1067
|
} catch (error) {
|
|
1117
|
-
ctx.logger.error("
|
|
1068
|
+
ctx.logger.error("vibecontrols_vibedecks_share_links_update failed", { error });
|
|
1118
1069
|
return errorResult(
|
|
1119
|
-
`Failed to
|
|
1070
|
+
`Failed to update VibeDeck share-link: ${error instanceof Error ? error.message : String(error)}`
|
|
1120
1071
|
);
|
|
1121
1072
|
}
|
|
1122
1073
|
}
|
|
1123
1074
|
);
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1075
|
+
server.registerTool(
|
|
1076
|
+
track(mcpToolName(ctx.productName, "vibe_deck_share_links_revoke")),
|
|
1077
|
+
{
|
|
1078
|
+
title: "Revoke VibeDeck Share-Link",
|
|
1079
|
+
description: "Revoke a VibeDeck share-link.",
|
|
1080
|
+
inputSchema: { id: z.string().describe("Share-link ID") }
|
|
1081
|
+
},
|
|
1082
|
+
async ({ id }) => {
|
|
1083
|
+
try {
|
|
1084
|
+
const data = await ctx.gql.workspace.request(
|
|
1085
|
+
REVOKE_VIBE_DECK_SHARE_LINK,
|
|
1086
|
+
{ id }
|
|
1087
|
+
);
|
|
1088
|
+
return jsonResult(data.revokeVibeDeckShareLink);
|
|
1089
|
+
} catch (error) {
|
|
1090
|
+
ctx.logger.error("vibecontrols_vibedecks_share_links_revoke failed", { error });
|
|
1091
|
+
return errorResult(
|
|
1092
|
+
`Failed to revoke VibeDeck share-link: ${error instanceof Error ? error.message : String(error)}`
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
);
|
|
1097
|
+
server.registerTool(
|
|
1098
|
+
track(mcpToolName(ctx.productName, "vibe_deck_share_links_validate")),
|
|
1099
|
+
{
|
|
1100
|
+
title: "Validate VibeDeck Share-Link",
|
|
1101
|
+
description: "Validate a share-link token (public). Returns access metadata.",
|
|
1102
|
+
inputSchema: { token: z.string().describe("Share-link token") }
|
|
1103
|
+
},
|
|
1104
|
+
async ({ token }) => {
|
|
1105
|
+
try {
|
|
1106
|
+
const data = await ctx.gql.workspace.request(VALIDATE_VIBE_DECK_SHARE_LINK, { token });
|
|
1107
|
+
return jsonResult(data.validateVibeDeckShareLink);
|
|
1108
|
+
} catch (error) {
|
|
1109
|
+
ctx.logger.error("vibecontrols_vibedecks_share_links_validate failed", { error });
|
|
1110
|
+
return errorResult(
|
|
1111
|
+
`Failed to validate VibeDeck share-link: ${error instanceof Error ? error.message : String(error)}`
|
|
1112
|
+
);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
);
|
|
1116
|
+
server.registerTool(
|
|
1117
|
+
track(mcpToolName(ctx.productName, "vibe_deck_share_links_get_shared")),
|
|
1118
|
+
{
|
|
1119
|
+
title: "Get Shared VibeDeck",
|
|
1120
|
+
description: "Fetch a publicly shared VibeDeck via its token.",
|
|
1121
|
+
inputSchema: {
|
|
1122
|
+
token: z.string().describe("Share-link token"),
|
|
1123
|
+
password: z.string().optional().describe("Password if required")
|
|
1124
|
+
}
|
|
1125
|
+
},
|
|
1126
|
+
async ({ token, password }) => {
|
|
1127
|
+
try {
|
|
1128
|
+
const data = await ctx.gql.workspace.request(
|
|
1129
|
+
SHARED_VIBE_DECK,
|
|
1130
|
+
{
|
|
1131
|
+
token,
|
|
1132
|
+
password
|
|
1133
|
+
}
|
|
1134
|
+
);
|
|
1135
|
+
return jsonResult(data.sharedVibeDeck);
|
|
1136
|
+
} catch (error) {
|
|
1137
|
+
ctx.logger.error("vibecontrols_vibedecks_shared_get failed", { error });
|
|
1138
|
+
return errorResult(
|
|
1139
|
+
`Failed to fetch shared VibeDeck: ${error instanceof Error ? error.message : String(error)}`
|
|
1140
|
+
);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
);
|
|
1144
|
+
server.registerTool(
|
|
1145
|
+
track(mcpToolName(ctx.productName, "vibe_deck_share_links_execute_shared_button")),
|
|
1146
|
+
{
|
|
1147
|
+
title: "Execute Shared VibeDeck Button",
|
|
1148
|
+
description: "Execute a button on a publicly shared VibeDeck.",
|
|
1149
|
+
inputSchema: {
|
|
1150
|
+
token: z.string().describe("Share-link token"),
|
|
1151
|
+
buttonId: z.string().describe("Button ID"),
|
|
1152
|
+
password: z.string().optional().describe("Password if required")
|
|
1153
|
+
}
|
|
1154
|
+
},
|
|
1155
|
+
async ({ token, buttonId, password }) => {
|
|
1156
|
+
try {
|
|
1157
|
+
const data = await ctx.gql.workspace.request(EXECUTE_SHARED_VIBE_DECK_BUTTON, { token, buttonId, password });
|
|
1158
|
+
return jsonResult(data.executeSharedVibeDeckButton);
|
|
1159
|
+
} catch (error) {
|
|
1160
|
+
ctx.logger.error("vibecontrols_vibedecks_shared_execute_button failed", { error });
|
|
1161
|
+
return errorResult(
|
|
1162
|
+
`Failed to execute shared VibeDeck button: ${error instanceof Error ? error.message : String(error)}`
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1168
|
+
var VisibilityEnum = z.enum(["INTERNAL", "PRIVATE", "PUBLIC"]);
|
|
1169
|
+
function registerCatalogTools(server, ctx, track) {
|
|
1170
|
+
server.registerTool(
|
|
1171
|
+
track(mcpToolName(ctx.productName, "catalogs_list")),
|
|
1172
|
+
{
|
|
1173
|
+
title: "List Catalogs",
|
|
1174
|
+
description: "List service catalogs with optional filters. Returns { items, total, hasMore }.",
|
|
1175
|
+
inputSchema: {
|
|
1176
|
+
search: z.string().optional().describe("Full-text search on name/description"),
|
|
1177
|
+
tags: z.array(z.string()).optional().describe("Filter by tags (has-some)"),
|
|
1178
|
+
visibility: VisibilityEnum.optional().describe("Filter by visibility"),
|
|
1179
|
+
limit: z.number().optional().describe("Max results"),
|
|
1180
|
+
offset: z.number().optional().describe("Pagination offset")
|
|
1181
|
+
}
|
|
1182
|
+
},
|
|
1183
|
+
async ({ search, tags, visibility, limit, offset }) => {
|
|
1184
|
+
try {
|
|
1185
|
+
const filter = {};
|
|
1186
|
+
if (search !== void 0) filter.search = search;
|
|
1187
|
+
if (tags !== void 0) filter.tags = tags;
|
|
1188
|
+
if (visibility !== void 0) filter.visibility = visibility;
|
|
1189
|
+
const pagination = {};
|
|
1190
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
1191
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
1192
|
+
const data = await ctx.gql.workspace.request(
|
|
1193
|
+
LIST_CATALOGS,
|
|
1194
|
+
{
|
|
1195
|
+
filter: Object.keys(filter).length ? filter : void 0,
|
|
1196
|
+
pagination: Object.keys(pagination).length ? pagination : void 0
|
|
1197
|
+
}
|
|
1198
|
+
);
|
|
1199
|
+
return jsonResult(data.vibecontrolsCatalogs);
|
|
1200
|
+
} catch (error) {
|
|
1201
|
+
ctx.logger.error("catalogs_list failed", { error });
|
|
1202
|
+
return errorResult(
|
|
1203
|
+
`Failed to list catalogs: ${error instanceof Error ? error.message : String(error)}`
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
);
|
|
1208
|
+
server.registerTool(
|
|
1209
|
+
track(mcpToolName(ctx.productName, "catalogs_get")),
|
|
1210
|
+
{
|
|
1211
|
+
title: "Get Catalog",
|
|
1212
|
+
description: "Get a catalog by ID. Returns the catalog object or null.",
|
|
1213
|
+
inputSchema: { id: z.string().describe("Catalog ID") }
|
|
1214
|
+
},
|
|
1215
|
+
async ({ id }) => {
|
|
1216
|
+
try {
|
|
1217
|
+
const data = await ctx.gql.workspace.request(
|
|
1218
|
+
GET_CATALOG,
|
|
1219
|
+
{ id }
|
|
1220
|
+
);
|
|
1221
|
+
return jsonResult(data.vibecontrolsCatalog);
|
|
1222
|
+
} catch (error) {
|
|
1223
|
+
ctx.logger.error("catalogs_get failed", { error });
|
|
1224
|
+
return errorResult(
|
|
1225
|
+
`Failed to get catalog: ${error instanceof Error ? error.message : String(error)}`
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
);
|
|
1230
|
+
server.registerTool(
|
|
1231
|
+
track(mcpToolName(ctx.productName, "catalogs_dependency_graph")),
|
|
1232
|
+
{
|
|
1233
|
+
title: "Catalog Dependency Graph",
|
|
1234
|
+
description: "Get the dependency graph for a catalog. Returns { nodes, edges }.",
|
|
1235
|
+
inputSchema: { catalogId: z.string().describe("Catalog ID") }
|
|
1236
|
+
},
|
|
1237
|
+
async ({ catalogId }) => {
|
|
1238
|
+
try {
|
|
1239
|
+
const data = await ctx.gql.workspace.request(GET_CATALOG_DEPENDENCY_GRAPH, { catalogId });
|
|
1240
|
+
return jsonResult(data.vibecontrolsCatalogDependencyGraph);
|
|
1241
|
+
} catch (error) {
|
|
1242
|
+
ctx.logger.error("catalogs_dependency_graph failed", { error });
|
|
1243
|
+
return errorResult(
|
|
1244
|
+
`Failed to get dependency graph: ${error instanceof Error ? error.message : String(error)}`
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
);
|
|
1249
|
+
server.registerTool(
|
|
1250
|
+
track(mcpToolName(ctx.productName, "catalogs_sbom")),
|
|
1251
|
+
{
|
|
1252
|
+
title: "Catalog SBOM",
|
|
1253
|
+
description: "Get the SBOM (software bill of materials) for a catalog. Returns { format, generatedAt, totalCount, components }.",
|
|
1254
|
+
inputSchema: { catalogId: z.string().describe("Catalog ID") }
|
|
1255
|
+
},
|
|
1256
|
+
async ({ catalogId }) => {
|
|
1257
|
+
try {
|
|
1258
|
+
const data = await ctx.gql.workspace.request(
|
|
1259
|
+
GET_CATALOG_SBOM,
|
|
1260
|
+
{ catalogId }
|
|
1261
|
+
);
|
|
1262
|
+
return jsonResult(data.vibecontrolsCatalogSBOM);
|
|
1263
|
+
} catch (error) {
|
|
1264
|
+
ctx.logger.error("catalogs_sbom failed", { error });
|
|
1265
|
+
return errorResult(
|
|
1266
|
+
`Failed to get SBOM: ${error instanceof Error ? error.message : String(error)}`
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
);
|
|
1271
|
+
server.registerTool(
|
|
1272
|
+
track(mcpToolName(ctx.productName, "catalogs_create")),
|
|
1273
|
+
{
|
|
1274
|
+
title: "Create Catalog",
|
|
1275
|
+
description: "Create a new catalog. Returns the created catalog.",
|
|
1276
|
+
inputSchema: {
|
|
1277
|
+
name: z.string().describe("Catalog name"),
|
|
1278
|
+
description: z.string().optional().describe("Catalog description"),
|
|
1279
|
+
visibility: VisibilityEnum.optional().describe("Visibility level"),
|
|
1280
|
+
ownerId: z.string().optional().describe("Owner actor ID"),
|
|
1281
|
+
ownerName: z.string().optional().describe("Owner display name"),
|
|
1282
|
+
tags: z.array(z.string()).optional().describe("Tags")
|
|
1283
|
+
}
|
|
1284
|
+
},
|
|
1285
|
+
async ({ name, description, visibility, ownerId, ownerName, tags }) => {
|
|
1286
|
+
try {
|
|
1287
|
+
const input = { name };
|
|
1288
|
+
if (description !== void 0) input.description = description;
|
|
1289
|
+
if (visibility !== void 0) input.visibility = visibility;
|
|
1290
|
+
if (ownerId !== void 0) input.ownerId = ownerId;
|
|
1291
|
+
if (ownerName !== void 0) input.ownerName = ownerName;
|
|
1292
|
+
if (tags !== void 0) input.tags = tags;
|
|
1293
|
+
const data = await ctx.gql.workspace.request(
|
|
1294
|
+
CREATE_CATALOG,
|
|
1295
|
+
{ input }
|
|
1296
|
+
);
|
|
1297
|
+
return jsonResult(data.createVibecontrolsCatalog);
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
ctx.logger.error("catalogs_create failed", { error });
|
|
1300
|
+
return errorResult(
|
|
1301
|
+
`Failed to create catalog: ${error instanceof Error ? error.message : String(error)}`
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
);
|
|
1306
|
+
server.registerTool(
|
|
1307
|
+
track(mcpToolName(ctx.productName, "catalogs_update")),
|
|
1308
|
+
{
|
|
1309
|
+
title: "Update Catalog",
|
|
1310
|
+
description: "Update an existing catalog. Returns the updated catalog.",
|
|
1311
|
+
inputSchema: {
|
|
1312
|
+
id: z.string().describe("Catalog ID"),
|
|
1313
|
+
name: z.string().optional().describe("Name"),
|
|
1314
|
+
description: z.string().optional().describe("Description"),
|
|
1315
|
+
visibility: VisibilityEnum.optional().describe("Visibility"),
|
|
1316
|
+
tags: z.array(z.string()).optional().describe("Tags")
|
|
1317
|
+
}
|
|
1318
|
+
},
|
|
1319
|
+
async ({ id, name, description, visibility, tags }) => {
|
|
1320
|
+
try {
|
|
1321
|
+
const input = {};
|
|
1322
|
+
if (name !== void 0) input.name = name;
|
|
1323
|
+
if (description !== void 0) input.description = description;
|
|
1324
|
+
if (visibility !== void 0) input.visibility = visibility;
|
|
1325
|
+
if (tags !== void 0) input.tags = tags;
|
|
1326
|
+
const data = await ctx.gql.workspace.request(
|
|
1327
|
+
UPDATE_CATALOG,
|
|
1328
|
+
{ id, input }
|
|
1329
|
+
);
|
|
1330
|
+
return jsonResult(data.updateVibecontrolsCatalog);
|
|
1331
|
+
} catch (error) {
|
|
1332
|
+
ctx.logger.error("catalogs_update failed", { error });
|
|
1333
|
+
return errorResult(
|
|
1334
|
+
`Failed to update catalog: ${error instanceof Error ? error.message : String(error)}`
|
|
1335
|
+
);
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
);
|
|
1339
|
+
server.registerTool(
|
|
1340
|
+
track(mcpToolName(ctx.productName, "catalogs_delete")),
|
|
1341
|
+
{
|
|
1342
|
+
title: "Delete Catalog",
|
|
1343
|
+
description: "Soft-delete a catalog. Returns { deleted: boolean, catalogId: string }.",
|
|
1344
|
+
inputSchema: { id: z.string().describe("Catalog ID") }
|
|
1345
|
+
},
|
|
1346
|
+
async ({ id }) => {
|
|
1347
|
+
try {
|
|
1348
|
+
const data = await ctx.gql.workspace.request(
|
|
1349
|
+
DELETE_CATALOG,
|
|
1350
|
+
{ id }
|
|
1351
|
+
);
|
|
1352
|
+
return jsonResult({ deleted: data.deleteVibecontrolsCatalog, catalogId: id });
|
|
1353
|
+
} catch (error) {
|
|
1354
|
+
ctx.logger.error("catalogs_delete failed", { error });
|
|
1355
|
+
return errorResult(
|
|
1356
|
+
`Failed to delete catalog: ${error instanceof Error ? error.message : String(error)}`
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
);
|
|
1361
|
+
server.registerTool(
|
|
1362
|
+
track(mcpToolName(ctx.productName, "catalogs_add_component")),
|
|
1363
|
+
{
|
|
1364
|
+
title: "Add Component To Catalog",
|
|
1365
|
+
description: "Add a component to a catalog. Returns the membership { id, catalogId, componentId, ... }.",
|
|
1366
|
+
inputSchema: {
|
|
1367
|
+
catalogId: z.string().describe("Catalog ID"),
|
|
1368
|
+
componentId: z.string().describe("Component ID")
|
|
1369
|
+
}
|
|
1370
|
+
},
|
|
1371
|
+
async ({ catalogId, componentId }) => {
|
|
1372
|
+
try {
|
|
1373
|
+
const data = await ctx.gql.workspace.request(ADD_COMPONENT_TO_CATALOG, { catalogId, componentId });
|
|
1374
|
+
return jsonResult(data.addComponentToVibecontrolsCatalog);
|
|
1375
|
+
} catch (error) {
|
|
1376
|
+
ctx.logger.error("catalogs_add_component failed", { error });
|
|
1377
|
+
return errorResult(
|
|
1378
|
+
`Failed to add component: ${error instanceof Error ? error.message : String(error)}`
|
|
1379
|
+
);
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
);
|
|
1383
|
+
server.registerTool(
|
|
1384
|
+
track(mcpToolName(ctx.productName, "catalogs_remove_component")),
|
|
1385
|
+
{
|
|
1386
|
+
title: "Remove Component From Catalog",
|
|
1387
|
+
description: "Remove a component from a catalog. Returns { removed: boolean }.",
|
|
1388
|
+
inputSchema: {
|
|
1389
|
+
catalogId: z.string().describe("Catalog ID"),
|
|
1390
|
+
componentId: z.string().describe("Component ID")
|
|
1391
|
+
}
|
|
1392
|
+
},
|
|
1393
|
+
async ({ catalogId, componentId }) => {
|
|
1394
|
+
try {
|
|
1395
|
+
const data = await ctx.gql.workspace.request(REMOVE_COMPONENT_FROM_CATALOG, { catalogId, componentId });
|
|
1396
|
+
return jsonResult({ removed: data.removeComponentFromVibecontrolsCatalog });
|
|
1397
|
+
} catch (error) {
|
|
1398
|
+
ctx.logger.error("catalogs_remove_component failed", { error });
|
|
1399
|
+
return errorResult(
|
|
1400
|
+
`Failed to remove component: ${error instanceof Error ? error.message : String(error)}`
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
);
|
|
1405
|
+
server.registerTool(
|
|
1406
|
+
track(mcpToolName(ctx.productName, "catalogs_add_vibe")),
|
|
1407
|
+
{
|
|
1408
|
+
title: "Add Vibe To Catalog",
|
|
1409
|
+
description: "Add a vibe to a catalog. Returns the membership object.",
|
|
1410
|
+
inputSchema: {
|
|
1411
|
+
catalogId: z.string().describe("Catalog ID"),
|
|
1412
|
+
vibeId: z.string().describe("Vibe ID")
|
|
1413
|
+
}
|
|
1414
|
+
},
|
|
1415
|
+
async ({ catalogId, vibeId }) => {
|
|
1416
|
+
try {
|
|
1417
|
+
const data = await ctx.gql.workspace.request(
|
|
1418
|
+
ADD_VIBE_TO_CATALOG,
|
|
1419
|
+
{ catalogId, vibeId }
|
|
1420
|
+
);
|
|
1421
|
+
return jsonResult(data.addVibeToVibecontrolsCatalog);
|
|
1422
|
+
} catch (error) {
|
|
1423
|
+
ctx.logger.error("catalogs_add_vibe failed", { error });
|
|
1424
|
+
return errorResult(
|
|
1425
|
+
`Failed to add vibe: ${error instanceof Error ? error.message : String(error)}`
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
);
|
|
1430
|
+
server.registerTool(
|
|
1431
|
+
track(mcpToolName(ctx.productName, "catalogs_remove_vibe")),
|
|
1432
|
+
{
|
|
1433
|
+
title: "Remove Vibe From Catalog",
|
|
1434
|
+
description: "Remove a vibe from a catalog. Returns { removed: boolean }.",
|
|
1435
|
+
inputSchema: {
|
|
1436
|
+
catalogId: z.string().describe("Catalog ID"),
|
|
1437
|
+
vibeId: z.string().describe("Vibe ID")
|
|
1438
|
+
}
|
|
1439
|
+
},
|
|
1440
|
+
async ({ catalogId, vibeId }) => {
|
|
1441
|
+
try {
|
|
1442
|
+
const data = await ctx.gql.workspace.request(REMOVE_VIBE_FROM_CATALOG, { catalogId, vibeId });
|
|
1443
|
+
return jsonResult({ removed: data.removeVibeFromVibecontrolsCatalog });
|
|
1444
|
+
} catch (error) {
|
|
1445
|
+
ctx.logger.error("catalogs_remove_vibe failed", { error });
|
|
1446
|
+
return errorResult(
|
|
1447
|
+
`Failed to remove vibe: ${error instanceof Error ? error.message : String(error)}`
|
|
1448
|
+
);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
);
|
|
1452
|
+
}
|
|
1453
|
+
var ComponentTypeEnum = z.enum([
|
|
1454
|
+
"API",
|
|
1455
|
+
"CUSTOM",
|
|
1456
|
+
"DATABASE",
|
|
1457
|
+
"DEPENDENCY",
|
|
1458
|
+
"DOCUMENTATION",
|
|
1459
|
+
"FRONTEND",
|
|
1460
|
+
"INFRASTRUCTURE",
|
|
1461
|
+
"JOB",
|
|
1462
|
+
"LIBRARY",
|
|
1463
|
+
"PACKAGE",
|
|
1464
|
+
"SERVICE",
|
|
1465
|
+
"TOOL",
|
|
1466
|
+
"WORKFLOW"
|
|
1467
|
+
]);
|
|
1468
|
+
var LifecycleEnum = z.enum(["ACTIVE", "DEPRECATED", "END_OF_LIFE", "EXPERIMENTAL"]);
|
|
1469
|
+
var TemplateCategoryEnum = z.enum([
|
|
1470
|
+
"BACKEND",
|
|
1471
|
+
"CUSTOM",
|
|
1472
|
+
"FRONTEND",
|
|
1473
|
+
"FULLSTACK",
|
|
1474
|
+
"INFRASTRUCTURE",
|
|
1475
|
+
"LIBRARY",
|
|
1476
|
+
"MICROSERVICE",
|
|
1477
|
+
"STARTER"
|
|
1478
|
+
]);
|
|
1479
|
+
var ScopeEnum = z.enum(["ORG", "USER"]);
|
|
1480
|
+
function registerComponentTools(server, ctx, track) {
|
|
1481
|
+
server.registerTool(
|
|
1482
|
+
track(mcpToolName(ctx.productName, "components_list")),
|
|
1483
|
+
{
|
|
1484
|
+
title: "List Components",
|
|
1485
|
+
description: "List software components. Returns { items, total, hasMore }.",
|
|
1486
|
+
inputSchema: {
|
|
1487
|
+
search: z.string().optional().describe("Search by name/description"),
|
|
1488
|
+
type: ComponentTypeEnum.optional().describe("Filter by component type"),
|
|
1489
|
+
lifecycle: LifecycleEnum.optional().describe("Filter by lifecycle stage"),
|
|
1490
|
+
teamId: z.string().optional().describe("Filter by team ID"),
|
|
1491
|
+
tags: z.array(z.string()).optional().describe("Filter by tags (any)"),
|
|
1492
|
+
limit: z.number().optional().describe("Max results"),
|
|
1493
|
+
offset: z.number().optional().describe("Pagination offset")
|
|
1494
|
+
}
|
|
1495
|
+
},
|
|
1496
|
+
async ({ search, type, lifecycle, teamId, tags, limit, offset }) => {
|
|
1497
|
+
try {
|
|
1498
|
+
const filter = {};
|
|
1499
|
+
if (search !== void 0) filter.search = search;
|
|
1500
|
+
if (type !== void 0) filter.type = type;
|
|
1501
|
+
if (lifecycle !== void 0) filter.lifecycle = lifecycle;
|
|
1502
|
+
if (teamId !== void 0) filter.teamId = teamId;
|
|
1503
|
+
if (tags !== void 0) filter.tags = tags;
|
|
1504
|
+
const pagination = {};
|
|
1505
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
1506
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
1507
|
+
const data = await ctx.gql.workspace.request(
|
|
1508
|
+
LIST_COMPONENTS,
|
|
1509
|
+
{
|
|
1510
|
+
filter: Object.keys(filter).length ? filter : void 0,
|
|
1511
|
+
pagination: Object.keys(pagination).length ? pagination : void 0
|
|
1512
|
+
}
|
|
1513
|
+
);
|
|
1514
|
+
return jsonResult(data.vibecontrolsComponents);
|
|
1515
|
+
} catch (error) {
|
|
1516
|
+
ctx.logger.error("components_list failed", { error });
|
|
1517
|
+
return errorResult(
|
|
1518
|
+
`Failed to list components: ${error instanceof Error ? error.message : String(error)}`
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
);
|
|
1523
|
+
server.registerTool(
|
|
1524
|
+
track(mcpToolName(ctx.productName, "components_get")),
|
|
1525
|
+
{
|
|
1526
|
+
title: "Get Component",
|
|
1527
|
+
description: "Get a component by ID. Returns the component object or null.",
|
|
1528
|
+
inputSchema: { id: z.string().describe("Component ID") }
|
|
1529
|
+
},
|
|
1530
|
+
async ({ id }) => {
|
|
1531
|
+
try {
|
|
1532
|
+
const data = await ctx.gql.workspace.request(
|
|
1533
|
+
GET_COMPONENT,
|
|
1534
|
+
{ id }
|
|
1535
|
+
);
|
|
1536
|
+
return jsonResult(data.vibecontrolsComponent);
|
|
1537
|
+
} catch (error) {
|
|
1538
|
+
ctx.logger.error("components_get failed", { error });
|
|
1539
|
+
return errorResult(
|
|
1540
|
+
`Failed to get component: ${error instanceof Error ? error.message : String(error)}`
|
|
1541
|
+
);
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
);
|
|
1545
|
+
server.registerTool(
|
|
1546
|
+
track(mcpToolName(ctx.productName, "components_create")),
|
|
1547
|
+
{
|
|
1548
|
+
title: "Create Component",
|
|
1549
|
+
description: "Create a new component. Returns the created component.",
|
|
1550
|
+
inputSchema: {
|
|
1551
|
+
name: z.string().describe("Component name"),
|
|
1552
|
+
description: z.string().optional().describe("Description"),
|
|
1553
|
+
type: ComponentTypeEnum.optional().describe("Component type"),
|
|
1554
|
+
lifecycle: LifecycleEnum.optional().describe("Lifecycle stage"),
|
|
1555
|
+
version: z.string().optional().describe("Semantic version"),
|
|
1556
|
+
language: z.string().optional().describe("Primary language"),
|
|
1557
|
+
framework: z.string().optional().describe("Primary framework"),
|
|
1558
|
+
repositoryUrl: z.string().optional().describe("Source repository URL"),
|
|
1559
|
+
documentationUrl: z.string().optional().describe("Documentation URL"),
|
|
1560
|
+
ownerId: z.string().optional().describe("Owner actor ID"),
|
|
1561
|
+
ownerName: z.string().optional().describe("Owner display name"),
|
|
1562
|
+
teamId: z.string().optional().describe("Team ID"),
|
|
1563
|
+
teamName: z.string().optional().describe("Team display name"),
|
|
1564
|
+
tags: z.array(z.string()).optional().describe("Tags")
|
|
1565
|
+
}
|
|
1566
|
+
},
|
|
1567
|
+
async (args) => {
|
|
1568
|
+
try {
|
|
1569
|
+
const input = { name: args.name };
|
|
1570
|
+
for (const k of [
|
|
1571
|
+
"description",
|
|
1572
|
+
"type",
|
|
1573
|
+
"lifecycle",
|
|
1574
|
+
"version",
|
|
1575
|
+
"language",
|
|
1576
|
+
"framework",
|
|
1577
|
+
"repositoryUrl",
|
|
1578
|
+
"documentationUrl",
|
|
1579
|
+
"ownerId",
|
|
1580
|
+
"ownerName",
|
|
1581
|
+
"teamId",
|
|
1582
|
+
"teamName",
|
|
1583
|
+
"tags"
|
|
1584
|
+
]) {
|
|
1585
|
+
const v = args[k];
|
|
1586
|
+
if (v !== void 0) input[k] = v;
|
|
1587
|
+
}
|
|
1588
|
+
const data = await ctx.gql.workspace.request(
|
|
1589
|
+
CREATE_COMPONENT,
|
|
1590
|
+
{ input }
|
|
1591
|
+
);
|
|
1592
|
+
return jsonResult(data.createVibecontrolsComponent);
|
|
1593
|
+
} catch (error) {
|
|
1594
|
+
ctx.logger.error("components_create failed", { error });
|
|
1595
|
+
return errorResult(
|
|
1596
|
+
`Failed to create component: ${error instanceof Error ? error.message : String(error)}`
|
|
1597
|
+
);
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
);
|
|
1601
|
+
server.registerTool(
|
|
1602
|
+
track(mcpToolName(ctx.productName, "components_update")),
|
|
1603
|
+
{
|
|
1604
|
+
title: "Update Component",
|
|
1605
|
+
description: "Update an existing component. Returns the updated component.",
|
|
1606
|
+
inputSchema: {
|
|
1607
|
+
id: z.string().describe("Component ID"),
|
|
1608
|
+
name: z.string().optional().describe("Name"),
|
|
1609
|
+
description: z.string().optional().describe("Description"),
|
|
1610
|
+
lifecycle: LifecycleEnum.optional().describe("Lifecycle"),
|
|
1611
|
+
version: z.string().optional().describe("Version"),
|
|
1612
|
+
repositoryUrl: z.string().optional().describe("Repository URL"),
|
|
1613
|
+
documentationUrl: z.string().optional().describe("Documentation URL"),
|
|
1614
|
+
tags: z.array(z.string()).optional().describe("Tags")
|
|
1615
|
+
}
|
|
1616
|
+
},
|
|
1617
|
+
async ({
|
|
1618
|
+
id,
|
|
1619
|
+
name,
|
|
1620
|
+
description,
|
|
1621
|
+
lifecycle,
|
|
1622
|
+
version,
|
|
1623
|
+
repositoryUrl,
|
|
1624
|
+
documentationUrl,
|
|
1625
|
+
tags
|
|
1626
|
+
}) => {
|
|
1627
|
+
try {
|
|
1628
|
+
const input = {};
|
|
1629
|
+
if (name !== void 0) input.name = name;
|
|
1630
|
+
if (description !== void 0) input.description = description;
|
|
1631
|
+
if (lifecycle !== void 0) input.lifecycle = lifecycle;
|
|
1632
|
+
if (version !== void 0) input.version = version;
|
|
1633
|
+
if (repositoryUrl !== void 0) input.repositoryUrl = repositoryUrl;
|
|
1634
|
+
if (documentationUrl !== void 0) input.documentationUrl = documentationUrl;
|
|
1635
|
+
if (tags !== void 0) input.tags = tags;
|
|
1636
|
+
const data = await ctx.gql.workspace.request(
|
|
1637
|
+
UPDATE_COMPONENT,
|
|
1638
|
+
{ id, input }
|
|
1639
|
+
);
|
|
1640
|
+
return jsonResult(data.updateVibecontrolsComponent);
|
|
1641
|
+
} catch (error) {
|
|
1642
|
+
ctx.logger.error("components_update failed", { error });
|
|
1643
|
+
return errorResult(
|
|
1644
|
+
`Failed to update component: ${error instanceof Error ? error.message : String(error)}`
|
|
1645
|
+
);
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
);
|
|
1649
|
+
server.registerTool(
|
|
1650
|
+
track(mcpToolName(ctx.productName, "components_delete")),
|
|
1651
|
+
{
|
|
1652
|
+
title: "Delete Component",
|
|
1653
|
+
description: "Soft-delete a component. Returns { deleted, componentId }.",
|
|
1654
|
+
inputSchema: { id: z.string().describe("Component ID") }
|
|
1655
|
+
},
|
|
1656
|
+
async ({ id }) => {
|
|
1657
|
+
try {
|
|
1658
|
+
const data = await ctx.gql.workspace.request(
|
|
1659
|
+
DELETE_COMPONENT,
|
|
1660
|
+
{ id }
|
|
1661
|
+
);
|
|
1662
|
+
return jsonResult({ deleted: data.deleteVibecontrolsComponent, componentId: id });
|
|
1663
|
+
} catch (error) {
|
|
1664
|
+
ctx.logger.error("components_delete failed", { error });
|
|
1665
|
+
return errorResult(
|
|
1666
|
+
`Failed to delete component: ${error instanceof Error ? error.message : String(error)}`
|
|
1667
|
+
);
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
);
|
|
1671
|
+
server.registerTool(
|
|
1672
|
+
track(mcpToolName(ctx.productName, "components_fork_git_hub_repo")),
|
|
1673
|
+
{
|
|
1674
|
+
title: "Fork GitHub Repo",
|
|
1675
|
+
description: "Fork or create a GitHub repo for component setup. Returns { isForked, repoFullName, repoUrl }.",
|
|
1676
|
+
inputSchema: {
|
|
1677
|
+
repoName: z.string().describe("Name of the new repository"),
|
|
1678
|
+
scope: ScopeEnum.describe("USER or ORG"),
|
|
1679
|
+
orgName: z.string().optional().describe("Org name (required when scope=ORG)"),
|
|
1680
|
+
sourceRepoUrl: z.string().optional().describe("Source repo URL to fork"),
|
|
1681
|
+
description: z.string().optional().describe("Repository description"),
|
|
1682
|
+
connectionId: z.string().optional().describe("OAuth connection ID"),
|
|
1683
|
+
token: z.string().optional().describe("Personal access token (if no connection)")
|
|
1684
|
+
}
|
|
1685
|
+
},
|
|
1686
|
+
async (args) => {
|
|
1687
|
+
try {
|
|
1688
|
+
const input = { repoName: args.repoName, scope: args.scope };
|
|
1689
|
+
for (const k of [
|
|
1690
|
+
"orgName",
|
|
1691
|
+
"sourceRepoUrl",
|
|
1692
|
+
"description",
|
|
1693
|
+
"connectionId",
|
|
1694
|
+
"token"
|
|
1695
|
+
]) {
|
|
1696
|
+
const v = args[k];
|
|
1697
|
+
if (v !== void 0) input[k] = v;
|
|
1698
|
+
}
|
|
1699
|
+
const data = await ctx.gql.workspace.request(
|
|
1700
|
+
FORK_GITHUB_REPO,
|
|
1701
|
+
{ input }
|
|
1702
|
+
);
|
|
1703
|
+
return jsonResult(data.forkVibecontrolsGitHubRepo);
|
|
1704
|
+
} catch (error) {
|
|
1705
|
+
ctx.logger.error("components_fork_github_repo failed", { error });
|
|
1706
|
+
return errorResult(
|
|
1707
|
+
`Failed to fork repo: ${error instanceof Error ? error.message : String(error)}`
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
);
|
|
1712
|
+
server.registerTool(
|
|
1713
|
+
track(mcpToolName(ctx.productName, "components_publish_as_template")),
|
|
1714
|
+
{
|
|
1715
|
+
title: "Publish Component As Template",
|
|
1716
|
+
description: "Publish a component as a reusable template (snapshots the component). Returns the created template.",
|
|
1717
|
+
inputSchema: {
|
|
1718
|
+
componentId: z.string().describe("Source component ID"),
|
|
1719
|
+
name: z.string().describe("Template name"),
|
|
1720
|
+
description: z.string().optional().describe("Description"),
|
|
1721
|
+
category: TemplateCategoryEnum.optional().describe("Category"),
|
|
1722
|
+
version: z.string().optional().describe("Version"),
|
|
1723
|
+
setupInstructions: z.string().optional().describe("Markdown setup instructions"),
|
|
1724
|
+
sourceRepositoryUrl: z.string().optional().describe("Source repository URL"),
|
|
1725
|
+
tags: z.array(z.string()).optional().describe("Tags")
|
|
1726
|
+
}
|
|
1727
|
+
},
|
|
1728
|
+
async ({
|
|
1729
|
+
componentId,
|
|
1730
|
+
name,
|
|
1731
|
+
description,
|
|
1732
|
+
category,
|
|
1733
|
+
version,
|
|
1734
|
+
setupInstructions,
|
|
1735
|
+
sourceRepositoryUrl,
|
|
1736
|
+
tags
|
|
1737
|
+
}) => {
|
|
1738
|
+
try {
|
|
1739
|
+
const input = { name };
|
|
1740
|
+
if (description !== void 0) input.description = description;
|
|
1741
|
+
if (category !== void 0) input.category = category;
|
|
1742
|
+
if (version !== void 0) input.version = version;
|
|
1743
|
+
if (setupInstructions !== void 0) input.setupInstructions = setupInstructions;
|
|
1744
|
+
if (sourceRepositoryUrl !== void 0) input.sourceRepositoryUrl = sourceRepositoryUrl;
|
|
1745
|
+
if (tags !== void 0) input.tags = tags;
|
|
1746
|
+
const data = await ctx.gql.workspace.request(PUBLISH_COMPONENT_AS_TEMPLATE, { componentId, input });
|
|
1747
|
+
return jsonResult(data.publishVibecontrolsComponentAsTemplate);
|
|
1748
|
+
} catch (error) {
|
|
1749
|
+
ctx.logger.error("components_publish_as_template failed", { error });
|
|
1750
|
+
return errorResult(
|
|
1751
|
+
`Failed to publish template: ${error instanceof Error ? error.message : String(error)}`
|
|
1752
|
+
);
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
);
|
|
1756
|
+
}
|
|
1757
|
+
var OwnerTypeEnum = z.enum(["CATALOG", "COMPONENT", "VIBE"]);
|
|
1758
|
+
var MetricStatusEnum = z.enum(["FAILING", "PASSING", "UNKNOWN", "WARNING"]);
|
|
1759
|
+
var MetricTypeEnum = z.enum([
|
|
1760
|
+
"CICD_HEALTH",
|
|
1761
|
+
"CUSTOM",
|
|
1762
|
+
"DEPENDENCY_FRESHNESS",
|
|
1763
|
+
"DOCUMENTATION_COVERAGE",
|
|
1764
|
+
"INCIDENT_COUNT",
|
|
1765
|
+
"SECURITY_SCORE",
|
|
1766
|
+
"SLO_COMPLIANCE",
|
|
1767
|
+
"TEST_COVERAGE"
|
|
1768
|
+
]);
|
|
1769
|
+
function registerScorecardTools(server, ctx, track) {
|
|
1770
|
+
server.registerTool(
|
|
1771
|
+
track(mcpToolName(ctx.productName, "scorecards_get")),
|
|
1772
|
+
{
|
|
1773
|
+
title: "Get Scorecard",
|
|
1774
|
+
description: "Get the scorecard for an owner entity (catalog/component/vibe). Returns the scorecard with metrics or null.",
|
|
1775
|
+
inputSchema: {
|
|
1776
|
+
ownerId: z.string().describe("Owner entity ID"),
|
|
1777
|
+
ownerType: OwnerTypeEnum.describe("Owner entity type")
|
|
1778
|
+
}
|
|
1779
|
+
},
|
|
1780
|
+
async ({ ownerId, ownerType }) => {
|
|
1781
|
+
try {
|
|
1782
|
+
const data = await ctx.gql.workspace.request(
|
|
1783
|
+
GET_SCORECARD,
|
|
1784
|
+
{ ownerId, ownerType }
|
|
1785
|
+
);
|
|
1786
|
+
return jsonResult(data.vibecontrolsScorecard);
|
|
1787
|
+
} catch (error) {
|
|
1788
|
+
ctx.logger.error("scorecards_get failed", { error });
|
|
1789
|
+
return errorResult(
|
|
1790
|
+
`Failed to get scorecard: ${error instanceof Error ? error.message : String(error)}`
|
|
1791
|
+
);
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
);
|
|
1795
|
+
server.registerTool(
|
|
1796
|
+
track(mcpToolName(ctx.productName, "scorecards_upsert")),
|
|
1797
|
+
{
|
|
1798
|
+
title: "Upsert Scorecard",
|
|
1799
|
+
description: "Create or update a scorecard for an owner. Returns the scorecard.",
|
|
1800
|
+
inputSchema: {
|
|
1801
|
+
ownerId: z.string().describe("Owner entity ID"),
|
|
1802
|
+
ownerType: OwnerTypeEnum.describe("Owner entity type")
|
|
1803
|
+
}
|
|
1804
|
+
},
|
|
1805
|
+
async ({ ownerId, ownerType }) => {
|
|
1806
|
+
try {
|
|
1807
|
+
const data = await ctx.gql.workspace.request(UPSERT_SCORECARD, { input: { ownerId, ownerType } });
|
|
1808
|
+
return jsonResult(data.upsertVibecontrolsScorecard);
|
|
1809
|
+
} catch (error) {
|
|
1810
|
+
ctx.logger.error("scorecards_upsert failed", { error });
|
|
1811
|
+
return errorResult(
|
|
1812
|
+
`Failed to upsert scorecard: ${error instanceof Error ? error.message : String(error)}`
|
|
1813
|
+
);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
);
|
|
1817
|
+
server.registerTool(
|
|
1818
|
+
track(mcpToolName(ctx.productName, "scorecards_add_metric")),
|
|
1819
|
+
{
|
|
1820
|
+
title: "Add Scorecard Metric",
|
|
1821
|
+
description: "Add a new metric to a scorecard. Returns the created metric.",
|
|
1822
|
+
inputSchema: {
|
|
1823
|
+
scorecardId: z.string().describe("Scorecard ID"),
|
|
1824
|
+
name: z.string().describe("Metric display name (unique within scorecard)"),
|
|
1825
|
+
description: z.string().optional().describe("Human-readable description"),
|
|
1826
|
+
type: MetricTypeEnum.optional().describe("Metric classification"),
|
|
1827
|
+
status: MetricStatusEnum.optional().describe("Current status"),
|
|
1828
|
+
value: z.number().optional().describe("Current metric value"),
|
|
1829
|
+
threshold: z.number().optional().describe("Target threshold"),
|
|
1830
|
+
unit: z.string().optional().describe("Unit of measurement (%, count, ms, ...)"),
|
|
1831
|
+
iframeUrl: z.string().optional().describe("Optional iframe embed URL"),
|
|
1832
|
+
iframeHeight: z.number().optional().describe("Iframe height in pixels")
|
|
1833
|
+
}
|
|
1834
|
+
},
|
|
1835
|
+
async (args) => {
|
|
1836
|
+
try {
|
|
1837
|
+
const input = { name: args.name };
|
|
1838
|
+
for (const k of [
|
|
1839
|
+
"description",
|
|
1840
|
+
"type",
|
|
1841
|
+
"status",
|
|
1842
|
+
"value",
|
|
1843
|
+
"threshold",
|
|
1844
|
+
"unit",
|
|
1845
|
+
"iframeUrl",
|
|
1846
|
+
"iframeHeight"
|
|
1847
|
+
]) {
|
|
1848
|
+
const v = args[k];
|
|
1849
|
+
if (v !== void 0) input[k] = v;
|
|
1850
|
+
}
|
|
1851
|
+
const data = await ctx.gql.workspace.request(ADD_SCORECARD_METRIC, { scorecardId: args.scorecardId, input });
|
|
1852
|
+
return jsonResult(data.addVibecontrolsScorecardMetric);
|
|
1853
|
+
} catch (error) {
|
|
1854
|
+
ctx.logger.error("scorecards_add_metric failed", { error });
|
|
1855
|
+
return errorResult(
|
|
1856
|
+
`Failed to add metric: ${error instanceof Error ? error.message : String(error)}`
|
|
1857
|
+
);
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
);
|
|
1861
|
+
server.registerTool(
|
|
1862
|
+
track(mcpToolName(ctx.productName, "scorecards_update_metric")),
|
|
1863
|
+
{
|
|
1864
|
+
title: "Update Scorecard Metric",
|
|
1865
|
+
description: "Update an existing scorecard metric. Returns the updated metric.",
|
|
1866
|
+
inputSchema: {
|
|
1867
|
+
id: z.string().describe("Metric ID"),
|
|
1868
|
+
name: z.string().optional().describe("Name"),
|
|
1869
|
+
description: z.string().optional().describe("Description"),
|
|
1870
|
+
type: MetricTypeEnum.optional().describe("Type"),
|
|
1871
|
+
status: MetricStatusEnum.optional().describe("Status"),
|
|
1872
|
+
value: z.number().optional().describe("Current value"),
|
|
1873
|
+
threshold: z.number().optional().describe("Threshold"),
|
|
1874
|
+
unit: z.string().optional().describe("Unit"),
|
|
1875
|
+
iframeUrl: z.string().optional().describe("Iframe URL"),
|
|
1876
|
+
iframeHeight: z.number().optional().describe("Iframe height")
|
|
1877
|
+
}
|
|
1878
|
+
},
|
|
1879
|
+
async (args) => {
|
|
1880
|
+
try {
|
|
1881
|
+
const input = {};
|
|
1882
|
+
for (const k of [
|
|
1883
|
+
"name",
|
|
1884
|
+
"description",
|
|
1885
|
+
"type",
|
|
1886
|
+
"status",
|
|
1887
|
+
"value",
|
|
1888
|
+
"threshold",
|
|
1889
|
+
"unit",
|
|
1890
|
+
"iframeUrl",
|
|
1891
|
+
"iframeHeight"
|
|
1892
|
+
]) {
|
|
1893
|
+
const v = args[k];
|
|
1894
|
+
if (v !== void 0) input[k] = v;
|
|
1895
|
+
}
|
|
1896
|
+
const data = await ctx.gql.workspace.request(UPDATE_SCORECARD_METRIC, { id: args.id, input });
|
|
1897
|
+
return jsonResult(data.updateVibecontrolsScorecardMetric);
|
|
1898
|
+
} catch (error) {
|
|
1899
|
+
ctx.logger.error("scorecards_update_metric failed", { error });
|
|
1900
|
+
return errorResult(
|
|
1901
|
+
`Failed to update metric: ${error instanceof Error ? error.message : String(error)}`
|
|
1902
|
+
);
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
);
|
|
1906
|
+
server.registerTool(
|
|
1907
|
+
track(mcpToolName(ctx.productName, "scorecards_remove_metric")),
|
|
1908
|
+
{
|
|
1909
|
+
title: "Remove Scorecard Metric",
|
|
1910
|
+
description: "Soft-delete a scorecard metric. Returns { removed: boolean, metricId }.",
|
|
1911
|
+
inputSchema: { id: z.string().describe("Metric ID") }
|
|
1912
|
+
},
|
|
1913
|
+
async ({ id }) => {
|
|
1914
|
+
try {
|
|
1915
|
+
const data = await ctx.gql.workspace.request(REMOVE_SCORECARD_METRIC, { id });
|
|
1916
|
+
return jsonResult({
|
|
1917
|
+
removed: data.removeVibecontrolsScorecardMetric,
|
|
1918
|
+
metricId: id
|
|
1919
|
+
});
|
|
1920
|
+
} catch (error) {
|
|
1921
|
+
ctx.logger.error("scorecards_remove_metric failed", { error });
|
|
1922
|
+
return errorResult(
|
|
1923
|
+
`Failed to remove metric: ${error instanceof Error ? error.message : String(error)}`
|
|
1924
|
+
);
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
);
|
|
1928
|
+
}
|
|
1929
|
+
var TemplateCategoryEnum2 = z.enum([
|
|
1930
|
+
"BACKEND",
|
|
1931
|
+
"CUSTOM",
|
|
1932
|
+
"FRONTEND",
|
|
1933
|
+
"FULLSTACK",
|
|
1934
|
+
"INFRASTRUCTURE",
|
|
1935
|
+
"LIBRARY",
|
|
1936
|
+
"MICROSERVICE",
|
|
1937
|
+
"STARTER"
|
|
1938
|
+
]);
|
|
1939
|
+
var TemplateStatusEnum = z.enum(["ARCHIVED", "DRAFT", "PUBLISHED"]);
|
|
1940
|
+
function registerTemplateTools(server, ctx, track) {
|
|
1941
|
+
server.registerTool(
|
|
1942
|
+
track(mcpToolName(ctx.productName, "templates_list")),
|
|
1943
|
+
{
|
|
1944
|
+
title: "List Templates",
|
|
1945
|
+
description: "List reusable component templates. Returns { items, total, hasMore }.",
|
|
1946
|
+
inputSchema: {
|
|
1947
|
+
search: z.string().optional().describe("Search by name/description"),
|
|
1948
|
+
category: TemplateCategoryEnum2.optional().describe("Filter by category"),
|
|
1949
|
+
status: TemplateStatusEnum.optional().describe("Filter by status"),
|
|
1950
|
+
tags: z.array(z.string()).optional().describe("Filter by tags"),
|
|
1951
|
+
limit: z.number().optional().describe("Max results"),
|
|
1952
|
+
offset: z.number().optional().describe("Pagination offset")
|
|
1953
|
+
}
|
|
1954
|
+
},
|
|
1955
|
+
async ({ search, category, status, tags, limit, offset }) => {
|
|
1956
|
+
try {
|
|
1957
|
+
const filter = {};
|
|
1958
|
+
if (search !== void 0) filter.search = search;
|
|
1959
|
+
if (category !== void 0) filter.category = category;
|
|
1960
|
+
if (status !== void 0) filter.status = status;
|
|
1961
|
+
if (tags !== void 0) filter.tags = tags;
|
|
1962
|
+
const pagination = {};
|
|
1963
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
1964
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
1965
|
+
const data = await ctx.gql.workspace.request(
|
|
1966
|
+
LIST_TEMPLATES,
|
|
1967
|
+
{
|
|
1968
|
+
filter: Object.keys(filter).length ? filter : void 0,
|
|
1969
|
+
pagination: Object.keys(pagination).length ? pagination : void 0
|
|
1970
|
+
}
|
|
1971
|
+
);
|
|
1972
|
+
return jsonResult(data.vibecontrolsTemplates);
|
|
1973
|
+
} catch (error) {
|
|
1974
|
+
ctx.logger.error("templates_list failed", { error });
|
|
1975
|
+
return errorResult(
|
|
1976
|
+
`Failed to list templates: ${error instanceof Error ? error.message : String(error)}`
|
|
1977
|
+
);
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
);
|
|
1981
|
+
server.registerTool(
|
|
1982
|
+
track(mcpToolName(ctx.productName, "templates_get")),
|
|
1983
|
+
{
|
|
1984
|
+
title: "Get Template",
|
|
1985
|
+
description: "Get a template by ID. Returns the template object or null.",
|
|
1986
|
+
inputSchema: { id: z.string().describe("Template ID") }
|
|
1987
|
+
},
|
|
1988
|
+
async ({ id }) => {
|
|
1989
|
+
try {
|
|
1990
|
+
const data = await ctx.gql.workspace.request(
|
|
1991
|
+
GET_TEMPLATE,
|
|
1992
|
+
{ id }
|
|
1993
|
+
);
|
|
1994
|
+
return jsonResult(data.vibecontrolsTemplate);
|
|
1995
|
+
} catch (error) {
|
|
1996
|
+
ctx.logger.error("templates_get failed", { error });
|
|
1997
|
+
return errorResult(
|
|
1998
|
+
`Failed to get template: ${error instanceof Error ? error.message : String(error)}`
|
|
1999
|
+
);
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
);
|
|
2003
|
+
server.registerTool(
|
|
2004
|
+
track(mcpToolName(ctx.productName, "templates_update")),
|
|
2005
|
+
{
|
|
2006
|
+
title: "Update Template",
|
|
2007
|
+
description: "Update an existing template. Returns the updated template.",
|
|
2008
|
+
inputSchema: {
|
|
2009
|
+
id: z.string().describe("Template ID"),
|
|
2010
|
+
name: z.string().optional().describe("Name"),
|
|
2011
|
+
description: z.string().optional().describe("Description"),
|
|
2012
|
+
category: TemplateCategoryEnum2.optional().describe("Category"),
|
|
2013
|
+
status: TemplateStatusEnum.optional().describe("Status"),
|
|
2014
|
+
version: z.string().optional().describe("Version"),
|
|
2015
|
+
setupInstructions: z.string().optional().describe("Markdown setup instructions"),
|
|
2016
|
+
sourceRepositoryUrl: z.string().optional().describe("Source repository URL"),
|
|
2017
|
+
tags: z.array(z.string()).optional().describe("Tags")
|
|
2018
|
+
}
|
|
2019
|
+
},
|
|
2020
|
+
async ({
|
|
2021
|
+
id,
|
|
2022
|
+
name,
|
|
2023
|
+
description,
|
|
2024
|
+
category,
|
|
2025
|
+
status,
|
|
2026
|
+
version,
|
|
2027
|
+
setupInstructions,
|
|
2028
|
+
sourceRepositoryUrl,
|
|
2029
|
+
tags
|
|
2030
|
+
}) => {
|
|
2031
|
+
try {
|
|
2032
|
+
const input = {};
|
|
2033
|
+
if (name !== void 0) input.name = name;
|
|
2034
|
+
if (description !== void 0) input.description = description;
|
|
2035
|
+
if (category !== void 0) input.category = category;
|
|
2036
|
+
if (status !== void 0) input.status = status;
|
|
2037
|
+
if (version !== void 0) input.version = version;
|
|
2038
|
+
if (setupInstructions !== void 0) input.setupInstructions = setupInstructions;
|
|
2039
|
+
if (sourceRepositoryUrl !== void 0) input.sourceRepositoryUrl = sourceRepositoryUrl;
|
|
2040
|
+
if (tags !== void 0) input.tags = tags;
|
|
2041
|
+
const data = await ctx.gql.workspace.request(
|
|
2042
|
+
UPDATE_TEMPLATE,
|
|
2043
|
+
{ id, input }
|
|
2044
|
+
);
|
|
2045
|
+
return jsonResult(data.updateVibecontrolsTemplate);
|
|
2046
|
+
} catch (error) {
|
|
2047
|
+
ctx.logger.error("templates_update failed", { error });
|
|
2048
|
+
return errorResult(
|
|
2049
|
+
`Failed to update template: ${error instanceof Error ? error.message : String(error)}`
|
|
2050
|
+
);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
);
|
|
2054
|
+
server.registerTool(
|
|
2055
|
+
track(mcpToolName(ctx.productName, "templates_delete")),
|
|
2056
|
+
{
|
|
2057
|
+
title: "Delete Template",
|
|
2058
|
+
description: "Soft-delete a template. Returns { deleted, templateId }.",
|
|
2059
|
+
inputSchema: { id: z.string().describe("Template ID") }
|
|
2060
|
+
},
|
|
2061
|
+
async ({ id }) => {
|
|
2062
|
+
try {
|
|
2063
|
+
const data = await ctx.gql.workspace.request(
|
|
2064
|
+
DELETE_TEMPLATE,
|
|
2065
|
+
{ id }
|
|
2066
|
+
);
|
|
2067
|
+
return jsonResult({ deleted: data.deleteVibecontrolsTemplate, templateId: id });
|
|
2068
|
+
} catch (error) {
|
|
2069
|
+
ctx.logger.error("templates_delete failed", { error });
|
|
2070
|
+
return errorResult(
|
|
2071
|
+
`Failed to delete template: ${error instanceof Error ? error.message : String(error)}`
|
|
2072
|
+
);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
);
|
|
2076
|
+
server.registerTool(
|
|
2077
|
+
track(mcpToolName(ctx.productName, "templates_instantiate")),
|
|
2078
|
+
{
|
|
2079
|
+
title: "Instantiate Template",
|
|
2080
|
+
description: "Create a new component from a template. Returns the new component.",
|
|
2081
|
+
inputSchema: {
|
|
2082
|
+
templateId: z.string().describe("Template ID"),
|
|
2083
|
+
name: z.string().describe("Name for the new component"),
|
|
2084
|
+
description: z.string().optional().describe("Description for the new component"),
|
|
2085
|
+
workspaceId: z.string().optional().describe("Target workspace (defaults to current)"),
|
|
2086
|
+
variableValues: z.record(z.unknown()).optional().describe("Variable value overrides as a JSON object")
|
|
2087
|
+
}
|
|
2088
|
+
},
|
|
2089
|
+
async ({ templateId, name, description, workspaceId, variableValues }) => {
|
|
2090
|
+
try {
|
|
2091
|
+
const input = { name };
|
|
2092
|
+
if (description !== void 0) input.description = description;
|
|
2093
|
+
if (workspaceId !== void 0) input.workspaceId = workspaceId;
|
|
2094
|
+
if (variableValues !== void 0) input.variableValues = variableValues;
|
|
2095
|
+
const data = await ctx.gql.workspace.request(INSTANTIATE_TEMPLATE, { templateId, input });
|
|
2096
|
+
return jsonResult(data.instantiateVibecontrolsTemplate);
|
|
2097
|
+
} catch (error) {
|
|
2098
|
+
ctx.logger.error("templates_instantiate failed", { error });
|
|
2099
|
+
return errorResult(
|
|
2100
|
+
`Failed to instantiate template: ${error instanceof Error ? error.message : String(error)}`
|
|
2101
|
+
);
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
);
|
|
2105
|
+
}
|
|
2106
|
+
function registerAiEventTools(server, ctx, track) {
|
|
2107
|
+
server.registerTool(
|
|
2108
|
+
track(mcpToolName(ctx.productName, "ai_events_list")),
|
|
2109
|
+
{
|
|
2110
|
+
title: "List AI Tool Events",
|
|
2111
|
+
description: "List AI tool events with optional filters and pagination.",
|
|
2112
|
+
inputSchema: {
|
|
2113
|
+
source: z.string().optional().describe("Filter by event source"),
|
|
2114
|
+
eventType: z.string().optional().describe("Filter by event type"),
|
|
2115
|
+
agentId: z.string().optional().describe("Filter by agent ID"),
|
|
2116
|
+
limit: z.number().optional().describe("Max results"),
|
|
2117
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
2118
|
+
}
|
|
2119
|
+
},
|
|
2120
|
+
async ({ source, eventType, agentId, limit, offset }) => {
|
|
2121
|
+
try {
|
|
2122
|
+
const filter = {};
|
|
2123
|
+
if (source !== void 0) filter.source = source;
|
|
2124
|
+
if (eventType !== void 0) filter.eventType = eventType;
|
|
2125
|
+
if (agentId !== void 0) filter.agentId = agentId;
|
|
2126
|
+
const pagination = {};
|
|
2127
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
2128
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
2129
|
+
const data = await ctx.gql.workspace.request(
|
|
2130
|
+
LIST_AI_TOOL_EVENTS,
|
|
2131
|
+
{
|
|
2132
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
2133
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
2134
|
+
}
|
|
2135
|
+
);
|
|
2136
|
+
return jsonResult(data.aiToolEvents);
|
|
2137
|
+
} catch (error) {
|
|
2138
|
+
ctx.logger.error("vibecontrols_ai_events_list failed", { error });
|
|
2139
|
+
return errorResult(
|
|
2140
|
+
`Failed to list AI events: ${error instanceof Error ? error.message : String(error)}`
|
|
2141
|
+
);
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
);
|
|
2145
|
+
server.registerTool(
|
|
2146
|
+
track(mcpToolName(ctx.productName, "ai_events_create")),
|
|
2147
|
+
{
|
|
2148
|
+
title: "Create AI Tool Event",
|
|
2149
|
+
description: "Record a new AI tool event.",
|
|
2150
|
+
inputSchema: {
|
|
2151
|
+
source: z.string().describe("Event source (e.g., mcp, cli, sdk)"),
|
|
2152
|
+
eventType: z.string().describe("Event type (e.g., tool_call, completion)"),
|
|
2153
|
+
payload: z.string().describe("Event payload as JSON string"),
|
|
2154
|
+
agentId: z.string().optional().describe("Associated agent ID")
|
|
2155
|
+
}
|
|
2156
|
+
},
|
|
2157
|
+
async ({ source, eventType, payload, agentId }) => {
|
|
2158
|
+
try {
|
|
2159
|
+
const input = { source, eventType };
|
|
2160
|
+
input.payload = JSON.parse(payload);
|
|
2161
|
+
if (agentId !== void 0) input.agentId = agentId;
|
|
2162
|
+
const data = await ctx.gql.workspace.request(
|
|
2163
|
+
CREATE_AI_TOOL_EVENT,
|
|
2164
|
+
{
|
|
2165
|
+
input
|
|
2166
|
+
}
|
|
2167
|
+
);
|
|
2168
|
+
return jsonResult(data.createAiToolEvent);
|
|
2169
|
+
} catch (error) {
|
|
2170
|
+
ctx.logger.error("vibecontrols_ai_events_create failed", { error });
|
|
2171
|
+
return errorResult(
|
|
2172
|
+
`Failed to create AI event: ${error instanceof Error ? error.message : String(error)}`
|
|
2173
|
+
);
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
);
|
|
2177
|
+
server.registerTool(
|
|
2178
|
+
track(mcpToolName(ctx.productName, "ai_events_recent")),
|
|
2179
|
+
{
|
|
2180
|
+
title: "Recent AI Tool Events",
|
|
2181
|
+
description: "Get recent AI tool events for a specific agent.",
|
|
2182
|
+
inputSchema: {
|
|
2183
|
+
agentId: z.string().describe("Agent ID"),
|
|
2184
|
+
limit: z.number().optional().describe("Maximum events to return")
|
|
2185
|
+
}
|
|
2186
|
+
},
|
|
2187
|
+
async ({ agentId, limit }) => {
|
|
2188
|
+
try {
|
|
2189
|
+
const data = await ctx.gql.workspace.request(
|
|
2190
|
+
RECENT_AI_TOOL_EVENTS,
|
|
2191
|
+
{ agentId, limit }
|
|
2192
|
+
);
|
|
2193
|
+
return jsonResult(data.recentAiToolEvents);
|
|
2194
|
+
} catch (error) {
|
|
2195
|
+
ctx.logger.error("vibecontrols_ai_events_recent failed", { error });
|
|
2196
|
+
return errorResult(
|
|
2197
|
+
`Failed to get recent AI events: ${error instanceof Error ? error.message : String(error)}`
|
|
2198
|
+
);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
);
|
|
2202
|
+
}
|
|
2203
|
+
function registerAnalyticsTools(server, ctx, track) {
|
|
2204
|
+
server.registerTool(
|
|
2205
|
+
track(mcpToolName(ctx.productName, "analytics_overview")),
|
|
2206
|
+
{
|
|
2207
|
+
title: "VibeControls Analytics Overview",
|
|
2208
|
+
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).",
|
|
2209
|
+
inputSchema: {
|
|
2210
|
+
startDate: z.string().optional().describe("Start date (ISO format). Defaults to 7 days ago."),
|
|
2211
|
+
endDate: z.string().optional().describe("End date (ISO format). Defaults to now."),
|
|
2212
|
+
granularity: z.enum(["HOUR", "DAY", "WEEK", "MONTH"]).optional().default("DAY").describe("Time series granularity"),
|
|
2213
|
+
entityTypes: z.array(
|
|
2214
|
+
z.enum([
|
|
2215
|
+
"AGENT",
|
|
2216
|
+
"TARGET",
|
|
2217
|
+
"SESSION",
|
|
2218
|
+
"VIBE",
|
|
2219
|
+
"ACTION",
|
|
2220
|
+
"WEBHOOK",
|
|
2221
|
+
"AI_EVENT",
|
|
2222
|
+
"VIBE_DECK",
|
|
2223
|
+
"AUDIT",
|
|
2224
|
+
"DOCS",
|
|
2225
|
+
"NOTE",
|
|
2226
|
+
"CONFIGURATION"
|
|
2227
|
+
])
|
|
2228
|
+
).optional().describe("Filter to specific entity types (null = all)"),
|
|
2229
|
+
agentId: z.string().optional().describe("Filter analytics by agent ID"),
|
|
2230
|
+
vibeId: z.string().optional().describe("Filter analytics by vibe ID")
|
|
2231
|
+
}
|
|
2232
|
+
},
|
|
2233
|
+
async ({ startDate, endDate, granularity, entityTypes, agentId, vibeId }) => {
|
|
2234
|
+
try {
|
|
2235
|
+
const input = {
|
|
2236
|
+
startDate: startDate || new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3).toISOString(),
|
|
2237
|
+
endDate: endDate || (/* @__PURE__ */ new Date()).toISOString(),
|
|
2238
|
+
granularity: granularity || "DAY"
|
|
2239
|
+
};
|
|
2240
|
+
if (entityTypes && entityTypes.length > 0) input.entityTypes = entityTypes;
|
|
2241
|
+
if (agentId) input.agentId = agentId;
|
|
2242
|
+
if (vibeId) input.vibeId = vibeId;
|
|
2243
|
+
const data = await ctx.gql.workspace.request(
|
|
2244
|
+
VIBECONTROLS_ANALYTICS,
|
|
2245
|
+
{ input }
|
|
2246
|
+
);
|
|
2247
|
+
return jsonResult(data.vibecontrolsAnalytics);
|
|
2248
|
+
} catch (error) {
|
|
2249
|
+
ctx.logger.error("vibecontrols_analytics_overview failed", { error });
|
|
2250
|
+
return errorResult(
|
|
2251
|
+
`Failed to get analytics: ${error instanceof Error ? error.message : String(error)}`
|
|
2252
|
+
);
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
);
|
|
2256
|
+
server.registerTool(
|
|
2257
|
+
track(mcpToolName(ctx.productName, "analytics_summary")),
|
|
2258
|
+
{
|
|
2259
|
+
title: "VibeControls Analytics Summary",
|
|
2260
|
+
description: "Get a quick KPI summary of all VibeControls entity counts (agents, sessions, vibes, actions, etc.). Lighter-weight than the full overview.",
|
|
2261
|
+
inputSchema: {
|
|
2262
|
+
startDate: z.string().optional().describe("Start date (ISO format). Defaults to 7 days ago."),
|
|
2263
|
+
endDate: z.string().optional().describe("End date (ISO format). Defaults to now.")
|
|
2264
|
+
}
|
|
2265
|
+
},
|
|
2266
|
+
async ({ startDate, endDate }) => {
|
|
2267
|
+
try {
|
|
2268
|
+
const input = {
|
|
2269
|
+
startDate: startDate || new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3).toISOString(),
|
|
2270
|
+
endDate: endDate || (/* @__PURE__ */ new Date()).toISOString(),
|
|
2271
|
+
granularity: "DAY"
|
|
2272
|
+
};
|
|
2273
|
+
const data = await ctx.gql.workspace.request(VIBECONTROLS_ANALYTICS, { input });
|
|
2274
|
+
const a = data.vibecontrolsAnalytics;
|
|
2275
|
+
const summary = {
|
|
2276
|
+
agents: { total: a.agents?.total, active: a.agents?.active },
|
|
2277
|
+
targets: { total: a.targets?.total },
|
|
2278
|
+
sessions: { total: a.sessions?.total, active: a.sessions?.active },
|
|
2279
|
+
vibes: { total: a.vibes?.total },
|
|
2280
|
+
actions: {
|
|
2281
|
+
total: a.actions?.total,
|
|
2282
|
+
executions: a.actions?.totalExecutions,
|
|
2283
|
+
successRate: a.actions?.successRate
|
|
2284
|
+
},
|
|
2285
|
+
webhooks: { total: a.webhooks?.total, active: a.webhooks?.active },
|
|
2286
|
+
aiEvents: { total: a.aiEvents?.total },
|
|
2287
|
+
vibeDecks: {
|
|
2288
|
+
totalDecks: a.vibeDecks?.totalDecks,
|
|
2289
|
+
totalButtons: a.vibeDecks?.totalButtons
|
|
2290
|
+
},
|
|
2291
|
+
audit: { total: a.audit?.total },
|
|
2292
|
+
docs: { sites: a.docs?.totalSites, pages: a.docs?.totalPages },
|
|
2293
|
+
notes: { total: a.notes?.total, pinned: a.notes?.pinned },
|
|
2294
|
+
configurations: { total: a.configurations?.total },
|
|
2295
|
+
executionTimeMs: a.executionTimeMs
|
|
2296
|
+
};
|
|
2297
|
+
return jsonResult(summary);
|
|
2298
|
+
} catch (error) {
|
|
2299
|
+
ctx.logger.error("vibecontrols_analytics_summary failed", { error });
|
|
2300
|
+
return errorResult(
|
|
2301
|
+
`Failed to get analytics summary: ${error instanceof Error ? error.message : String(error)}`
|
|
2302
|
+
);
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
);
|
|
2306
|
+
}
|
|
2307
|
+
function registerAuditTools(server, ctx, track) {
|
|
2308
|
+
server.registerTool(
|
|
2309
|
+
track(mcpToolName(ctx.productName, "audit_list")),
|
|
2310
|
+
{
|
|
2311
|
+
title: "List Audit Logs",
|
|
2312
|
+
description: "List audit logs with optional filters and pagination.",
|
|
2313
|
+
inputSchema: {
|
|
2314
|
+
action: z.string().optional().describe("Filter by action type"),
|
|
2315
|
+
resourceType: z.string().optional().describe("Filter by resource type"),
|
|
2316
|
+
resourceId: z.string().optional().describe("Filter by resource ID"),
|
|
2317
|
+
actorId: z.string().optional().describe("Filter by actor ID"),
|
|
2318
|
+
status: z.string().optional().describe("Filter by status"),
|
|
2319
|
+
limit: z.number().optional().describe("Max results"),
|
|
2320
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
2321
|
+
}
|
|
2322
|
+
},
|
|
2323
|
+
async ({ action, resourceType, resourceId, actorId, status, limit, offset }) => {
|
|
2324
|
+
try {
|
|
2325
|
+
const filter = {};
|
|
2326
|
+
if (action !== void 0) filter.action = action;
|
|
2327
|
+
if (resourceType !== void 0) filter.resourceType = resourceType;
|
|
2328
|
+
if (resourceId !== void 0) filter.resourceId = resourceId;
|
|
2329
|
+
if (actorId !== void 0) filter.actorId = actorId;
|
|
2330
|
+
if (status !== void 0) filter.status = status;
|
|
2331
|
+
const pagination = {};
|
|
2332
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
2333
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
2334
|
+
const data = await ctx.gql.workspace.request(LIST_AUDIT_LOGS, {
|
|
2335
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
2336
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
2337
|
+
});
|
|
2338
|
+
return jsonResult(data.vibeAuditLogs);
|
|
2339
|
+
} catch (error) {
|
|
2340
|
+
ctx.logger.error("vibecontrols_audit_list failed", { error });
|
|
2341
|
+
return errorResult(
|
|
2342
|
+
`Failed to list audit logs: ${error instanceof Error ? error.message : String(error)}`
|
|
2343
|
+
);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
);
|
|
2347
|
+
server.registerTool(
|
|
2348
|
+
track(mcpToolName(ctx.productName, "audit_get")),
|
|
2349
|
+
{
|
|
2350
|
+
title: "Get Audit Log",
|
|
2351
|
+
description: "Get an audit log entry by its ID.",
|
|
2352
|
+
inputSchema: { id: z.string().describe("Audit log ID") }
|
|
2353
|
+
},
|
|
2354
|
+
async ({ id }) => {
|
|
2355
|
+
try {
|
|
2356
|
+
const data = await ctx.gql.workspace.request(GET_AUDIT_LOG, {
|
|
2357
|
+
id
|
|
2358
|
+
});
|
|
2359
|
+
return jsonResult(data.vibeAuditLog);
|
|
2360
|
+
} catch (error) {
|
|
2361
|
+
ctx.logger.error("vibecontrols_audit_get failed", { error });
|
|
2362
|
+
return errorResult(
|
|
2363
|
+
`Failed to get audit log: ${error instanceof Error ? error.message : String(error)}`
|
|
2364
|
+
);
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
);
|
|
2368
|
+
server.registerTool(
|
|
2369
|
+
track(mcpToolName(ctx.productName, "audit_stats")),
|
|
2370
|
+
{
|
|
2371
|
+
title: "Audit Log Stats",
|
|
2372
|
+
description: "Get aggregated statistics for audit logs.",
|
|
2373
|
+
inputSchema: {
|
|
2374
|
+
action: z.string().optional().describe("Filter stats by action type"),
|
|
2375
|
+
resourceType: z.string().optional().describe("Filter stats by resource type"),
|
|
2376
|
+
status: z.string().optional().describe("Filter stats by status")
|
|
2377
|
+
}
|
|
2378
|
+
},
|
|
2379
|
+
async ({ action, resourceType, status }) => {
|
|
2380
|
+
try {
|
|
2381
|
+
const filter = {};
|
|
2382
|
+
if (action !== void 0) filter.action = action;
|
|
2383
|
+
if (resourceType !== void 0) filter.resourceType = resourceType;
|
|
2384
|
+
if (status !== void 0) filter.status = status;
|
|
2385
|
+
const data = await ctx.gql.workspace.request(
|
|
2386
|
+
AUDIT_LOG_STATS,
|
|
2387
|
+
{
|
|
2388
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0
|
|
2389
|
+
}
|
|
2390
|
+
);
|
|
2391
|
+
return jsonResult(data.vibeAuditLogStats);
|
|
2392
|
+
} catch (error) {
|
|
2393
|
+
ctx.logger.error("vibecontrols_audit_stats failed", { error });
|
|
2394
|
+
return errorResult(
|
|
2395
|
+
`Failed to get audit log stats: ${error instanceof Error ? error.message : String(error)}`
|
|
2396
|
+
);
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
);
|
|
2400
|
+
server.registerTool(
|
|
2401
|
+
track(mcpToolName(ctx.productName, "audit_export")),
|
|
2402
|
+
{
|
|
2403
|
+
title: "Export Audit Logs",
|
|
2404
|
+
description: "Export audit logs in a specified format.",
|
|
2405
|
+
inputSchema: {
|
|
2406
|
+
action: z.string().optional().describe("Filter by action type"),
|
|
2407
|
+
resourceType: z.string().optional().describe("Filter by resource type"),
|
|
2408
|
+
status: z.string().optional().describe("Filter by status"),
|
|
2409
|
+
format: z.string().optional().describe("Export format: json or csv")
|
|
2410
|
+
}
|
|
2411
|
+
},
|
|
2412
|
+
async ({ action, resourceType, status, format }) => {
|
|
2413
|
+
try {
|
|
2414
|
+
const filter = {};
|
|
2415
|
+
if (action !== void 0) filter.action = action;
|
|
2416
|
+
if (resourceType !== void 0) filter.resourceType = resourceType;
|
|
2417
|
+
if (status !== void 0) filter.status = status;
|
|
2418
|
+
const variables = {
|
|
2419
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0
|
|
2420
|
+
};
|
|
2421
|
+
if (format !== void 0) variables.format = format;
|
|
2422
|
+
const data = await ctx.gql.workspace.request(
|
|
2423
|
+
EXPORT_AUDIT_LOGS,
|
|
2424
|
+
variables
|
|
2425
|
+
);
|
|
2426
|
+
return jsonResult(data.exportVibeAuditLogs);
|
|
2427
|
+
} catch (error) {
|
|
2428
|
+
ctx.logger.error("vibecontrols_audit_export failed", { error });
|
|
2429
|
+
return errorResult(
|
|
2430
|
+
`Failed to export audit logs: ${error instanceof Error ? error.message : String(error)}`
|
|
2431
|
+
);
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
);
|
|
2435
|
+
server.registerTool(
|
|
2436
|
+
track(mcpToolName(ctx.productName, "audit_delete")),
|
|
2437
|
+
{
|
|
2438
|
+
title: "Delete Audit Log",
|
|
2439
|
+
description: "Delete an audit log entry.",
|
|
2440
|
+
inputSchema: {
|
|
2441
|
+
id: z.string().describe("Audit log ID to delete"),
|
|
2442
|
+
reason: z.string().optional().describe("Reason for deletion")
|
|
2443
|
+
}
|
|
2444
|
+
},
|
|
2445
|
+
async ({ id, reason }) => {
|
|
2446
|
+
try {
|
|
2447
|
+
const variables = { id };
|
|
2448
|
+
if (reason !== void 0) variables.reason = reason;
|
|
2449
|
+
const data = await ctx.gql.workspace.request(
|
|
2450
|
+
DELETE_AUDIT_LOG,
|
|
2451
|
+
variables
|
|
2452
|
+
);
|
|
2453
|
+
return jsonResult(data.deleteVibeAuditLog);
|
|
2454
|
+
} catch (error) {
|
|
2455
|
+
ctx.logger.error("vibecontrols_audit_delete failed", { error });
|
|
2456
|
+
return errorResult(
|
|
2457
|
+
`Failed to delete audit log: ${error instanceof Error ? error.message : String(error)}`
|
|
2458
|
+
);
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
);
|
|
2462
|
+
}
|
|
2463
|
+
var ConfigScopeEnum = z.enum(["WORKSPACE", "VIBE", "SESSION", "AGENT", "USER", "GLOBAL"]);
|
|
2464
|
+
function registerConfigurationTools(server, ctx, track) {
|
|
1127
2465
|
server.registerTool(
|
|
1128
2466
|
track(mcpToolName(ctx.productName, "config_list")),
|
|
1129
2467
|
{
|
|
1130
|
-
title: "List Configurations",
|
|
1131
|
-
description: "List configuration key-value pairs with required filter.",
|
|
2468
|
+
title: "List Configurations",
|
|
2469
|
+
description: "List configuration key-value pairs with required filter.",
|
|
2470
|
+
inputSchema: {
|
|
2471
|
+
key: z.string().optional().describe("Filter by key pattern"),
|
|
2472
|
+
scope: ConfigScopeEnum.describe("Configuration scope"),
|
|
2473
|
+
scopeId: z.string().optional().describe("Filter by scope entity ID"),
|
|
2474
|
+
isSecret: z.boolean().optional().describe("Filter by secret status"),
|
|
2475
|
+
limit: z.number().optional().describe("Max results"),
|
|
2476
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
2477
|
+
}
|
|
2478
|
+
},
|
|
2479
|
+
async ({ key, scope, scopeId, isSecret, limit, offset }) => {
|
|
2480
|
+
try {
|
|
2481
|
+
const filter = { scope };
|
|
2482
|
+
if (key !== void 0) filter.key = key;
|
|
2483
|
+
if (scopeId !== void 0) filter.scopeId = scopeId;
|
|
2484
|
+
if (isSecret !== void 0) filter.isSecret = isSecret;
|
|
2485
|
+
const pagination = {};
|
|
2486
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
2487
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
2488
|
+
const data = await ctx.gql.workspace.request(
|
|
2489
|
+
LIST_CONFIGURATIONS,
|
|
2490
|
+
{
|
|
2491
|
+
filter,
|
|
2492
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
2493
|
+
}
|
|
2494
|
+
);
|
|
2495
|
+
return jsonResult(data.configurations);
|
|
2496
|
+
} catch (error) {
|
|
2497
|
+
ctx.logger.error("vibecontrols_config_list failed", { error });
|
|
2498
|
+
return errorResult(
|
|
2499
|
+
`Failed to list configurations: ${error instanceof Error ? error.message : String(error)}`
|
|
2500
|
+
);
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
);
|
|
2504
|
+
server.registerTool(
|
|
2505
|
+
track(mcpToolName(ctx.productName, "config_get")),
|
|
2506
|
+
{
|
|
2507
|
+
title: "Get Configuration",
|
|
2508
|
+
description: "Get a configuration value by key and scope.",
|
|
2509
|
+
inputSchema: {
|
|
2510
|
+
key: z.string().describe("Configuration key"),
|
|
2511
|
+
scope: ConfigScopeEnum.describe("Configuration scope"),
|
|
2512
|
+
scopeId: z.string().optional().describe("Scope entity ID")
|
|
2513
|
+
}
|
|
2514
|
+
},
|
|
2515
|
+
async ({ key, scope, scopeId }) => {
|
|
2516
|
+
try {
|
|
2517
|
+
const data = await ctx.gql.workspace.request(
|
|
2518
|
+
GET_CONFIGURATION,
|
|
2519
|
+
{
|
|
2520
|
+
key,
|
|
2521
|
+
scope,
|
|
2522
|
+
scopeId
|
|
2523
|
+
}
|
|
2524
|
+
);
|
|
2525
|
+
return jsonResult(data.configuration);
|
|
2526
|
+
} catch (error) {
|
|
2527
|
+
ctx.logger.error("vibecontrols_config_get failed", { error });
|
|
2528
|
+
return errorResult(
|
|
2529
|
+
`Failed to get configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
2530
|
+
);
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
);
|
|
2534
|
+
server.registerTool(
|
|
2535
|
+
track(mcpToolName(ctx.productName, "config_set")),
|
|
2536
|
+
{
|
|
2537
|
+
title: "Set Configuration",
|
|
2538
|
+
description: "Set (create or update) a configuration value.",
|
|
2539
|
+
inputSchema: {
|
|
2540
|
+
key: z.string().describe("Configuration key"),
|
|
2541
|
+
scope: ConfigScopeEnum.describe("Configuration scope"),
|
|
2542
|
+
scopeId: z.string().optional().describe("Scope entity ID"),
|
|
2543
|
+
value: z.string().describe("Configuration value as a JSON string"),
|
|
2544
|
+
isSecret: z.boolean().optional().describe("Mark as secret (value will be masked in reads)")
|
|
2545
|
+
}
|
|
2546
|
+
},
|
|
2547
|
+
async ({ key, scope, scopeId, value, isSecret }) => {
|
|
2548
|
+
try {
|
|
2549
|
+
const parsedValue = JSON.parse(value);
|
|
2550
|
+
const variables = { key, scope, value: parsedValue };
|
|
2551
|
+
if (scopeId !== void 0) variables.scopeId = scopeId;
|
|
2552
|
+
if (isSecret !== void 0) variables.isSecret = isSecret;
|
|
2553
|
+
const data = await ctx.gql.workspace.request(
|
|
2554
|
+
SET_CONFIGURATION,
|
|
2555
|
+
variables
|
|
2556
|
+
);
|
|
2557
|
+
return jsonResult(data.setConfiguration);
|
|
2558
|
+
} catch (error) {
|
|
2559
|
+
ctx.logger.error("vibecontrols_config_set failed", { error });
|
|
2560
|
+
return errorResult(
|
|
2561
|
+
`Failed to set configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
2562
|
+
);
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
);
|
|
2566
|
+
server.registerTool(
|
|
2567
|
+
track(mcpToolName(ctx.productName, "config_delete")),
|
|
2568
|
+
{
|
|
2569
|
+
title: "Delete Configuration",
|
|
2570
|
+
description: "Delete a configuration by key and scope.",
|
|
2571
|
+
inputSchema: {
|
|
2572
|
+
key: z.string().describe("Configuration key to delete"),
|
|
2573
|
+
scope: ConfigScopeEnum.describe("Configuration scope"),
|
|
2574
|
+
scopeId: z.string().optional().describe("Scope entity ID")
|
|
2575
|
+
}
|
|
2576
|
+
},
|
|
2577
|
+
async ({ key, scope, scopeId }) => {
|
|
2578
|
+
try {
|
|
2579
|
+
const data = await ctx.gql.workspace.request(
|
|
2580
|
+
DELETE_CONFIGURATION,
|
|
2581
|
+
{ key, scope, scopeId }
|
|
2582
|
+
);
|
|
2583
|
+
return jsonResult({ deleted: data.deleteConfiguration, key, scope });
|
|
2584
|
+
} catch (error) {
|
|
2585
|
+
ctx.logger.error("vibecontrols_config_delete failed", { error });
|
|
2586
|
+
return errorResult(
|
|
2587
|
+
`Failed to delete configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
2588
|
+
);
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
);
|
|
2592
|
+
server.registerTool(
|
|
2593
|
+
track(mcpToolName(ctx.productName, "config_by_scope")),
|
|
2594
|
+
{
|
|
2595
|
+
title: "Configurations by Scope",
|
|
2596
|
+
description: "Get all configuration values for a given scope.",
|
|
2597
|
+
inputSchema: {
|
|
2598
|
+
scope: ConfigScopeEnum.describe("Configuration scope"),
|
|
2599
|
+
scopeId: z.string().optional().describe("Scope entity ID")
|
|
2600
|
+
}
|
|
2601
|
+
},
|
|
2602
|
+
async ({ scope, scopeId }) => {
|
|
2603
|
+
try {
|
|
2604
|
+
const data = await ctx.gql.workspace.request(
|
|
2605
|
+
CONFIGURATIONS_BY_SCOPE,
|
|
2606
|
+
{ scope, scopeId }
|
|
2607
|
+
);
|
|
2608
|
+
return jsonResult(data.configurationsByScope);
|
|
2609
|
+
} catch (error) {
|
|
2610
|
+
ctx.logger.error("vibecontrols_config_by_scope failed", { error });
|
|
2611
|
+
return errorResult(
|
|
2612
|
+
`Failed to get configurations by scope: ${error instanceof Error ? error.message : String(error)}`
|
|
2613
|
+
);
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
);
|
|
2617
|
+
}
|
|
2618
|
+
var StageEnum = z.enum([
|
|
2619
|
+
"ARCHIVE_OFFBOARD",
|
|
2620
|
+
"BUILD",
|
|
2621
|
+
"DEPLOY_ALPHA",
|
|
2622
|
+
"DEPLOY_PREVIEW",
|
|
2623
|
+
"DEVELOPER_LOCAL",
|
|
2624
|
+
"INCIDENT_RESPONSE",
|
|
2625
|
+
"MAIN_MERGE",
|
|
2626
|
+
"PACKAGE_PUBLISH",
|
|
2627
|
+
"PROMOTE_PROD",
|
|
2628
|
+
"PULL_REQUEST_DEEP",
|
|
2629
|
+
"PULL_REQUEST_FAST",
|
|
2630
|
+
"REPO_ONBOARD",
|
|
2631
|
+
"RUNTIME_CONTINUOUS",
|
|
2632
|
+
"SCHEDULED_RESCAN"
|
|
2633
|
+
]);
|
|
2634
|
+
var SeverityEnum = z.enum(["CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO"]);
|
|
2635
|
+
var ScanStatusEnum = z.enum(["CANCELLED", "ERRORED", "FAILED", "QUEUED", "RUNNING", "SUCCEEDED"]);
|
|
2636
|
+
var ScanConclusionEnum = z.enum(["FAIL", "PASS", "SKIPPED", "WARN"]);
|
|
2637
|
+
var FindingCategoryEnum = z.enum([
|
|
2638
|
+
"CONFIG",
|
|
2639
|
+
"LICENSE",
|
|
2640
|
+
"POLICY",
|
|
2641
|
+
"SAST",
|
|
2642
|
+
"SECRET",
|
|
2643
|
+
"SUPPLYCHAIN",
|
|
2644
|
+
"VULN"
|
|
2645
|
+
]);
|
|
2646
|
+
var FindingStatusEnum = z.enum(["ACCEPTED", "FALSE_POSITIVE", "FIXED", "OPEN", "SUPPRESSED"]);
|
|
2647
|
+
var EvidenceTypeEnum = z.enum([
|
|
2648
|
+
"COSIGN_BUNDLE",
|
|
2649
|
+
"GRYPE_JSON",
|
|
2650
|
+
"OPA_DECISION",
|
|
2651
|
+
"PROVENANCE",
|
|
2652
|
+
"SARIF",
|
|
2653
|
+
"SBOM_CYCLONEDX",
|
|
2654
|
+
"SBOM_SPDX"
|
|
2655
|
+
]);
|
|
2656
|
+
var PolicyLevelEnum = z.enum(["ADVISORY", "BLOCK", "WARN"]);
|
|
2657
|
+
function strip(obj) {
|
|
2658
|
+
const out = {};
|
|
2659
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
2660
|
+
if (v !== void 0) out[k] = v;
|
|
2661
|
+
}
|
|
2662
|
+
return out;
|
|
2663
|
+
}
|
|
2664
|
+
function registerConfigSecurityTools(server, ctx, track) {
|
|
2665
|
+
server.registerTool(
|
|
2666
|
+
track(mcpToolName(ctx.productName, "configuration_security_providers")),
|
|
2667
|
+
{
|
|
2668
|
+
title: "List Security Providers",
|
|
2669
|
+
description: "List configured security scanner providers in the current workspace.",
|
|
2670
|
+
inputSchema: {}
|
|
2671
|
+
},
|
|
2672
|
+
async () => {
|
|
2673
|
+
try {
|
|
2674
|
+
const data = await ctx.gql.workspace.request(
|
|
2675
|
+
SECURITY_PROVIDERS_Q
|
|
2676
|
+
);
|
|
2677
|
+
return jsonResult(data.securityProviders);
|
|
2678
|
+
} catch (error) {
|
|
2679
|
+
ctx.logger.error("config_security_providers_list failed", { error });
|
|
2680
|
+
return errorResult(
|
|
2681
|
+
`Failed to list security providers: ${error instanceof Error ? error.message : String(error)}`
|
|
2682
|
+
);
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
);
|
|
2686
|
+
server.registerTool(
|
|
2687
|
+
track(mcpToolName(ctx.productName, "configuration_security_set_provider")),
|
|
2688
|
+
{
|
|
2689
|
+
title: "Set Security Provider",
|
|
2690
|
+
description: "Configure (or update) a security provider for a vibe and stage.",
|
|
2691
|
+
inputSchema: {
|
|
2692
|
+
vibeId: z.string().describe("Vibe ID this provider applies to"),
|
|
2693
|
+
stage: StageEnum.describe("Security stage this provider runs at"),
|
|
2694
|
+
providerKey: z.string().describe("Provider plugin key (e.g. trivy, gitleaks, semgrep)"),
|
|
2695
|
+
config: z.string().optional().describe("Optional provider-specific config as a JSON string")
|
|
2696
|
+
}
|
|
2697
|
+
},
|
|
2698
|
+
async ({ vibeId, stage, providerKey, config }) => {
|
|
2699
|
+
try {
|
|
2700
|
+
const input = { vibeId, stage, providerKey };
|
|
2701
|
+
if (config !== void 0) input.config = JSON.parse(config);
|
|
2702
|
+
const data = await ctx.gql.workspace.request(
|
|
2703
|
+
SET_SECURITY_PROVIDER_M,
|
|
2704
|
+
{ input }
|
|
2705
|
+
);
|
|
2706
|
+
return jsonResult(data.setSecurityProvider);
|
|
2707
|
+
} catch (error) {
|
|
2708
|
+
ctx.logger.error("config_security_provider_set failed", { error });
|
|
2709
|
+
return errorResult(
|
|
2710
|
+
`Failed to set security provider: ${error instanceof Error ? error.message : String(error)}`
|
|
2711
|
+
);
|
|
2712
|
+
}
|
|
2713
|
+
}
|
|
2714
|
+
);
|
|
2715
|
+
const scansListSchema = {
|
|
2716
|
+
vibeId: z.string().optional().describe("Filter by vibe ID"),
|
|
2717
|
+
status: ScanStatusEnum.optional(),
|
|
2718
|
+
stage: StageEnum.optional(),
|
|
2719
|
+
conclusion: ScanConclusionEnum.optional(),
|
|
2720
|
+
limit: z.number().optional(),
|
|
2721
|
+
offset: z.number().optional()
|
|
2722
|
+
};
|
|
2723
|
+
server.registerTool(
|
|
2724
|
+
track(mcpToolName(ctx.productName, "configuration_security_my_security_scans")),
|
|
2725
|
+
{
|
|
2726
|
+
title: "My Security Scans",
|
|
2727
|
+
description: "List security scan runs created by the current user.",
|
|
2728
|
+
inputSchema: scansListSchema
|
|
2729
|
+
},
|
|
2730
|
+
async ({ vibeId, status, stage, conclusion, limit, offset }) => {
|
|
2731
|
+
try {
|
|
2732
|
+
const filter = strip({ vibeId, status, stage, conclusion });
|
|
2733
|
+
const pagination = strip({ limit, offset });
|
|
2734
|
+
const data = await ctx.gql.workspace.request(
|
|
2735
|
+
MY_SECURITY_SCANS_Q,
|
|
2736
|
+
{
|
|
2737
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
2738
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
2739
|
+
}
|
|
2740
|
+
);
|
|
2741
|
+
return jsonResult(data.mySecurityScans);
|
|
2742
|
+
} catch (error) {
|
|
2743
|
+
ctx.logger.error("configuration_security_my_security_scans failed", { error });
|
|
2744
|
+
return errorResult(
|
|
2745
|
+
`Failed to list my scans: ${error instanceof Error ? error.message : String(error)}`
|
|
2746
|
+
);
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
);
|
|
2750
|
+
server.registerTool(
|
|
2751
|
+
track(mcpToolName(ctx.productName, "configuration_security_all_security_scans")),
|
|
2752
|
+
{
|
|
2753
|
+
title: "All Security Scans",
|
|
2754
|
+
description: "List all security scan runs in the workspace (requires elevated permissions).",
|
|
2755
|
+
inputSchema: scansListSchema
|
|
2756
|
+
},
|
|
2757
|
+
async ({ vibeId, status, stage, conclusion, limit, offset }) => {
|
|
2758
|
+
try {
|
|
2759
|
+
const filter = strip({ vibeId, status, stage, conclusion });
|
|
2760
|
+
const pagination = strip({ limit, offset });
|
|
2761
|
+
const data = await ctx.gql.workspace.request(
|
|
2762
|
+
ALL_SECURITY_SCANS_Q,
|
|
2763
|
+
{
|
|
2764
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
2765
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
2766
|
+
}
|
|
2767
|
+
);
|
|
2768
|
+
return jsonResult(data.allSecurityScans);
|
|
2769
|
+
} catch (error) {
|
|
2770
|
+
ctx.logger.error("configuration_security_all_security_scans failed", { error });
|
|
2771
|
+
return errorResult(
|
|
2772
|
+
`Failed to list all scans: ${error instanceof Error ? error.message : String(error)}`
|
|
2773
|
+
);
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
);
|
|
2777
|
+
server.registerTool(
|
|
2778
|
+
track(mcpToolName(ctx.productName, "configuration_security_scan")),
|
|
2779
|
+
{
|
|
2780
|
+
title: "Get Security Scan",
|
|
2781
|
+
description: "Get a single security scan run including findings and evidence.",
|
|
2782
|
+
inputSchema: { id: z.string().describe("Scan run ID") }
|
|
2783
|
+
},
|
|
2784
|
+
async ({ id }) => {
|
|
2785
|
+
try {
|
|
2786
|
+
const data = await ctx.gql.workspace.request(SECURITY_SCAN_Q, {
|
|
2787
|
+
id
|
|
2788
|
+
});
|
|
2789
|
+
return jsonResult(data.securityScan);
|
|
2790
|
+
} catch (error) {
|
|
2791
|
+
ctx.logger.error("config_security_scan_get failed", { error });
|
|
2792
|
+
return errorResult(
|
|
2793
|
+
`Failed to get security scan: ${error instanceof Error ? error.message : String(error)}`
|
|
2794
|
+
);
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2797
|
+
);
|
|
2798
|
+
server.registerTool(
|
|
2799
|
+
track(mcpToolName(ctx.productName, "configuration_security_run_scan")),
|
|
2800
|
+
{
|
|
2801
|
+
title: "Run Security Scan",
|
|
2802
|
+
description: "Trigger a security scan for a vibe at a specific stage.",
|
|
2803
|
+
inputSchema: { vibeId: z.string(), stage: StageEnum }
|
|
2804
|
+
},
|
|
2805
|
+
async ({ vibeId, stage }) => {
|
|
2806
|
+
try {
|
|
2807
|
+
const data = await ctx.gql.workspace.request(
|
|
2808
|
+
RUN_SECURITY_SCAN_M,
|
|
2809
|
+
{ vibeId, stage }
|
|
2810
|
+
);
|
|
2811
|
+
return jsonResult(data.runSecurityScan);
|
|
2812
|
+
} catch (error) {
|
|
2813
|
+
ctx.logger.error("config_security_scan_run failed", { error });
|
|
2814
|
+
return errorResult(
|
|
2815
|
+
`Failed to run security scan: ${error instanceof Error ? error.message : String(error)}`
|
|
2816
|
+
);
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
);
|
|
2820
|
+
server.registerTool(
|
|
2821
|
+
track(mcpToolName(ctx.productName, "configuration_security_cancel_scan")),
|
|
2822
|
+
{
|
|
2823
|
+
title: "Cancel Security Scan",
|
|
2824
|
+
description: "Cancel an in-flight security scan run.",
|
|
2825
|
+
inputSchema: { id: z.string().describe("Scan run ID") }
|
|
2826
|
+
},
|
|
2827
|
+
async ({ id }) => {
|
|
2828
|
+
try {
|
|
2829
|
+
const data = await ctx.gql.workspace.request(
|
|
2830
|
+
CANCEL_SECURITY_SCAN_M,
|
|
2831
|
+
{ id }
|
|
2832
|
+
);
|
|
2833
|
+
return jsonResult(data.cancelSecurityScan);
|
|
2834
|
+
} catch (error) {
|
|
2835
|
+
ctx.logger.error("config_security_scan_cancel failed", { error });
|
|
2836
|
+
return errorResult(
|
|
2837
|
+
`Failed to cancel security scan: ${error instanceof Error ? error.message : String(error)}`
|
|
2838
|
+
);
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
);
|
|
2842
|
+
server.registerTool(
|
|
2843
|
+
track(mcpToolName(ctx.productName, "configuration_security_findings")),
|
|
2844
|
+
{
|
|
2845
|
+
title: "List Security Findings",
|
|
2846
|
+
description: "List security findings with optional filters (vibe, severity, category, status).",
|
|
2847
|
+
inputSchema: {
|
|
2848
|
+
vibeId: z.string().optional(),
|
|
2849
|
+
status: FindingStatusEnum.optional(),
|
|
2850
|
+
severity: SeverityEnum.optional(),
|
|
2851
|
+
category: FindingCategoryEnum.optional(),
|
|
2852
|
+
search: z.string().optional(),
|
|
2853
|
+
limit: z.number().optional(),
|
|
2854
|
+
offset: z.number().optional()
|
|
2855
|
+
}
|
|
2856
|
+
},
|
|
2857
|
+
async ({ vibeId, status, severity, category, search, limit, offset }) => {
|
|
2858
|
+
try {
|
|
2859
|
+
const filter = strip({ vibeId, status, severity, category, search });
|
|
2860
|
+
const pagination = strip({ limit, offset });
|
|
2861
|
+
const data = await ctx.gql.workspace.request(
|
|
2862
|
+
SECURITY_FINDINGS_Q,
|
|
2863
|
+
{
|
|
2864
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
2865
|
+
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
2866
|
+
}
|
|
2867
|
+
);
|
|
2868
|
+
return jsonResult(data.securityFindings);
|
|
2869
|
+
} catch (error) {
|
|
2870
|
+
ctx.logger.error("config_security_findings_list failed", { error });
|
|
2871
|
+
return errorResult(
|
|
2872
|
+
`Failed to list security findings: ${error instanceof Error ? error.message : String(error)}`
|
|
2873
|
+
);
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
);
|
|
2877
|
+
server.registerTool(
|
|
2878
|
+
track(mcpToolName(ctx.productName, "configuration_security_update_finding_status")),
|
|
2879
|
+
{
|
|
2880
|
+
title: "Update Security Finding Status",
|
|
2881
|
+
description: "Update the workflow status of a security finding (e.g. OPEN \u2192 SUPPRESSED).",
|
|
2882
|
+
inputSchema: { id: z.string(), status: FindingStatusEnum }
|
|
2883
|
+
},
|
|
2884
|
+
async ({ id, status }) => {
|
|
2885
|
+
try {
|
|
2886
|
+
const data = await ctx.gql.workspace.request(
|
|
2887
|
+
UPDATE_SECURITY_FINDING_STATUS_M,
|
|
2888
|
+
{ id, status }
|
|
2889
|
+
);
|
|
2890
|
+
return jsonResult(data.updateSecurityFindingStatus);
|
|
2891
|
+
} catch (error) {
|
|
2892
|
+
ctx.logger.error("config_security_finding_update_status failed", { error });
|
|
2893
|
+
return errorResult(
|
|
2894
|
+
`Failed to update finding status: ${error instanceof Error ? error.message : String(error)}`
|
|
2895
|
+
);
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
);
|
|
2899
|
+
server.registerTool(
|
|
2900
|
+
track(mcpToolName(ctx.productName, "configuration_security_policy_decision")),
|
|
2901
|
+
{
|
|
2902
|
+
title: "Security Policy Decision",
|
|
2903
|
+
description: "Fetch the OPA policy decision for a security scan run.",
|
|
2904
|
+
inputSchema: { scanRunId: z.string() }
|
|
2905
|
+
},
|
|
2906
|
+
async ({ scanRunId }) => {
|
|
2907
|
+
try {
|
|
2908
|
+
const data = await ctx.gql.workspace.request(
|
|
2909
|
+
SECURITY_POLICY_DECISION_Q,
|
|
2910
|
+
{ scanRunId }
|
|
2911
|
+
);
|
|
2912
|
+
return jsonResult(data.securityPolicyDecision);
|
|
2913
|
+
} catch (error) {
|
|
2914
|
+
ctx.logger.error("config_security_policy_decision failed", { error });
|
|
2915
|
+
return errorResult(
|
|
2916
|
+
`Failed to get policy decision: ${error instanceof Error ? error.message : String(error)}`
|
|
2917
|
+
);
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
);
|
|
2921
|
+
server.registerTool(
|
|
2922
|
+
track(mcpToolName(ctx.productName, "configuration_security_status")),
|
|
2923
|
+
{
|
|
2924
|
+
title: "Security Status",
|
|
2925
|
+
description: "Aggregated security posture for a single vibe.",
|
|
2926
|
+
inputSchema: { vibeId: z.string() }
|
|
2927
|
+
},
|
|
2928
|
+
async ({ vibeId }) => {
|
|
2929
|
+
try {
|
|
2930
|
+
const data = await ctx.gql.workspace.request(
|
|
2931
|
+
SECURITY_STATUS_Q,
|
|
2932
|
+
{ vibeId }
|
|
2933
|
+
);
|
|
2934
|
+
return jsonResult(data.securityStatus);
|
|
2935
|
+
} catch (error) {
|
|
2936
|
+
ctx.logger.error("config_security_status failed", { error });
|
|
2937
|
+
return errorResult(
|
|
2938
|
+
`Failed to get security status: ${error instanceof Error ? error.message : String(error)}`
|
|
2939
|
+
);
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
);
|
|
2943
|
+
server.registerTool(
|
|
2944
|
+
track(mcpToolName(ctx.productName, "configuration_security_repository_config")),
|
|
2945
|
+
{
|
|
2946
|
+
title: "Get Repository Security Config",
|
|
2947
|
+
description: "Get the repository-level security policy config for a vibe.",
|
|
2948
|
+
inputSchema: { vibeId: z.string() }
|
|
2949
|
+
},
|
|
2950
|
+
async ({ vibeId }) => {
|
|
2951
|
+
try {
|
|
2952
|
+
const data = await ctx.gql.workspace.request(
|
|
2953
|
+
REPOSITORY_SECURITY_CONFIG_Q,
|
|
2954
|
+
{ vibeId }
|
|
2955
|
+
);
|
|
2956
|
+
return jsonResult(data.repositorySecurityConfig);
|
|
2957
|
+
} catch (error) {
|
|
2958
|
+
ctx.logger.error("config_security_repo_config_get failed", { error });
|
|
2959
|
+
return errorResult(
|
|
2960
|
+
`Failed to get repo security config: ${error instanceof Error ? error.message : String(error)}`
|
|
2961
|
+
);
|
|
2962
|
+
}
|
|
2963
|
+
}
|
|
2964
|
+
);
|
|
2965
|
+
server.registerTool(
|
|
2966
|
+
track(mcpToolName(ctx.productName, "configuration_security_update_repository_config")),
|
|
2967
|
+
{
|
|
2968
|
+
title: "Update Repository Security Config",
|
|
2969
|
+
description: "Update the repository-level security policy config for a vibe.",
|
|
2970
|
+
inputSchema: {
|
|
2971
|
+
vibeId: z.string(),
|
|
2972
|
+
policyLevel: PolicyLevelEnum.optional(),
|
|
2973
|
+
enabledStages: z.array(StageEnum).optional(),
|
|
2974
|
+
pluginAssignments: z.string().optional().describe("JSON string"),
|
|
2975
|
+
configYamlEquivalent: z.string().optional().describe("JSON string")
|
|
2976
|
+
}
|
|
2977
|
+
},
|
|
2978
|
+
async ({ vibeId, policyLevel, enabledStages, pluginAssignments, configYamlEquivalent }) => {
|
|
2979
|
+
try {
|
|
2980
|
+
const input = {};
|
|
2981
|
+
if (policyLevel !== void 0) input.policyLevel = policyLevel;
|
|
2982
|
+
if (enabledStages !== void 0) input.enabledStages = enabledStages;
|
|
2983
|
+
if (pluginAssignments !== void 0)
|
|
2984
|
+
input.pluginAssignments = JSON.parse(pluginAssignments);
|
|
2985
|
+
if (configYamlEquivalent !== void 0)
|
|
2986
|
+
input.configYamlEquivalent = JSON.parse(configYamlEquivalent);
|
|
2987
|
+
const data = await ctx.gql.workspace.request(UPDATE_REPOSITORY_SECURITY_CONFIG_M, { vibeId, input });
|
|
2988
|
+
return jsonResult(data.updateRepositorySecurityConfig);
|
|
2989
|
+
} catch (error) {
|
|
2990
|
+
ctx.logger.error("config_security_repo_config_update failed", { error });
|
|
2991
|
+
return errorResult(
|
|
2992
|
+
`Failed to update repo security config: ${error instanceof Error ? error.message : String(error)}`
|
|
2993
|
+
);
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
);
|
|
2997
|
+
server.registerTool(
|
|
2998
|
+
track(mcpToolName(ctx.productName, "configuration_security_create_exception")),
|
|
2999
|
+
{
|
|
3000
|
+
title: "Create Security Exception",
|
|
3001
|
+
description: "Approve a time-bounded exception (waiver) for a security finding.",
|
|
3002
|
+
inputSchema: {
|
|
3003
|
+
vibeId: z.string(),
|
|
3004
|
+
findingFingerprint: z.string(),
|
|
3005
|
+
reason: z.string(),
|
|
3006
|
+
expiresAt: z.string().describe("ISO 8601 timestamp"),
|
|
3007
|
+
compensatingControls: z.string().optional()
|
|
3008
|
+
}
|
|
3009
|
+
},
|
|
3010
|
+
async ({ vibeId, findingFingerprint, reason, expiresAt, compensatingControls }) => {
|
|
3011
|
+
try {
|
|
3012
|
+
const input = strip({
|
|
3013
|
+
vibeId,
|
|
3014
|
+
findingFingerprint,
|
|
3015
|
+
reason,
|
|
3016
|
+
expiresAt,
|
|
3017
|
+
compensatingControls
|
|
3018
|
+
});
|
|
3019
|
+
const data = await ctx.gql.workspace.request(
|
|
3020
|
+
CREATE_SECURITY_EXCEPTION_M,
|
|
3021
|
+
{ input }
|
|
3022
|
+
);
|
|
3023
|
+
return jsonResult(data.createSecurityException);
|
|
3024
|
+
} catch (error) {
|
|
3025
|
+
ctx.logger.error("config_security_exception_create failed", { error });
|
|
3026
|
+
return errorResult(
|
|
3027
|
+
`Failed to create exception: ${error instanceof Error ? error.message : String(error)}`
|
|
3028
|
+
);
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
);
|
|
3032
|
+
server.registerTool(
|
|
3033
|
+
track(mcpToolName(ctx.productName, "configuration_security_revoke_exception")),
|
|
3034
|
+
{
|
|
3035
|
+
title: "Revoke Security Exception",
|
|
3036
|
+
description: "Revoke a previously-granted security exception.",
|
|
3037
|
+
inputSchema: { id: z.string() }
|
|
3038
|
+
},
|
|
3039
|
+
async ({ id }) => {
|
|
3040
|
+
try {
|
|
3041
|
+
const data = await ctx.gql.workspace.request(
|
|
3042
|
+
REVOKE_SECURITY_EXCEPTION_M,
|
|
3043
|
+
{ id }
|
|
3044
|
+
);
|
|
3045
|
+
return jsonResult({ revoked: data.revokeSecurityException, id });
|
|
3046
|
+
} catch (error) {
|
|
3047
|
+
ctx.logger.error("config_security_exception_revoke failed", { error });
|
|
3048
|
+
return errorResult(
|
|
3049
|
+
`Failed to revoke exception: ${error instanceof Error ? error.message : String(error)}`
|
|
3050
|
+
);
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
);
|
|
3054
|
+
server.registerTool(
|
|
3055
|
+
track(mcpToolName(ctx.productName, "configuration_security_presign_evidence")),
|
|
3056
|
+
{
|
|
3057
|
+
title: "Presign Security Evidence Upload",
|
|
3058
|
+
description: "Get a presigned URL for uploading a security evidence artifact (SBOM/SARIF/etc).",
|
|
3059
|
+
inputSchema: {
|
|
3060
|
+
scanRunId: z.string(),
|
|
3061
|
+
sha256: z.string().describe("Hex sha256 digest of the artifact"),
|
|
3062
|
+
sizeBytes: z.number().describe("Size of the artifact in bytes"),
|
|
3063
|
+
type: EvidenceTypeEnum
|
|
3064
|
+
}
|
|
3065
|
+
},
|
|
3066
|
+
async ({ scanRunId, sha256, sizeBytes, type }) => {
|
|
3067
|
+
try {
|
|
3068
|
+
const data = await ctx.gql.workspace.request(
|
|
3069
|
+
PRESIGN_SECURITY_EVIDENCE_M,
|
|
3070
|
+
{ scanRunId, sha256, sizeBytes, type }
|
|
3071
|
+
);
|
|
3072
|
+
return jsonResult(data.presignSecurityEvidence);
|
|
3073
|
+
} catch (error) {
|
|
3074
|
+
ctx.logger.error("config_security_evidence_presign failed", { error });
|
|
3075
|
+
return errorResult(
|
|
3076
|
+
`Failed to presign evidence: ${error instanceof Error ? error.message : String(error)}`
|
|
3077
|
+
);
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
);
|
|
3081
|
+
server.registerTool(
|
|
3082
|
+
track(mcpToolName(ctx.productName, "configuration_security_push_scan_run")),
|
|
3083
|
+
{
|
|
3084
|
+
title: "Push Security Scan Run",
|
|
3085
|
+
description: "Push a complete security scan run from an agent (provider report + findings + evidence refs).",
|
|
3086
|
+
inputSchema: { input: z.string().describe("PushSecurityScanRunInput as a JSON string") }
|
|
3087
|
+
},
|
|
3088
|
+
async ({ input }) => {
|
|
3089
|
+
try {
|
|
3090
|
+
const parsed = JSON.parse(input);
|
|
3091
|
+
const data = await ctx.gql.workspace.request(
|
|
3092
|
+
PUSH_SECURITY_SCAN_RUN_M,
|
|
3093
|
+
{ input: parsed }
|
|
3094
|
+
);
|
|
3095
|
+
return jsonResult(data.pushSecurityScanRun);
|
|
3096
|
+
} catch (error) {
|
|
3097
|
+
ctx.logger.error("config_security_scan_run_push failed", { error });
|
|
3098
|
+
return errorResult(
|
|
3099
|
+
`Failed to push scan run: ${error instanceof Error ? error.message : String(error)}`
|
|
3100
|
+
);
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
);
|
|
3104
|
+
}
|
|
3105
|
+
function registerConfigCITools(server, ctx, track) {
|
|
3106
|
+
server.registerTool(
|
|
3107
|
+
track(mcpToolName(ctx.productName, "configuration_ci_get_status")),
|
|
3108
|
+
{
|
|
3109
|
+
title: "Get CI Status",
|
|
3110
|
+
description: "Get the cached CI/CD pipeline status for a GitOps provider on an agent (recent runs + workflows + aggregate metrics).",
|
|
3111
|
+
inputSchema: {
|
|
3112
|
+
providerId: z.string().describe("GitOps provider ID"),
|
|
3113
|
+
agentId: z.string().describe("Agent ID executing the request"),
|
|
3114
|
+
limit: z.number().optional().describe("Limit recent runs")
|
|
3115
|
+
}
|
|
3116
|
+
},
|
|
3117
|
+
async ({ providerId, agentId, limit }) => {
|
|
3118
|
+
try {
|
|
3119
|
+
const data = await ctx.gql.workspace.request(GET_CI_STATUS_Q, {
|
|
3120
|
+
providerId,
|
|
3121
|
+
agentId,
|
|
3122
|
+
limit
|
|
3123
|
+
});
|
|
3124
|
+
return jsonResult(data.getCIStatus);
|
|
3125
|
+
} catch (error) {
|
|
3126
|
+
ctx.logger.error("config_ci_status_get failed", { error });
|
|
3127
|
+
return errorResult(
|
|
3128
|
+
`Failed to get CI status: ${error instanceof Error ? error.message : String(error)}`
|
|
3129
|
+
);
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3132
|
+
);
|
|
3133
|
+
server.registerTool(
|
|
3134
|
+
track(mcpToolName(ctx.productName, "configuration_ci_refresh_status")),
|
|
3135
|
+
{
|
|
3136
|
+
title: "Refresh CI Status",
|
|
3137
|
+
description: "Force refresh of the cached CI/CD pipeline status snapshot.",
|
|
3138
|
+
inputSchema: { providerId: z.string(), agentId: z.string() }
|
|
3139
|
+
},
|
|
3140
|
+
async ({ providerId, agentId }) => {
|
|
3141
|
+
try {
|
|
3142
|
+
const data = await ctx.gql.workspace.request(
|
|
3143
|
+
REFRESH_CI_STATUS_M,
|
|
3144
|
+
{ providerId, agentId }
|
|
3145
|
+
);
|
|
3146
|
+
return jsonResult(data.refreshCIStatus);
|
|
3147
|
+
} catch (error) {
|
|
3148
|
+
ctx.logger.error("config_ci_status_refresh failed", { error });
|
|
3149
|
+
return errorResult(
|
|
3150
|
+
`Failed to refresh CI status: ${error instanceof Error ? error.message : String(error)}`
|
|
3151
|
+
);
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
);
|
|
3155
|
+
server.registerTool(
|
|
3156
|
+
track(mcpToolName(ctx.productName, "configuration_ci_get_pipeline_runs")),
|
|
3157
|
+
{
|
|
3158
|
+
title: "List CI Pipeline Runs",
|
|
3159
|
+
description: "List recent CI pipeline runs from a GitOps provider, optionally filtered by branch.",
|
|
1132
3160
|
inputSchema: {
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
limit: z.number().optional().describe("Max results"),
|
|
1138
|
-
offset: z.number().optional().describe("Offset for pagination")
|
|
3161
|
+
providerId: z.string(),
|
|
3162
|
+
agentId: z.string(),
|
|
3163
|
+
branch: z.string().optional(),
|
|
3164
|
+
limit: z.number().optional()
|
|
1139
3165
|
}
|
|
1140
3166
|
},
|
|
1141
|
-
async ({
|
|
3167
|
+
async ({ providerId, agentId, branch, limit }) => {
|
|
1142
3168
|
try {
|
|
1143
|
-
const
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
3169
|
+
const data = await ctx.gql.workspace.request(
|
|
3170
|
+
GET_CI_PIPELINE_RUNS_Q,
|
|
3171
|
+
{ providerId, agentId, branch, limit }
|
|
3172
|
+
);
|
|
3173
|
+
return jsonResult(data.getCIPipelineRuns);
|
|
3174
|
+
} catch (error) {
|
|
3175
|
+
ctx.logger.error("config_ci_pipeline_runs_list failed", { error });
|
|
3176
|
+
return errorResult(
|
|
3177
|
+
`Failed to list CI runs: ${error instanceof Error ? error.message : String(error)}`
|
|
3178
|
+
);
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
);
|
|
3182
|
+
server.registerTool(
|
|
3183
|
+
track(mcpToolName(ctx.productName, "configuration_ci_get_pipeline_details")),
|
|
3184
|
+
{
|
|
3185
|
+
title: "Get CI Pipeline Details",
|
|
3186
|
+
description: "Get detailed information (commit, jobs) for a single CI pipeline run.",
|
|
3187
|
+
inputSchema: {
|
|
3188
|
+
providerId: z.string(),
|
|
3189
|
+
agentId: z.string(),
|
|
3190
|
+
runId: z.string()
|
|
3191
|
+
}
|
|
3192
|
+
},
|
|
3193
|
+
async ({ providerId, agentId, runId }) => {
|
|
3194
|
+
try {
|
|
3195
|
+
const data = await ctx.gql.workspace.request(
|
|
3196
|
+
GET_CI_PIPELINE_DETAILS_Q,
|
|
3197
|
+
{ providerId, agentId, runId }
|
|
3198
|
+
);
|
|
3199
|
+
return jsonResult(data.getCIPipelineDetails);
|
|
3200
|
+
} catch (error) {
|
|
3201
|
+
ctx.logger.error("config_ci_pipeline_details_get failed", { error });
|
|
3202
|
+
return errorResult(
|
|
3203
|
+
`Failed to get pipeline details: ${error instanceof Error ? error.message : String(error)}`
|
|
3204
|
+
);
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
);
|
|
3208
|
+
server.registerTool(
|
|
3209
|
+
track(mcpToolName(ctx.productName, "configuration_ci_get_repo_stats")),
|
|
3210
|
+
{
|
|
3211
|
+
title: "Get Repository Stats",
|
|
3212
|
+
description: "Get cached repository statistics (stars, forks, languages, PRs, contributors, etc) for a GitOps provider.",
|
|
3213
|
+
inputSchema: { providerId: z.string(), agentId: z.string() }
|
|
3214
|
+
},
|
|
3215
|
+
async ({ providerId, agentId }) => {
|
|
3216
|
+
try {
|
|
3217
|
+
const data = await ctx.gql.workspace.request(GET_REPO_STATS_Q, {
|
|
3218
|
+
providerId,
|
|
3219
|
+
agentId
|
|
3220
|
+
});
|
|
3221
|
+
return jsonResult(data.getRepoStats);
|
|
3222
|
+
} catch (error) {
|
|
3223
|
+
ctx.logger.error("config_ci_repo_stats_get failed", { error });
|
|
3224
|
+
return errorResult(
|
|
3225
|
+
`Failed to get repo stats: ${error instanceof Error ? error.message : String(error)}`
|
|
3226
|
+
);
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
);
|
|
3230
|
+
server.registerTool(
|
|
3231
|
+
track(mcpToolName(ctx.productName, "configuration_ci_refresh_repo_stats")),
|
|
3232
|
+
{
|
|
3233
|
+
title: "Refresh Repository Stats",
|
|
3234
|
+
description: "Force refresh of the cached repository statistics snapshot.",
|
|
3235
|
+
inputSchema: { providerId: z.string(), agentId: z.string() }
|
|
3236
|
+
},
|
|
3237
|
+
async ({ providerId, agentId }) => {
|
|
3238
|
+
try {
|
|
3239
|
+
const data = await ctx.gql.workspace.request(
|
|
3240
|
+
REFRESH_REPO_STATS_M,
|
|
3241
|
+
{ providerId, agentId }
|
|
3242
|
+
);
|
|
3243
|
+
return jsonResult(data.refreshRepoStats);
|
|
3244
|
+
} catch (error) {
|
|
3245
|
+
ctx.logger.error("config_ci_repo_stats_refresh failed", { error });
|
|
3246
|
+
return errorResult(
|
|
3247
|
+
`Failed to refresh repo stats: ${error instanceof Error ? error.message : String(error)}`
|
|
3248
|
+
);
|
|
3249
|
+
}
|
|
3250
|
+
}
|
|
3251
|
+
);
|
|
3252
|
+
}
|
|
3253
|
+
var ProviderTypeEnum = z.enum(["AZURE_DEVOPS", "BITBUCKET", "GITHUB", "GITLAB"]);
|
|
3254
|
+
function registerConfigGitopsTools(server, ctx, track) {
|
|
3255
|
+
server.registerTool(
|
|
3256
|
+
track(mcpToolName(ctx.productName, "configuration_gitops_list")),
|
|
3257
|
+
{
|
|
3258
|
+
title: "List GitOps Providers",
|
|
3259
|
+
description: "List GitOps providers (GitHub/GitLab/Bitbucket/Azure DevOps) in the current workspace.",
|
|
3260
|
+
inputSchema: {
|
|
3261
|
+
providerType: ProviderTypeEnum.optional(),
|
|
3262
|
+
isActive: z.boolean().optional(),
|
|
3263
|
+
vibeId: z.string().optional(),
|
|
3264
|
+
limit: z.number().optional(),
|
|
3265
|
+
offset: z.number().optional()
|
|
3266
|
+
}
|
|
3267
|
+
},
|
|
3268
|
+
async ({ providerType, isActive, vibeId, limit, offset }) => {
|
|
3269
|
+
try {
|
|
3270
|
+
const filter = {};
|
|
3271
|
+
if (providerType !== void 0) filter.providerType = providerType;
|
|
3272
|
+
if (isActive !== void 0) filter.isActive = isActive;
|
|
3273
|
+
if (vibeId !== void 0) filter.vibeId = vibeId;
|
|
1147
3274
|
const pagination = {};
|
|
1148
3275
|
if (limit !== void 0) pagination.limit = limit;
|
|
1149
3276
|
if (offset !== void 0) pagination.offset = offset;
|
|
1150
3277
|
const data = await ctx.gql.workspace.request(
|
|
1151
|
-
|
|
3278
|
+
LIST_GITOPS_PROVIDERS_Q,
|
|
1152
3279
|
{
|
|
1153
|
-
filter,
|
|
3280
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
1154
3281
|
pagination: Object.keys(pagination).length > 0 ? pagination : void 0
|
|
1155
3282
|
}
|
|
1156
3283
|
);
|
|
1157
|
-
return jsonResult(data.
|
|
3284
|
+
return jsonResult(data.listGitopsProviders);
|
|
1158
3285
|
} catch (error) {
|
|
1159
|
-
ctx.logger.error("
|
|
3286
|
+
ctx.logger.error("config_gitops_list failed", { error });
|
|
1160
3287
|
return errorResult(
|
|
1161
|
-
`Failed to list
|
|
3288
|
+
`Failed to list gitops providers: ${error instanceof Error ? error.message : String(error)}`
|
|
1162
3289
|
);
|
|
1163
3290
|
}
|
|
1164
3291
|
}
|
|
1165
3292
|
);
|
|
1166
3293
|
server.registerTool(
|
|
1167
|
-
track(mcpToolName(ctx.productName, "
|
|
3294
|
+
track(mcpToolName(ctx.productName, "configuration_gitops_get")),
|
|
1168
3295
|
{
|
|
1169
|
-
title: "Get
|
|
1170
|
-
description: "Get a
|
|
3296
|
+
title: "Get GitOps Provider",
|
|
3297
|
+
description: "Get a single GitOps provider by ID.",
|
|
3298
|
+
inputSchema: { id: z.string() }
|
|
3299
|
+
},
|
|
3300
|
+
async ({ id }) => {
|
|
3301
|
+
try {
|
|
3302
|
+
const data = await ctx.gql.workspace.request(
|
|
3303
|
+
GET_GITOPS_PROVIDER_Q,
|
|
3304
|
+
{ id }
|
|
3305
|
+
);
|
|
3306
|
+
return jsonResult(data.getGitopsProvider);
|
|
3307
|
+
} catch (error) {
|
|
3308
|
+
ctx.logger.error("config_gitops_get failed", { error });
|
|
3309
|
+
return errorResult(
|
|
3310
|
+
`Failed to get gitops provider: ${error instanceof Error ? error.message : String(error)}`
|
|
3311
|
+
);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
);
|
|
3315
|
+
server.registerTool(
|
|
3316
|
+
track(mcpToolName(ctx.productName, "configuration_gitops_create")),
|
|
3317
|
+
{
|
|
3318
|
+
title: "Create GitOps Provider",
|
|
3319
|
+
description: "Create a new GitOps provider connection.",
|
|
1171
3320
|
inputSchema: {
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
3321
|
+
name: z.string(),
|
|
3322
|
+
providerType: ProviderTypeEnum,
|
|
3323
|
+
repoUrl: z.string(),
|
|
3324
|
+
vibeId: z.string().optional(),
|
|
3325
|
+
isActive: z.boolean().optional(),
|
|
3326
|
+
metadata: z.string().optional().describe("Optional JSON-string metadata blob")
|
|
1175
3327
|
}
|
|
1176
3328
|
},
|
|
1177
|
-
async ({
|
|
3329
|
+
async ({ name, providerType, repoUrl, vibeId, isActive, metadata }) => {
|
|
1178
3330
|
try {
|
|
3331
|
+
const input = { name, providerType, repoUrl };
|
|
3332
|
+
if (vibeId !== void 0) input.vibeId = vibeId;
|
|
3333
|
+
if (isActive !== void 0) input.isActive = isActive;
|
|
3334
|
+
if (metadata !== void 0) input.metadata = JSON.parse(metadata);
|
|
1179
3335
|
const data = await ctx.gql.workspace.request(
|
|
1180
|
-
|
|
1181
|
-
{
|
|
1182
|
-
key,
|
|
1183
|
-
scope,
|
|
1184
|
-
scopeId
|
|
1185
|
-
}
|
|
3336
|
+
CREATE_GITOPS_PROVIDER_M,
|
|
3337
|
+
{ input }
|
|
1186
3338
|
);
|
|
1187
|
-
return jsonResult(data.
|
|
3339
|
+
return jsonResult(data.createGitopsProvider);
|
|
1188
3340
|
} catch (error) {
|
|
1189
|
-
ctx.logger.error("
|
|
3341
|
+
ctx.logger.error("config_gitops_create failed", { error });
|
|
1190
3342
|
return errorResult(
|
|
1191
|
-
`Failed to
|
|
3343
|
+
`Failed to create gitops provider: ${error instanceof Error ? error.message : String(error)}`
|
|
1192
3344
|
);
|
|
1193
3345
|
}
|
|
1194
3346
|
}
|
|
1195
3347
|
);
|
|
1196
3348
|
server.registerTool(
|
|
1197
|
-
track(mcpToolName(ctx.productName, "
|
|
3349
|
+
track(mcpToolName(ctx.productName, "configuration_gitops_update")),
|
|
1198
3350
|
{
|
|
1199
|
-
title: "
|
|
1200
|
-
description: "
|
|
3351
|
+
title: "Update GitOps Provider",
|
|
3352
|
+
description: "Update an existing GitOps provider connection.",
|
|
1201
3353
|
inputSchema: {
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
3354
|
+
id: z.string(),
|
|
3355
|
+
name: z.string().optional(),
|
|
3356
|
+
repoUrl: z.string().optional(),
|
|
3357
|
+
vibeId: z.string().optional(),
|
|
3358
|
+
isActive: z.boolean().optional(),
|
|
3359
|
+
metadata: z.string().optional().describe("Optional JSON-string metadata blob")
|
|
1207
3360
|
}
|
|
1208
3361
|
},
|
|
1209
|
-
async ({
|
|
3362
|
+
async ({ id, name, repoUrl, vibeId, isActive, metadata }) => {
|
|
1210
3363
|
try {
|
|
1211
|
-
const
|
|
1212
|
-
|
|
1213
|
-
if (
|
|
1214
|
-
if (
|
|
3364
|
+
const input = {};
|
|
3365
|
+
if (name !== void 0) input.name = name;
|
|
3366
|
+
if (repoUrl !== void 0) input.repoUrl = repoUrl;
|
|
3367
|
+
if (vibeId !== void 0) input.vibeId = vibeId;
|
|
3368
|
+
if (isActive !== void 0) input.isActive = isActive;
|
|
3369
|
+
if (metadata !== void 0) input.metadata = JSON.parse(metadata);
|
|
1215
3370
|
const data = await ctx.gql.workspace.request(
|
|
1216
|
-
|
|
1217
|
-
|
|
3371
|
+
UPDATE_GITOPS_PROVIDER_M,
|
|
3372
|
+
{ id, input }
|
|
1218
3373
|
);
|
|
1219
|
-
return jsonResult(data.
|
|
3374
|
+
return jsonResult(data.updateGitopsProvider);
|
|
1220
3375
|
} catch (error) {
|
|
1221
|
-
ctx.logger.error("
|
|
3376
|
+
ctx.logger.error("config_gitops_update failed", { error });
|
|
1222
3377
|
return errorResult(
|
|
1223
|
-
`Failed to
|
|
3378
|
+
`Failed to update gitops provider: ${error instanceof Error ? error.message : String(error)}`
|
|
1224
3379
|
);
|
|
1225
3380
|
}
|
|
1226
3381
|
}
|
|
1227
3382
|
);
|
|
1228
3383
|
server.registerTool(
|
|
1229
|
-
track(mcpToolName(ctx.productName, "
|
|
3384
|
+
track(mcpToolName(ctx.productName, "configuration_gitops_delete")),
|
|
1230
3385
|
{
|
|
1231
|
-
title: "Delete
|
|
1232
|
-
description: "Delete a
|
|
3386
|
+
title: "Delete GitOps Provider",
|
|
3387
|
+
description: "Delete a GitOps provider connection.",
|
|
3388
|
+
inputSchema: { id: z.string() }
|
|
3389
|
+
},
|
|
3390
|
+
async ({ id }) => {
|
|
3391
|
+
try {
|
|
3392
|
+
const data = await ctx.gql.workspace.request(
|
|
3393
|
+
DELETE_GITOPS_PROVIDER_M,
|
|
3394
|
+
{ id }
|
|
3395
|
+
);
|
|
3396
|
+
return jsonResult({ deleted: data.deleteGitopsProvider, id });
|
|
3397
|
+
} catch (error) {
|
|
3398
|
+
ctx.logger.error("config_gitops_delete failed", { error });
|
|
3399
|
+
return errorResult(
|
|
3400
|
+
`Failed to delete gitops provider: ${error instanceof Error ? error.message : String(error)}`
|
|
3401
|
+
);
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3404
|
+
);
|
|
3405
|
+
}
|
|
3406
|
+
var SettingsCategoryEnum = z.enum([
|
|
3407
|
+
"ADVANCED",
|
|
3408
|
+
"NOTIFICATIONS",
|
|
3409
|
+
"PREFERENCES",
|
|
3410
|
+
"PROFILE",
|
|
3411
|
+
"SECURITY",
|
|
3412
|
+
"WORKSPACE_DEFAULTS"
|
|
3413
|
+
]);
|
|
3414
|
+
function registerConfigSettingsTools(server, ctx, track) {
|
|
3415
|
+
server.registerTool(
|
|
3416
|
+
track(mcpToolName(ctx.productName, "configuration_settings_mine")),
|
|
3417
|
+
{
|
|
3418
|
+
title: "Get My Settings",
|
|
3419
|
+
description: "Get the complete settings bundle for the current user (preferences + notifications + workspace defaults + profile + security).",
|
|
3420
|
+
inputSchema: {}
|
|
3421
|
+
},
|
|
3422
|
+
async () => {
|
|
3423
|
+
try {
|
|
3424
|
+
const data = await ctx.gql.workspace.request(MY_SETTINGS_Q);
|
|
3425
|
+
return jsonResult(data.mySettings);
|
|
3426
|
+
} catch (error) {
|
|
3427
|
+
ctx.logger.error("config_settings_mine failed", { error });
|
|
3428
|
+
return errorResult(
|
|
3429
|
+
`Failed to get settings: ${error instanceof Error ? error.message : String(error)}`
|
|
3430
|
+
);
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
);
|
|
3434
|
+
server.registerTool(
|
|
3435
|
+
track(mcpToolName(ctx.productName, "configuration_settings_mine_by_category")),
|
|
3436
|
+
{
|
|
3437
|
+
title: "Get My Settings by Category",
|
|
3438
|
+
description: "Get a single settings category as a JSON blob.",
|
|
3439
|
+
inputSchema: { category: SettingsCategoryEnum }
|
|
3440
|
+
},
|
|
3441
|
+
async ({ category }) => {
|
|
3442
|
+
try {
|
|
3443
|
+
const data = await ctx.gql.workspace.request(
|
|
3444
|
+
MY_SETTINGS_BY_CATEGORY_Q,
|
|
3445
|
+
{ category }
|
|
3446
|
+
);
|
|
3447
|
+
return jsonResult(data.mySettingsByCategory);
|
|
3448
|
+
} catch (error) {
|
|
3449
|
+
ctx.logger.error("config_settings_mine_by_category failed", { error });
|
|
3450
|
+
return errorResult(
|
|
3451
|
+
`Failed to get settings category: ${error instanceof Error ? error.message : String(error)}`
|
|
3452
|
+
);
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
);
|
|
3456
|
+
server.registerTool(
|
|
3457
|
+
track(mcpToolName(ctx.productName, "configuration_settings_reset")),
|
|
3458
|
+
{
|
|
3459
|
+
title: "Reset Settings Category",
|
|
3460
|
+
description: "Reset a settings category to its workspace defaults.",
|
|
3461
|
+
inputSchema: { category: SettingsCategoryEnum }
|
|
3462
|
+
},
|
|
3463
|
+
async ({ category }) => {
|
|
3464
|
+
try {
|
|
3465
|
+
const data = await ctx.gql.workspace.request(RESET_SETTINGS_M, {
|
|
3466
|
+
category
|
|
3467
|
+
});
|
|
3468
|
+
return jsonResult({ reset: data.resetSettings, category });
|
|
3469
|
+
} catch (error) {
|
|
3470
|
+
ctx.logger.error("config_settings_reset failed", { error });
|
|
3471
|
+
return errorResult(
|
|
3472
|
+
`Failed to reset settings: ${error instanceof Error ? error.message : String(error)}`
|
|
3473
|
+
);
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
);
|
|
3477
|
+
server.registerTool(
|
|
3478
|
+
track(mcpToolName(ctx.productName, "configuration_settings_update_preferences")),
|
|
3479
|
+
{
|
|
3480
|
+
title: "Update Preferences",
|
|
3481
|
+
description: "Update the current user UI preferences (theme, density, IDE, font, tab order, etc).",
|
|
1233
3482
|
inputSchema: {
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
3483
|
+
theme: z.string().optional(),
|
|
3484
|
+
uiDensity: z.string().optional(),
|
|
3485
|
+
sidebarCollapsed: z.boolean().optional(),
|
|
3486
|
+
codeFont: z.string().optional(),
|
|
3487
|
+
codeFontSize: z.number().optional(),
|
|
3488
|
+
preferredIdeCommand: z.string().nullable().optional(),
|
|
3489
|
+
defaultAgentForVibe: z.string().optional().describe("JSON blob"),
|
|
3490
|
+
vibeIdeOverrides: z.string().optional().describe("JSON blob"),
|
|
3491
|
+
vibeDetailTabOrder: z.string().optional().describe("JSON blob")
|
|
3492
|
+
}
|
|
3493
|
+
},
|
|
3494
|
+
async ({
|
|
3495
|
+
theme,
|
|
3496
|
+
uiDensity,
|
|
3497
|
+
sidebarCollapsed,
|
|
3498
|
+
codeFont,
|
|
3499
|
+
codeFontSize,
|
|
3500
|
+
preferredIdeCommand,
|
|
3501
|
+
defaultAgentForVibe,
|
|
3502
|
+
vibeIdeOverrides,
|
|
3503
|
+
vibeDetailTabOrder
|
|
3504
|
+
}) => {
|
|
3505
|
+
try {
|
|
3506
|
+
const input = {};
|
|
3507
|
+
if (theme !== void 0) input.theme = theme;
|
|
3508
|
+
if (uiDensity !== void 0) input.uiDensity = uiDensity;
|
|
3509
|
+
if (sidebarCollapsed !== void 0) input.sidebarCollapsed = sidebarCollapsed;
|
|
3510
|
+
if (codeFont !== void 0) input.codeFont = codeFont;
|
|
3511
|
+
if (codeFontSize !== void 0) input.codeFontSize = codeFontSize;
|
|
3512
|
+
if (preferredIdeCommand !== void 0) input.preferredIdeCommand = preferredIdeCommand;
|
|
3513
|
+
if (defaultAgentForVibe !== void 0)
|
|
3514
|
+
input.defaultAgentForVibe = JSON.parse(defaultAgentForVibe);
|
|
3515
|
+
if (vibeIdeOverrides !== void 0) input.vibeIdeOverrides = JSON.parse(vibeIdeOverrides);
|
|
3516
|
+
if (vibeDetailTabOrder !== void 0)
|
|
3517
|
+
input.vibeDetailTabOrder = JSON.parse(vibeDetailTabOrder);
|
|
3518
|
+
const data = await ctx.gql.workspace.request(
|
|
3519
|
+
UPDATE_PREFERENCES_M,
|
|
3520
|
+
{ input }
|
|
3521
|
+
);
|
|
3522
|
+
return jsonResult(data.updatePreferences);
|
|
3523
|
+
} catch (error) {
|
|
3524
|
+
ctx.logger.error("config_settings_preferences_update failed", { error });
|
|
3525
|
+
return errorResult(
|
|
3526
|
+
`Failed to update preferences: ${error instanceof Error ? error.message : String(error)}`
|
|
3527
|
+
);
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
);
|
|
3531
|
+
server.registerTool(
|
|
3532
|
+
track(mcpToolName(ctx.productName, "configuration_settings_update_notif_prefs")),
|
|
3533
|
+
{
|
|
3534
|
+
title: "Update Notification Preferences",
|
|
3535
|
+
description: "Update notification toggles and digest cadence.",
|
|
3536
|
+
inputSchema: {
|
|
3537
|
+
emailDigest: z.boolean().optional(),
|
|
3538
|
+
digestFrequency: z.string().optional(),
|
|
3539
|
+
agentOffline: z.boolean().optional(),
|
|
3540
|
+
sessionError: z.boolean().optional(),
|
|
3541
|
+
vibeStatusChange: z.boolean().optional()
|
|
3542
|
+
}
|
|
3543
|
+
},
|
|
3544
|
+
async (input) => {
|
|
3545
|
+
try {
|
|
3546
|
+
const cleaned = {};
|
|
3547
|
+
for (const [k, v] of Object.entries(input)) {
|
|
3548
|
+
if (v !== void 0) cleaned[k] = v;
|
|
3549
|
+
}
|
|
3550
|
+
const data = await ctx.gql.workspace.request(
|
|
3551
|
+
UPDATE_NOTIFICATION_PREFERENCES_M,
|
|
3552
|
+
{ input: cleaned }
|
|
3553
|
+
);
|
|
3554
|
+
return jsonResult(data.updateNotificationPreferences);
|
|
3555
|
+
} catch (error) {
|
|
3556
|
+
ctx.logger.error("config_settings_notifications_update failed", { error });
|
|
3557
|
+
return errorResult(
|
|
3558
|
+
`Failed to update notifications: ${error instanceof Error ? error.message : String(error)}`
|
|
3559
|
+
);
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
);
|
|
3563
|
+
server.registerTool(
|
|
3564
|
+
track(mcpToolName(ctx.productName, "configuration_settings_update_workspace_defaults")),
|
|
3565
|
+
{
|
|
3566
|
+
title: "Update Workspace Defaults",
|
|
3567
|
+
description: "Update workspace-level default settings for agents, sessions, vibes, telemetry.",
|
|
3568
|
+
inputSchema: {
|
|
3569
|
+
defaultAgent: z.string().optional(),
|
|
3570
|
+
defaultSessionType: z.string().optional(),
|
|
3571
|
+
defaultVibeType: z.string().optional(),
|
|
3572
|
+
defaultEnvironmentVariables: z.string().optional(),
|
|
3573
|
+
autoStartSessions: z.boolean().optional(),
|
|
3574
|
+
autoGitSync: z.boolean().optional(),
|
|
3575
|
+
agentHeartbeatInterval: z.number().optional(),
|
|
3576
|
+
agentMaxSessions: z.number().optional(),
|
|
3577
|
+
agentAutoReconnect: z.boolean().optional(),
|
|
3578
|
+
autoUpdate: z.boolean().optional(),
|
|
3579
|
+
telemetryEnabled: z.boolean().optional(),
|
|
3580
|
+
logLevel: z.string().optional()
|
|
3581
|
+
}
|
|
3582
|
+
},
|
|
3583
|
+
async (input) => {
|
|
3584
|
+
try {
|
|
3585
|
+
const cleaned = {};
|
|
3586
|
+
for (const [k, v] of Object.entries(input)) {
|
|
3587
|
+
if (v !== void 0) cleaned[k] = v;
|
|
3588
|
+
}
|
|
3589
|
+
const data = await ctx.gql.workspace.request(
|
|
3590
|
+
UPDATE_WORKSPACE_DEFAULTS_M,
|
|
3591
|
+
{ input: cleaned }
|
|
3592
|
+
);
|
|
3593
|
+
return jsonResult(data.updateWorkspaceDefaults);
|
|
3594
|
+
} catch (error) {
|
|
3595
|
+
ctx.logger.error("config_settings_workspace_defaults_update failed", { error });
|
|
3596
|
+
return errorResult(
|
|
3597
|
+
`Failed to update workspace defaults: ${error instanceof Error ? error.message : String(error)}`
|
|
3598
|
+
);
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3601
|
+
);
|
|
3602
|
+
server.registerTool(
|
|
3603
|
+
track(mcpToolName(ctx.productName, "configuration_settings_list_secrets")),
|
|
3604
|
+
{
|
|
3605
|
+
title: "List Settings Secrets",
|
|
3606
|
+
description: "List stored settings secrets (values are hidden by default).",
|
|
3607
|
+
inputSchema: {}
|
|
3608
|
+
},
|
|
3609
|
+
async () => {
|
|
3610
|
+
try {
|
|
3611
|
+
const data = await ctx.gql.workspace.request(
|
|
3612
|
+
LIST_SETTINGS_SECRETS_Q
|
|
3613
|
+
);
|
|
3614
|
+
return jsonResult(data.listSettingsSecrets);
|
|
3615
|
+
} catch (error) {
|
|
3616
|
+
ctx.logger.error("config_settings_secrets_list failed", { error });
|
|
3617
|
+
return errorResult(
|
|
3618
|
+
`Failed to list secrets: ${error instanceof Error ? error.message : String(error)}`
|
|
3619
|
+
);
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
);
|
|
3623
|
+
server.registerTool(
|
|
3624
|
+
track(mcpToolName(ctx.productName, "configuration_settings_set_secret")),
|
|
3625
|
+
{
|
|
3626
|
+
title: "Set Settings Secret",
|
|
3627
|
+
description: "Create or update a settings secret (value is encrypted at rest).",
|
|
3628
|
+
inputSchema: {
|
|
3629
|
+
key: z.string(),
|
|
3630
|
+
value: z.string()
|
|
3631
|
+
}
|
|
3632
|
+
},
|
|
3633
|
+
async ({ key, value }) => {
|
|
3634
|
+
try {
|
|
3635
|
+
const data = await ctx.gql.workspace.request(
|
|
3636
|
+
SET_SETTINGS_SECRET_M,
|
|
3637
|
+
{ input: { key, value } }
|
|
3638
|
+
);
|
|
3639
|
+
return jsonResult(data.setSettingsSecret);
|
|
3640
|
+
} catch (error) {
|
|
3641
|
+
ctx.logger.error("config_settings_secret_set failed", { error });
|
|
3642
|
+
return errorResult(
|
|
3643
|
+
`Failed to set secret: ${error instanceof Error ? error.message : String(error)}`
|
|
3644
|
+
);
|
|
1237
3645
|
}
|
|
3646
|
+
}
|
|
3647
|
+
);
|
|
3648
|
+
server.registerTool(
|
|
3649
|
+
track(mcpToolName(ctx.productName, "configuration_settings_delete_secret")),
|
|
3650
|
+
{
|
|
3651
|
+
title: "Delete Settings Secret",
|
|
3652
|
+
description: "Delete a settings secret by key.",
|
|
3653
|
+
inputSchema: { key: z.string() }
|
|
1238
3654
|
},
|
|
1239
|
-
async ({ key
|
|
3655
|
+
async ({ key }) => {
|
|
1240
3656
|
try {
|
|
1241
3657
|
const data = await ctx.gql.workspace.request(
|
|
1242
|
-
|
|
1243
|
-
{ key
|
|
3658
|
+
DELETE_SETTINGS_SECRET_M,
|
|
3659
|
+
{ key }
|
|
1244
3660
|
);
|
|
1245
|
-
return jsonResult({ deleted: data.
|
|
3661
|
+
return jsonResult({ deleted: data.deleteSettingsSecret, key });
|
|
1246
3662
|
} catch (error) {
|
|
1247
|
-
ctx.logger.error("
|
|
3663
|
+
ctx.logger.error("config_settings_secret_delete failed", { error });
|
|
1248
3664
|
return errorResult(
|
|
1249
|
-
`Failed to delete
|
|
3665
|
+
`Failed to delete secret: ${error instanceof Error ? error.message : String(error)}`
|
|
1250
3666
|
);
|
|
1251
3667
|
}
|
|
1252
3668
|
}
|
|
1253
3669
|
);
|
|
1254
3670
|
server.registerTool(
|
|
1255
|
-
track(mcpToolName(ctx.productName, "
|
|
3671
|
+
track(mcpToolName(ctx.productName, "configuration_settings_resolve_integration_token")),
|
|
1256
3672
|
{
|
|
1257
|
-
title: "
|
|
1258
|
-
description: "
|
|
1259
|
-
inputSchema: {
|
|
1260
|
-
scope: ConfigScopeEnum.describe("Configuration scope"),
|
|
1261
|
-
scopeId: z.string().optional().describe("Scope entity ID")
|
|
1262
|
-
}
|
|
3673
|
+
title: "Resolve Integration Token",
|
|
3674
|
+
description: "Resolve a decrypted integration token for an agent to call third-party APIs (handles OAuth refresh).",
|
|
3675
|
+
inputSchema: { connectionId: z.string() }
|
|
1263
3676
|
},
|
|
1264
|
-
async ({
|
|
3677
|
+
async ({ connectionId }) => {
|
|
1265
3678
|
try {
|
|
1266
|
-
const data = await ctx.gql.workspace.request(
|
|
1267
|
-
|
|
1268
|
-
{ scope, scopeId }
|
|
1269
|
-
);
|
|
1270
|
-
return jsonResult(data.configurationsByScope);
|
|
3679
|
+
const data = await ctx.gql.workspace.request(RESOLVE_INTEGRATION_TOKEN_M, { connectionId });
|
|
3680
|
+
return jsonResult(data.vibecontrolsResolveIntegrationToken);
|
|
1271
3681
|
} catch (error) {
|
|
1272
|
-
ctx.logger.error("
|
|
3682
|
+
ctx.logger.error("config_settings_integration_token_resolve failed", { error });
|
|
1273
3683
|
return errorResult(
|
|
1274
|
-
`Failed to
|
|
3684
|
+
`Failed to resolve token: ${error instanceof Error ? error.message : String(error)}`
|
|
1275
3685
|
);
|
|
1276
3686
|
}
|
|
1277
3687
|
}
|
|
@@ -2048,6 +4458,156 @@ function registerSessionSharingTools(server, ctx, track) {
|
|
|
2048
4458
|
}
|
|
2049
4459
|
}
|
|
2050
4460
|
);
|
|
4461
|
+
server.registerTool(
|
|
4462
|
+
track(mcpToolName(ctx.productName, "sessions_share_update")),
|
|
4463
|
+
{
|
|
4464
|
+
title: "Update Session Share",
|
|
4465
|
+
description: "Update an existing session share (permission/expiry).",
|
|
4466
|
+
inputSchema: {
|
|
4467
|
+
id: z.string().describe("Session share ID"),
|
|
4468
|
+
permission: z.string().optional().describe("VIEW or INTERACT"),
|
|
4469
|
+
expiresAt: z.string().optional().describe("Expiration date in ISO format")
|
|
4470
|
+
}
|
|
4471
|
+
},
|
|
4472
|
+
async ({ id, permission, expiresAt }) => {
|
|
4473
|
+
try {
|
|
4474
|
+
const input = {};
|
|
4475
|
+
if (permission !== void 0) input.permission = permission;
|
|
4476
|
+
if (expiresAt !== void 0) input.expiresAt = expiresAt;
|
|
4477
|
+
const data = await ctx.gql.workspace.request(
|
|
4478
|
+
UPDATE_SESSION_SHARE,
|
|
4479
|
+
{ id, input }
|
|
4480
|
+
);
|
|
4481
|
+
return jsonResult(data.updateSessionShare);
|
|
4482
|
+
} catch (error) {
|
|
4483
|
+
ctx.logger.error("vibecontrols_sessions_share_update failed", { error });
|
|
4484
|
+
return errorResult(
|
|
4485
|
+
`Failed to update session share: ${error instanceof Error ? error.message : String(error)}`
|
|
4486
|
+
);
|
|
4487
|
+
}
|
|
4488
|
+
}
|
|
4489
|
+
);
|
|
4490
|
+
server.registerTool(
|
|
4491
|
+
track(mcpToolName(ctx.productName, "sessions_join")),
|
|
4492
|
+
{
|
|
4493
|
+
title: "Join Shared Session",
|
|
4494
|
+
description: "Join a shared session via share id or share-link token.",
|
|
4495
|
+
inputSchema: {
|
|
4496
|
+
shareId: z.string().optional().describe("Direct share ID"),
|
|
4497
|
+
shareToken: z.string().optional().describe("Share link token"),
|
|
4498
|
+
password: z.string().optional().describe("Password if the link is protected")
|
|
4499
|
+
}
|
|
4500
|
+
},
|
|
4501
|
+
async ({ shareId, shareToken, password }) => {
|
|
4502
|
+
try {
|
|
4503
|
+
const input = {};
|
|
4504
|
+
if (shareId !== void 0) input.shareId = shareId;
|
|
4505
|
+
if (shareToken !== void 0) input.shareToken = shareToken;
|
|
4506
|
+
if (password !== void 0) input.password = password;
|
|
4507
|
+
const data = await ctx.gql.workspace.request(
|
|
4508
|
+
JOIN_SHARED_SESSION,
|
|
4509
|
+
{ input }
|
|
4510
|
+
);
|
|
4511
|
+
return jsonResult(data.joinSharedSession);
|
|
4512
|
+
} catch (error) {
|
|
4513
|
+
ctx.logger.error("vibecontrols_sessions_join failed", { error });
|
|
4514
|
+
return errorResult(
|
|
4515
|
+
`Failed to join shared session: ${error instanceof Error ? error.message : String(error)}`
|
|
4516
|
+
);
|
|
4517
|
+
}
|
|
4518
|
+
}
|
|
4519
|
+
);
|
|
4520
|
+
server.registerTool(
|
|
4521
|
+
track(mcpToolName(ctx.productName, "sessions_leave")),
|
|
4522
|
+
{
|
|
4523
|
+
title: "Leave Shared Session",
|
|
4524
|
+
description: "Leave a shared session as a collaborator.",
|
|
4525
|
+
inputSchema: { sessionId: z.string().describe("Session ID") }
|
|
4526
|
+
},
|
|
4527
|
+
async ({ sessionId }) => {
|
|
4528
|
+
try {
|
|
4529
|
+
const data = await ctx.gql.workspace.request(
|
|
4530
|
+
LEAVE_SHARED_SESSION,
|
|
4531
|
+
{ sessionId }
|
|
4532
|
+
);
|
|
4533
|
+
return jsonResult({ left: data.leaveSharedSession });
|
|
4534
|
+
} catch (error) {
|
|
4535
|
+
ctx.logger.error("vibecontrols_sessions_leave failed", { error });
|
|
4536
|
+
return errorResult(
|
|
4537
|
+
`Failed to leave shared session: ${error instanceof Error ? error.message : String(error)}`
|
|
4538
|
+
);
|
|
4539
|
+
}
|
|
4540
|
+
}
|
|
4541
|
+
);
|
|
4542
|
+
server.registerTool(
|
|
4543
|
+
track(mcpToolName(ctx.productName, "sessions_request_control")),
|
|
4544
|
+
{
|
|
4545
|
+
title: "Request Session Control",
|
|
4546
|
+
description: "Request control of a shared session (INTERACT permission).",
|
|
4547
|
+
inputSchema: { sessionId: z.string().describe("Session ID") }
|
|
4548
|
+
},
|
|
4549
|
+
async ({ sessionId }) => {
|
|
4550
|
+
try {
|
|
4551
|
+
const data = await ctx.gql.workspace.request(
|
|
4552
|
+
REQUEST_SESSION_CONTROL,
|
|
4553
|
+
{ sessionId }
|
|
4554
|
+
);
|
|
4555
|
+
return jsonResult({ requested: data.requestSessionControl });
|
|
4556
|
+
} catch (error) {
|
|
4557
|
+
ctx.logger.error("vibecontrols_sessions_request_control failed", { error });
|
|
4558
|
+
return errorResult(
|
|
4559
|
+
`Failed to request session control: ${error instanceof Error ? error.message : String(error)}`
|
|
4560
|
+
);
|
|
4561
|
+
}
|
|
4562
|
+
}
|
|
4563
|
+
);
|
|
4564
|
+
server.registerTool(
|
|
4565
|
+
track(mcpToolName(ctx.productName, "sessions_release_control")),
|
|
4566
|
+
{
|
|
4567
|
+
title: "Release Session Control",
|
|
4568
|
+
description: "Release control of a shared session.",
|
|
4569
|
+
inputSchema: { sessionId: z.string().describe("Session ID") }
|
|
4570
|
+
},
|
|
4571
|
+
async ({ sessionId }) => {
|
|
4572
|
+
try {
|
|
4573
|
+
const data = await ctx.gql.workspace.request(
|
|
4574
|
+
RELEASE_SESSION_CONTROL,
|
|
4575
|
+
{ sessionId }
|
|
4576
|
+
);
|
|
4577
|
+
return jsonResult({ released: data.releaseSessionControl });
|
|
4578
|
+
} catch (error) {
|
|
4579
|
+
ctx.logger.error("vibecontrols_sessions_release_control failed", { error });
|
|
4580
|
+
return errorResult(
|
|
4581
|
+
`Failed to release session control: ${error instanceof Error ? error.message : String(error)}`
|
|
4582
|
+
);
|
|
4583
|
+
}
|
|
4584
|
+
}
|
|
4585
|
+
);
|
|
4586
|
+
server.registerTool(
|
|
4587
|
+
track(mcpToolName(ctx.productName, "sessions_transfer_control")),
|
|
4588
|
+
{
|
|
4589
|
+
title: "Transfer Session Control",
|
|
4590
|
+
description: "Transfer control of a shared session to another collaborator.",
|
|
4591
|
+
inputSchema: {
|
|
4592
|
+
sessionId: z.string().describe("Session ID"),
|
|
4593
|
+
toUserId: z.string().describe("User ID to transfer control to")
|
|
4594
|
+
}
|
|
4595
|
+
},
|
|
4596
|
+
async ({ sessionId, toUserId }) => {
|
|
4597
|
+
try {
|
|
4598
|
+
const data = await ctx.gql.workspace.request(
|
|
4599
|
+
TRANSFER_SESSION_CONTROL,
|
|
4600
|
+
{ sessionId, toUserId }
|
|
4601
|
+
);
|
|
4602
|
+
return jsonResult({ transferred: data.transferSessionControl });
|
|
4603
|
+
} catch (error) {
|
|
4604
|
+
ctx.logger.error("vibecontrols_sessions_transfer_control failed", { error });
|
|
4605
|
+
return errorResult(
|
|
4606
|
+
`Failed to transfer session control: ${error instanceof Error ? error.message : String(error)}`
|
|
4607
|
+
);
|
|
4608
|
+
}
|
|
4609
|
+
}
|
|
4610
|
+
);
|
|
2051
4611
|
}
|
|
2052
4612
|
var VibecontrolsSessionStatusEnum = z.enum(["PENDING", "STARTING", "RUNNING", "STOPPED", "ERROR", "TERMINATED"]).describe("Lifecycle status of a vibecontrols session");
|
|
2053
4613
|
function registerSessionTools(server, ctx, track) {
|
|
@@ -2537,6 +5097,130 @@ function registerSessionTools(server, ctx, track) {
|
|
|
2537
5097
|
}
|
|
2538
5098
|
}
|
|
2539
5099
|
);
|
|
5100
|
+
server.registerTool(
|
|
5101
|
+
track(mcpToolName(ctx.productName, "sessions_stop_terminal")),
|
|
5102
|
+
{
|
|
5103
|
+
title: "Stop Session Terminal",
|
|
5104
|
+
description: "Stop the ttyd web terminal for a session.",
|
|
5105
|
+
inputSchema: { id: z.string().describe("Session ID") }
|
|
5106
|
+
},
|
|
5107
|
+
async ({ id }) => {
|
|
5108
|
+
try {
|
|
5109
|
+
const data = await ctx.gql.workspace.request(
|
|
5110
|
+
STOP_SESSION_TERMINAL,
|
|
5111
|
+
{ id }
|
|
5112
|
+
);
|
|
5113
|
+
return jsonResult(data.stopSessionTerminal);
|
|
5114
|
+
} catch (error) {
|
|
5115
|
+
ctx.logger.error("vibecontrols_sessions_stop_terminal failed", { error });
|
|
5116
|
+
return errorResult(
|
|
5117
|
+
`Failed to stop session terminal: ${error instanceof Error ? error.message : String(error)}`
|
|
5118
|
+
);
|
|
5119
|
+
}
|
|
5120
|
+
}
|
|
5121
|
+
);
|
|
5122
|
+
server.registerTool(
|
|
5123
|
+
track(mcpToolName(ctx.productName, "sessions_restart_terminal")),
|
|
5124
|
+
{
|
|
5125
|
+
title: "Restart Session Terminal",
|
|
5126
|
+
description: "Restart the web terminal for a session.",
|
|
5127
|
+
inputSchema: { id: z.string().describe("Session ID") }
|
|
5128
|
+
},
|
|
5129
|
+
async ({ id }) => {
|
|
5130
|
+
try {
|
|
5131
|
+
const data = await ctx.gql.workspace.request(
|
|
5132
|
+
RESTART_SESSION_TERMINAL,
|
|
5133
|
+
{ id }
|
|
5134
|
+
);
|
|
5135
|
+
return jsonResult(data.restartSessionTerminal);
|
|
5136
|
+
} catch (error) {
|
|
5137
|
+
ctx.logger.error("vibecontrols_sessions_restart_terminal failed", { error });
|
|
5138
|
+
return errorResult(
|
|
5139
|
+
`Failed to restart session terminal: ${error instanceof Error ? error.message : String(error)}`
|
|
5140
|
+
);
|
|
5141
|
+
}
|
|
5142
|
+
}
|
|
5143
|
+
);
|
|
5144
|
+
server.registerTool(
|
|
5145
|
+
track(mcpToolName(ctx.productName, "sessions_start_target_terminal")),
|
|
5146
|
+
{
|
|
5147
|
+
title: "Start Target Terminal",
|
|
5148
|
+
description: "Open a web terminal against a target host (SSH/RDP/VNC/DIRECT). Returns the connection info incl. ttydUrl.",
|
|
5149
|
+
inputSchema: {
|
|
5150
|
+
targetId: z.string().describe("Target ID"),
|
|
5151
|
+
shell: z.string().optional().describe("Shell binary path")
|
|
5152
|
+
}
|
|
5153
|
+
},
|
|
5154
|
+
async ({ targetId, shell }) => {
|
|
5155
|
+
try {
|
|
5156
|
+
const data = await ctx.gql.workspace.request(
|
|
5157
|
+
START_TARGET_TERMINAL,
|
|
5158
|
+
{ targetId, shell }
|
|
5159
|
+
);
|
|
5160
|
+
return jsonResult(data.startTerminal);
|
|
5161
|
+
} catch (error) {
|
|
5162
|
+
ctx.logger.error("vibecontrols_sessions_start_target_terminal failed", { error });
|
|
5163
|
+
return errorResult(
|
|
5164
|
+
`Failed to start target terminal: ${error instanceof Error ? error.message : String(error)}`
|
|
5165
|
+
);
|
|
5166
|
+
}
|
|
5167
|
+
}
|
|
5168
|
+
);
|
|
5169
|
+
server.registerTool(
|
|
5170
|
+
track(mcpToolName(ctx.productName, "sessions_stop_target_terminal")),
|
|
5171
|
+
{
|
|
5172
|
+
title: "Stop Target Terminal",
|
|
5173
|
+
description: "Stop a target terminal session.",
|
|
5174
|
+
inputSchema: { sessionId: z.string().describe("Target terminal session ID") }
|
|
5175
|
+
},
|
|
5176
|
+
async ({ sessionId }) => {
|
|
5177
|
+
try {
|
|
5178
|
+
const data = await ctx.gql.workspace.request(
|
|
5179
|
+
STOP_TARGET_TERMINAL,
|
|
5180
|
+
{ sessionId }
|
|
5181
|
+
);
|
|
5182
|
+
return jsonResult({ stopped: data.stopTerminal, sessionId });
|
|
5183
|
+
} catch (error) {
|
|
5184
|
+
ctx.logger.error("vibecontrols_sessions_stop_target_terminal failed", { error });
|
|
5185
|
+
return errorResult(
|
|
5186
|
+
`Failed to stop target terminal: ${error instanceof Error ? error.message : String(error)}`
|
|
5187
|
+
);
|
|
5188
|
+
}
|
|
5189
|
+
}
|
|
5190
|
+
);
|
|
5191
|
+
server.registerTool(
|
|
5192
|
+
track(mcpToolName(ctx.productName, "sessions_export")),
|
|
5193
|
+
{
|
|
5194
|
+
title: "Export Sessions",
|
|
5195
|
+
description: "Export sessions to CSV or JSON.",
|
|
5196
|
+
inputSchema: {
|
|
5197
|
+
format: z.enum(["CSV", "JSON"]).optional().describe("Output format"),
|
|
5198
|
+
status: z.string().optional(),
|
|
5199
|
+
type: z.string().optional(),
|
|
5200
|
+
agentId: z.string().optional(),
|
|
5201
|
+
vibeId: z.string().optional()
|
|
5202
|
+
}
|
|
5203
|
+
},
|
|
5204
|
+
async ({ format, status, type, agentId, vibeId }) => {
|
|
5205
|
+
try {
|
|
5206
|
+
const filter = {};
|
|
5207
|
+
if (status !== void 0) filter.status = status;
|
|
5208
|
+
if (type !== void 0) filter.type = type;
|
|
5209
|
+
if (agentId !== void 0) filter.agentId = agentId;
|
|
5210
|
+
if (vibeId !== void 0) filter.vibeId = vibeId;
|
|
5211
|
+
const input = {};
|
|
5212
|
+
if (Object.keys(filter).length) input.filter = filter;
|
|
5213
|
+
if (format !== void 0) input.format = format;
|
|
5214
|
+
const data = await ctx.gql.workspace.request(EXPORT_SESSIONS, { input });
|
|
5215
|
+
return jsonResult(data.exportSessions);
|
|
5216
|
+
} catch (error) {
|
|
5217
|
+
ctx.logger.error("vibecontrols_sessions_export failed", { error });
|
|
5218
|
+
return errorResult(
|
|
5219
|
+
`Failed to export sessions: ${error instanceof Error ? error.message : String(error)}`
|
|
5220
|
+
);
|
|
5221
|
+
}
|
|
5222
|
+
}
|
|
5223
|
+
);
|
|
2540
5224
|
}
|
|
2541
5225
|
function registerTargetTools(server, ctx, track) {
|
|
2542
5226
|
server.registerTool(
|
|
@@ -2787,108 +5471,437 @@ function registerTargetTools(server, ctx, track) {
|
|
|
2787
5471
|
}
|
|
2788
5472
|
);
|
|
2789
5473
|
}
|
|
5474
|
+
var tunnelProviderKey = z.enum(["VIBETUNNELS", "CLOUDFLARE"]);
|
|
5475
|
+
var tunnelEnvironment = z.enum(["ALPHA", "PROD"]);
|
|
5476
|
+
var tunnelProtocol = z.enum(["HTTP", "HTTPS", "TCP", "UDP"]);
|
|
2790
5477
|
function registerTunnelTools(server, ctx, track) {
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
} catch (error) {
|
|
2805
|
-
ctx.logger.error("vibecontrols_tunnels_list failed", { error });
|
|
2806
|
-
return errorResult(
|
|
2807
|
-
`Failed to list tunnels: ${error instanceof Error ? error.message : String(error)}`
|
|
2808
|
-
);
|
|
5478
|
+
const w = ctx.gql.workspace;
|
|
5479
|
+
const tool = (name, title, description, inputSchema, handler) => {
|
|
5480
|
+
server.registerTool(
|
|
5481
|
+
track(mcpToolName(ctx.productName, name)),
|
|
5482
|
+
{ title, description, inputSchema },
|
|
5483
|
+
async (args) => {
|
|
5484
|
+
try {
|
|
5485
|
+
const data = await handler(args);
|
|
5486
|
+
return jsonResult(data);
|
|
5487
|
+
} catch (error) {
|
|
5488
|
+
ctx.logger.error(`vibecontrols_${name} failed`, { error });
|
|
5489
|
+
return errorResult(`Failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
5490
|
+
}
|
|
2809
5491
|
}
|
|
5492
|
+
);
|
|
5493
|
+
};
|
|
5494
|
+
tool(
|
|
5495
|
+
"tunnels_list",
|
|
5496
|
+
"List Tunnels",
|
|
5497
|
+
"List tunnels in the workspace with optional filters.",
|
|
5498
|
+
{
|
|
5499
|
+
agentId: z.string().optional(),
|
|
5500
|
+
providerKey: tunnelProviderKey.optional(),
|
|
5501
|
+
search: z.string().optional(),
|
|
5502
|
+
status: z.array(z.string()).optional(),
|
|
5503
|
+
limit: z.number().optional(),
|
|
5504
|
+
offset: z.number().optional()
|
|
5505
|
+
},
|
|
5506
|
+
async ({ agentId, providerKey, search, status, limit, offset }) => {
|
|
5507
|
+
const filter = {};
|
|
5508
|
+
if (agentId !== void 0) filter.agentId = agentId;
|
|
5509
|
+
if (providerKey !== void 0) filter.providerKey = providerKey;
|
|
5510
|
+
if (search !== void 0) filter.search = search;
|
|
5511
|
+
if (status !== void 0) filter.status = status;
|
|
5512
|
+
const pagination = {};
|
|
5513
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
5514
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
5515
|
+
const data = await w.request(LIST_TUNNELS, {
|
|
5516
|
+
filter: Object.keys(filter).length ? filter : void 0,
|
|
5517
|
+
pagination: Object.keys(pagination).length ? pagination : void 0
|
|
5518
|
+
});
|
|
5519
|
+
return data.tunnels;
|
|
5520
|
+
}
|
|
5521
|
+
);
|
|
5522
|
+
tool(
|
|
5523
|
+
"tunnels_get",
|
|
5524
|
+
"Get Tunnel",
|
|
5525
|
+
"Get a tunnel by ID.",
|
|
5526
|
+
{ id: z.string().describe("Tunnel ID") },
|
|
5527
|
+
async ({ id }) => {
|
|
5528
|
+
const data = await w.request(GET_TUNNEL, { id });
|
|
5529
|
+
return data.tunnel;
|
|
5530
|
+
}
|
|
5531
|
+
);
|
|
5532
|
+
tool(
|
|
5533
|
+
"tunnels_by_slug",
|
|
5534
|
+
"Get Tunnel by Slug",
|
|
5535
|
+
"Get a tunnel by its workspace-unique slug.",
|
|
5536
|
+
{ slug: z.string().describe("Tunnel slug") },
|
|
5537
|
+
async ({ slug }) => {
|
|
5538
|
+
const data = await w.request(GET_TUNNEL_BY_SLUG, { slug });
|
|
5539
|
+
return data.tunnelBySlug;
|
|
5540
|
+
}
|
|
5541
|
+
);
|
|
5542
|
+
tool(
|
|
5543
|
+
"tunnels_create",
|
|
5544
|
+
"Create Tunnel",
|
|
5545
|
+
"Create a tunnel in DRAFT status. Call tunnels_start to bring it up.",
|
|
5546
|
+
{
|
|
5547
|
+
agentId: z.string(),
|
|
5548
|
+
name: z.string(),
|
|
5549
|
+
providerKey: tunnelProviderKey,
|
|
5550
|
+
localPort: z.number(),
|
|
5551
|
+
description: z.string().optional(),
|
|
5552
|
+
localHost: z.string().optional(),
|
|
5553
|
+
protocol: tunnelProtocol.optional(),
|
|
5554
|
+
environment: tunnelEnvironment.optional(),
|
|
5555
|
+
managedSubdomain: z.string().optional(),
|
|
5556
|
+
slug: z.string().optional(),
|
|
5557
|
+
tlsMode: z.string().optional(),
|
|
5558
|
+
basicAuthUser: z.string().optional(),
|
|
5559
|
+
basicAuthPassword: z.string().optional()
|
|
5560
|
+
},
|
|
5561
|
+
async (args) => {
|
|
5562
|
+
const data = await w.request(CREATE_TUNNEL, { input: args });
|
|
5563
|
+
return data.createTunnel;
|
|
5564
|
+
}
|
|
5565
|
+
);
|
|
5566
|
+
tool(
|
|
5567
|
+
"tunnels_update",
|
|
5568
|
+
"Update Tunnel",
|
|
5569
|
+
"Update tunnel metadata, target host/port, basic auth, etc.",
|
|
5570
|
+
{
|
|
5571
|
+
id: z.string(),
|
|
5572
|
+
name: z.string().optional(),
|
|
5573
|
+
description: z.string().optional(),
|
|
5574
|
+
localHost: z.string().optional(),
|
|
5575
|
+
localPort: z.number().optional(),
|
|
5576
|
+
tlsMode: z.string().optional(),
|
|
5577
|
+
basicAuthUser: z.string().optional(),
|
|
5578
|
+
basicAuthPassword: z.string().optional()
|
|
5579
|
+
},
|
|
5580
|
+
async ({ id, ...input }) => {
|
|
5581
|
+
const data = await w.request(UPDATE_TUNNEL, { id, input });
|
|
5582
|
+
return data.updateTunnel;
|
|
5583
|
+
}
|
|
5584
|
+
);
|
|
5585
|
+
tool(
|
|
5586
|
+
"tunnels_delete",
|
|
5587
|
+
"Delete Tunnel",
|
|
5588
|
+
"Soft-delete a tunnel (stops it first if active).",
|
|
5589
|
+
{ id: z.string() },
|
|
5590
|
+
async ({ id }) => {
|
|
5591
|
+
const data = await w.request(DELETE_TUNNEL, { id });
|
|
5592
|
+
return { deleted: data.deleteTunnel, id };
|
|
2810
5593
|
}
|
|
2811
5594
|
);
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
}
|
|
2821
|
-
},
|
|
2822
|
-
async ({ agentId, provider }) => {
|
|
2823
|
-
try {
|
|
2824
|
-
const input = { agentId };
|
|
2825
|
-
if (provider !== void 0) input.provider = provider;
|
|
2826
|
-
const data = await ctx.gql.workspace.request(
|
|
2827
|
-
CREATE_TUNNEL,
|
|
2828
|
-
{
|
|
2829
|
-
input
|
|
2830
|
-
}
|
|
2831
|
-
);
|
|
2832
|
-
return jsonResult(data.createAgentTunnel);
|
|
2833
|
-
} catch (error) {
|
|
2834
|
-
ctx.logger.error("vibecontrols_tunnels_create failed", { error });
|
|
2835
|
-
return errorResult(
|
|
2836
|
-
`Failed to create tunnel: ${error instanceof Error ? error.message : String(error)}`
|
|
2837
|
-
);
|
|
2838
|
-
}
|
|
5595
|
+
tool(
|
|
5596
|
+
"tunnels_start",
|
|
5597
|
+
"Start Tunnel",
|
|
5598
|
+
"Transition a tunnel to ACTIVE.",
|
|
5599
|
+
{ id: z.string() },
|
|
5600
|
+
async ({ id }) => {
|
|
5601
|
+
const data = await w.request(START_TUNNEL, { id });
|
|
5602
|
+
return data.startTunnel;
|
|
2839
5603
|
}
|
|
2840
5604
|
);
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
}
|
|
2850
|
-
},
|
|
2851
|
-
async ({ agentId, tunnelId }) => {
|
|
2852
|
-
try {
|
|
2853
|
-
const data = await ctx.gql.workspace.request(STOP_TUNNEL, {
|
|
2854
|
-
agentId,
|
|
2855
|
-
tunnelId
|
|
2856
|
-
});
|
|
2857
|
-
return jsonResult({ stopped: data.stopAgentTunnel, agentId, tunnelId });
|
|
2858
|
-
} catch (error) {
|
|
2859
|
-
ctx.logger.error("vibecontrols_tunnels_stop failed", { error });
|
|
2860
|
-
return errorResult(
|
|
2861
|
-
`Failed to stop tunnel: ${error instanceof Error ? error.message : String(error)}`
|
|
2862
|
-
);
|
|
2863
|
-
}
|
|
5605
|
+
tool(
|
|
5606
|
+
"tunnels_stop",
|
|
5607
|
+
"Stop Tunnel",
|
|
5608
|
+
"Gracefully stop a running tunnel.",
|
|
5609
|
+
{ id: z.string() },
|
|
5610
|
+
async ({ id }) => {
|
|
5611
|
+
const data = await w.request(STOP_TUNNEL, { id });
|
|
5612
|
+
return data.stopTunnel;
|
|
2864
5613
|
}
|
|
2865
5614
|
);
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
}
|
|
5615
|
+
tool(
|
|
5616
|
+
"tunnels_rotate_credentials",
|
|
5617
|
+
"Rotate Tunnel Credentials",
|
|
5618
|
+
"Rotate basic-auth + provider secrets. Active sessions are revoked.",
|
|
5619
|
+
{ id: z.string() },
|
|
5620
|
+
async ({ id }) => {
|
|
5621
|
+
const data = await w.request(
|
|
5622
|
+
ROTATE_TUNNEL_CREDENTIALS,
|
|
5623
|
+
{ id }
|
|
5624
|
+
);
|
|
5625
|
+
return data.rotateTunnelCredentials;
|
|
5626
|
+
}
|
|
5627
|
+
);
|
|
5628
|
+
tool(
|
|
5629
|
+
"tunnels_issue_session",
|
|
5630
|
+
"Issue Tunnel Session",
|
|
5631
|
+
"Issue a short-lived session token for an agent to connect with. Token is returned exactly once.",
|
|
5632
|
+
{
|
|
5633
|
+
tunnelId: z.string(),
|
|
5634
|
+
ttlSeconds: z.number().optional()
|
|
5635
|
+
},
|
|
5636
|
+
async ({ tunnelId, ttlSeconds }) => {
|
|
5637
|
+
const data = await w.request(ISSUE_TUNNEL_SESSION, {
|
|
5638
|
+
tunnelId,
|
|
5639
|
+
ttlSeconds
|
|
5640
|
+
});
|
|
5641
|
+
return data.issueTunnelSession;
|
|
5642
|
+
}
|
|
5643
|
+
);
|
|
5644
|
+
tool(
|
|
5645
|
+
"tunnels_revoke_session",
|
|
5646
|
+
"Revoke Tunnel Session",
|
|
5647
|
+
"Revoke an active session (kills the live connection).",
|
|
5648
|
+
{ sessionId: z.string(), reason: z.string().optional() },
|
|
5649
|
+
async ({ sessionId, reason }) => {
|
|
5650
|
+
const data = await w.request(REVOKE_TUNNEL_SESSION, {
|
|
5651
|
+
sessionId,
|
|
5652
|
+
reason
|
|
5653
|
+
});
|
|
5654
|
+
return { revoked: data.revokeTunnelSession, sessionId };
|
|
5655
|
+
}
|
|
5656
|
+
);
|
|
5657
|
+
tool(
|
|
5658
|
+
"tunnels_list_sessions",
|
|
5659
|
+
"List Tunnel Sessions",
|
|
5660
|
+
"List sessions for a tunnel.",
|
|
5661
|
+
{
|
|
5662
|
+
tunnelId: z.string(),
|
|
5663
|
+
limit: z.number().optional(),
|
|
5664
|
+
offset: z.number().optional()
|
|
5665
|
+
},
|
|
5666
|
+
async ({ tunnelId, limit, offset }) => {
|
|
5667
|
+
const pagination = {};
|
|
5668
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
5669
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
5670
|
+
const data = await w.request(LIST_TUNNEL_SESSIONS, {
|
|
5671
|
+
tunnelId,
|
|
5672
|
+
pagination: Object.keys(pagination).length ? pagination : void 0
|
|
5673
|
+
});
|
|
5674
|
+
return data.tunnelSessions;
|
|
5675
|
+
}
|
|
5676
|
+
);
|
|
5677
|
+
tool("tunnels_providers", "List Tunnel Providers", "List all tunnel providers.", {}, async () => {
|
|
5678
|
+
const data = await w.request(LIST_TUNNEL_PROVIDERS);
|
|
5679
|
+
return data.tunnelProviders;
|
|
5680
|
+
});
|
|
5681
|
+
tool(
|
|
5682
|
+
"tunnels_provider",
|
|
5683
|
+
"Get Tunnel Provider",
|
|
5684
|
+
"Get a single tunnel provider by key.",
|
|
5685
|
+
{ key: tunnelProviderKey },
|
|
5686
|
+
async ({ key }) => {
|
|
5687
|
+
const data = await w.request(GET_TUNNEL_PROVIDER, { key });
|
|
5688
|
+
return data.tunnelProvider;
|
|
5689
|
+
}
|
|
5690
|
+
);
|
|
5691
|
+
tool(
|
|
5692
|
+
"tunnels_shards",
|
|
5693
|
+
"List Tunnel Shards",
|
|
5694
|
+
"List tunnel server shards (frps instances), optionally filtered by environment.",
|
|
5695
|
+
{ environment: tunnelEnvironment.optional() },
|
|
5696
|
+
async ({ environment }) => {
|
|
5697
|
+
const data = await w.request(LIST_TUNNEL_SHARDS, {
|
|
5698
|
+
environment
|
|
5699
|
+
});
|
|
5700
|
+
return data.tunnelShards;
|
|
5701
|
+
}
|
|
5702
|
+
);
|
|
5703
|
+
tool(
|
|
5704
|
+
"tunnels_usage",
|
|
5705
|
+
"Tunnel Usage",
|
|
5706
|
+
"Hourly usage buckets for a tunnel in a time range.",
|
|
5707
|
+
{
|
|
5708
|
+
tunnelId: z.string(),
|
|
5709
|
+
from: z.string().describe("ISO8601 start"),
|
|
5710
|
+
to: z.string().describe("ISO8601 end")
|
|
5711
|
+
},
|
|
5712
|
+
async ({ tunnelId, from, to }) => {
|
|
5713
|
+
const data = await w.request(TUNNEL_USAGE, {
|
|
5714
|
+
tunnelId,
|
|
5715
|
+
from,
|
|
5716
|
+
to
|
|
5717
|
+
});
|
|
5718
|
+
return data.tunnelUsage;
|
|
5719
|
+
}
|
|
5720
|
+
);
|
|
5721
|
+
tool(
|
|
5722
|
+
"tunnels_audit",
|
|
5723
|
+
"Tunnel Audit",
|
|
5724
|
+
"Audit log entries scoped to a tunnel.",
|
|
5725
|
+
{
|
|
5726
|
+
tunnelId: z.string(),
|
|
5727
|
+
limit: z.number().optional(),
|
|
5728
|
+
offset: z.number().optional()
|
|
5729
|
+
},
|
|
5730
|
+
async ({ tunnelId, limit, offset }) => {
|
|
5731
|
+
const pagination = {};
|
|
5732
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
5733
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
5734
|
+
const data = await w.request(TUNNEL_AUDIT, {
|
|
5735
|
+
tunnelId,
|
|
5736
|
+
pagination: Object.keys(pagination).length ? pagination : void 0
|
|
5737
|
+
});
|
|
5738
|
+
return data.tunnelAudit;
|
|
5739
|
+
}
|
|
5740
|
+
);
|
|
5741
|
+
tool(
|
|
5742
|
+
"tunnels_list_domains",
|
|
5743
|
+
"List Tunnel Domains",
|
|
5744
|
+
"List tunnel domains, optionally scoped to a single tunnel.",
|
|
5745
|
+
{
|
|
5746
|
+
tunnelId: z.string().optional(),
|
|
5747
|
+
type: z.enum(["CUSTOM", "MANAGED_SUBDOMAIN"]).optional(),
|
|
5748
|
+
verificationStatus: z.enum(["EXPIRED", "FAILED", "PENDING", "VERIFIED", "VERIFYING"]).optional(),
|
|
5749
|
+
environment: tunnelEnvironment.optional(),
|
|
5750
|
+
search: z.string().optional(),
|
|
5751
|
+
limit: z.number().optional(),
|
|
5752
|
+
offset: z.number().optional()
|
|
5753
|
+
},
|
|
5754
|
+
async ({ tunnelId, type, verificationStatus, environment, search, limit, offset }) => {
|
|
5755
|
+
const filter = {};
|
|
5756
|
+
if (type !== void 0) filter.type = type;
|
|
5757
|
+
if (verificationStatus !== void 0) filter.verificationStatus = verificationStatus;
|
|
5758
|
+
if (environment !== void 0) filter.environment = environment;
|
|
5759
|
+
if (search !== void 0) filter.search = search;
|
|
5760
|
+
const pagination = {};
|
|
5761
|
+
if (limit !== void 0) pagination.limit = limit;
|
|
5762
|
+
if (offset !== void 0) pagination.offset = offset;
|
|
5763
|
+
const data = await w.request(LIST_TUNNEL_DOMAINS, {
|
|
5764
|
+
tunnelId,
|
|
5765
|
+
filter: Object.keys(filter).length ? filter : void 0,
|
|
5766
|
+
pagination: Object.keys(pagination).length ? pagination : void 0
|
|
5767
|
+
});
|
|
5768
|
+
return data.tunnelDomains;
|
|
5769
|
+
}
|
|
5770
|
+
);
|
|
5771
|
+
tool(
|
|
5772
|
+
"tunnels_get_domain",
|
|
5773
|
+
"Get Tunnel Domain",
|
|
5774
|
+
"Get a tunnel domain by ID.",
|
|
5775
|
+
{ id: z.string() },
|
|
5776
|
+
async ({ id }) => {
|
|
5777
|
+
const data = await w.request(GET_TUNNEL_DOMAIN, { id });
|
|
5778
|
+
return data.tunnelDomain;
|
|
5779
|
+
}
|
|
5780
|
+
);
|
|
5781
|
+
tool(
|
|
5782
|
+
"tunnels_reserve_subdomain",
|
|
5783
|
+
"Reserve Tunnel Subdomain",
|
|
5784
|
+
"Reserve a managed subdomain under *.vibetunnels.com.",
|
|
5785
|
+
{
|
|
5786
|
+
label: z.string().describe("Subdomain label (without zone suffix)"),
|
|
5787
|
+
environment: tunnelEnvironment
|
|
5788
|
+
},
|
|
5789
|
+
async ({ label, environment }) => {
|
|
5790
|
+
const data = await w.request(RESERVE_TUNNEL_SUBDOMAIN, {
|
|
5791
|
+
input: { label, environment }
|
|
5792
|
+
});
|
|
5793
|
+
return data.reserveTunnelSubdomain;
|
|
5794
|
+
}
|
|
5795
|
+
);
|
|
5796
|
+
tool(
|
|
5797
|
+
"tunnels_register_custom_domain",
|
|
5798
|
+
"Register Custom Tunnel Domain",
|
|
5799
|
+
"Register a user-owned custom domain. A TXT challenge record will be returned for verification.",
|
|
5800
|
+
{ hostname: z.string() },
|
|
5801
|
+
async ({ hostname }) => {
|
|
5802
|
+
const data = await w.request(
|
|
5803
|
+
REGISTER_CUSTOM_TUNNEL_DOMAIN,
|
|
5804
|
+
{ input: { hostname } }
|
|
5805
|
+
);
|
|
5806
|
+
return data.registerCustomTunnelDomain;
|
|
5807
|
+
}
|
|
5808
|
+
);
|
|
5809
|
+
tool(
|
|
5810
|
+
"tunnels_verify_domain",
|
|
5811
|
+
"Verify Tunnel Domain",
|
|
5812
|
+
"Force a verification check for a custom domain.",
|
|
5813
|
+
{ domainId: z.string() },
|
|
5814
|
+
async ({ domainId }) => {
|
|
5815
|
+
const data = await w.request(VERIFY_TUNNEL_DOMAIN, {
|
|
5816
|
+
domainId
|
|
5817
|
+
});
|
|
5818
|
+
return data.verifyTunnelDomain;
|
|
5819
|
+
}
|
|
5820
|
+
);
|
|
5821
|
+
tool(
|
|
5822
|
+
"tunnels_attach_domain",
|
|
5823
|
+
"Attach Tunnel Domain",
|
|
5824
|
+
"Attach a verified domain to a tunnel.",
|
|
5825
|
+
{
|
|
5826
|
+
tunnelId: z.string(),
|
|
5827
|
+
domainId: z.string(),
|
|
5828
|
+
makePrimary: z.boolean().optional()
|
|
5829
|
+
},
|
|
5830
|
+
async ({ tunnelId, domainId, makePrimary }) => {
|
|
5831
|
+
const data = await w.request(ATTACH_TUNNEL_DOMAIN, {
|
|
5832
|
+
tunnelId,
|
|
5833
|
+
domainId,
|
|
5834
|
+
makePrimary
|
|
5835
|
+
});
|
|
5836
|
+
return data.attachTunnelDomain;
|
|
5837
|
+
}
|
|
5838
|
+
);
|
|
5839
|
+
tool(
|
|
5840
|
+
"tunnels_detach_domain",
|
|
5841
|
+
"Detach Tunnel Domain",
|
|
5842
|
+
"Detach a domain from a tunnel. The domain record remains for re-use.",
|
|
5843
|
+
{ tunnelId: z.string(), domainId: z.string() },
|
|
5844
|
+
async ({ tunnelId, domainId }) => {
|
|
5845
|
+
const data = await w.request(DETACH_TUNNEL_DOMAIN, {
|
|
5846
|
+
tunnelId,
|
|
5847
|
+
domainId
|
|
5848
|
+
});
|
|
5849
|
+
return data.detachTunnelDomain;
|
|
5850
|
+
}
|
|
5851
|
+
);
|
|
5852
|
+
tool(
|
|
5853
|
+
"tunnels_delete_domain",
|
|
5854
|
+
"Delete Tunnel Domain",
|
|
5855
|
+
"Permanently delete a tunnel domain record.",
|
|
5856
|
+
{ domainId: z.string() },
|
|
5857
|
+
async ({ domainId }) => {
|
|
5858
|
+
const data = await w.request(DELETE_TUNNEL_DOMAIN, {
|
|
5859
|
+
domainId
|
|
5860
|
+
});
|
|
5861
|
+
return { deleted: data.deleteTunnelDomain, domainId };
|
|
5862
|
+
}
|
|
5863
|
+
);
|
|
5864
|
+
tool(
|
|
5865
|
+
"tunnels_probe_agent",
|
|
5866
|
+
"Probe Agent Tunnel",
|
|
5867
|
+
"Probe an agent tunnel URL for health and identity.",
|
|
5868
|
+
{ url: z.string(), agentApiKey: z.string().optional() },
|
|
5869
|
+
async ({ url, agentApiKey }) => {
|
|
5870
|
+
const data = await w.request(PROBE_AGENT_TUNNEL, {
|
|
5871
|
+
url,
|
|
5872
|
+
agentApiKey
|
|
5873
|
+
});
|
|
5874
|
+
return data.probeAgentTunnel;
|
|
5875
|
+
}
|
|
5876
|
+
);
|
|
5877
|
+
tool(
|
|
5878
|
+
"tunnels_add_agent_from_tunnel",
|
|
5879
|
+
"Add Agent From Tunnel",
|
|
5880
|
+
"Zero-config agent onboarding: probe a tunnel URL + API key, register + configure the agent in one shot.",
|
|
5881
|
+
{
|
|
5882
|
+
tunnelUrl: z.string(),
|
|
5883
|
+
apiKey: z.string(),
|
|
5884
|
+
name: z.string().optional(),
|
|
5885
|
+
scopes: z.array(z.string()).optional(),
|
|
5886
|
+
targetId: z.string().optional(),
|
|
5887
|
+
skipDevportalApp: z.boolean().optional()
|
|
5888
|
+
},
|
|
5889
|
+
async (args) => {
|
|
5890
|
+
const data = await w.request(
|
|
5891
|
+
ADD_AGENT_FROM_TUNNEL,
|
|
5892
|
+
{ input: args }
|
|
5893
|
+
);
|
|
5894
|
+
return data.addVibecontrolsAgentFromTunnel;
|
|
5895
|
+
}
|
|
5896
|
+
);
|
|
5897
|
+
tool(
|
|
5898
|
+
"tunnels_check",
|
|
5899
|
+
"Check Tunnel (poll for updates)",
|
|
5900
|
+
"Poll a tunnel by ID. Use this in place of the GraphQL `tunnelUpdated` subscription which has no MCP equivalent \u2014 call repeatedly with a delay.",
|
|
5901
|
+
{ id: z.string() },
|
|
5902
|
+
async ({ id }) => {
|
|
5903
|
+
const data = await w.request(GET_TUNNEL, { id });
|
|
5904
|
+
return { polledAt: (/* @__PURE__ */ new Date()).toISOString(), tunnel: data.tunnel };
|
|
2892
5905
|
}
|
|
2893
5906
|
);
|
|
2894
5907
|
}
|
|
@@ -4526,6 +7539,10 @@ var vibecontrolsModule = {
|
|
|
4526
7539
|
registerSessionTools(server, ctx, trackTool);
|
|
4527
7540
|
registerNoteTools(server, ctx, trackTool);
|
|
4528
7541
|
registerConfigurationTools(server, ctx, trackTool);
|
|
7542
|
+
registerConfigSecurityTools(server, ctx, trackTool);
|
|
7543
|
+
registerConfigCITools(server, ctx, trackTool);
|
|
7544
|
+
registerConfigGitopsTools(server, ctx, trackTool);
|
|
7545
|
+
registerConfigSettingsTools(server, ctx, trackTool);
|
|
4529
7546
|
registerWebhookTools(server, ctx, trackTool);
|
|
4530
7547
|
registerTunnelTools(server, ctx, trackTool);
|
|
4531
7548
|
registerUISessionTools(server, ctx, trackTool);
|
|
@@ -4536,7 +7553,13 @@ var vibecontrolsModule = {
|
|
|
4536
7553
|
registerSessionSharingTools(server, ctx, trackTool);
|
|
4537
7554
|
registerAuditTools(server, ctx, trackTool);
|
|
4538
7555
|
registerActionTools(server, ctx, trackTool);
|
|
7556
|
+
registerAiPromptTools(server, ctx, trackTool);
|
|
7557
|
+
registerVibeDeckShareLinkTools(server, ctx, trackTool);
|
|
4539
7558
|
registerAnalyticsTools(server, ctx, trackTool);
|
|
7559
|
+
registerCatalogTools(server, ctx, trackTool);
|
|
7560
|
+
registerComponentTools(server, ctx, trackTool);
|
|
7561
|
+
registerTemplateTools(server, ctx, trackTool);
|
|
7562
|
+
registerScorecardTools(server, ctx, trackTool);
|
|
4540
7563
|
registerVibecontrolsResources(server, ctx, trackResource);
|
|
4541
7564
|
registerVibecontrolsPrompts(server, ctx, trackPrompt);
|
|
4542
7565
|
return { tools, resources, prompts };
|