@walkeros/mcp 3.4.1-next-1776790594143 → 3.4.2
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/index.js +598 -356
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -156,7 +156,7 @@ function registerFlowBundleTool(server2) {
|
|
|
156
156
|
inputSchema: {
|
|
157
157
|
...schemas2.BundleInputShape,
|
|
158
158
|
remote: z2.boolean().optional().describe(
|
|
159
|
-
"Use remote cloud bundling (requires
|
|
159
|
+
"Use remote cloud bundling (requires authentication). Default: false (local)"
|
|
160
160
|
),
|
|
161
161
|
content: z2.record(z2.string(), z2.unknown()).optional().describe("Flow.Config JSON content (required when remote: true)")
|
|
162
162
|
},
|
|
@@ -182,7 +182,7 @@ function registerFlowBundleTool(server2) {
|
|
|
182
182
|
{
|
|
183
183
|
next: [
|
|
184
184
|
"Use flow_simulate to test",
|
|
185
|
-
|
|
185
|
+
'Use deploy_manage with action "deploy" to publish'
|
|
186
186
|
]
|
|
187
187
|
}
|
|
188
188
|
);
|
|
@@ -209,7 +209,7 @@ function registerFlowBundleTool(server2) {
|
|
|
209
209
|
{
|
|
210
210
|
next: [
|
|
211
211
|
"Use flow_simulate to test",
|
|
212
|
-
|
|
212
|
+
'Use deploy_manage with action "deploy" to publish'
|
|
213
213
|
]
|
|
214
214
|
}
|
|
215
215
|
);
|
|
@@ -863,7 +863,11 @@ function registerFlowLoadTool(server2) {
|
|
|
863
863
|
|
|
864
864
|
// src/tools/feedback.ts
|
|
865
865
|
import { z as z8 } from "zod";
|
|
866
|
-
import {
|
|
866
|
+
import {
|
|
867
|
+
feedback,
|
|
868
|
+
getFeedbackPreference,
|
|
869
|
+
setFeedbackPreference
|
|
870
|
+
} from "@walkeros/cli";
|
|
867
871
|
import { mcpResult as mcpResult8, mcpError as mcpError8 } from "@walkeros/core";
|
|
868
872
|
function registerFeedbackTool(server2) {
|
|
869
873
|
server2.registerTool(
|
|
@@ -887,8 +891,7 @@ function registerFeedbackTool(server2) {
|
|
|
887
891
|
async (params) => {
|
|
888
892
|
try {
|
|
889
893
|
const { text, anonymous: explicitAnonymous } = params;
|
|
890
|
-
|
|
891
|
-
let anonymous = config?.anonymousFeedback;
|
|
894
|
+
let anonymous = getFeedbackPreference();
|
|
892
895
|
if (anonymous === void 0 && explicitAnonymous === void 0) {
|
|
893
896
|
return mcpResult8(
|
|
894
897
|
{ needsConsent: true },
|
|
@@ -902,11 +905,10 @@ function registerFeedbackTool(server2) {
|
|
|
902
905
|
}
|
|
903
906
|
if (anonymous === void 0 && explicitAnonymous !== void 0) {
|
|
904
907
|
anonymous = explicitAnonymous;
|
|
905
|
-
|
|
906
|
-
writeConfig({ ...base, anonymousFeedback: anonymous });
|
|
908
|
+
setFeedbackPreference(anonymous);
|
|
907
909
|
}
|
|
908
910
|
const isAnonymous = explicitAnonymous ?? anonymous ?? true;
|
|
909
|
-
await feedback(text, { anonymous: isAnonymous, version: "3.4.
|
|
911
|
+
await feedback(text, { anonymous: isAnonymous, version: "3.4.2" });
|
|
910
912
|
return mcpResult8({ ok: true });
|
|
911
913
|
} catch (error) {
|
|
912
914
|
return mcpError8(error);
|
|
@@ -915,102 +917,332 @@ function registerFeedbackTool(server2) {
|
|
|
915
917
|
);
|
|
916
918
|
}
|
|
917
919
|
|
|
918
|
-
// src/tools/
|
|
920
|
+
// src/tools/auth.ts
|
|
921
|
+
import { z as z9 } from "zod";
|
|
922
|
+
import {
|
|
923
|
+
resolveToken,
|
|
924
|
+
deleteConfig,
|
|
925
|
+
requestDeviceCode,
|
|
926
|
+
pollForToken,
|
|
927
|
+
whoami
|
|
928
|
+
} from "@walkeros/cli";
|
|
929
|
+
import { mcpResult as mcpResult9, mcpError as mcpError9 } from "@walkeros/core";
|
|
930
|
+
function registerAuthTool(server2) {
|
|
931
|
+
server2.registerTool(
|
|
932
|
+
"auth",
|
|
933
|
+
{
|
|
934
|
+
title: "Authentication",
|
|
935
|
+
description: "Manage walkerOS authentication. Check login status, log in via device code flow, or log out. No terminal or browser required \u2014 the MCP client handles the authorization URL.",
|
|
936
|
+
inputSchema: {
|
|
937
|
+
action: z9.enum(["status", "login", "logout"]).describe("Authentication action to perform"),
|
|
938
|
+
deviceCode: z9.string().optional().describe(
|
|
939
|
+
"Device code from a previous pending login attempt. Provide to resume polling without requesting a new code."
|
|
940
|
+
)
|
|
941
|
+
},
|
|
942
|
+
// No outputSchema: action-dispatched tool — each action returns a different shape
|
|
943
|
+
annotations: {
|
|
944
|
+
readOnlyHint: false,
|
|
945
|
+
destructiveHint: true,
|
|
946
|
+
idempotentHint: false,
|
|
947
|
+
openWorldHint: true
|
|
948
|
+
}
|
|
949
|
+
},
|
|
950
|
+
async ({ action, deviceCode }) => {
|
|
951
|
+
try {
|
|
952
|
+
switch (action) {
|
|
953
|
+
case "status": {
|
|
954
|
+
const resolved = resolveToken();
|
|
955
|
+
if (!resolved) {
|
|
956
|
+
return mcpResult9(
|
|
957
|
+
{ authenticated: false },
|
|
958
|
+
{ next: ['Use auth with action "login" to authenticate'] }
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
const user = await whoami();
|
|
962
|
+
return mcpResult9({ authenticated: true, ...user });
|
|
963
|
+
}
|
|
964
|
+
case "login": {
|
|
965
|
+
if (deviceCode) {
|
|
966
|
+
const pollResult = await pollForToken(deviceCode, {
|
|
967
|
+
timeoutMs: 6e4
|
|
968
|
+
});
|
|
969
|
+
if (pollResult.success) {
|
|
970
|
+
return mcpResult9(
|
|
971
|
+
{ authenticated: true, email: pollResult.email },
|
|
972
|
+
{
|
|
973
|
+
next: [
|
|
974
|
+
'Use project_manage with action "list" to see your projects'
|
|
975
|
+
]
|
|
976
|
+
}
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
if (pollResult.status === "pending") {
|
|
980
|
+
return mcpResult9({
|
|
981
|
+
authenticated: false,
|
|
982
|
+
status: "pending",
|
|
983
|
+
message: "Still waiting for authorization. Try again shortly.",
|
|
984
|
+
deviceCode
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
return mcpError9(
|
|
988
|
+
new Error(pollResult.error || "Authorization failed")
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
const code = await requestDeviceCode();
|
|
992
|
+
const loginUrl = code.verificationUriComplete || code.verificationUri;
|
|
993
|
+
return mcpResult9({
|
|
994
|
+
authenticated: false,
|
|
995
|
+
status: "awaiting_authorization",
|
|
996
|
+
loginUrl,
|
|
997
|
+
message: `Open this link to authorize: ${loginUrl}`,
|
|
998
|
+
deviceCode: code.deviceCode
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
case "logout": {
|
|
1002
|
+
const deleted = deleteConfig();
|
|
1003
|
+
const hadEnvToken = typeof process.env.WALKEROS_TOKEN === "string" && process.env.WALKEROS_TOKEN.length > 0;
|
|
1004
|
+
delete process.env.WALKEROS_TOKEN;
|
|
1005
|
+
let message;
|
|
1006
|
+
if (deleted && hadEnvToken) {
|
|
1007
|
+
message = "Logged out. Config removed and WALKEROS_TOKEN cleared from process environment.";
|
|
1008
|
+
} else if (deleted) {
|
|
1009
|
+
message = "Logged out and config removed.";
|
|
1010
|
+
} else if (hadEnvToken) {
|
|
1011
|
+
message = "No config found. WALKEROS_TOKEN cleared from process environment.";
|
|
1012
|
+
} else {
|
|
1013
|
+
message = "No config found \u2014 already logged out.";
|
|
1014
|
+
}
|
|
1015
|
+
return mcpResult9({
|
|
1016
|
+
loggedOut: true,
|
|
1017
|
+
message
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
default:
|
|
1021
|
+
throw new Error(
|
|
1022
|
+
`Unknown action: ${action}. Use one of: status, login, logout`
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
return mcpError9(error);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// src/tools/project-manage.ts
|
|
919
1033
|
import { z as z10 } from "zod";
|
|
920
1034
|
import {
|
|
921
|
-
whoami,
|
|
922
1035
|
listProjects,
|
|
923
1036
|
getProject,
|
|
924
1037
|
createProject,
|
|
925
1038
|
updateProject,
|
|
926
1039
|
deleteProject,
|
|
1040
|
+
setDefaultProject
|
|
1041
|
+
} from "@walkeros/cli";
|
|
1042
|
+
import { mcpResult as mcpResult10, mcpError as mcpError10 } from "@walkeros/core";
|
|
1043
|
+
|
|
1044
|
+
// src/types.ts
|
|
1045
|
+
function isAuthError(error) {
|
|
1046
|
+
if (!(error instanceof Error)) return false;
|
|
1047
|
+
const msg = error.message.toLowerCase();
|
|
1048
|
+
if (msg.includes("unauthorized") || msg.includes("forbidden") || msg.includes("invalid token") || msg.includes("token expired") || msg.includes("not authenticated")) {
|
|
1049
|
+
return true;
|
|
1050
|
+
}
|
|
1051
|
+
const code = error.code;
|
|
1052
|
+
if (!code) return false;
|
|
1053
|
+
const upperCode = code.toUpperCase();
|
|
1054
|
+
return upperCode === "UNAUTHORIZED" || upperCode === "FORBIDDEN" || upperCode === "401" || upperCode === "403" || upperCode.startsWith("AUTH_");
|
|
1055
|
+
}
|
|
1056
|
+
var AUTH_HINT = 'Are you logged in? Use auth(action: "status") to check.';
|
|
1057
|
+
|
|
1058
|
+
// src/tools/project-manage.ts
|
|
1059
|
+
function registerProjectManageTool(server2) {
|
|
1060
|
+
server2.registerTool(
|
|
1061
|
+
"project_manage",
|
|
1062
|
+
{
|
|
1063
|
+
title: "Project Management",
|
|
1064
|
+
description: "Manage walkerOS projects. List, create, update, delete projects, or set a default project for CLI operations.",
|
|
1065
|
+
inputSchema: {
|
|
1066
|
+
action: z10.enum(["list", "get", "create", "update", "delete", "set_default"]).describe("Project management action to perform"),
|
|
1067
|
+
projectId: z10.string().optional().describe(
|
|
1068
|
+
"Project ID. Required for get, update, delete, and set_default actions."
|
|
1069
|
+
),
|
|
1070
|
+
name: z10.string().optional().describe(
|
|
1071
|
+
"Project name. Required for create. Optional for update (to rename)."
|
|
1072
|
+
)
|
|
1073
|
+
},
|
|
1074
|
+
// No outputSchema: action-dispatched tool — each action returns a different shape
|
|
1075
|
+
annotations: {
|
|
1076
|
+
readOnlyHint: false,
|
|
1077
|
+
destructiveHint: true,
|
|
1078
|
+
idempotentHint: false,
|
|
1079
|
+
openWorldHint: true
|
|
1080
|
+
}
|
|
1081
|
+
},
|
|
1082
|
+
async ({ action, projectId, name }) => {
|
|
1083
|
+
try {
|
|
1084
|
+
switch (action) {
|
|
1085
|
+
case "list": {
|
|
1086
|
+
const projects = await listProjects();
|
|
1087
|
+
const items = Array.isArray(projects) ? projects : projects?.projects || [];
|
|
1088
|
+
if (items.length === 0) {
|
|
1089
|
+
return mcpResult10(
|
|
1090
|
+
{ projects: [] },
|
|
1091
|
+
{
|
|
1092
|
+
next: [
|
|
1093
|
+
'Use project_manage with action "create" to create your first project',
|
|
1094
|
+
'Use project_manage with action "set_default" after creating to set it as default'
|
|
1095
|
+
]
|
|
1096
|
+
}
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
return mcpResult10(projects);
|
|
1100
|
+
}
|
|
1101
|
+
case "get": {
|
|
1102
|
+
if (!projectId) {
|
|
1103
|
+
return mcpError10(
|
|
1104
|
+
new Error(
|
|
1105
|
+
'projectId is required for get action. Use action "list" to see available projects.'
|
|
1106
|
+
)
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
const project = await getProject({ projectId });
|
|
1110
|
+
return mcpResult10(project);
|
|
1111
|
+
}
|
|
1112
|
+
case "create": {
|
|
1113
|
+
if (!name) {
|
|
1114
|
+
return mcpError10(new Error("name is required for create action."));
|
|
1115
|
+
}
|
|
1116
|
+
const created = await createProject({ name });
|
|
1117
|
+
return mcpResult10(created, {
|
|
1118
|
+
next: [
|
|
1119
|
+
'Use project_manage with action "set_default" to make this your active project'
|
|
1120
|
+
]
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
case "update": {
|
|
1124
|
+
if (!projectId) {
|
|
1125
|
+
return mcpError10(
|
|
1126
|
+
new Error(
|
|
1127
|
+
'projectId is required for update action. Use action "list" to see available projects.'
|
|
1128
|
+
)
|
|
1129
|
+
);
|
|
1130
|
+
}
|
|
1131
|
+
if (!name) {
|
|
1132
|
+
return mcpError10(new Error("name is required for update action."));
|
|
1133
|
+
}
|
|
1134
|
+
const updated = await updateProject({ projectId, name });
|
|
1135
|
+
return mcpResult10(updated);
|
|
1136
|
+
}
|
|
1137
|
+
case "delete": {
|
|
1138
|
+
if (!projectId) {
|
|
1139
|
+
return mcpError10(
|
|
1140
|
+
new Error(
|
|
1141
|
+
'projectId is required for delete action. Use action "list" to see available projects.'
|
|
1142
|
+
)
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
const deleted = await deleteProject({ projectId });
|
|
1146
|
+
return mcpResult10(deleted);
|
|
1147
|
+
}
|
|
1148
|
+
case "set_default": {
|
|
1149
|
+
if (!projectId) {
|
|
1150
|
+
return mcpError10(
|
|
1151
|
+
new Error(
|
|
1152
|
+
'projectId is required for set_default action. Use action "list" to see available projects.'
|
|
1153
|
+
)
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
setDefaultProject(projectId);
|
|
1157
|
+
return mcpResult10(
|
|
1158
|
+
{ defaultProjectId: projectId },
|
|
1159
|
+
{
|
|
1160
|
+
next: [
|
|
1161
|
+
'Use flow_manage with action "list" to see flows in this project'
|
|
1162
|
+
]
|
|
1163
|
+
}
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
default:
|
|
1167
|
+
throw new Error(
|
|
1168
|
+
`Unknown action: ${action}. Use one of: list, get, create, update, delete, set_default`
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
} catch (error) {
|
|
1172
|
+
return mcpError10(error, isAuthError(error) ? AUTH_HINT : void 0);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// src/tools/flow-manage.ts
|
|
1179
|
+
import { z as z11 } from "zod";
|
|
1180
|
+
import {
|
|
1181
|
+
listAllFlows,
|
|
927
1182
|
listFlows,
|
|
928
1183
|
getFlow,
|
|
929
1184
|
createFlow,
|
|
930
1185
|
updateFlow,
|
|
931
1186
|
deleteFlow,
|
|
932
1187
|
duplicateFlow,
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
createDeployment as createDep,
|
|
938
|
-
deleteDeployment as deleteDep,
|
|
939
|
-
listPreviews as listPreviewsApi,
|
|
940
|
-
getPreview as getPreviewApi,
|
|
941
|
-
createPreview as createPreviewApi,
|
|
942
|
-
deletePreview as deletePreviewApi
|
|
1188
|
+
listPreviews,
|
|
1189
|
+
getPreview,
|
|
1190
|
+
createPreview,
|
|
1191
|
+
deletePreview
|
|
943
1192
|
} from "@walkeros/cli";
|
|
944
|
-
import { mcpResult as
|
|
945
|
-
|
|
946
|
-
// src/schemas/api-output.ts
|
|
947
|
-
import { z as z9 } from "zod";
|
|
948
|
-
var ApiOutputShape = {
|
|
949
|
-
action: z9.string().describe("Action that was executed"),
|
|
950
|
-
ok: z9.boolean().describe("Whether the action succeeded"),
|
|
951
|
-
data: z9.unknown().describe("Action-specific result data")
|
|
952
|
-
};
|
|
953
|
-
|
|
954
|
-
// src/tools/api.ts
|
|
955
|
-
var ACTIONS = [
|
|
956
|
-
"whoami",
|
|
957
|
-
"project.list",
|
|
958
|
-
"project.get",
|
|
959
|
-
"project.create",
|
|
960
|
-
"project.update",
|
|
961
|
-
"project.delete",
|
|
962
|
-
"flow.list",
|
|
963
|
-
"flow.get",
|
|
964
|
-
"flow.create",
|
|
965
|
-
"flow.update",
|
|
966
|
-
"flow.delete",
|
|
967
|
-
"flow.duplicate",
|
|
968
|
-
"deploy",
|
|
969
|
-
"deployment.get",
|
|
970
|
-
"deployment.list",
|
|
971
|
-
"deployment.create",
|
|
972
|
-
"deployment.delete",
|
|
973
|
-
"preview.list",
|
|
974
|
-
"preview.get",
|
|
975
|
-
"preview.create",
|
|
976
|
-
"preview.delete"
|
|
977
|
-
];
|
|
978
|
-
function registerApiTool(server2) {
|
|
1193
|
+
import { mcpResult as mcpResult11, mcpError as mcpError11 } from "@walkeros/core";
|
|
1194
|
+
function registerFlowManageTool(server2) {
|
|
979
1195
|
server2.registerTool(
|
|
980
|
-
"
|
|
1196
|
+
"flow_manage",
|
|
981
1197
|
{
|
|
982
|
-
title: "
|
|
983
|
-
description: "Manage walkerOS
|
|
1198
|
+
title: "Flow Management",
|
|
1199
|
+
description: "Manage walkerOS flows and their previews. List/get/create/update/delete/duplicate flows, or create/inspect/delete preview bundles for testing flow changes on live sites.",
|
|
984
1200
|
inputSchema: {
|
|
985
|
-
action:
|
|
986
|
-
|
|
987
|
-
"
|
|
1201
|
+
action: z11.enum([
|
|
1202
|
+
"list",
|
|
1203
|
+
"get",
|
|
1204
|
+
"create",
|
|
1205
|
+
"update",
|
|
1206
|
+
"delete",
|
|
1207
|
+
"duplicate",
|
|
1208
|
+
"preview_list",
|
|
1209
|
+
"preview_get",
|
|
1210
|
+
"preview_create",
|
|
1211
|
+
"preview_delete"
|
|
1212
|
+
]).describe("Flow management action to perform"),
|
|
1213
|
+
flowId: z11.string().optional().describe(
|
|
1214
|
+
"Flow ID (flow_...) or config ID (cfg_...). Required for get, update, delete, duplicate."
|
|
1215
|
+
),
|
|
1216
|
+
projectId: z11.string().optional().describe(
|
|
1217
|
+
"Project ID. Optional filter for list (omit to list all projects). Required for create if no default project set."
|
|
988
1218
|
),
|
|
989
|
-
|
|
990
|
-
"Flow
|
|
1219
|
+
name: z11.string().optional().describe(
|
|
1220
|
+
"Flow name. Required for create. Optional for update (to rename) and duplicate."
|
|
991
1221
|
),
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
wait: z10.boolean().optional().describe("Wait for deploy to complete (default: true)"),
|
|
996
|
-
flowName: z10.string().optional().describe("Flow name for multi-settings flows"),
|
|
997
|
-
fields: z10.array(z10.string()).optional().describe("Dot-path field selectors for flow.get"),
|
|
998
|
-
type: z10.enum(["web", "server"]).optional().describe("Deployment type for deployment.create"),
|
|
999
|
-
sort: z10.string().optional().describe("Sort field for list operations"),
|
|
1000
|
-
order: z10.enum(["asc", "desc"]).optional().describe("Sort order"),
|
|
1001
|
-
status: z10.string().optional().describe("Status filter for deployment.list"),
|
|
1002
|
-
includeDeleted: z10.boolean().optional().describe("Include deleted items in lists"),
|
|
1003
|
-
previewId: z10.string().optional().describe(
|
|
1004
|
-
"Preview ID (e.g., prv_abc123). Required for preview.get/delete."
|
|
1222
|
+
content: z11.record(z11.string(), z11.unknown()).optional().describe("Flow.Config JSON content. Used for create and update."),
|
|
1223
|
+
patch: z11.boolean().optional().describe(
|
|
1224
|
+
"Merge-patch for update (default true). When true, only provided fields are updated."
|
|
1005
1225
|
),
|
|
1006
|
-
|
|
1007
|
-
"
|
|
1226
|
+
fields: z11.array(z11.string()).optional().describe(
|
|
1227
|
+
"Dot-path selectors for get to return only specific fields."
|
|
1008
1228
|
),
|
|
1009
|
-
|
|
1010
|
-
|
|
1229
|
+
sort: z11.enum(["name", "updated_at", "created_at"]).optional().describe("Sort field for list."),
|
|
1230
|
+
order: z11.enum(["asc", "desc"]).optional().describe("Sort order for list."),
|
|
1231
|
+
includeDeleted: z11.boolean().optional().describe("Include soft-deleted flows in list results."),
|
|
1232
|
+
previewId: z11.string().optional().describe(
|
|
1233
|
+
"Preview ID (prv_...). Required for preview_get and preview_delete."
|
|
1234
|
+
),
|
|
1235
|
+
flowName: z11.string().optional().describe(
|
|
1236
|
+
"Flow settings name. Used by preview_create as an alternative to flowSettingsId."
|
|
1237
|
+
),
|
|
1238
|
+
flowSettingsId: z11.string().optional().describe(
|
|
1239
|
+
"Flow settings ID. Used by preview_create as an alternative to flowName."
|
|
1240
|
+
),
|
|
1241
|
+
siteUrl: z11.string().optional().describe(
|
|
1242
|
+
"Optional site URL for preview_create. When provided, the response includes full activationUrl and deactivationUrl the user can click."
|
|
1011
1243
|
)
|
|
1012
1244
|
},
|
|
1013
|
-
outputSchema:
|
|
1245
|
+
// No outputSchema: action-dispatched tool — each action returns a different shape
|
|
1014
1246
|
annotations: {
|
|
1015
1247
|
readOnlyHint: false,
|
|
1016
1248
|
destructiveHint: true,
|
|
@@ -1018,249 +1250,152 @@ function registerApiTool(server2) {
|
|
|
1018
1250
|
openWorldHint: true
|
|
1019
1251
|
}
|
|
1020
1252
|
},
|
|
1021
|
-
async (
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
previewId,
|
|
1038
|
-
flowSettingsId,
|
|
1039
|
-
siteUrl
|
|
1040
|
-
} = params;
|
|
1253
|
+
async ({
|
|
1254
|
+
action,
|
|
1255
|
+
flowId,
|
|
1256
|
+
projectId,
|
|
1257
|
+
name,
|
|
1258
|
+
content,
|
|
1259
|
+
patch,
|
|
1260
|
+
fields,
|
|
1261
|
+
sort,
|
|
1262
|
+
order,
|
|
1263
|
+
includeDeleted,
|
|
1264
|
+
previewId,
|
|
1265
|
+
flowName,
|
|
1266
|
+
flowSettingsId,
|
|
1267
|
+
siteUrl
|
|
1268
|
+
}) => {
|
|
1041
1269
|
try {
|
|
1042
|
-
let data;
|
|
1043
1270
|
switch (action) {
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
if (!name) throw new Error("name required for project.update");
|
|
1065
|
-
data = await updateProject({ projectId, name });
|
|
1066
|
-
break;
|
|
1067
|
-
}
|
|
1068
|
-
case "project.delete": {
|
|
1069
|
-
data = await deleteProject({ projectId });
|
|
1070
|
-
break;
|
|
1271
|
+
case "list": {
|
|
1272
|
+
if (projectId) {
|
|
1273
|
+
const data2 = await listFlows({
|
|
1274
|
+
projectId,
|
|
1275
|
+
sort,
|
|
1276
|
+
order,
|
|
1277
|
+
includeDeleted
|
|
1278
|
+
});
|
|
1279
|
+
return mcpResult11(data2);
|
|
1280
|
+
}
|
|
1281
|
+
const data = await listAllFlows({ sort, order, includeDeleted });
|
|
1282
|
+
return mcpResult11(
|
|
1283
|
+
{ projects: data },
|
|
1284
|
+
{
|
|
1285
|
+
next: [
|
|
1286
|
+
'Use flow_manage with action "get" and a flowId to inspect a specific flow',
|
|
1287
|
+
"Use flow_load to open a flow for editing"
|
|
1288
|
+
]
|
|
1289
|
+
}
|
|
1290
|
+
);
|
|
1071
1291
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1292
|
+
case "get": {
|
|
1293
|
+
if (!flowId) {
|
|
1294
|
+
return mcpError11(
|
|
1295
|
+
new Error(
|
|
1296
|
+
'flowId is required for get action. Use action "list" to see available flows.'
|
|
1297
|
+
)
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
const flow = await getFlow({ flowId, projectId, fields });
|
|
1301
|
+
return mcpResult11(flow, {
|
|
1302
|
+
next: [
|
|
1303
|
+
"Use flow_load to open this flow for editing and validation"
|
|
1304
|
+
]
|
|
1079
1305
|
});
|
|
1080
|
-
break;
|
|
1081
1306
|
}
|
|
1082
|
-
case "
|
|
1083
|
-
if (!
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1307
|
+
case "create": {
|
|
1308
|
+
if (!name) {
|
|
1309
|
+
return mcpError11(new Error("name is required for create action."));
|
|
1310
|
+
}
|
|
1311
|
+
const created = await createFlow({
|
|
1312
|
+
name,
|
|
1313
|
+
content: content ?? {},
|
|
1314
|
+
projectId
|
|
1315
|
+
});
|
|
1316
|
+
return mcpResult11(created, {
|
|
1317
|
+
next: [
|
|
1318
|
+
"Use flow_load to open this flow for editing and validation"
|
|
1319
|
+
]
|
|
1320
|
+
});
|
|
1092
1321
|
}
|
|
1093
|
-
case "
|
|
1094
|
-
if (!flowId)
|
|
1095
|
-
|
|
1322
|
+
case "update": {
|
|
1323
|
+
if (!flowId) {
|
|
1324
|
+
return mcpError11(
|
|
1325
|
+
new Error(
|
|
1326
|
+
'flowId is required for update action. Use action "list" to see available flows.'
|
|
1327
|
+
)
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
const updated = await updateFlow({
|
|
1096
1331
|
flowId,
|
|
1332
|
+
projectId,
|
|
1097
1333
|
name,
|
|
1098
1334
|
content,
|
|
1099
|
-
projectId,
|
|
1100
1335
|
mergePatch: patch ?? true
|
|
1101
1336
|
});
|
|
1102
|
-
|
|
1337
|
+
return mcpResult11(updated);
|
|
1103
1338
|
}
|
|
1104
|
-
case "
|
|
1105
|
-
if (!flowId)
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
if (!flowId) throw new Error("flowId required for flow.duplicate");
|
|
1111
|
-
data = await duplicateFlow({ flowId, name, projectId });
|
|
1112
|
-
break;
|
|
1113
|
-
}
|
|
1114
|
-
// Deploy
|
|
1115
|
-
case "deploy": {
|
|
1116
|
-
if (!flowId) throw new Error("flowId required for deploy");
|
|
1117
|
-
const progressToken = extra._meta?.progressToken;
|
|
1118
|
-
const DEPLOY_TIMEOUT_MS = 9e4;
|
|
1119
|
-
const timeoutSignal = AbortSignal.timeout(DEPLOY_TIMEOUT_MS);
|
|
1120
|
-
const combinedAbort = new AbortController();
|
|
1121
|
-
const onAbort = () => combinedAbort.abort();
|
|
1122
|
-
timeoutSignal.addEventListener("abort", onAbort);
|
|
1123
|
-
extra.signal?.addEventListener("abort", onAbort);
|
|
1124
|
-
data = await deploy({
|
|
1125
|
-
flowId,
|
|
1126
|
-
projectId,
|
|
1127
|
-
wait: wait ?? true,
|
|
1128
|
-
flowName,
|
|
1129
|
-
timeout: DEPLOY_TIMEOUT_MS,
|
|
1130
|
-
onStatus: (s, sub) => {
|
|
1131
|
-
if (!progressToken) return;
|
|
1132
|
-
const key = sub ? `${s}:${sub}` : s;
|
|
1133
|
-
const stages = {
|
|
1134
|
-
"bundling:building": {
|
|
1135
|
-
progress: 20,
|
|
1136
|
-
label: "Building bundle..."
|
|
1137
|
-
},
|
|
1138
|
-
"deploying:publishing": {
|
|
1139
|
-
progress: 60,
|
|
1140
|
-
label: "Publishing to CDN..."
|
|
1141
|
-
},
|
|
1142
|
-
"deploying:provisioning": {
|
|
1143
|
-
progress: 60,
|
|
1144
|
-
label: "Provisioning container..."
|
|
1145
|
-
},
|
|
1146
|
-
"deploying:starting": {
|
|
1147
|
-
progress: 80,
|
|
1148
|
-
label: "Starting container..."
|
|
1149
|
-
},
|
|
1150
|
-
published: { progress: 100, label: "Published" },
|
|
1151
|
-
active: { progress: 100, label: "Active" },
|
|
1152
|
-
failed: { progress: 100, label: "Failed" }
|
|
1153
|
-
};
|
|
1154
|
-
const stage = stages[key] ?? stages[s] ?? { progress: 10, label: key };
|
|
1155
|
-
extra.sendNotification({
|
|
1156
|
-
method: "notifications/progress",
|
|
1157
|
-
params: {
|
|
1158
|
-
progressToken,
|
|
1159
|
-
progress: stage.progress,
|
|
1160
|
-
total: 100,
|
|
1161
|
-
message: stage.label
|
|
1162
|
-
}
|
|
1163
|
-
});
|
|
1164
|
-
},
|
|
1165
|
-
signal: combinedAbort.signal
|
|
1166
|
-
});
|
|
1167
|
-
timeoutSignal.removeEventListener("abort", onAbort);
|
|
1168
|
-
extra.signal?.removeEventListener("abort", onAbort);
|
|
1169
|
-
const st = data.status;
|
|
1170
|
-
const deployData = data;
|
|
1171
|
-
if (st === "failed") {
|
|
1172
|
-
return mcpResult9(
|
|
1173
|
-
{ action, ok: false, data },
|
|
1174
|
-
{
|
|
1175
|
-
next: ["Run flow_validate to check your configuration"]
|
|
1176
|
-
}
|
|
1339
|
+
case "delete": {
|
|
1340
|
+
if (!flowId) {
|
|
1341
|
+
return mcpError11(
|
|
1342
|
+
new Error(
|
|
1343
|
+
'flowId is required for delete action. Use action "list" to see available flows.'
|
|
1344
|
+
)
|
|
1177
1345
|
);
|
|
1178
|
-
} else {
|
|
1179
|
-
const publicUrl = deployData.publicUrl;
|
|
1180
|
-
const containerUrl = deployData.containerUrl;
|
|
1181
|
-
const deployType = deployData.type;
|
|
1182
|
-
const nextHints = [];
|
|
1183
|
-
if (deployType === "web" && publicUrl) {
|
|
1184
|
-
nextHints.push(`Bundle at ${publicUrl}`);
|
|
1185
|
-
nextHints.push(`Add <script src='${publicUrl}'></script>`);
|
|
1186
|
-
} else if (deployType === "server" && containerUrl) {
|
|
1187
|
-
nextHints.push(`Container at ${containerUrl}`);
|
|
1188
|
-
nextHints.push(`Test: curl ${containerUrl}/health`);
|
|
1189
|
-
}
|
|
1190
|
-
if (nextHints.length > 0) {
|
|
1191
|
-
return mcpResult9(
|
|
1192
|
-
{ action, ok: true, data },
|
|
1193
|
-
{
|
|
1194
|
-
next: nextHints
|
|
1195
|
-
}
|
|
1196
|
-
);
|
|
1197
|
-
}
|
|
1198
1346
|
}
|
|
1199
|
-
|
|
1347
|
+
const deleted = await deleteFlow({ flowId, projectId });
|
|
1348
|
+
return mcpResult11(deleted);
|
|
1200
1349
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1350
|
+
case "duplicate": {
|
|
1351
|
+
if (!flowId) {
|
|
1352
|
+
return mcpError11(
|
|
1353
|
+
new Error(
|
|
1354
|
+
'flowId is required for duplicate action. Use action "list" to see available flows.'
|
|
1355
|
+
)
|
|
1206
1356
|
);
|
|
1207
|
-
try {
|
|
1208
|
-
data = await getDeployment({ flowId, flowName });
|
|
1209
|
-
} catch {
|
|
1210
|
-
data = await getDeploymentBySlug({ slug: flowId });
|
|
1211
1357
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
projectId,
|
|
1217
|
-
type,
|
|
1218
|
-
status
|
|
1358
|
+
const duplicated = await duplicateFlow({
|
|
1359
|
+
flowId,
|
|
1360
|
+
name,
|
|
1361
|
+
projectId
|
|
1219
1362
|
});
|
|
1220
|
-
|
|
1363
|
+
return mcpResult11(duplicated);
|
|
1221
1364
|
}
|
|
1222
|
-
case "
|
|
1223
|
-
if (!
|
|
1224
|
-
|
|
1225
|
-
|
|
1365
|
+
case "preview_list": {
|
|
1366
|
+
if (!flowId) {
|
|
1367
|
+
return mcpError11(
|
|
1368
|
+
new Error(
|
|
1369
|
+
'flowId is required for preview_list. Use action "list" to see available flows.'
|
|
1370
|
+
)
|
|
1226
1371
|
);
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
case "deployment.delete": {
|
|
1231
|
-
if (!flowId)
|
|
1232
|
-
throw new Error("flowId (slug) required for deployment.delete");
|
|
1233
|
-
data = await deleteDep({ slug: flowId });
|
|
1234
|
-
break;
|
|
1235
|
-
}
|
|
1236
|
-
// Previews
|
|
1237
|
-
case "preview.list": {
|
|
1238
|
-
if (!flowId) throw new Error("flowId required for preview.list");
|
|
1239
|
-
data = await listPreviewsApi({ projectId, flowId });
|
|
1240
|
-
break;
|
|
1372
|
+
}
|
|
1373
|
+
const data = await listPreviews({ projectId, flowId });
|
|
1374
|
+
return mcpResult11(data);
|
|
1241
1375
|
}
|
|
1242
|
-
case "
|
|
1376
|
+
case "preview_get": {
|
|
1243
1377
|
if (!flowId || !previewId) {
|
|
1244
|
-
|
|
1378
|
+
return mcpError11(
|
|
1379
|
+
new Error("flowId and previewId are required for preview_get.")
|
|
1380
|
+
);
|
|
1245
1381
|
}
|
|
1246
|
-
data = await
|
|
1247
|
-
|
|
1382
|
+
const data = await getPreview({ projectId, flowId, previewId });
|
|
1383
|
+
return mcpResult11(data);
|
|
1248
1384
|
}
|
|
1249
|
-
case "
|
|
1250
|
-
if (!flowId)
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
"flowName or flowSettingsId required for preview.create"
|
|
1385
|
+
case "preview_create": {
|
|
1386
|
+
if (!flowId) {
|
|
1387
|
+
return mcpError11(
|
|
1388
|
+
new Error("flowId is required for preview_create.")
|
|
1254
1389
|
);
|
|
1255
1390
|
}
|
|
1256
|
-
if (
|
|
1257
|
-
|
|
1258
|
-
new
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1391
|
+
if (!flowName && !flowSettingsId) {
|
|
1392
|
+
return mcpError11(
|
|
1393
|
+
new Error(
|
|
1394
|
+
"flowName or flowSettingsId is required for preview_create."
|
|
1395
|
+
)
|
|
1396
|
+
);
|
|
1262
1397
|
}
|
|
1263
|
-
const preview = await
|
|
1398
|
+
const preview = await createPreview({
|
|
1264
1399
|
projectId,
|
|
1265
1400
|
flowId,
|
|
1266
1401
|
flowName,
|
|
@@ -1281,52 +1416,155 @@ function registerApiTool(server2) {
|
|
|
1281
1416
|
} else {
|
|
1282
1417
|
delete enriched.activationUrl;
|
|
1283
1418
|
}
|
|
1284
|
-
|
|
1285
|
-
|
|
1419
|
+
return mcpResult11(enriched, {
|
|
1420
|
+
next: siteUrl ? [
|
|
1421
|
+
"Open activationUrl to activate preview mode; open deactivationUrl to exit."
|
|
1422
|
+
] : [
|
|
1423
|
+
"Append activationParam to any URL on your site to activate preview mode."
|
|
1424
|
+
]
|
|
1425
|
+
});
|
|
1286
1426
|
}
|
|
1287
|
-
case "
|
|
1427
|
+
case "preview_delete": {
|
|
1288
1428
|
if (!flowId || !previewId) {
|
|
1289
|
-
|
|
1290
|
-
|
|
1429
|
+
return mcpError11(
|
|
1430
|
+
new Error(
|
|
1431
|
+
"flowId and previewId are required for preview_delete."
|
|
1432
|
+
)
|
|
1291
1433
|
);
|
|
1292
1434
|
}
|
|
1293
|
-
data = await
|
|
1294
|
-
|
|
1435
|
+
const data = await deletePreview({
|
|
1436
|
+
projectId,
|
|
1437
|
+
flowId,
|
|
1438
|
+
previewId
|
|
1439
|
+
});
|
|
1440
|
+
return mcpResult11(data);
|
|
1295
1441
|
}
|
|
1296
1442
|
default:
|
|
1297
1443
|
throw new Error(
|
|
1298
|
-
`Unknown action: ${action}. Use one of:
|
|
1444
|
+
`Unknown action: ${action}. Use one of: list, get, create, update, delete, duplicate, preview_list, preview_get, preview_create, preview_delete`
|
|
1299
1445
|
);
|
|
1300
1446
|
}
|
|
1301
|
-
return mcpResult9({ action, ok: true, data });
|
|
1302
1447
|
} catch (error) {
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1448
|
+
return mcpError11(error, isAuthError(error) ? AUTH_HINT : void 0);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
);
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
// src/tools/deploy-manage.ts
|
|
1455
|
+
import { z as z12 } from "zod";
|
|
1456
|
+
import {
|
|
1457
|
+
deploy as deployFlow,
|
|
1458
|
+
listDeployments,
|
|
1459
|
+
getDeployment,
|
|
1460
|
+
getDeploymentBySlug,
|
|
1461
|
+
deleteDeployment
|
|
1462
|
+
} from "@walkeros/cli";
|
|
1463
|
+
import { mcpResult as mcpResult12, mcpError as mcpError12 } from "@walkeros/core";
|
|
1464
|
+
function registerDeployTool(server2) {
|
|
1465
|
+
server2.registerTool(
|
|
1466
|
+
"deploy_manage",
|
|
1467
|
+
{
|
|
1468
|
+
title: "Deploy Management",
|
|
1469
|
+
description: 'Deploy walkerOS flows and manage deployments. Deploy a flow, list deployments, get deployment details, or delete deployments. Note: the "get" and "delete" actions accept a deployment slug (e.g. "dep_..."), not a flow ID. If you only have a flowId, resolve the latest deployment slug first via flow_manage with action "get".',
|
|
1470
|
+
inputSchema: {
|
|
1471
|
+
action: z12.enum(["deploy", "list", "get", "delete"]).describe("Deployment action to perform"),
|
|
1472
|
+
flowId: z12.string().optional().describe("Flow ID. Required for deploy action."),
|
|
1473
|
+
id: z12.string().optional().describe(
|
|
1474
|
+
'Deployment slug (e.g. "dep_..."). Required for get and delete actions. This is the deployment slug, not a flow ID \u2014 if you only have a flowId, use flow_manage action "get" to resolve the latest deployment slug.'
|
|
1475
|
+
),
|
|
1476
|
+
projectId: z12.string().optional().describe("Project ID. Optional filter for list."),
|
|
1477
|
+
type: z12.enum(["web", "server"]).optional().describe("Deployment type filter for list."),
|
|
1478
|
+
status: z12.string().optional().describe("Status filter for list."),
|
|
1479
|
+
wait: z12.boolean().optional().describe(
|
|
1480
|
+
"Wait for deploy to complete (default true). Only used with deploy action."
|
|
1481
|
+
),
|
|
1482
|
+
flowName: z12.string().optional().describe(
|
|
1483
|
+
"Flow name for multi-settings flows. Only used with deploy action."
|
|
1484
|
+
)
|
|
1485
|
+
},
|
|
1486
|
+
// No outputSchema: action-dispatched tool — each action returns a different shape
|
|
1487
|
+
annotations: {
|
|
1488
|
+
readOnlyHint: false,
|
|
1489
|
+
destructiveHint: true,
|
|
1490
|
+
idempotentHint: false,
|
|
1491
|
+
openWorldHint: true
|
|
1492
|
+
}
|
|
1493
|
+
},
|
|
1494
|
+
async ({ action, flowId, id, projectId, type, status, wait, flowName }) => {
|
|
1495
|
+
try {
|
|
1496
|
+
switch (action) {
|
|
1497
|
+
case "deploy": {
|
|
1498
|
+
if (!flowId) {
|
|
1499
|
+
return mcpError12(
|
|
1500
|
+
new Error(
|
|
1501
|
+
'flowId is required for deploy action. Use flow_manage with action "list" to see available flows.'
|
|
1502
|
+
)
|
|
1503
|
+
);
|
|
1504
|
+
}
|
|
1505
|
+
const result = await deployFlow({
|
|
1506
|
+
flowId,
|
|
1507
|
+
wait: wait ?? true,
|
|
1508
|
+
flowName
|
|
1509
|
+
});
|
|
1510
|
+
return mcpResult12(result, {
|
|
1313
1511
|
next: [
|
|
1314
|
-
'Use
|
|
1512
|
+
'Use deploy_manage with action "get" to check deployment status'
|
|
1315
1513
|
]
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
case "list": {
|
|
1517
|
+
const data = await listDeployments({ projectId, type, status });
|
|
1518
|
+
return mcpResult12(data);
|
|
1519
|
+
}
|
|
1520
|
+
case "get": {
|
|
1521
|
+
if (!id) {
|
|
1522
|
+
return mcpError12(
|
|
1523
|
+
new Error(
|
|
1524
|
+
'id is required for get action. Use deploy_manage with action "list" to see available deployments.'
|
|
1525
|
+
)
|
|
1526
|
+
);
|
|
1316
1527
|
}
|
|
1317
|
-
|
|
1528
|
+
try {
|
|
1529
|
+
const data = await getDeploymentBySlug({ slug: id, projectId });
|
|
1530
|
+
return mcpResult12(data);
|
|
1531
|
+
} catch {
|
|
1532
|
+
const data = await getDeployment({ flowId: id, projectId });
|
|
1533
|
+
return mcpResult12(data);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
case "delete": {
|
|
1537
|
+
if (!id) {
|
|
1538
|
+
return mcpError12(
|
|
1539
|
+
new Error(
|
|
1540
|
+
'id is required for delete action. Use deploy_manage with action "list" to see available deployments.'
|
|
1541
|
+
)
|
|
1542
|
+
);
|
|
1543
|
+
}
|
|
1544
|
+
try {
|
|
1545
|
+
const data = await deleteDeployment({ slug: id, projectId });
|
|
1546
|
+
return mcpResult12({ deleted: true, ...data });
|
|
1547
|
+
} catch (error) {
|
|
1548
|
+
if (isAuthError(error)) {
|
|
1549
|
+
return mcpError12(error, AUTH_HINT);
|
|
1550
|
+
}
|
|
1551
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1552
|
+
if (/not[\s_-]?found|404/i.test(message)) {
|
|
1553
|
+
return mcpError12(
|
|
1554
|
+
error,
|
|
1555
|
+
'Deployment not found. The "delete" action expects a deployment slug (e.g. "dep_..."), not a flow ID. If you only have a flowId, use flow_manage with action "get" to resolve the latest deployment slug first.'
|
|
1556
|
+
);
|
|
1557
|
+
}
|
|
1558
|
+
return mcpError12(error);
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
default:
|
|
1562
|
+
throw new Error(
|
|
1563
|
+
`Unknown action: ${action}. Use one of: deploy, list, get, delete`
|
|
1564
|
+
);
|
|
1318
1565
|
}
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
error,
|
|
1322
|
-
"Set WALKEROS_TOKEN env var or check token expiry"
|
|
1323
|
-
);
|
|
1324
|
-
if (msg.includes("required"))
|
|
1325
|
-
return mcpError9(
|
|
1326
|
-
error,
|
|
1327
|
-
`See api tool description for ${action} parameters.`
|
|
1328
|
-
);
|
|
1329
|
-
return mcpError9(error);
|
|
1566
|
+
} catch (error) {
|
|
1567
|
+
return mcpError12(error, isAuthError(error) ? AUTH_HINT : void 0);
|
|
1330
1568
|
}
|
|
1331
1569
|
}
|
|
1332
1570
|
);
|
|
@@ -1554,8 +1792,8 @@ function registerReferenceResources(server2) {
|
|
|
1554
1792
|
}
|
|
1555
1793
|
);
|
|
1556
1794
|
server2.resource(
|
|
1557
|
-
"
|
|
1558
|
-
"walkeros://reference/
|
|
1795
|
+
"openapi",
|
|
1796
|
+
"walkeros://reference/openapi",
|
|
1559
1797
|
{
|
|
1560
1798
|
description: "walkerOS cloud API \u2014 OpenAPI 3.1 specification",
|
|
1561
1799
|
mimeType: "application/json"
|
|
@@ -1574,7 +1812,7 @@ function registerReferenceResources(server2) {
|
|
|
1574
1812
|
return {
|
|
1575
1813
|
contents: [
|
|
1576
1814
|
{
|
|
1577
|
-
uri: "walkeros://reference/
|
|
1815
|
+
uri: "walkeros://reference/openapi",
|
|
1578
1816
|
text: openApiSpec,
|
|
1579
1817
|
mimeType: "application/json"
|
|
1580
1818
|
}
|
|
@@ -1605,17 +1843,17 @@ function registerReferenceResources(server2) {
|
|
|
1605
1843
|
}
|
|
1606
1844
|
|
|
1607
1845
|
// src/prompts/add-step.ts
|
|
1608
|
-
import { z as
|
|
1846
|
+
import { z as z13 } from "zod";
|
|
1609
1847
|
function registerAddStepPrompt(server2) {
|
|
1610
1848
|
server2.registerPrompt(
|
|
1611
1849
|
"add-step",
|
|
1612
1850
|
{
|
|
1613
1851
|
description: "Add a source, destination, transformer, or store step to a flow configuration. Guides through package selection, config scaffolding, and wiring.",
|
|
1614
1852
|
argsSchema: {
|
|
1615
|
-
stepType:
|
|
1853
|
+
stepType: z13.string().optional().describe(
|
|
1616
1854
|
"Type of step to add: source, destination, transformer, or store"
|
|
1617
1855
|
),
|
|
1618
|
-
flowPath:
|
|
1856
|
+
flowPath: z13.string().optional().describe("Path to the flow.json file to modify")
|
|
1619
1857
|
}
|
|
1620
1858
|
},
|
|
1621
1859
|
async ({ stepType, flowPath }) => ({
|
|
@@ -1656,14 +1894,14 @@ function registerAddStepPrompt(server2) {
|
|
|
1656
1894
|
}
|
|
1657
1895
|
|
|
1658
1896
|
// src/prompts/setup-mapping.ts
|
|
1659
|
-
import { z as
|
|
1897
|
+
import { z as z14 } from "zod";
|
|
1660
1898
|
function registerSetupMappingPrompt(server2) {
|
|
1661
1899
|
server2.registerPrompt(
|
|
1662
1900
|
"setup-mapping",
|
|
1663
1901
|
{
|
|
1664
1902
|
description: "Set up event mapping for any step in a flow. Teaches mapping syntax and uses package examples as templates.",
|
|
1665
1903
|
argsSchema: {
|
|
1666
|
-
stepName:
|
|
1904
|
+
stepName: z14.string().optional().describe('Step name in the flow (e.g., "gtag", "meta", "express")')
|
|
1667
1905
|
}
|
|
1668
1906
|
},
|
|
1669
1907
|
async ({ stepName }) => ({
|
|
@@ -1701,14 +1939,14 @@ function registerSetupMappingPrompt(server2) {
|
|
|
1701
1939
|
}
|
|
1702
1940
|
|
|
1703
1941
|
// src/prompts/manage-contract.ts
|
|
1704
|
-
import { z as
|
|
1942
|
+
import { z as z15 } from "zod";
|
|
1705
1943
|
function registerManageContractPrompt(server2) {
|
|
1706
1944
|
server2.registerPrompt(
|
|
1707
1945
|
"manage-contract",
|
|
1708
1946
|
{
|
|
1709
1947
|
description: "Create or update event contracts for a flow. Can generate contracts from existing mappings or scaffold mappings from contracts.",
|
|
1710
1948
|
argsSchema: {
|
|
1711
|
-
direction:
|
|
1949
|
+
direction: z15.string().optional().describe(
|
|
1712
1950
|
'Direction: "from-mappings" (extract contract from existing mappings), "from-scratch" (create new contract), or "to-mappings" (scaffold mappings from contract)'
|
|
1713
1951
|
)
|
|
1714
1952
|
}
|
|
@@ -1746,14 +1984,14 @@ function registerManageContractPrompt(server2) {
|
|
|
1746
1984
|
}
|
|
1747
1985
|
|
|
1748
1986
|
// src/prompts/use-definitions.ts
|
|
1749
|
-
import { z as
|
|
1987
|
+
import { z as z16 } from "zod";
|
|
1750
1988
|
function registerUseDefinitionsPrompt(server2) {
|
|
1751
1989
|
server2.registerPrompt(
|
|
1752
1990
|
"use-definitions",
|
|
1753
1991
|
{
|
|
1754
1992
|
description: "Extract shared patterns into definitions and variables for DRY, environment-aware flow configurations.",
|
|
1755
1993
|
argsSchema: {
|
|
1756
|
-
flowPath:
|
|
1994
|
+
flowPath: z16.string().optional().describe("Path to the flow.json file to analyze")
|
|
1757
1995
|
}
|
|
1758
1996
|
},
|
|
1759
1997
|
async ({ flowPath }) => ({
|
|
@@ -1794,11 +2032,11 @@ function registerUseDefinitionsPrompt(server2) {
|
|
|
1794
2032
|
}
|
|
1795
2033
|
|
|
1796
2034
|
// src/index.ts
|
|
1797
|
-
setClientContext({ type: "mcp", version: "3.4.
|
|
2035
|
+
setClientContext({ type: "mcp", version: "3.4.2" });
|
|
1798
2036
|
var server = new McpServer(
|
|
1799
2037
|
{
|
|
1800
2038
|
name: "walkeros-flow",
|
|
1801
|
-
version: "3.4.
|
|
2039
|
+
version: "3.4.2"
|
|
1802
2040
|
},
|
|
1803
2041
|
{
|
|
1804
2042
|
instructions: `walkerOS is an open-source, privacy-first event data collection platform. Define event pipelines as code using JSON flow configurations.
|
|
@@ -1812,15 +2050,18 @@ var server = new McpServer(
|
|
|
1812
2050
|
|
|
1813
2051
|
## Workflow
|
|
1814
2052
|
|
|
1815
|
-
1. \`
|
|
1816
|
-
2. \`
|
|
1817
|
-
3. \`
|
|
1818
|
-
4.
|
|
1819
|
-
5.
|
|
1820
|
-
6. \`
|
|
1821
|
-
7.
|
|
1822
|
-
8.
|
|
1823
|
-
9. \`
|
|
2053
|
+
1. \`auth({ action: "status" })\` \u2014 check if logged in, or \`auth({ action: "login" })\` to connect
|
|
2054
|
+
2. \`project_manage({ action: "list" })\` \u2014 see your projects
|
|
2055
|
+
3. \`flow_manage({ action: "list" })\` \u2014 see all flows across projects
|
|
2056
|
+
4. \`flow_load({ platform: "web" })\` or \`flow_load({ source: "./flow.json" })\` \u2014 create or load
|
|
2057
|
+
5. \`package_search({ type: "destination", platform: "web" })\` \u2014 discover packages
|
|
2058
|
+
6. \`package_get({ package: "..." })\` \u2014 read schemas, hints, examples
|
|
2059
|
+
7. Use the \`add-step\` prompt \u2014 guided step addition
|
|
2060
|
+
8. Use the \`setup-mapping\` prompt \u2014 event transformation config
|
|
2061
|
+
9. \`flow_validate({ type: "flow", input: "flow.json" })\` \u2014 verify
|
|
2062
|
+
10. \`flow_simulate({ configPath: "flow.json", event: "..." })\` \u2014 test
|
|
2063
|
+
11. \`flow_manage({ action: "update", flowId: "...", content: {...} })\` \u2014 save to cloud
|
|
2064
|
+
12. \`deploy_manage({ action: "deploy", flowId: "..." })\` \u2014 deploy
|
|
1824
2065
|
|
|
1825
2066
|
## Architecture: Source \u2192 Collector \u2192 Destination(s)
|
|
1826
2067
|
|
|
@@ -1874,15 +2115,16 @@ registerPackageSearchTool(server);
|
|
|
1874
2115
|
registerGetPackageSchemaTool(server);
|
|
1875
2116
|
registerFlowLoadTool(server);
|
|
1876
2117
|
registerFeedbackTool(server);
|
|
2118
|
+
registerAuthTool(server);
|
|
2119
|
+
registerProjectManageTool(server);
|
|
2120
|
+
registerFlowManageTool(server);
|
|
2121
|
+
registerDeployTool(server);
|
|
1877
2122
|
registerPackageSchemaResources(server);
|
|
1878
2123
|
registerReferenceResources(server);
|
|
1879
2124
|
registerAddStepPrompt(server);
|
|
1880
2125
|
registerSetupMappingPrompt(server);
|
|
1881
2126
|
registerManageContractPrompt(server);
|
|
1882
2127
|
registerUseDefinitionsPrompt(server);
|
|
1883
|
-
if (process.env.WALKEROS_TOKEN) {
|
|
1884
|
-
registerApiTool(server);
|
|
1885
|
-
}
|
|
1886
2128
|
async function main() {
|
|
1887
2129
|
const transport = new StdioServerTransport();
|
|
1888
2130
|
await server.connect(transport);
|