wopee-mcp 1.8.1 → 1.11.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
@@ -38,6 +38,38 @@ Add this server to your MCP configuration.
38
38
 
39
39
  - **`WOPEE_API_URL`** - The Wopee API endpoint URL. Should be specified only for testing/development purposes.
40
40
 
41
+ ### Corporate Proxy Configuration
42
+
43
+ If you're behind a corporate proxy/VPN and experiencing connection timeouts, you can configure proxy settings using standard environment variables:
44
+
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "wopee": {
49
+ "command": "npx wopee-mcp",
50
+ "env": {
51
+ "WOPEE_PROJECT_UUID": "your-project-uuid-here",
52
+ "WOPEE_API_KEY": "your-api-key-here",
53
+ "HTTPS_PROXY": "http://your-proxy-server:8080"
54
+ }
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ #### Supported Proxy Environment Variables
61
+
62
+ - **`HTTPS_PROXY`** or **`https_proxy`** - Proxy server URL for HTTPS connections (recommended)
63
+ - **`HTTP_PROXY`** or **`http_proxy`** - Fallback proxy server URL
64
+
65
+ #### Finding Your Proxy Settings
66
+
67
+ If you're unsure about your proxy settings, check your VS Code settings (`settings.json`) for `http.proxy` value, or consult your IT department. Common corporate proxy formats:
68
+
69
+ - `http://proxy.company.com:8080`
70
+ - `http://10.x.x.x:8080`
71
+ - `http://username:password@proxy.company.com:8080` (if authentication is required)
72
+
41
73
  ## Getting Started
42
74
 
43
75
  Most tools in this MCP server require a `suiteUuid` to operate. You have two options to get started:
@@ -92,15 +124,15 @@ Dispatch a new analysis suite
92
124
 
93
125
  ### Generation Tools
94
126
 
95
- These tools generate various artifacts for a specific suite. All require a `suiteUuid` and `fileType` to generate.
127
+ These tools generate various artifacts for a specific suite. All require a `suiteUuid` and `type` to generate.
96
128
 
97
- #### `wopee_generate_file`
129
+ #### `wopee_generate_artifact`
98
130
 
99
131
  Generates a specific file(artifact) for the selected suite.
100
132
 
101
133
  - **Parameters:**
102
134
  - `suiteUuid` - The UUID of the suite
103
- - `fileType` - `"APP_CONTEXT" | "GENERAL_USER_STORIES" | "USER_STORIES_WITH_TEST_CASES" | "TEST_CASES" | "TEST_CASE_STEPS" | "REUSABLE_TEST_CASES" | "REUSABLE_TEST_CASE_STEPS"`
135
+ - `type` - `"APP_CONTEXT" | "GENERAL_USER_STORIES" | "USER_STORIES_WITH_TEST_CASES" | "TEST_CASES" | "TEST_CASE_STEPS" | "REUSABLE_TEST_CASES" | "REUSABLE_TEST_CASE_STEPS"`
104
136
  - **Returns:** Generated output in case of successful generation.
105
137
 
106
138
  **Example Usage:**
@@ -111,15 +143,16 @@ Generate app context for my most recent analysis suite
111
143
 
112
144
  ### Fetch Tools
113
145
 
114
- These tools retrieve generated artifacts for a specific suite. All require a `suiteUuid` and `fileType`.
146
+ These tools retrieve generated artifacts for a specific suite. All require a `suiteUuid` and `type`.
115
147
 
116
- #### `wopee_fetch_file`
148
+ #### `wopee_fetch_artifact`
117
149
 
118
150
  Fetches the enquired file(artifact) from the selected suite.
119
151
 
120
152
  - **Parameters:**
121
153
  - `suiteUuid` - The UUID of the suite
122
- - `fileType` - `"APP_CONTEXT" | "GENERAL_USER_STORIES" | "USER_STORIES" | "TEST_CASES"`
154
+ - `type` - `"APP_CONTEXT" | "GENERAL_USER_STORIES" | "USER_STORIES" | "PLAYWRIGHT_CODE" | "PROJECT_CONTEXT"`
155
+ - `identifier` - Identifier of the test case to fetch Playwright code for, ex. `US003:TC004`
123
156
  - **Returns:** The file contents in case of successful fetch.
124
157
 
125
158
  **Example Usage:**
@@ -130,16 +163,17 @@ Fetch user stories for the latest suite
130
163
 
131
164
  ### Update Tools
132
165
 
133
- These tools are used to update or set certain files(artifacts) for a specific suite. `suiteUuid`, `fileType` and `fileContent` is required.
166
+ These tools are used to update or set certain files(artifacts) for a specific suite. `suiteUuid`, `type` and `content` is required.
134
167
 
135
- #### `wopee_update_file`
168
+ #### `wopee_update_artifact`
136
169
 
137
170
  Updates/replaces existing file(artifact) for a specific suite
138
171
 
139
172
  - **Parameters:**
140
173
  - `suiteUuid` - The UUID of the suite
141
- - `fileType` - `"APP_CONTEXT" | "GENERAL_USER_STORIES" | "USER_STORIES" | "TEST_CASES"`
142
- - `fileContent` - Markdown content for `app context` and `general user stories`, structured JSON for `user stories` and `test cases`
174
+ - `type` - `"APP_CONTEXT" | "GENERAL_USER_STORIES" | "USER_STORIES" | "PLAYWRIGHT_CODE" | "PROJECT_CONTEXT"`
175
+ - `content` - Markdown content for `app context`, `general user stories` and `project context`, structured JSON for `user stories`
176
+ - `identifier` - Identifier of the test case to fetch Playwright code for, ex. `US003:TC004`
143
177
  - **Returns:** Boolean based of success status of the tool call
144
178
 
145
179
  **Example Usage:**
@@ -177,10 +211,12 @@ Dispatch agent for my latest suite's user story US001 and test case TC003
177
211
 
178
212
  2. **Generate artifacts:**
179
213
 
180
- - Generate app context: `wopee_generate_file` with `APP_CONTEXT` and specific `suiteUuid`
181
- - Generate general user stories: `wopee_generate_file` with `GENERAL_USER_STORIES` and specific `suiteUuid`
182
- - Generate user stories: `wopee_generate_file` with `USER_STORIES` and specific `suiteUuid`
183
- - Generate test cases: `wopee_generate_file` with `TEST_CASES` and specific `suiteUuid`
214
+ - Generate app context: `wopee_generate_artifact` with `APP_CONTEXT` and specific `suiteUuid`
215
+ - Generate general user stories: `wopee_generate_artifact` with `GENERAL_USER_STORIES` and specific `suiteUuid`
216
+ - Generate user stories with test cases: `wopee_generate_artifact` with `USER_STORIES_WITH_TEST_CASES` and specific `suiteUuid`
217
+ - Generate reusable test cases: `wopee_generate_artifact` with `REUSABLE_TEST_CASES` and specific `suiteUuid`
218
+ - Generate reusable test case steps: `wopee_generate_artifact` with `REUSABLE_TEST_CASE_STEPS` and specific `suiteUuid`
219
+ - Generate test case steps: `wopee_generate_artifact` with `TEST_CASE_STEPS` and specific `suiteUuid`
184
220
 
185
221
  3. **Fetch generated content:**
186
222
 
package/build/index.js CHANGED
@@ -1,8 +1,17 @@
1
1
  #!/usr/bin/env node
2
+ import { setGlobalDispatcher, ProxyAgent } from "undici";
2
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
5
  import { TOOLS } from "./tools/index.js";
5
6
  import { PROMPTS } from "./prompts/index.js";
7
+ const proxyUrl = process.env.HTTPS_PROXY ||
8
+ process.env.https_proxy ||
9
+ process.env.HTTP_PROXY ||
10
+ process.env.http_proxy;
11
+ if (proxyUrl) {
12
+ setGlobalDispatcher(new ProxyAgent(proxyUrl));
13
+ console.error(`[WOPEE]: Using proxy ${proxyUrl}`);
14
+ }
6
15
  const server = new McpServer({
7
16
  name: "wopee-mcp",
8
17
  version: "1.0.0",
@@ -1,6 +1,6 @@
1
- import { wopeeFetchFile } from "./wopee_fetch_file/index.js";
2
- import { wopeeUpdateFile } from "./wopee_update_file/index.js";
3
- import { wopeeGenerateFile } from "./wopee_generate_file/index.js";
1
+ import { wopeeFetchArtifact } from "./wopee_fetch_artifact/index.js";
2
+ import { wopeeUpdateArtifact } from "./wopee_update_artifact/index.js";
3
+ import { wopeeGenerateArtifact } from "./wopee_generate_artifact/index.js";
4
4
  import { wopeeDispatchAgent } from "./wopee_dispatch_agent/index.js";
5
5
  import { wopeeDispatchAnalysis } from "./wopee_dispatch_analysis/index.js";
6
6
  import { wopeeFetchAnalysisSuites } from "./wopee_fetch_analysis_suites/index.js";
@@ -8,7 +8,7 @@ export const TOOLS = [
8
8
  wopeeFetchAnalysisSuites,
9
9
  wopeeDispatchAnalysis,
10
10
  wopeeDispatchAgent,
11
- wopeeFetchFile,
12
- wopeeUpdateFile,
13
- wopeeGenerateFile,
11
+ wopeeFetchArtifact,
12
+ wopeeUpdateArtifact,
13
+ wopeeGenerateArtifact,
14
14
  ];
@@ -1,19 +1,14 @@
1
1
  import { getConfig } from "../../utils/getConfig.js";
2
- export const createFetchFileInput = (input) => {
2
+ export const createFetchArtifactInput = (input) => {
3
3
  const { WOPEE_PROJECT_UUID } = getConfig();
4
4
  if (!WOPEE_PROJECT_UUID)
5
5
  throw new Error("WOPEE_PROJECT_UUID is not set");
6
- let testCaseId;
7
- if (input.identifier) {
8
- // Temporary solution for fetching playwright code for a specific test case TODO: replace with proper identifier later
9
- const [usId, tcId] = input.identifier.split(":");
10
- testCaseId = `${usId}/${tcId}`;
11
- }
6
+ const { type, suiteUuid, identifier } = input;
12
7
  return {
8
+ type,
9
+ suiteUuid,
13
10
  projectUuid: WOPEE_PROJECT_UUID,
14
- suiteUuid: input.suiteUuid,
15
- bucket: input.bucket,
16
- ...(testCaseId ? { testCaseId } : {}),
11
+ ...(identifier ? { identifier } : {}),
17
12
  };
18
13
  };
19
14
  export const createGenerateAIDataInput = (input) => {
@@ -38,22 +33,16 @@ export const createGenerateAIDataInput = (input) => {
38
33
  sourceSuiteUuid: null,
39
34
  };
40
35
  };
41
- export const createUpdateFileInput = (input) => {
36
+ export const createUpdateArtifactInput = (input) => {
42
37
  const { WOPEE_PROJECT_UUID } = getConfig();
43
38
  if (!WOPEE_PROJECT_UUID)
44
39
  throw new Error("WOPEE_PROJECT_UUID is not set");
45
- let userStoryId;
46
- let testCaseId;
47
- if (input.identifier) {
48
- [userStoryId, testCaseId] = input.identifier.split(":");
49
- }
40
+ const { type, suiteUuid, content, identifier } = input;
50
41
  return {
51
- bucket: input.bucket,
42
+ type,
43
+ content,
44
+ suiteUuid,
52
45
  projectUuid: WOPEE_PROJECT_UUID,
53
- suiteUuid: input.suiteUuid,
54
- [input.outputType === "markdown" || input.outputType === "typescript"
55
- ? "code"
56
- : "json"]: input.fileContent,
57
- ...(userStoryId && testCaseId ? { testCaseId, userStoryId } : {}),
46
+ ...(identifier ? { identifier } : {}),
58
47
  };
59
48
  };
@@ -1,13 +1,38 @@
1
- export const FetchFile = `
2
- query FetchFile($projectUuid: ID!, $suiteUuid: ID!, $bucket: String!, $testCaseId: String) {
3
- fetchFile(projectUuid: $projectUuid, suiteUuid: $suiteUuid, bucket: $bucket, testCaseId: $testCaseId)
1
+ export const FetchArtifact = `
2
+ query FetchArtifact($input: FetchArtifactInput!) {
3
+ fetchArtifact(input: $input) {
4
+ content
5
+ blobSha
6
+ commitSha
7
+ commitDate
8
+ }
9
+ }
10
+ `;
11
+ export const UpdateArtifact = `
12
+ mutation Mutation($input: UpdateArtifactInput!) {
13
+ updateArtifact(input: $input)
4
14
  }
5
15
  `;
6
16
  export const DispatchAgent = `
7
17
  mutation DispatchAgent(
8
18
  $input: TestCasesInput!
9
19
  ) {
10
- dispatchAgent(input: $input)
20
+ dispatchAgent(input: $input) {
21
+ uuid
22
+ projectUuid
23
+ suiteUuid
24
+ analysisSuiteUuid
25
+ analysisIdentifier
26
+ userStoryId
27
+ testCaseId
28
+ executionStatus
29
+ agentReport
30
+ agentReportStatus
31
+ codeReport
32
+ codeReportStatus
33
+ createdAt
34
+ updatedAt
35
+ }
11
36
  }
12
37
  `;
13
38
  export const DispatchAnalysis = `
@@ -130,8 +155,3 @@ export const GenerateReusableTestCaseSteps = `
130
155
  generateReusableTestCaseSteps(input: $input)
131
156
  }
132
157
  `;
133
- export const UpdateFile = `
134
- mutation UpdateFile($input: UpdateFileInput!) {
135
- updateFile(input: $input)
136
- }
137
- `;
@@ -1,122 +1,21 @@
1
- import { z } from "zod";
2
- import { FetchFileInputSchema, UpdateFileInputSchema, GenerateAIDataInputSchema, } from "./schemas.js";
3
- import { FetchFile, UpdateFile, GenerateAppContext, GenerateGeneralUserStories, GenerateUserStoriesWithTestCases, GenerateTestCases, GenerateReusableTestCases, GenerateReusableTestCaseSteps, GenerateTestCaseSteps, } from "./gql-queries.js";
4
- import { createFetchFileInput, createUpdateFileInput, createGenerateAIDataInput, } from "./factories.js";
5
- import { Bucket, FileType } from "./types.js";
1
+ import { FetchArtifactInputSchema, UpdateArtifactInputSchema, GenerateAIDataInputSchema, } from "./schemas.js";
2
+ import { FetchArtifact, UpdateArtifact } from "./gql-queries.js";
3
+ import { createFetchArtifactInput, createUpdateArtifactInput, createGenerateAIDataInput, } from "./factories.js";
6
4
  import { requestClient } from "../../utils/requestClient.js";
7
- export function parseError(error) {
8
- console.error(error instanceof z.ZodError ? error.issues : error);
9
- return {
10
- content: [
11
- {
12
- type: "text",
13
- text: `Failed to parse input: ${error instanceof z.ZodError
14
- ? error.issues
15
- .map((issue) => `${issue.path[0] ?? "Unknown"}: ${issue.message}`)
16
- .join("\n")
17
- : error instanceof Error
18
- ? error.message
19
- : "Unknown zod validation error"}`,
20
- },
21
- ],
22
- };
23
- }
24
- function parseFileType(type) {
25
- switch (type) {
26
- case FileType.APP_CONTEXT:
27
- return {
28
- query: GenerateAppContext,
29
- dataKey: "generateAppContext",
30
- bucket: Bucket.APP_CONTEXT,
31
- outputType: "markdown",
32
- description: "application's context markdown file for selected suite",
33
- };
34
- case FileType.GENERAL_USER_STORIES:
35
- return {
36
- query: GenerateGeneralUserStories,
37
- dataKey: "generateGeneralUserStories",
38
- bucket: Bucket.GENERAL_USER_STORIES,
39
- outputType: "markdown",
40
- description: "general user stories markdown file for selected suite",
41
- };
42
- case FileType.USER_STORIES_WITH_TEST_CASES:
43
- return {
44
- query: GenerateUserStoriesWithTestCases,
45
- dataKey: "generateUserStoriesWithTestCases",
46
- bucket: Bucket.USER_STORIES,
47
- outputType: "json",
48
- description: "generate user stories with test cases without test case steps JSON file for selected suite",
49
- };
50
- case FileType.TEST_CASES:
51
- return {
52
- query: GenerateTestCases,
53
- dataKey: "generateTestCases",
54
- bucket: Bucket.USER_STORIES,
55
- outputType: "json",
56
- description: "generate test cases without test case steps in user stories for selected suite",
57
- };
58
- case FileType.REUSABLE_TEST_CASES:
59
- return {
60
- query: GenerateReusableTestCases,
61
- dataKey: "generateReusableTestCases",
62
- bucket: Bucket.USER_STORIES,
63
- outputType: "json",
64
- description: "generate reusable blocks without test case steps in user stories for selected suite",
65
- };
66
- case FileType.REUSABLE_TEST_CASE_STEPS:
67
- return {
68
- query: GenerateReusableTestCaseSteps,
69
- dataKey: "generateReusableTestCaseSteps",
70
- bucket: Bucket.USER_STORIES,
71
- outputType: "json",
72
- description: "generate steps for reusable blocks in user stories for selected suite",
73
- };
74
- case FileType.TEST_CASE_STEPS:
75
- return {
76
- query: GenerateTestCaseSteps,
77
- dataKey: "generateTestCaseSteps",
78
- bucket: Bucket.USER_STORIES,
79
- outputType: "json",
80
- description: "generate test case steps for test cases in user stories for selected suite",
81
- };
82
- case FileType.PLAYWRIGHT_CODE:
83
- return {
84
- query: null,
85
- dataKey: null,
86
- bucket: Bucket.PLAYWRIGHT_CODE,
87
- outputType: "typescript",
88
- description: "fetch playwright code for selected test case",
89
- };
90
- default:
91
- return {
92
- query: null,
93
- dataKey: null,
94
- bucket: null,
95
- outputType: null,
96
- description: null,
97
- };
98
- }
99
- }
100
- export async function fetchFile(input) {
5
+ import { _convertToArtifactType, _parseError, _parseGenerateArtifactType, } from "./helpers.js";
6
+ export async function fetchArtifact(input) {
101
7
  try {
102
- const { bucket, description } = parseFileType(input.fileType);
103
- if (!bucket || !description)
104
- return {
105
- content: [
106
- {
107
- type: "text",
108
- text: "Failed to parse file type",
109
- },
110
- ],
111
- };
112
- const fetchFileInput = createFetchFileInput({
113
- bucket,
114
- suiteUuid: input.suiteUuid,
115
- identifier: input.identifier,
8
+ const { type, suiteUuid, identifier } = input;
9
+ const fetchArtifactInput = createFetchArtifactInput({
10
+ type,
11
+ suiteUuid,
12
+ ...(identifier ? { identifier } : {}),
116
13
  });
117
- const parsedInput = FetchFileInputSchema.parse(fetchFileInput);
118
- const result = await requestClient(FetchFile, parsedInput);
119
- if (!result || !result.fetchFile)
14
+ const parsedInput = FetchArtifactInputSchema.parse(fetchArtifactInput);
15
+ const result = await requestClient(FetchArtifact, {
16
+ input: parsedInput,
17
+ });
18
+ if (!result || !result?.fetchArtifact || !result?.fetchArtifact?.content)
120
19
  return {
121
20
  content: [
122
21
  {
@@ -129,18 +28,18 @@ export async function fetchFile(input) {
129
28
  content: [
130
29
  {
131
30
  type: "text",
132
- text: result.fetchFile,
31
+ text: result.fetchArtifact.content,
133
32
  },
134
33
  ],
135
34
  };
136
35
  }
137
36
  catch (error) {
138
- return parseError(error);
37
+ return _parseError(error);
139
38
  }
140
39
  }
141
40
  export async function generateAIDataFile(input) {
142
- const { query, dataKey, bucket, description } = parseFileType(input.fileType);
143
- if (!query || !dataKey || !description || !bucket)
41
+ const { query, dataKey, description } = _parseGenerateArtifactType(input.type);
42
+ if (!query || !dataKey || !description)
144
43
  return {
145
44
  content: [
146
45
  {
@@ -164,39 +63,30 @@ export async function generateAIDataFile(input) {
164
63
  },
165
64
  ],
166
65
  };
167
- return await fetchFile({
66
+ const convertedType = _convertToArtifactType(input.type);
67
+ return await fetchArtifact({
168
68
  suiteUuid: parsedInput.suiteUuid,
169
- fileType: input.fileType,
69
+ type: convertedType,
170
70
  });
171
71
  }
172
72
  catch (error) {
173
- return parseError(error);
73
+ return _parseError(error);
174
74
  }
175
75
  }
176
- export async function updateFile(input) {
76
+ export async function updateArtifact(input) {
177
77
  try {
178
- const { bucket, outputType } = parseFileType(input.fileType);
179
- if (!bucket || !outputType)
180
- return {
181
- content: [
182
- {
183
- type: "text",
184
- text: "Failed to parse file type",
185
- },
186
- ],
187
- };
188
- const updateFileInput = createUpdateFileInput({
189
- bucket,
190
- outputType,
191
- suiteUuid: input.suiteUuid,
192
- fileContent: input.fileContent,
193
- identifier: input.identifier,
78
+ const { type, suiteUuid, content, identifier } = input;
79
+ const updateArtifactInput = createUpdateArtifactInput({
80
+ type,
81
+ content,
82
+ suiteUuid,
83
+ ...(identifier ? { identifier } : {}),
194
84
  });
195
- const parsedInput = UpdateFileInputSchema.parse(updateFileInput);
196
- const updateFileResult = await requestClient(UpdateFile, {
85
+ const parsedInput = UpdateArtifactInputSchema.parse(updateArtifactInput);
86
+ const updateFileResult = await requestClient(UpdateArtifact, {
197
87
  input: parsedInput,
198
88
  });
199
- if (!updateFileResult || !updateFileResult.updateFile)
89
+ if (!updateFileResult || !updateFileResult.updateArtifact)
200
90
  return {
201
91
  content: [
202
92
  {
@@ -215,6 +105,6 @@ export async function updateFile(input) {
215
105
  };
216
106
  }
217
107
  catch (error) {
218
- return parseError(error);
108
+ return _parseError(error);
219
109
  }
220
110
  }
@@ -0,0 +1,86 @@
1
+ import { z } from "zod";
2
+ import { GenerateAppContext, GenerateGeneralUserStories, GenerateReusableTestCases, GenerateReusableTestCaseSteps, GenerateTestCases, GenerateTestCaseSteps, GenerateUserStoriesWithTestCases, } from "./gql-queries.js";
3
+ import { ArtifactType, GenerateArtifactType } from "./types.js";
4
+ export function _convertToArtifactType(type) {
5
+ switch (type) {
6
+ case GenerateArtifactType.APP_CONTEXT:
7
+ return ArtifactType.APP_CONTEXT;
8
+ case GenerateArtifactType.GENERAL_USER_STORIES:
9
+ return ArtifactType.GENERAL_USER_STORIES;
10
+ case GenerateArtifactType.USER_STORIES_WITH_TEST_CASES:
11
+ case GenerateArtifactType.REUSABLE_TEST_CASES:
12
+ case GenerateArtifactType.REUSABLE_TEST_CASE_STEPS:
13
+ case GenerateArtifactType.TEST_CASES:
14
+ case GenerateArtifactType.TEST_CASE_STEPS:
15
+ return ArtifactType.USER_STORIES;
16
+ }
17
+ }
18
+ export function _parseGenerateArtifactType(type) {
19
+ switch (type) {
20
+ case GenerateArtifactType.APP_CONTEXT:
21
+ return {
22
+ query: GenerateAppContext,
23
+ dataKey: "generateAppContext",
24
+ description: "application's context markdown file for selected suite",
25
+ };
26
+ case GenerateArtifactType.GENERAL_USER_STORIES:
27
+ return {
28
+ query: GenerateGeneralUserStories,
29
+ dataKey: "generateGeneralUserStories",
30
+ description: "general user stories markdown file for selected suite",
31
+ };
32
+ case GenerateArtifactType.USER_STORIES_WITH_TEST_CASES:
33
+ return {
34
+ query: GenerateUserStoriesWithTestCases,
35
+ dataKey: "generateUserStoriesWithTestCases",
36
+ description: "generate user stories with test cases without test case steps JSON file for selected suite",
37
+ };
38
+ case GenerateArtifactType.TEST_CASES:
39
+ return {
40
+ query: GenerateTestCases,
41
+ dataKey: "generateTestCases",
42
+ description: "generate test cases without test case steps in user stories for selected suite",
43
+ };
44
+ case GenerateArtifactType.REUSABLE_TEST_CASES:
45
+ return {
46
+ query: GenerateReusableTestCases,
47
+ dataKey: "generateReusableTestCases",
48
+ description: "generate reusable blocks without test case steps in user stories for selected suite",
49
+ };
50
+ case GenerateArtifactType.REUSABLE_TEST_CASE_STEPS:
51
+ return {
52
+ query: GenerateReusableTestCaseSteps,
53
+ dataKey: "generateReusableTestCaseSteps",
54
+ description: "generate steps for reusable blocks in user stories for selected suite",
55
+ };
56
+ case GenerateArtifactType.TEST_CASE_STEPS:
57
+ return {
58
+ query: GenerateTestCaseSteps,
59
+ dataKey: "generateTestCaseSteps",
60
+ description: "generate test case steps for test cases in user stories for selected suite",
61
+ };
62
+ default:
63
+ return {
64
+ query: null,
65
+ dataKey: null,
66
+ description: null,
67
+ };
68
+ }
69
+ }
70
+ export function _parseError(error) {
71
+ console.error(error instanceof z.ZodError ? error.issues : error);
72
+ return {
73
+ content: [
74
+ {
75
+ type: "text",
76
+ text: `Failed to parse input: ${error instanceof z.ZodError
77
+ ? error.issues
78
+ .map((issue) => `${issue.path[0] ?? "Unknown"}: ${issue.message}`)
79
+ .join("\n")
80
+ : error instanceof Error
81
+ ? error.message
82
+ : "Unknown zod validation error"}`,
83
+ },
84
+ ],
85
+ };
86
+ }
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { Bucket, FileType } from "./types.js";
2
+ import { ArtifactType, GenerateArtifactType } from "./types.js";
3
3
  var CookiesPreference;
4
4
  (function (CookiesPreference) {
5
5
  CookiesPreference["ACCEPT_ALL"] = "ACCEPT_ALL";
@@ -15,7 +15,7 @@ export const SuiteAnalysisConfigSchema = z.object({
15
15
  additionalVariables: z.string().nullable().default(null),
16
16
  });
17
17
  export const GenerateAIDataHandlerInputSchema = z.object({
18
- fileType: z.enum(Object.values(FileType).filter((type) => type !== FileType.PLAYWRIGHT_CODE), {
18
+ type: z.nativeEnum(GenerateArtifactType, {
19
19
  description: "Chosen type of file(artifact) to generate",
20
20
  }),
21
21
  suiteUuid: z
@@ -32,8 +32,8 @@ export const GenerateAIDataInputSchema = z.object({
32
32
  suiteAnalysisConfig: SuiteAnalysisConfigSchema,
33
33
  continueGeneration: z.boolean().nullish().default(false),
34
34
  });
35
- export const FetchFileHandlerInputSchema = z.object({
36
- fileType: z.nativeEnum(FileType, {
35
+ export const FetchArtifactHandlerInputSchema = z.object({
36
+ type: z.nativeEnum(ArtifactType, {
37
37
  description: "Chosen file(artifact) to fetch",
38
38
  }),
39
39
  suiteUuid: z
@@ -41,26 +41,35 @@ export const FetchFileHandlerInputSchema = z.object({
41
41
  .min(1, "Suite UUID is required"),
42
42
  identifier: z
43
43
  .string({
44
- description: "Identifier for the test case to fetch playwright code for, ex. `US004:TC006`, should be provided only for `PLAYWRIGHT_CODE` file type",
44
+ description: "Identifier for the test case to fetch playwright code for, ex. `US004:TC006`, should be provided only for `PLAYWRIGHT_CODE` artifact type",
45
45
  })
46
46
  .optional(),
47
47
  });
48
- export const FetchFileFactoryInputSchema = z.object({
48
+ export const FetchArtifactFactoryInputSchema = z.object({
49
49
  suiteUuid: z.string().min(1, "Suite UUID is required"),
50
- bucket: z.nativeEnum(Bucket),
51
- identifier: z.string().nullish(),
50
+ type: z.nativeEnum(ArtifactType),
51
+ identifier: z
52
+ .string({
53
+ description: "Identifier for the test case to fetch playwright code for, ex. `US004:TC006`, should be provided only for `PLAYWRIGHT_CODE` artifact type",
54
+ })
55
+ .nullish(),
52
56
  });
53
- export const FetchFileInputSchema = z.object({
57
+ export const FetchArtifactInputSchema = z.object({
54
58
  projectUuid: z.string().min(1, "Project UUID is required"),
55
59
  suiteUuid: z.string().min(1, "Suite UUID is required"),
56
- bucket: z.nativeEnum(Bucket),
57
- testCaseId: z.string().nullish(),
60
+ type: z.nativeEnum(ArtifactType),
61
+ identifier: z
62
+ .string({
63
+ description: "Identifier for the test case to fetch playwright code for, ex. `US004:TC006`, should be provided only for `PLAYWRIGHT_CODE` artifact type",
64
+ })
65
+ .nullish(),
66
+ ref: z.string().nullish(), // branch, tag or commit sha
58
67
  });
59
- export const UpdateFileHandlerInputSchema = z.object({
60
- fileType: z.nativeEnum(FileType, {
68
+ export const UpdateArtifactHandlerInputSchema = z.object({
69
+ type: z.nativeEnum(ArtifactType, {
61
70
  description: "Chosen file(artifact) to update",
62
71
  }),
63
- fileContent: z.string({
72
+ content: z.string({
64
73
  description: "Content of the file(artifact) to update",
65
74
  }),
66
75
  suiteUuid: z
@@ -68,23 +77,26 @@ export const UpdateFileHandlerInputSchema = z.object({
68
77
  .min(1, "Suite UUID is required"),
69
78
  identifier: z
70
79
  .string({
71
- description: "Identifier for the test case to update playwright code for, ex. `US004:TC006`, should be provided only for `PLAYWRIGHT_CODE` file type",
80
+ description: "Identifier for the test case to update playwright code for, ex. `US004:TC006`, should be provided only for `PLAYWRIGHT_CODE` artifact type",
72
81
  })
73
82
  .optional(),
74
83
  });
75
- export const UpdateFileFactoryInputSchema = z.object({
76
- bucket: z.nativeEnum(Bucket),
84
+ export const UpdateArtifactFactoryInputSchema = z.object({
85
+ type: z.nativeEnum(ArtifactType),
77
86
  suiteUuid: z.string().min(1, "Suite UUID is required"),
78
- fileContent: z.string(),
79
- outputType: z.enum(["markdown", "json", "typescript"]),
87
+ content: z.string(),
80
88
  identifier: z.string().optional(),
81
89
  });
82
- export const UpdateFileInputSchema = z.object({
90
+ export const UpdateArtifactInputSchema = z.object({
83
91
  projectUuid: z.string().min(1, "Project UUID is required"),
84
92
  suiteUuid: z.string().min(1, "Suite UUID is required"),
85
- bucket: z.nativeEnum(Bucket),
86
- json: z.string().nullish(),
87
- code: z.string().nullish(),
88
- testCaseId: z.string().nullish(),
89
- userStoryId: z.string().nullish(),
93
+ type: z.nativeEnum(ArtifactType),
94
+ identifier: z
95
+ .string({
96
+ description: "Identifier for the test case to update playwright code for, ex. `US004:TC006`, should be provided only for `PLAYWRIGHT_CODE` artifact type",
97
+ })
98
+ .nullish(),
99
+ content: z.string({
100
+ description: "Content of the artifact to update",
101
+ }),
90
102
  });
@@ -3,30 +3,28 @@ export var ToolName;
3
3
  ToolName["WOPEE_FETCH_ANALYSIS_SUITES"] = "wopee_fetch_analysis_suites";
4
4
  ToolName["WOPEE_DISPATCH_ANALYSIS"] = "wopee_dispatch_analysis";
5
5
  ToolName["WOPEE_DISPATCH_AGENT"] = "wopee_dispatch_agent";
6
- ToolName["WOPEE_FETCH_FILE"] = "wopee_fetch_file";
7
- ToolName["WOPEE_UPDATE_FILE"] = "wopee_update_file";
8
- ToolName["WOPEE_GENERATE_FILE"] = "wopee_generate_file";
6
+ ToolName["WOPEE_FETCH_ARTIFACT"] = "wopee_fetch_artifact";
7
+ ToolName["WOPEE_UPDATE_ARTIFACT"] = "wopee_update_artifact";
8
+ ToolName["WOPEE_GENERATE_ARTIFACT"] = "wopee_generate_artifact";
9
9
  })(ToolName || (ToolName = {}));
10
- export const Bucket = {
11
- APP_CONTEXT: "project-suite-app-context",
12
- GENERAL_USER_STORIES: "project-suite-general-user-stories",
13
- USER_STORIES: "project-suite-user-stories",
14
- PAGE_CONTENT: "screen-instance-page-content",
15
- PROMPTS: "project-prompts",
16
- PLAYWRIGHT_CODE: "project-suite-playwright-code",
17
- UPLOADED_PAGE_DATA: "project-uploaded-page-data",
18
- };
19
- export var FileType;
20
- (function (FileType) {
21
- FileType["APP_CONTEXT"] = "APP_CONTEXT";
22
- FileType["GENERAL_USER_STORIES"] = "GENERAL_USER_STORIES";
23
- FileType["USER_STORIES_WITH_TEST_CASES"] = "USER_STORIES_WITH_TEST_CASES";
24
- FileType["TEST_CASES"] = "TEST_CASES";
25
- FileType["TEST_CASE_STEPS"] = "TEST_CASE_STEPS";
26
- FileType["REUSABLE_TEST_CASES"] = "REUSABLE_TEST_CASES";
27
- FileType["REUSABLE_TEST_CASE_STEPS"] = "REUSABLE_TEST_CASE_STEPS";
28
- FileType["PLAYWRIGHT_CODE"] = "PLAYWRIGHT_CODE";
29
- })(FileType || (FileType = {}));
10
+ export var GenerateArtifactType;
11
+ (function (GenerateArtifactType) {
12
+ GenerateArtifactType["APP_CONTEXT"] = "APP_CONTEXT";
13
+ GenerateArtifactType["GENERAL_USER_STORIES"] = "GENERAL_USER_STORIES";
14
+ GenerateArtifactType["USER_STORIES_WITH_TEST_CASES"] = "USER_STORIES_WITH_TEST_CASES";
15
+ GenerateArtifactType["TEST_CASES"] = "TEST_CASES";
16
+ GenerateArtifactType["TEST_CASE_STEPS"] = "TEST_CASE_STEPS";
17
+ GenerateArtifactType["REUSABLE_TEST_CASES"] = "REUSABLE_TEST_CASES";
18
+ GenerateArtifactType["REUSABLE_TEST_CASE_STEPS"] = "REUSABLE_TEST_CASE_STEPS";
19
+ })(GenerateArtifactType || (GenerateArtifactType = {}));
20
+ export var ArtifactType;
21
+ (function (ArtifactType) {
22
+ ArtifactType["APP_CONTEXT"] = "APP_CONTEXT";
23
+ ArtifactType["GENERAL_USER_STORIES"] = "GENERAL_USER_STORIES";
24
+ ArtifactType["USER_STORIES"] = "USER_STORIES";
25
+ ArtifactType["PLAYWRIGHT_CODE"] = "PLAYWRIGHT_CODE";
26
+ ArtifactType["PROJECT_CONTEXT"] = "PROJECT_CONTEXT";
27
+ })(ArtifactType || (ArtifactType = {}));
30
28
  export var SuiteType;
31
29
  (function (SuiteType) {
32
30
  SuiteType["BOT"] = "BOT";
@@ -1,6 +1,6 @@
1
1
  import { DispatchAgentInputSchema, WopeeDispatchAgentInputSchema, } from "./schema.js";
2
2
  import { ToolName } from "../shared/types.js";
3
- import { parseError } from "../shared/handlers.js";
3
+ import { _parseError } from "../shared/helpers.js";
4
4
  import { createDispatchAgentInput } from "./factory.js";
5
5
  import { DispatchAgent } from "../shared/gql-queries.js";
6
6
  import { requestClient } from "../../utils/requestClient.js";
@@ -18,7 +18,7 @@ export const wopeeDispatchAgent = {
18
18
  const result = await requestClient(DispatchAgent, {
19
19
  input: parsedInput,
20
20
  });
21
- if (!result || !result.dispatchAgent)
21
+ if (!result || result?.dispatchAgent?.length === 0)
22
22
  return {
23
23
  content: [
24
24
  {
@@ -37,7 +37,7 @@ export const wopeeDispatchAgent = {
37
37
  };
38
38
  }
39
39
  catch (error) {
40
- return parseError(error);
40
+ return _parseError(error);
41
41
  }
42
42
  },
43
43
  };
@@ -1,4 +1,4 @@
1
- import { parseError } from "../shared/handlers.js";
1
+ import { _parseError } from "../shared/helpers.js";
2
2
  import { DispatchAnalysisInputSchema } from "./schema.js";
3
3
  import { createDispatchAnalysisInput } from "./factory.js";
4
4
  import { DispatchAnalysis } from "../shared/gql-queries.js";
@@ -36,7 +36,7 @@ export const wopeeDispatchAnalysis = {
36
36
  };
37
37
  }
38
38
  catch (error) {
39
- return parseError(error);
39
+ return _parseError(error);
40
40
  }
41
41
  },
42
42
  };
@@ -0,0 +1,12 @@
1
+ import { FetchArtifactHandlerInputSchema, } from "../shared/schemas.js";
2
+ import { ToolName } from "../shared/types.js";
3
+ import { fetchArtifact } from "../shared/handlers.js";
4
+ export const wopeeFetchArtifact = {
5
+ name: ToolName.WOPEE_FETCH_ARTIFACT,
6
+ config: {
7
+ title: "Fetch file(artifact)",
8
+ description: "Fetch suite's file(artifact) for selected project",
9
+ inputSchema: FetchArtifactHandlerInputSchema.shape,
10
+ },
11
+ handler: async (input) => await fetchArtifact(input),
12
+ };
@@ -1,8 +1,8 @@
1
1
  import { GenerateAIDataHandlerInputSchema, } from "../shared/schemas.js";
2
2
  import { ToolName } from "../shared/types.js";
3
3
  import { generateAIDataFile } from "../shared/handlers.js";
4
- export const wopeeGenerateFile = {
5
- name: ToolName.WOPEE_GENERATE_FILE,
4
+ export const wopeeGenerateArtifact = {
5
+ name: ToolName.WOPEE_GENERATE_ARTIFACT,
6
6
  config: {
7
7
  title: "Generate file(artifact)",
8
8
  description: "Generate AI data file for selected suite",
@@ -0,0 +1,12 @@
1
+ import { UpdateArtifactHandlerInputSchema, } from "../shared/schemas.js";
2
+ import { ToolName } from "../shared/types.js";
3
+ import { updateArtifact } from "../shared/handlers.js";
4
+ export const wopeeUpdateArtifact = {
5
+ name: ToolName.WOPEE_UPDATE_ARTIFACT,
6
+ config: {
7
+ title: "Update file",
8
+ description: "Update file(artifact) in the project",
9
+ inputSchema: UpdateArtifactHandlerInputSchema.shape,
10
+ },
11
+ handler: async (input) => await updateArtifact(input),
12
+ };
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "bin": {
5
5
  "wopee-mcp": "./build/index.js"
6
6
  },
7
- "version": "1.8.1",
7
+ "version": "1.11.0",
8
8
  "description": "Wopee.io MCP server",
9
9
  "main": "./build/index.js",
10
10
  "scripts": {
@@ -30,13 +30,14 @@
30
30
  "license": "ISC",
31
31
  "dependencies": {
32
32
  "@modelcontextprotocol/sdk": "^1.21.0",
33
+ "undici": "^7.18.2",
33
34
  "zod": "^3.25.76"
34
35
  },
35
36
  "devDependencies": {
36
- "typescript": "^5.9.3",
37
+ "@semantic-release/changelog": "^6.0.3",
38
+ "@semantic-release/git": "^10.0.1",
37
39
  "@types/node": "^24.10.0",
38
40
  "semantic-release": "^24.2.7",
39
- "@semantic-release/git": "^10.0.1",
40
- "@semantic-release/changelog": "^6.0.3"
41
+ "typescript": "^5.9.3"
41
42
  }
42
43
  }
@@ -1,12 +0,0 @@
1
- import { FetchFileHandlerInputSchema, } from "../shared/schemas.js";
2
- import { ToolName } from "../shared/types.js";
3
- import { fetchFile } from "../shared/handlers.js";
4
- export const wopeeFetchFile = {
5
- name: ToolName.WOPEE_FETCH_FILE,
6
- config: {
7
- title: "Fetch file(artifact)",
8
- description: "Fetch suite's file(artifact) for selected project",
9
- inputSchema: FetchFileHandlerInputSchema.shape,
10
- },
11
- handler: async (input) => await fetchFile(input),
12
- };
@@ -1,12 +0,0 @@
1
- import { UpdateFileHandlerInputSchema, } from "../shared/schemas.js";
2
- import { ToolName } from "../shared/types.js";
3
- import { updateFile } from "../shared/handlers.js";
4
- export const wopeeUpdateFile = {
5
- name: ToolName.WOPEE_UPDATE_FILE,
6
- config: {
7
- title: "Update file",
8
- description: "Update file(artifact) in the project",
9
- inputSchema: UpdateFileHandlerInputSchema.shape,
10
- },
11
- handler: async (input) => await updateFile(input),
12
- };