@uuv/mcp-server 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to use,
8
+ copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
9
+ Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # UUV MCP Server
2
+
3
+ This library is an MCP (Model Context Protocol) server for UUV - a solution to facilitate the writing and execution of E2E tests understandable by any human being(English or French) using cucumber(BDD) and cypress or playwright.
4
+
5
+ ## Exposed MCP Tools
6
+
7
+ This MCP server exposes the following tools:
8
+
9
+ ### 1. retrieve_prompt
10
+ - **Description**: Retrieve a uuv prompt template for a coding agent based on a prompt name and arguments.
11
+ - **Input Schema**:
12
+ - `promptName` (enum): Either "generate_table" or "generate_role_and_name"
13
+ - `baseUrl` (string): The base URL of the page
14
+ - For generate_role_and_name:
15
+ - `accessibleName` (string, optional): Accessible name
16
+ - `accessibleRole` (string, optional): Accessible role
17
+
18
+ ### 2. available_sentences
19
+ - **Description**: List all available UUV test sentences/phrases in Gherkin format.
20
+ - **Input Schema**:
21
+ - `category` (enum, optional): Filters sentences by action type (general, keyboard, click, contains, type, checkable)
22
+ - `role` (string, optional): Filters sentences related to an accessible role
23
+
24
+ ### 3. generate_role_and_name
25
+ - **Description**: Generate a complete UUV test scenario (Gherkin format) to verify the presence of an element with specified accessible name and role.
26
+ - **Input Schema**:
27
+ - `baseUrl` (string): The base URL of the page where the element is located
28
+ - `accessibleName` (string): Accessible name of the element
29
+ - `accessibleRole` (string): Accessible role of the element
30
+
31
+ ### 4. generate_table
32
+ - **Description**: Generate a complete UUV test scenario (Gherkin format) to verify the presence and content of html table, grid or treegrid.
33
+ - **Input Schema**:
34
+ - `baseUrl` (string): The base URL of the page where the table/grid/treegrid is located
35
+ - `innerHtmlFilePath` (string): File path containing the raw innerHTML content
36
+
37
+ ## Command
38
+ Add the following command to execute **UUV MCP Server** `npx @uuv/mcp-server`.
39
+
40
+ ### Opencode configuration example (opencode.json)
41
+ ```json
42
+ ...
43
+ "mcp": {
44
+ "playwright": {
45
+ "type": "local",
46
+ "enabled": true,
47
+ "command": [
48
+ "npx",
49
+ "@uuv/mcp-server@latest"
50
+ ]
51
+ }
52
+ }
53
+ ...
54
+ ```
package/dist/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # UUV MCP Server
2
+
3
+ This library is an MCP (Model Context Protocol) server for UUV - a solution to facilitate the writing and execution of E2E tests understandable by any human being(English or French) using cucumber(BDD) and cypress or playwright.
4
+
5
+ ## Exposed MCP Tools
6
+
7
+ This MCP server exposes the following tools:
8
+
9
+ ### 1. retrieve_prompt
10
+ - **Description**: Retrieve a uuv prompt template for a coding agent based on a prompt name and arguments.
11
+ - **Input Schema**:
12
+ - `promptName` (enum): Either "generate_table" or "generate_role_and_name"
13
+ - `baseUrl` (string): The base URL of the page
14
+ - For generate_role_and_name:
15
+ - `accessibleName` (string, optional): Accessible name
16
+ - `accessibleRole` (string, optional): Accessible role
17
+
18
+ ### 2. available_sentences
19
+ - **Description**: List all available UUV test sentences/phrases in Gherkin format.
20
+ - **Input Schema**:
21
+ - `category` (enum, optional): Filters sentences by action type (general, keyboard, click, contains, type, checkable)
22
+ - `role` (string, optional): Filters sentences related to an accessible role
23
+
24
+ ### 3. generate_role_and_name
25
+ - **Description**: Generate a complete UUV test scenario (Gherkin format) to verify the presence of an element with specified accessible name and role.
26
+ - **Input Schema**:
27
+ - `baseUrl` (string): The base URL of the page where the element is located
28
+ - `accessibleName` (string): Accessible name of the element
29
+ - `accessibleRole` (string): Accessible role of the element
30
+
31
+ ### 4. generate_table
32
+ - **Description**: Generate a complete UUV test scenario (Gherkin format) to verify the presence and content of html table, grid or treegrid.
33
+ - **Input Schema**:
34
+ - `baseUrl` (string): The base URL of the page where the table/grid/treegrid is located
35
+ - `innerHtmlFilePath` (string): File path containing the raw innerHTML content
36
+
37
+ ## Command
38
+ Add the following command to execute **UUV MCP Server** `npx @uuv/mcp-server`.
39
+
40
+ ### Opencode configuration example (opencode.json)
41
+ ```json
42
+ ...
43
+ "mcp": {
44
+ "playwright": {
45
+ "type": "local",
46
+ "enabled": true,
47
+ "command": [
48
+ "npx",
49
+ "@uuv/mcp-server@latest"
50
+ ]
51
+ }
52
+ }
53
+ ...
54
+ ```
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export * from "./lib/mcp-server";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const tslib_1 = require("tslib");
5
+ tslib_1.__exportStar(require("./lib/mcp-server"), exports);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
4
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
5
+ const zod_1 = require("zod");
6
+ const sentence_service_1 = require("./services/sentence.service");
7
+ const prompt_retriever_service_1 = require("./services/prompt-retriever.service");
8
+ const expect_service_1 = require("./services/expect.service");
9
+ const dictionary_1 = require("@uuv/dictionary");
10
+ // Create an MCP server
11
+ const server = new mcp_js_1.McpServer({
12
+ name: "uuv-mcp-server",
13
+ version: "0.0.1-beta",
14
+ });
15
+ server.registerTool("retrieve_prompt", {
16
+ title: "Retrieve uuv prompt",
17
+ description: "Retrieve a uuv prompt template for a coding agent based on a prompt name and arguments.",
18
+ inputSchema: {
19
+ promptName: zod_1.z.enum(["generate_table", "generate_role_and_name"]),
20
+ baseUrl: zod_1.z.string().describe("The base URL of the page"),
21
+ // generate_role_and_name Fields
22
+ accessibleName: zod_1.z.string().optional().describe("Accessible name (required for generate_role_and_name)"),
23
+ accessibleRole: zod_1.z.string().optional().describe("Accessible role (required for generate_role_and_name)")
24
+ },
25
+ }, async ({ ...args }) => {
26
+ return {
27
+ content: [
28
+ {
29
+ type: "text",
30
+ text: prompt_retriever_service_1.PromptRetrieverService.retrievePrompt(args),
31
+ },
32
+ ],
33
+ };
34
+ });
35
+ server.registerTool("available_sentences", {
36
+ title: "List Available UUV Sentences",
37
+ description:
38
+ // eslint-disable-next-line max-len
39
+ "List all available UUV test sentences/phrases in Gherkin format. Use this when the user asks about UUV syntax, available commands, what sentences/phrases are available for testing, or needs help with UUV sentence structure. Can be filtered by category (given/when/then) or ARIA role (button, textbox, etc.) to show specific test actions.",
40
+ inputSchema: {
41
+ category: zod_1.z
42
+ .enum(["general", "keyboard", "click", "contains", "type", "checkable"])
43
+ .optional()
44
+ .describe("Filters sentences based on the action type"),
45
+ role: zod_1.z.string().optional().describe("Filters sentences related to an accessible role"),
46
+ },
47
+ }, async ({ category, role }) => {
48
+ const sentenceService = new sentence_service_1.SentenceService((0, dictionary_1.getDefinedDictionary)("en"));
49
+ const allSentences = sentenceService.searchSentences({ category, role });
50
+ return {
51
+ content: [
52
+ {
53
+ type: "text",
54
+ text: JSON.stringify(allSentences, null, 2),
55
+ },
56
+ ],
57
+ };
58
+ });
59
+ server.registerTool("generate_role_and_name", {
60
+ title: "Generate with role and name",
61
+ description:
62
+ // eslint-disable-next-line max-len
63
+ "Generate a complete UUV test scenario (Gherkin format) to verify the presence of an element with specified accessible name and role. Use this when the user asks to create/write/generate a UUV scenario or test for checking element visibility. DON'T USE IF ACCESSIBLE ROLE IS grid, treegrid, table, or form",
64
+ inputSchema: {
65
+ baseUrl: zod_1.z.string().describe("The base URL of the page where the element is located."),
66
+ accessibleName: zod_1.z.string().describe("Accessible name of the element"),
67
+ accessibleRole: zod_1.z.string().describe("Accessible role of the element"),
68
+ },
69
+ }, async ({ baseUrl, accessibleName, accessibleRole }) => {
70
+ if (accessibleRole === "table" || accessibleRole === "grid" || accessibleRole === "treegrid") {
71
+ throw new Error("For role 'table/grid/treegrid', you must use generateExpectForTable.");
72
+ }
73
+ return {
74
+ content: [
75
+ {
76
+ type: "text",
77
+ text: expect_service_1.ExpectService.generateForAccessibleNameAndRole(baseUrl, accessibleName, accessibleRole),
78
+ },
79
+ ],
80
+ };
81
+ });
82
+ server.registerTool("generate_table", {
83
+ title: "Generate test for html table or grid or treeGrid",
84
+ description:
85
+ // eslint-disable-next-line max-len
86
+ "Generate a complete UUV test scenario (Gherkin format) to verify the presence and the content of html table, grid or treegrid given innerHtml. ONLY USE IF ACCESSIBLE ROLE IS grid, treegrid, table, or form",
87
+ inputSchema: {
88
+ baseUrl: zod_1.z.string().describe("The base URL of the page where the table/grid/treegrid is located."),
89
+ innerHtmlFilePath: zod_1.z.string().describe("File path containing the raw innerHTML content of the table, grid, or treegrid element"),
90
+ },
91
+ }, async ({ baseUrl, innerHtmlFilePath }) => {
92
+ return {
93
+ content: [
94
+ {
95
+ type: "text",
96
+ text: await expect_service_1.ExpectService.generateForTable(baseUrl, innerHtmlFilePath),
97
+ },
98
+ ],
99
+ };
100
+ });
101
+ const transport = new stdio_js_1.StdioServerTransport();
102
+ server.connect(transport);
@@ -0,0 +1,4 @@
1
+ export declare class ExpectService {
2
+ static generateForAccessibleNameAndRole(baseUrl: string, accessibleName: string, accessibleRole: string): string;
3
+ static generateForTable(baseUrl: string, innerHtmlFilePath: string): Promise<string>;
4
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExpectService = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const assistant_1 = require("@uuv/assistant");
6
+ const jsdom_1 = require("jsdom");
7
+ const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
8
+ class ExpectService {
9
+ static generateForAccessibleNameAndRole(baseUrl, accessibleName, accessibleRole) {
10
+ const translator = new assistant_1.ExpectTranslator();
11
+ const result = translator.getSentenceFromAccessibleRoleAndName(accessibleRole, accessibleName);
12
+ return (0, assistant_1.buildResultingScript)("Your amazing feature name", "Action - An action", result.sentences, baseUrl);
13
+ }
14
+ static async generateForTable(baseUrl, innerHtmlFilePath) {
15
+ const tableAndGridService = new assistant_1.TableAndGridService();
16
+ const dom = new jsdom_1.JSDOM(node_fs_1.default.readFileSync(innerHtmlFilePath, "utf8"));
17
+ const element = dom.window.document.body.firstElementChild;
18
+ const result = await tableAndGridService.buildResultSentence(element);
19
+ return (0, assistant_1.buildResultingScript)("Your amazing feature name", "Action - Expect Array", result, baseUrl);
20
+ }
21
+ }
22
+ exports.ExpectService = ExpectService;
@@ -0,0 +1,12 @@
1
+ type PromptExtraArgs = Record<string, any>;
2
+ export type PromptArgs = {
3
+ promptName: string;
4
+ } | PromptExtraArgs;
5
+ export declare class PromptRetrieverService {
6
+ private static loadPromptTemplate;
7
+ private static renderPrompt;
8
+ private static generatePrompt;
9
+ private static validatePromptGenerationRequest;
10
+ static retrievePrompt(args: PromptArgs): string;
11
+ }
12
+ export {};
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PromptRetrieverService = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const path = tslib_1.__importStar(require("node:path"));
6
+ const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
7
+ const zod_1 = require("zod");
8
+ class PromptRetrieverService {
9
+ static loadPromptTemplate(promptName) {
10
+ const templatePath = path.join(__dirname, "..", "prompts", `${promptName}.mustache`);
11
+ return node_fs_1.default.readFileSync(templatePath, "utf8");
12
+ }
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ static renderPrompt(template, variables) {
15
+ let result = template;
16
+ for (const [key, value] of Object.entries(variables)) {
17
+ if (Array.isArray(value)) {
18
+ // Handle array values for Mustache-style list rendering
19
+ const listItems = value.map(item => `{{#${key}}}${item}{{/${key}}}`).join("\n");
20
+ result = result.replaceAll(`{{#${key}}}`, listItems);
21
+ }
22
+ else {
23
+ result = result.replaceAll(`{{${key}}}`, value);
24
+ }
25
+ }
26
+ return result;
27
+ }
28
+ static generatePrompt(args) {
29
+ const template = this.loadPromptTemplate(args.promptName);
30
+ return this.renderPrompt(template, args);
31
+ }
32
+ static validatePromptGenerationRequest(args) {
33
+ const promptSchemas = zod_1.z.discriminatedUnion("promptName", [
34
+ zod_1.z.object({
35
+ promptName: zod_1.z.literal("generate_table"),
36
+ baseUrl: zod_1.z.string().describe("The base URL of the page where the table/grid/treegrid is located."),
37
+ }),
38
+ zod_1.z.object({
39
+ promptName: zod_1.z.literal("generate_role_and_name"),
40
+ baseUrl: zod_1.z.string().describe("The base URL of the page where the element is located."),
41
+ accessibleName: zod_1.z.string().describe("Accessible name of the element"),
42
+ accessibleRole: zod_1.z.string().describe("Accessible role of the element"),
43
+ }),
44
+ ]);
45
+ return promptSchemas.parse(args);
46
+ }
47
+ static retrievePrompt(args) {
48
+ const validatedPrompt = PromptRetrieverService.validatePromptGenerationRequest(args);
49
+ let prompt;
50
+ switch (validatedPrompt.promptName) {
51
+ case "generate_table":
52
+ prompt = PromptRetrieverService.generatePrompt(args);
53
+ break;
54
+ case "generate_role_and_name":
55
+ prompt = PromptRetrieverService.generatePrompt(args);
56
+ break;
57
+ default:
58
+ throw new Error(`Bad parameters for request ${args}`);
59
+ }
60
+ return prompt;
61
+ }
62
+ }
63
+ exports.PromptRetrieverService = PromptRetrieverService;
@@ -0,0 +1,12 @@
1
+ import { Dictionary } from "@uuv/dictionary";
2
+ export type SentenceSearchQuery = {
3
+ category?: string;
4
+ role?: string;
5
+ };
6
+ export declare class SentenceService {
7
+ private dictionary;
8
+ constructor(dictionary: Dictionary);
9
+ private getBaseSentences;
10
+ private getSentencesByRole;
11
+ searchSentences(query: SentenceSearchQuery): import("@uuv/dictionary").BaseSentence[];
12
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SentenceService = void 0;
4
+ class SentenceService {
5
+ dictionary;
6
+ constructor(dictionary) {
7
+ this.dictionary = dictionary;
8
+ }
9
+ getBaseSentences() {
10
+ return this.dictionary.getBaseSentences();
11
+ }
12
+ getSentencesByRole(role) {
13
+ return this.dictionary.getRoleBasedSentences().filter(r => !role || r.role === role);
14
+ }
15
+ searchSentences(query) {
16
+ let sentences = [...this.getBaseSentences()];
17
+ sentences.push(...this.getSentencesByRole(query.role));
18
+ if (query.category) {
19
+ sentences = sentences.filter(s => s.section === query.category);
20
+ }
21
+ return sentences;
22
+ }
23
+ }
24
+ exports.SentenceService = SentenceService;
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@uuv/mcp-server",
3
+ "version": "0.0.1",
4
+ "description": "A Model Context Protocol (MCP) server for UUV - a solution to facilitate the writing and execution of E2E tests understandable by any human being(English or French) using cucumber(BDD) and cypress or playwright.",
5
+ "author": "Louis Fredice NJAKO MOLOM (https://github.com/luifr10) & Stanley SERVICAL (https://github.com/stanlee974)",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/e2e-test-quest/uuv.git",
10
+ "directory": "packages/mcp-server"
11
+ },
12
+ "keywords": [
13
+ "uuv",
14
+ "mcp",
15
+ "model-context-protocol",
16
+ "e2e",
17
+ "end2end",
18
+ "end 2 end",
19
+ "test",
20
+ "testing",
21
+ "accessibility",
22
+ "accessibilite",
23
+ "a11y",
24
+ "cypress",
25
+ "playwright",
26
+ "testing-library",
27
+ "cucumber",
28
+ "gherkin",
29
+ "bdd",
30
+ "tdd",
31
+ "acceptance"
32
+ ],
33
+ "type": "commonjs",
34
+ "main": "./dist/index.js",
35
+ "types": "./dist/index.d.ts",
36
+ "files": [
37
+ "dist/**/*",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "scripts": {
42
+ "start": "ts-node src/lib/mcp-server.ts",
43
+ "lint": "npx eslint . --ext .js,.ts,.feature --fix",
44
+ "tests": "jest --coverage --config=./jest.config.ts"
45
+ },
46
+ "bin": {
47
+ "mcp-server": "./dist/index.js"
48
+ },
49
+ "exports": {
50
+ ".": {
51
+ "import": "./dist/index.js",
52
+ "require": "./dist/index.js",
53
+ "types": "./dist/index.d.ts"
54
+ }
55
+ },
56
+ "dependencies": {
57
+ "@modelcontextprotocol/sdk": "1.17.5",
58
+ "jsdom": "26.1.0",
59
+ "tsconfig-paths": "4.2.0",
60
+ "tslib": "2.3.0",
61
+ "@uuv/dictionary": "0.0.1",
62
+ "@uuv/assistant": "2.72.0",
63
+ "zod": "3.25.76"
64
+ },
65
+ "funding": {
66
+ "type": "opencollective",
67
+ "url": "https://opencollective.com/uuv"
68
+ }
69
+ }
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@uuv/mcp-server",
3
+ "version": "0.0.1",
4
+ "description": "A Model Context Protocol (MCP) server for UUV - a solution to facilitate the writing and execution of E2E tests understandable by any human being(English or French) using cucumber(BDD) and cypress or playwright.",
5
+ "author": "Louis Fredice NJAKO MOLOM (https://github.com/luifr10) & Stanley SERVICAL (https://github.com/stanlee974)",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/e2e-test-quest/uuv.git",
10
+ "directory": "packages/mcp-server"
11
+ },
12
+ "keywords": [
13
+ "uuv",
14
+ "mcp",
15
+ "model-context-protocol",
16
+ "e2e",
17
+ "end2end",
18
+ "end 2 end",
19
+ "test",
20
+ "testing",
21
+ "accessibility",
22
+ "accessibilite",
23
+ "a11y",
24
+ "cypress",
25
+ "playwright",
26
+ "testing-library",
27
+ "cucumber",
28
+ "gherkin",
29
+ "bdd",
30
+ "tdd",
31
+ "acceptance"
32
+ ],
33
+ "type": "commonjs",
34
+ "main": "./dist/index.js",
35
+ "types": "./dist/index.d.ts",
36
+ "files": [
37
+ "dist/**/*",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "scripts": {
42
+ "start": "ts-node src/lib/mcp-server.ts",
43
+ "lint": "npx eslint . --ext .js,.ts,.feature --fix",
44
+ "tests": "jest --coverage --config=./jest.config.ts",
45
+ "package": "npm pack --pack-destination=\"../../dist/packages\""
46
+ },
47
+ "bin": {
48
+ "mcp-server": "./dist/index.js"
49
+ },
50
+ "exports": {
51
+ ".": {
52
+ "import": "./dist/index.js",
53
+ "require": "./dist/index.js",
54
+ "types": "./dist/index.d.ts"
55
+ }
56
+ },
57
+ "dependencies": {
58
+ "@modelcontextprotocol/sdk": "1.17.5",
59
+ "jsdom": "26.1.0",
60
+ "tsconfig-paths": "4.2.0",
61
+ "tslib": "2.3.0",
62
+ "@uuv/dictionary": "0.0.1",
63
+ "@uuv/assistant": "2.72.0",
64
+ "zod": "3.25.76"
65
+ },
66
+ "funding": {
67
+ "type": "opencollective",
68
+ "url": "https://opencollective.com/uuv"
69
+ }
70
+ }