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 +50 -14
- package/build/index.js +9 -0
- package/build/tools/index.js +6 -6
- package/build/tools/shared/factories.js +11 -7
- package/build/tools/shared/gql-queries.js +29 -9
- package/build/tools/shared/handlers.js +34 -134
- package/build/tools/shared/helpers.js +86 -0
- package/build/tools/shared/schemas.js +46 -19
- package/build/tools/shared/types.js +21 -22
- package/build/tools/wopee_dispatch_agent/index.js +3 -3
- package/build/tools/wopee_dispatch_analysis/index.js +2 -2
- package/build/tools/wopee_fetch_artifact/index.js +12 -0
- package/build/tools/{wopee_generate_file → wopee_generate_artifact}/index.js +2 -2
- package/build/tools/wopee_update_artifact/index.js +12 -0
- package/package.json +5 -4
- package/build/tools/wopee_fetch_file/index.js +0 -12
- package/build/tools/wopee_update_file/index.js +0 -12
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 `
|
|
127
|
+
These tools generate various artifacts for a specific suite. All require a `suiteUuid` and `type` to generate.
|
|
96
128
|
|
|
97
|
-
#### `
|
|
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
|
-
- `
|
|
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 `
|
|
146
|
+
These tools retrieve generated artifacts for a specific suite. All require a `suiteUuid` and `type`.
|
|
115
147
|
|
|
116
|
-
#### `
|
|
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
|
-
- `
|
|
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`, `
|
|
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
|
-
#### `
|
|
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
|
-
- `
|
|
142
|
-
- `
|
|
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: `
|
|
181
|
-
- Generate general user stories: `
|
|
182
|
-
- Generate user stories: `
|
|
183
|
-
- Generate test cases: `
|
|
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",
|
package/build/tools/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
wopeeFetchArtifact,
|
|
12
|
+
wopeeUpdateArtifact,
|
|
13
|
+
wopeeGenerateArtifact,
|
|
14
14
|
];
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { getConfig } from "../../utils/getConfig.js";
|
|
2
|
-
export const
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
42
|
+
type,
|
|
43
|
+
content,
|
|
44
|
+
suiteUuid,
|
|
40
45
|
projectUuid: WOPEE_PROJECT_UUID,
|
|
41
|
-
|
|
42
|
-
[input.outputType === "markdown" ? "code" : "json"]: input.fileContent,
|
|
46
|
+
...(identifier ? { identifier } : {}),
|
|
43
47
|
};
|
|
44
48
|
};
|
|
@@ -1,13 +1,38 @@
|
|
|
1
|
-
export const
|
|
2
|
-
query
|
|
3
|
-
|
|
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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
|
-
|
|
8
|
-
|
|
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 {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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 =
|
|
109
|
-
const result = await requestClient(
|
|
110
|
-
|
|
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.
|
|
31
|
+
text: result.fetchArtifact.content,
|
|
124
32
|
},
|
|
125
33
|
],
|
|
126
34
|
};
|
|
127
35
|
}
|
|
128
36
|
catch (error) {
|
|
129
|
-
return
|
|
37
|
+
return _parseError(error);
|
|
130
38
|
}
|
|
131
39
|
}
|
|
132
40
|
export async function generateAIDataFile(input) {
|
|
133
|
-
const { query, dataKey,
|
|
134
|
-
if (!query || !dataKey || !description
|
|
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
|
-
|
|
66
|
+
const convertedType = _convertToArtifactType(input.type);
|
|
67
|
+
return await fetchArtifact({
|
|
159
68
|
suiteUuid: parsedInput.suiteUuid,
|
|
160
|
-
|
|
69
|
+
type: convertedType,
|
|
161
70
|
});
|
|
162
71
|
}
|
|
163
72
|
catch (error) {
|
|
164
|
-
return
|
|
73
|
+
return _parseError(error);
|
|
165
74
|
}
|
|
166
75
|
}
|
|
167
|
-
export async function
|
|
76
|
+
export async function updateArtifact(input) {
|
|
168
77
|
try {
|
|
169
|
-
const {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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 =
|
|
186
|
-
const updateFileResult = await requestClient(
|
|
85
|
+
const parsedInput = UpdateArtifactInputSchema.parse(updateArtifactInput);
|
|
86
|
+
const updateFileResult = await requestClient(UpdateArtifact, {
|
|
187
87
|
input: parsedInput,
|
|
188
88
|
});
|
|
189
|
-
if (!updateFileResult || !updateFileResult.
|
|
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
|
|
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 {
|
|
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
|
-
|
|
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
|
|
36
|
-
|
|
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
|
|
48
|
+
export const FetchArtifactFactoryInputSchema = z.object({
|
|
44
49
|
suiteUuid: z.string().min(1, "Suite UUID is required"),
|
|
45
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
53
|
-
|
|
68
|
+
export const UpdateArtifactHandlerInputSchema = z.object({
|
|
69
|
+
type: z.nativeEnum(ArtifactType, {
|
|
54
70
|
description: "Chosen file(artifact) to update",
|
|
55
71
|
}),
|
|
56
|
-
|
|
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
|
|
64
|
-
|
|
84
|
+
export const UpdateArtifactFactoryInputSchema = z.object({
|
|
85
|
+
type: z.nativeEnum(ArtifactType),
|
|
65
86
|
suiteUuid: z.string().min(1, "Suite UUID is required"),
|
|
66
|
-
|
|
67
|
-
|
|
87
|
+
content: z.string(),
|
|
88
|
+
identifier: z.string().optional(),
|
|
68
89
|
});
|
|
69
|
-
export const
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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["
|
|
7
|
-
ToolName["
|
|
8
|
-
ToolName["
|
|
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
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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 {
|
|
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 ||
|
|
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
|
|
40
|
+
return _parseError(error);
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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
|
|
5
|
-
name: ToolName.
|
|
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
|
+
"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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
};
|