wopee-mcp 1.26.2 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -290,7 +290,7 @@ Update app context file for the most recent suite with this content: <YourMarkdo
290
290
 
291
291
  #### `wopee_dispatch_agent`
292
292
 
293
- Dispatches an autonomous testing agent to execute test cases for a selected suite.
293
+ Dispatches an autonomous testing agent to execute test cases for a selected suite. Tests run **asynchronously** (typically 1-3 minutes). This tool confirms dispatch and returns tracking info — not final results.
294
294
 
295
295
  - **Parameters:**
296
296
  - `suiteUuid` - The UUID of the suite containing the test cases
@@ -298,7 +298,7 @@ Dispatches an autonomous testing agent to execute test cases for a selected suit
298
298
  - `testCases` - Array of test case objects to execute, each containing:
299
299
  - `testCaseId` - The ID of the test case
300
300
  - `userStoryId` - The ID of the associated user story
301
- - **Returns:** Array of executed test case objects with their initial execution state (uuid, executionStatus, agentReportStatus, codeReportStatus, etc.)
301
+ - **Returns:** Dispatch confirmation with tracking info (suite UUID, analysis identifier, per-test-case execution status). Does NOT return pass/fail results — use `wopee_fetch_recent_executions` or `wopee_fetch_executed_test_cases` to check results later.
302
302
 
303
303
  **Example Usage:**
304
304
 
@@ -308,6 +308,23 @@ Dispatch agent for my latest suite's user story US001 and test case TC003
308
308
 
309
309
  ### Test Results
310
310
 
311
+ #### `wopee_fetch_recent_executions`
312
+
313
+ Fetches the most recent test case executions for the current project (up to 20, newest first). Use this to quickly check the status of recently dispatched tests without needing to remember specific suite UUIDs.
314
+
315
+ - **Parameters:** None (uses `WOPEE_PROJECT_UUID` from environment)
316
+ - **Returns:** List of recent executions with execution status (IN_PROGRESS, IN_QUEUE, FINISHED, FAILED), agent reports, and pass/fail results
317
+
318
+ **Example Usage:**
319
+
320
+ ```
321
+ What's the status of my recent test runs?
322
+ ```
323
+
324
+ ```
325
+ How did my tests go?
326
+ ```
327
+
311
328
  #### `wopee_fetch_executed_test_cases`
312
329
 
313
330
  Fetches executed test cases and their results for a given analysis suite. Use this to check the status and reports of dispatched agent runs.
@@ -348,7 +365,8 @@ Show me the executed test cases for my latest analysis suite
348
365
  - Use `wopee_dispatch_agent` to execute test cases with the autonomous testing agent
349
366
 
350
367
  5. **Check results:**
351
- - Use `wopee_fetch_executed_test_cases` to check the status and reports of dispatched agent runs
368
+ - Use `wopee_fetch_recent_executions` to quickly check status of recent test runs
369
+ - Use `wopee_fetch_executed_test_cases` to check detailed status and reports for a specific suite
352
370
  - Or use the `fetch-test-results` prompt for a formatted summary of all test results
353
371
 
354
372
  ## Available Prompts
@@ -6,13 +6,19 @@ import { wopeeDispatchAnalysis } from "./wopee_dispatch_analysis/index.js";
6
6
  import { wopeeCreateBlankSuite } from "./wopee_create_blank_suite/index.js";
7
7
  import { wopeeFetchAnalysisSuites } from "./wopee_fetch_analysis_suites/index.js";
8
8
  import { wopeeFetchExecutedTestCases } from "./wopee_fetch_executed_test_cases/index.js";
9
+ import { wopeeFetchRecentExecutions } from "./wopee_fetch_recent_executions/index.js";
9
10
  import { wopeeSendChatMessage } from "./wopee_send_chat_message/index.js";
10
11
  import { wopeeReadChatHistory } from "./wopee_read_chat_history/index.js";
11
12
  import { wopeeCreateGithubIssue } from "./wopee_create_github_issue/index.js";
