wopee-mcp 1.7.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,12 +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
+ const { type, suiteUuid, identifier } = input;
6
7
  return {
8
+ type,
9
+ suiteUuid,
7
10
  projectUuid: WOPEE_PROJECT_UUID,
8
- suiteUuid: input.suiteUuid,
9
- bucket: input.bucket,
11
+ ...(identifier ? { identifier } : {}),
10
12
  };
11
13
  };
12
14
  export const createGenerateAIDataInput = (input) => {
@@ -31,14 +33,16 @@ export const createGenerateAIDataInput = (input) => {
31
33
  sourceSuiteUuid: null,
32
34
  };
33
35
  };
34
- export const createUpdateFileInput = (input) => {
36
+ export const createUpdateArtifactInput = (input) => {
35
37
  const { WOPEE_PROJECT_UUID } = getConfig();
36
38
  if (!WOPEE_PROJECT_UUID)
37
39
  throw new Error("WOPEE_PROJECT_UUID is not set");
40
+ const { type, suiteUuid, content, identifier } = input;
38
41
  return {
39
- bucket: input.bucket,
42
+ type,
43
+ content,
44
+ suiteUuid,
40
45
  projectUuid: WOPEE_PROJECT_UUID,
41
- suiteUuid: input.suiteUuid,
42
- [input.outputType === "markdown" ? "code" : "json"]: input.fileContent,
46
+ ...(identifier ? { identifier } : {}),
43
47
  };
44
48
  };
@@ -1,13 +1,38 @@
1
- export const FetchFile = `
2
- query FetchFile($projectUuid: ID!, $suiteUuid: ID!, $bucket: String!) {
3
- fetchFile(projectUuid: $projectUuid, suiteUuid: $suiteUuid, bucket: $bucket)
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,113 +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
- default:
83
- return {
84
- query: null,
85
- dataKey: null,
86
- bucket: null,
87
- outputType: null,
88
- description: null,
89
- };
90
- }
91
- }
92
- export async function fetchFile(input) {
5
+ import { _convertToArtifactType, _parseError, _parseGenerateArtifactType, } from "./helpers.js";
6
+ export async function fetchArtifact(input) {
93
7
  try {
94
- const { bucket, description } = parseFileType(input.fileType);
95
- if (!bucket || !description)
96
- return {
97
- content: [
98
- {
99
- type: "text",
100
- text: "Failed to parse file type",
101
- },
102
- ],
103
- };
104
- const fetchFileInput = createFetchFileInput({
105
- bucket,
106
- suiteUuid: input.suiteUuid,
8
+ const { type, suiteUuid, identifier } = input;
9
+ const fetchArtifactInput = createFetchArtifactInput({
10
+ type,
11
+ suiteUuid,
12
+ ...(identifier ? { identifier } : {}),
107
13
  });
108
- const parsedInput = FetchFileInputSchema.parse(fetchFileInput);
109
- const result = await requestClient(FetchFile, parsedInput);
110
- 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)
111
19
  return {
112
20
  content: [
113
21
  {
@@ -120,18 +28,18 @@ export async function fetchFile(input) {
120
28
  content: [
121
29
  {
122
30
  type: "text",
123
- text: result.fetchFile,
31
+ text: result.fetchArtifact.content,
124
32
  },
125
33
  ],
126
34
  };
127
35
  }
128
36
  catch (error) {
129
- return parseError(error);
37
+ return _parseError(error);
130
38
  }
131
39
  }
132
40
  export async function generateAIDataFile(input) {
133
- const { query, dataKey, bucket, description } = parseFileType(input.fileType);
134
- if (!query || !dataKey || !description || !bucket)
41
+ const { query, dataKey, description } = _parseGenerateArtifactType(input.type);
42
+ if (!query || !dataKey || !description)
135
43
  return {
136
44
  content: [
137
45
  {
@@ -155,38 +63,30 @@ export async function generateAIDataFile(input) {
155
63
  },
156
64
  ],
157
65
  };
158
- return await fetchFile({
66
+ const convertedType = _convertToArtifactType(input.type);
67
+ return await fetchArtifact({
159
68
  suiteUuid: parsedInput.suiteUuid,
160
- fileType: input.fileType,
69
+ type: convertedType,
161
70
  });
162
71
  }
163
72
  catch (error) {
164
- return parseError(error);
73
+ return _parseError(error);
165
74
  }
166
75
  }
167
- export async function updateFile(input) {
76
+ export async function updateArtifact(input) {
168
77
  try {
169
- const { bucket, outputType } = parseFileType(input.fileType);
170
- if (!bucket || !outputType)
171
- return {
172
- content: [
173
- {
174
- type: "text",
175
- text: "Failed to parse file type",
176
- },
177
- ],
178
- };
179
- const updateFileInput = createUpdateFileInput({
180
- bucket,
181
- outputType,
182
- suiteUuid: input.suiteUuid,
183
- fileContent: input.fileContent,
78
+ const { type, suiteUuid, content, identifier } = input;
79
+ const updateArtifactInput = createUpdateArtifactInput({
80
+ type,
81
+ content,
82
+ suiteUuid,
83
+ ...(identifier ? { identifier } : {}),
184
84
  });
185
- const parsedInput = UpdateFileInputSchema.parse(updateFileInput);
186
- const updateFileResult = await requestClient(UpdateFile, {
85
+ const parsedInput = UpdateArtifactInputSchema.parse(updateArtifactInput);
86
+ const updateFileResult = await requestClient(UpdateArtifact, {
187
87
  input: parsedInput,
188
88
  });
189
- if (!updateFileResult || !updateFileResult.updateFile)
89
+ if (!updateFileResult || !updateFileResult.updateArtifact)
190
90
  return {
191
91
  content: [
192
92
  {
@@ -205,6 +105,6 @@ export async function updateFile(input) {
205
105
  };
206
106
  }
207
107
  catch (error) {
208
- return parseError(error);
108
+ return _parseError(error);
209
109
  }
210
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.nativeEnum(FileType, {
18
+ type: z.nativeEnum(GenerateArtifactType, {
19
19
  description: "Chosen type of file(artifact) to generate",
20
20
  }),
21
21
  suiteUuid: z
@@ -32,44 +32,71 @@ 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
40
40
  .string({ description: "UUID of the suite to fetch the file from" })
41
41
  .min(1, "Suite UUID is required"),
42
+ identifier: z
43
+ .string({
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
+ })
46
+ .optional(),
42
47
  });
43
- export const FetchFileFactoryInputSchema = z.object({
48
+ export const FetchArtifactFactoryInputSchema = z.object({
44
49
  suiteUuid: z.string().min(1, "Suite UUID is required"),
45
- bucket: z.nativeEnum(Bucket),
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(),
46
56
  });
47
- export const FetchFileInputSchema = z.object({
57
+ export const FetchArtifactInputSchema = z.object({
48
58
  projectUuid: z.string().min(1, "Project UUID is required"),
49
59
  suiteUuid: z.string().min(1, "Suite UUID is required"),
50
- bucket: z.nativeEnum(Bucket),
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
51
67
  });
52
- export const UpdateFileHandlerInputSchema = z.object({
53
- fileType: z.nativeEnum(FileType, {
68
+ export const UpdateArtifactHandlerInputSchema = z.object({
69
+ type: z.nativeEnum(ArtifactType, {
54
70
  description: "Chosen file(artifact) to update",
55
71
  }),
56
- fileContent: z.string({
72
+ content: z.string({
57
73
  description: "Content of the file(artifact) to update",
58
74
  }),
59
75
  suiteUuid: z
60
76
  .string({ description: "UUID of the suite to update the file for" })
61
77
  .min(1, "Suite UUID is required"),
78
+ identifier: z
79
+ .string({
80
+ description: "Identifier for the test case to update playwright code for, ex. `US004:TC006`, should be provided only for `PLAYWRIGHT_CODE` artifact type",
81
+ })
82
+ .optional(),
62
83
  });
63
- export const UpdateFileFactoryInputSchema = z.object({
64
- bucket: z.nativeEnum(Bucket),
84
+ export const UpdateArtifactFactoryInputSchema = z.object({
85
+ type: z.nativeEnum(ArtifactType),
65
86
  suiteUuid: z.string().min(1, "Suite UUID is required"),
66
- fileContent: z.string(),
67
- outputType: z.enum(["markdown", "json"]),
87
+ content: z.string(),
88
+ identifier: z.string().optional(),
68
89
  });
69
- export const UpdateFileInputSchema = z.object({
90
+ export const UpdateArtifactInputSchema = z.object({
70
91
  projectUuid: z.string().min(1, "Project UUID is required"),
71
92
  suiteUuid: z.string().min(1, "Suite UUID is required"),
72
- bucket: z.nativeEnum(Bucket),
73
- json: z.string().nullish(),
74
- code: 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
+ }),
75
102
  });
@@ -3,29 +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 || (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 = {}));
29
28
  export var SuiteType;
30
29
  (function (SuiteType) {
31
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.7.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
- };