13
+ import { wopeeFetchVariables } from "./wopee_fetch_variables/index.js";
14
+ import { wopeeUpdateVariables } from "./wopee_update_variables/index.js";
12
15
  export const TOOLS = [
13
16
  wopeeCreateBlankSuite,
14
17
  wopeeFetchAnalysisSuites,
15
18
  wopeeFetchExecutedTestCases,
19
+ wopeeFetchRecentExecutions,
20
+ wopeeFetchVariables,
21
+ wopeeUpdateVariables,
16
22
  wopeeDispatchAnalysis,
17
23
  wopeeDispatchAgent,
18
24
  wopeeFetchArtifact,
@@ -13,6 +13,26 @@ export const UpdateArtifact = `
13
13
  updateArtifact(input: $input)
14
14
  }
15
15
  `;
16
+ export const FetchProjectVariables = `
17
+ query FetchProjectVariables($projectUuid: ID!) {
18
+ fetchProjectVariables(projectUuid: $projectUuid)
19
+ }
20
+ `;
21
+ export const FetchSuiteVariables = `
22
+ query FetchSuiteVariables($suiteUuid: ID!) {
23
+ fetchSuiteVariables(suiteUuid: $suiteUuid)
24
+ }
25
+ `;
26
+ export const UpdateProjectVariables = `
27
+ mutation UpdateProjectVariables($input: UpdateProjectVariablesInput!) {
28
+ updateProjectVariables(input: $input)
29
+ }
30
+ `;
31
+ export const UpdateSuiteVariables = `
32
+ mutation UpdateSuiteVariables($suiteUuid: ID!, $additionalVariables: String!) {
33
+ updateSuiteVariables(suiteUuid: $suiteUuid, additionalVariables: $additionalVariables)
34
+ }
35
+ `;
16
36
  export const DispatchAgent = `
17
37
  mutation DispatchAgent(
18
38
  $input: TestCasesInput!
@@ -249,6 +269,25 @@ export const FetchChatRoom = `
249
269
  }
250
270
  }
251
271
  `;
272
+ export const FetchRecentExecutedTestCases = `
273
+ query FetchRecentExecutedTestCases($projectUuid: ID!) {
274
+ fetchRecentExecutedTestCases(projectUuid: $projectUuid) {
275
+ uuid
276
+ suiteUuid
277
+ analysisSuiteUuid
278
+ analysisIdentifier
279
+ userStoryId
280
+ testCaseId
281
+ executionStatus
282
+ agentReport
283
+ agentReportStatus
284
+ codeReport
285
+ codeReportStatus
286
+ createdAt
287
+ updatedAt
288
+ }
289
+ }
290
+ `;
252
291
  export const CreateGitHubIssue = `
253
292
  mutation CreateGitHubIssue($projectUuid: ID!, $title: String!, $body: String!, $labels: [String!]) {
254
293
  createGitHubIssue(projectUuid: $projectUuid, title: $title, body: $body, labels: $labels) {
@@ -14,6 +14,18 @@ export const SuiteAnalysisConfigSchema = z.object({
14
14
  additionalInstructions: z.string().nullable().default(null),
15
15
  additionalVariables: z.string().nullable().default(null),
16
16
  });
17
+ // Shared by wopee_dispatch_analysis and wopee_update_variables. Keys must be
18
+ // uppercase (server enforces the same EnvVarKeyRegex on write).
19
+ export const AdditionalVariableSchema = z.object({
20
+ key: z
21
+ .string({
22
+ description: "Variable name. Must be uppercase with underscores only (e.g. MY_VAR, BASE_URL).",
23
+ })
24
+ .regex(/^[A-Z_][A-Z0-9_]*$/, "Key must be uppercase alphanumeric with underscores, starting with a letter or underscore"),
25
+ value: z
26
+ .string({ description: "Variable value. Must be a non-empty string." })
27
+ .min(1, "Value must be a non-empty string"),
28
+ });
17
29
  export const GenerateAIDataHandlerInputSchema = z.object({
18
30
  type: z.nativeEnum(GenerateArtifactType, {
19
31
  description: "Type of test artifact to generate. One of: APP_CONTEXT, GENERAL_USER_STORIES, USER_STORIES_WITH_TEST_CASES, TEST_CASES, TEST_CASE_STEPS, REUSABLE_TEST_CASES, REUSABLE_TEST_CASE_STEPS. Start with APP_CONTEXT, then generate stories and test cases from it.",
@@ -3,6 +3,7 @@ export var ToolName;
3
3
  ToolName["WOPEE_CREATE_BLANK_SUITE"] = "wopee_create_blank_suite";
4
4
  ToolName["WOPEE_FETCH_ANALYSIS_SUITES"] = "wopee_fetch_analysis_suites";
5
5
  ToolName["WOPEE_FETCH_EXECUTED_TEST_CASES"] = "wopee_fetch_executed_test_cases";
6
+ ToolName["WOPEE_FETCH_RECENT_EXECUTIONS"] = "wopee_fetch_recent_executions";
6
7
  ToolName["WOPEE_DISPATCH_ANALYSIS"] = "wopee_dispatch_analysis";
7
8
  ToolName["WOPEE_DISPATCH_AGENT"] = "wopee_dispatch_agent";
8
9
  ToolName["WOPEE_FETCH_ARTIFACT"] = "wopee_fetch_artifact";
@@ -11,7 +12,14 @@ export var ToolName;
11
12
  ToolName["WOPEE_SEND_CHAT_MESSAGE"] = "wopee_send_chat_message";
12
13
  ToolName["WOPEE_READ_CHAT_HISTORY"] = "wopee_read_chat_history";
13
14
  ToolName["WOPEE_CREATE_GITHUB_ISSUE"] = "wopee_create_github_issue";
15
+ ToolName["WOPEE_FETCH_VARIABLES"] = "wopee_fetch_variables";
16
+ ToolName["WOPEE_UPDATE_VARIABLES"] = "wopee_update_variables";
14
17
  })(ToolName || (ToolName = {}));
18
+ export var VariableLevel;
19
+ (function (VariableLevel) {
20
+ VariableLevel["PROJECT"] = "PROJECT";
21
+ VariableLevel["ANALYSIS"] = "ANALYSIS";
22
+ })(VariableLevel || (VariableLevel = {}));
15
23
  export var GenerateArtifactType;
16
24
  (function (GenerateArtifactType) {
17
25
  GenerateArtifactType["APP_CONTEXT"] = "APP_CONTEXT";
@@ -5,11 +5,28 @@ import { createDispatchAgentInput } from "./factory.js";
5
5
  import { DispatchAgent } from "../shared/gql-queries.js";
6
6
  import { requestClient } from "../../utils/requestClient.js";
7
7
  import { withRetry } from "../../utils/withRetry.js";
8
+ function formatDispatchSuccess(testCases, input) {
9
+ const lines = [
10
+ "DISPATCH SUCCESSFUL — tests are now RUNNING (not yet completed).",
11
+ "",
12
+ "Tracking:",
13
+ `- Suite UUID: ${testCases[0]?.suiteUuid ?? input.suiteUuid}`,
14
+ `- Analysis Suite UUID: ${testCases[0]?.analysisSuiteUuid ?? "N/A"}`,
15
+ `- Analysis Identifier: ${testCases[0]?.analysisIdentifier ?? input.analysisIdentifier}`,
16
+ "",
17
+ "Test cases dispatched:",
18
+ ];
19
+ for (const tc of testCases) {
20
+ lines.push(`- ${tc.userStoryId}:${tc.testCaseId} → executionStatus: ${tc.executionStatus}`);
21
+ }
22
+ lines.push("", "IMPORTANT: These tests are RUNNING asynchronously. Do NOT report them as passed or failed.", "Tell the user their tests are running and results will be available shortly (typically 1-3 minutes).", "You will receive a follow-up notification in chat when tests complete with full results.");
23
+ return lines.join("\n");
24
+ }
8
25
  export const wopeeDispatchAgent = {
9
26
  name: ToolName.WOPEE_DISPATCH_AGENT,
10
27
  config: {
11
28
  title: "Dispatch autonomous testing agent",
12
- description: "Execute a specific test case by dispatching an autonomous AI agent. The agent opens a real browser, navigates the web app, follows the test case steps, captures screenshots at each step, and reports pass/fail with detailed findings. Prerequisite: test cases must exist in the suite — generate them first with wopee_generate_artifact (type USER_STORIES_WITH_TEST_CASES). Do NOT use this to analyze or crawl an app — use wopee_dispatch_analysis for that. Side effects: creates execution records and screenshots on the Wopee.io platform. Rate limit: 10 seconds between dispatches per project; concurrent calls auto-retry with exponential backoff. On success, returns executed test case results. On failure (invalid suite/test case ID), returns an error message. Use wopee_fetch_executed_test_cases afterward to get full results.",
29
+ description: "Dispatch an autonomous AI agent to execute specific test cases. The agent opens a real browser, navigates the app, follows test steps, and reports results. Tests run ASYNCHRONOUSLY (1-3 minutes). This tool returns tracking info confirming dispatch — NOT final results. Do NOT interpret the response as pass/fail. Results arrive later via chat notifications. Prerequisite: test cases must exist in the suite (generate with wopee_generate_artifact type USER_STORIES_WITH_TEST_CASES). Use wopee_fetch_recent_executions or wopee_fetch_executed_test_cases to check status later.",
13
30
  inputSchema: WopeeDispatchAgentInputSchema.shape,
14
31
  },
15
32
  handler: async (input) => {
@@ -24,7 +41,7 @@ export const wopeeDispatchAgent = {
24
41
  content: [
25
42
  {
26
43
  type: "text",
27
- text: "Failed to dispatch agent: no dispatch result returned",
44
+ text: "DISPATCH FAILED — tests were NOT started.\nReason: No dispatch result returned from the API.\nSuggest the user try again or check that the suite and test cases exist.",
28
45
  },
29
46
  ],
30
47
  };
@@ -32,12 +49,22 @@ export const wopeeDispatchAgent = {
32
49
  content: [
33
50
  {
34
51
  type: "text",
35
- text: JSON.stringify(result.dispatchAgent, null, 2),
52
+ text: formatDispatchSuccess(result.dispatchAgent, input),
36
53
  },
37
54
  ],
38
55
  };
39
56
  }
40
57
  catch (error) {
58
+ if (error instanceof Error) {
59
+ return {
60
+ content: [
61
+ {
62
+ type: "text",
63
+ text: `DISPATCH FAILED — tests were NOT started.\nReason: ${error.message}\nThis is a dispatch/infrastructure error, not a test failure. Suggest the user try again.`,
64
+ },
65
+ ],
66
+ };
67
+ }
41
68
  return _parseError(error);
42
69
  }
43
70
  },
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { SuiteAnalysisConfigSchema } from "../shared/schemas.js";
2
+ import { SuiteAnalysisConfigSchema, AdditionalVariableSchema, } from "../shared/schemas.js";
3
3
  var RerunMode;
4
4
  (function (RerunMode) {
5
5
  RerunMode["FULL"] = "FULL";
@@ -15,16 +15,6 @@ export const DispatchAnalysisInputSchema = z.object({
15
15
  suiteAnalysisConfig: SuiteAnalysisConfigSchema,
16
16
  rerun: RerunOptionsSchema.nullable().default(null),
17
17
  });
18
- const AdditionalVariableSchema = z.object({
19
- key: z
20
- .string({
21
- description: "Variable name. Must be uppercase with underscores only (e.g. MY_VAR, BASE_URL).",
22
- })
23
- .regex(/^[A-Z_][A-Z0-9_]*$/, "Key must be uppercase alphanumeric with underscores, starting with a letter or underscore"),
24
- value: z
25
- .string({ description: "Variable value. Must be a non-empty string." })
26
- .min(1, "Value must be a non-empty string"),
27
- });
28
18
  const WopeeRerunOptionsSchema = z.object({
29
19
  suiteUuid: z
30
20
  .string({
@@ -0,0 +1,78 @@
1
+ import { getConfig } from "../../utils/getConfig.js";
2
+ import { requestClient } from "../../utils/requestClient.js";
3
+ import { _parseError } from "../shared/helpers.js";
4
+ import { ToolName } from "../shared/types.js";
5
+ import { FetchRecentExecutedTestCases } from "../shared/gql-queries.js";
6
+ export const wopeeFetchRecentExecutions = {
7
+ name: ToolName.WOPEE_FETCH_RECENT_EXECUTIONS,
8
+ config: {
9
+ title: "Fetch recent test executions",
10
+ description: "Fetch the most recent test case executions for the current project (up to 20, newest first). Use this to check the status of recently dispatched tests without needing to remember specific suite UUIDs. Returns execution status (IN_PROGRESS, IN_QUEUE, FINISHED, FAILED), agent reports, and pass/fail results. Takes no input; uses WOPEE_PROJECT_UUID from environment. Prefer this tool when the user asks 'what's the status?' or 'how did the tests go?' and you don't have the specific suite UUID handy.",
11
+ },
12
+ handler: async () => {
13
+ try {
14
+ const { WOPEE_PROJECT_UUID } = getConfig();
15
+ if (!WOPEE_PROJECT_UUID)
16
+ return {
17
+ content: [
18
+ {
19
+ type: "text",
20
+ text: "WOPEE_PROJECT_UUID is not set",
21
+ },
22
+ ],
23
+ };
24
+ const result = await requestClient(FetchRecentExecutedTestCases, {
25
+ projectUuid: WOPEE_PROJECT_UUID,
26
+ });
27
+ if (!result?.fetchRecentExecutedTestCases)
28
+ return {
29
+ content: [
30
+ {
31
+ type: "text",
32
+ text: "No recent test executions found for this project.",
33
+ },
34
+ ],
35
+ };
36
+ const executions = result.fetchRecentExecutedTestCases;
37
+ if (executions.length === 0)
38
+ return {
39
+ content: [
40
+ {
41
+ type: "text",
42
+ text: "No recent test executions found for this project.",
43
+ },
44
+ ],
45
+ };
46
+ const lines = [
47
+ `Recent test executions (${executions.length} most recent):`,
48
+ "",
49
+ ];
50
+ for (const tc of executions) {
51
+ let status;
52
+ if (tc.executionStatus === "FINISHED") {
53
+ status = tc.agentReportStatus ?? "FINISHED";
54
+ }
55
+ else {
56
+ status = tc.executionStatus;
57
+ }
58
+ lines.push(`- ${tc.userStoryId}:${tc.testCaseId} [${tc.analysisIdentifier}] → ${status} (${tc.updatedAt})`);
59
+ if (tc.executionStatus === "FINISHED" && tc.agentReport) {
60
+ const shortReport = tc.agentReport.slice(0, 200);
61
+ lines.push(` Report: ${shortReport}${tc.agentReport.length > 200 ? "..." : ""}`);
62
+ }
63
+ }
64
+ lines.push("", `Suite UUID of most recent: ${executions[0].suiteUuid}`, `Analysis Identifier of most recent: ${executions[0].analysisIdentifier}`);
65
+ return {
66
+ content: [
67
+ {
68
+ type: "text",
69
+ text: lines.join("\n"),
70
+ },
71
+ ],
72
+ };
73
+ }
74
+ catch (error) {
75
+ return _parseError(error);
76
+ }
77
+ },
78
+ };
@@ -0,0 +1,36 @@
1
+ import { getConfig } from "../../utils/getConfig.js";
2
+ import { requestClient } from "../../utils/requestClient.js";
3
+ import { _parseError } from "../shared/helpers.js";
4
+ import { ToolName, VariableLevel } from "../shared/types.js";
5
+ import { FetchProjectVariables, FetchSuiteVariables, } from "../shared/gql-queries.js";
6
+ import { WopeeFetchVariablesInputSchema, } from "./schema.js";
7
+ const textResult = (text) => ({
8
+ content: [{ type: "text", text }],
9
+ });
10
+ export const wopeeFetchVariables = {
11
+ name: ToolName.WOPEE_FETCH_VARIABLES,
12
+ config: {
13
+ title: "Fetch run-time variables",
14
+ description: "Read the run-time variables (additionalVariables) that drive analysis/agent runs, at either level. level: PROJECT returns the project-level variables (uses WOPEE_PROJECT_UUID from the environment); level: ANALYSIS returns a specific analysis suite's variables and requires suiteUuid. Read-only. Returns a JSON string array of { key, value, sourceType } entries, or [] when none are set. Use wopee_fetch_analysis_suites to discover suite UUIDs.",
15
+ inputSchema: WopeeFetchVariablesInputSchema.shape,
16
+ },
17
+ handler: async (input) => {
18
+ try {
19
+ const { level, suiteUuid } = input;
20
+ if (level === VariableLevel.ANALYSIS) {
21
+ if (!suiteUuid)
22
+ return textResult("suiteUuid is required when level is ANALYSIS");
23
+ const result = await requestClient(FetchSuiteVariables, { suiteUuid });
24
+ return textResult(result?.fetchSuiteVariables ?? "[]");
25
+ }
26
+ const { WOPEE_PROJECT_UUID } = getConfig();
27
+ if (!WOPEE_PROJECT_UUID)
28
+ return textResult("WOPEE_PROJECT_UUID is not set");
29
+ const result = await requestClient(FetchProjectVariables, { projectUuid: WOPEE_PROJECT_UUID });
30
+ return textResult(result?.fetchProjectVariables ?? "[]");
31
+ }
32
+ catch (error) {
33
+ return _parseError(error);
34
+ }
35
+ },
36
+ };
@@ -0,0 +1,12 @@
1
+ import { z } from "zod";
2
+ import { VariableLevel } from "../shared/types.js";
3
+ export const WopeeFetchVariablesInputSchema = z.object({
4
+ level: z.nativeEnum(VariableLevel, {
5
+ description: "Which variable set to read. PROJECT reads the project-level variables (uses WOPEE_PROJECT_UUID from the environment). ANALYSIS reads a specific analysis suite's variables and requires suiteUuid.",
6
+ }),
7
+ suiteUuid: z
8
+ .string({
9
+ description: "UUID of the analysis suite to read variables from. Required when level is ANALYSIS; ignored when level is PROJECT.",
10
+ })
11
+ .nullish(),
12
+ });
@@ -0,0 +1,24 @@
1
+ import { getConfig } from "../../utils/getConfig.js";
2
+ /**
3
+ * Wire payload for the updateSuiteVariables mutation. The handler guarantees
4
+ * suiteUuid is present before calling this (ANALYSIS level).
5
+ */
6
+ export const createUpdateSuiteVariablesInput = (input) => ({
7
+ suiteUuid: input.suiteUuid,
8
+ additionalVariables: JSON.stringify(input.variables),
9
+ });
10
+ /**
11
+ * Wire payload for the updateProjectVariables mutation, injecting
12
+ * WOPEE_PROJECT_UUID from the environment (PROJECT level).
13
+ */
14
+ export const createUpdateProjectVariablesInput = (input) => {
15
+ const { WOPEE_PROJECT_UUID } = getConfig();
16
+ if (!WOPEE_PROJECT_UUID)
17
+ throw new Error("WOPEE_PROJECT_UUID is not set");
18
+ return {
19
+ input: {
20
+ projectUuid: WOPEE_PROJECT_UUID,
21
+ additionalVariables: JSON.stringify(input.variables),
22
+ },
23
+ };
24
+ };
@@ -0,0 +1,38 @@
1
+ import { requestClient } from "../../utils/requestClient.js";
2
+ import { withRetry } from "../../utils/withRetry.js";
3
+ import { _parseError } from "../shared/helpers.js";
4
+ import { ToolName, VariableLevel } from "../shared/types.js";
5
+ import { UpdateProjectVariables, UpdateSuiteVariables, } from "../shared/gql-queries.js";
6
+ import { createUpdateProjectVariablesInput, createUpdateSuiteVariablesInput, } from "./factory.js";
7
+ import { WopeeUpdateVariablesInputSchema, } from "./schema.js";
8
+ const textResult = (text) => ({
9
+ content: [{ type: "text", text }],
10
+ });
11
+ export const wopeeUpdateVariables = {
12
+ name: ToolName.WOPEE_UPDATE_VARIABLES,
13
+ config: {
14
+ title: "Update run-time variables",
15
+ description: "Upsert the run-time variables (additionalVariables) that drive analysis/agent runs, at either level. level: PROJECT writes the project-level variables (uses WOPEE_PROJECT_UUID from the environment); level: ANALYSIS writes a specific analysis suite's variables and requires suiteUuid. Merge semantics: keys in variables[] are added or overwritten, existing keys not listed are preserved. Keys must be uppercase (e.g. BASE_URL); the server re-sanitizes and drops invalid keys. Returns a confirmation on success.",
16
+ inputSchema: WopeeUpdateVariablesInputSchema.shape,
17
+ },
18
+ handler: async (input) => {
19
+ try {
20
+ const { level, suiteUuid } = input;
21
+ if (level === VariableLevel.ANALYSIS) {
22
+ if (!suiteUuid)
23
+ return textResult("suiteUuid is required when level is ANALYSIS");
24
+ const result = await withRetry(() => requestClient(UpdateSuiteVariables, createUpdateSuiteVariablesInput(input)));
25
+ if (!result?.updateSuiteVariables)
26
+ return textResult("Failed to update suite variables");
27
+ return textResult("Suite variables updated successfully");
28
+ }
29
+ const result = await withRetry(() => requestClient(UpdateProjectVariables, createUpdateProjectVariablesInput(input)));
30
+ if (!result?.updateProjectVariables)
31
+ return textResult("Failed to update project variables");
32
+ return textResult("Project variables updated successfully");
33
+ }
34
+ catch (error) {
35
+ return _parseError(error);
36
+ }
37
+ },
38
+ };
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+ import { VariableLevel } from "../shared/types.js";
3
+ import { AdditionalVariableSchema } from "../shared/schemas.js";
4
+ export const WopeeUpdateVariablesInputSchema = z.object({
5
+ level: z.nativeEnum(VariableLevel, {
6
+ description: "Which variable set to write. PROJECT writes the project-level variables (uses WOPEE_PROJECT_UUID from the environment). ANALYSIS writes a specific analysis suite's variables and requires suiteUuid.",
7
+ }),
8
+ suiteUuid: z
9
+ .string({
10
+ description: "UUID of the analysis suite to write variables to. Required when level is ANALYSIS; ignored when level is PROJECT.",
11
+ })
12
+ .nullish(),
13
+ variables: z.array(AdditionalVariableSchema, {
14
+ description: "Variables to upsert. Each needs an uppercase key (e.g. BASE_URL) and a non-empty value. Merge semantics: keys listed here are added or overwritten; existing keys not listed here are preserved.",
15
+ }),
16
+ });
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "bin": {
5
5
  "wopee-mcp": "./build/index.js"
6
6
  },
7
- "version": "1.26.2",
7
+ "version": "1.28.0",
8
8
  "mcpName": "io.github.Wopee-io/wopee-mcp",
9
9
  "description": "Wopee.io MCP server for autonomous testing platform",
10
10
  "main": "./build/index.js",