genat-mcp 2.2.1 → 2.2.3
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 +33 -2
- package/index.js +16 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,6 +38,7 @@ npm install /path/to/n8n_playwright_tests/mcp-genat
|
|
|
38
38
|
| **N8N_MAX_ASSERTIONS** | No | (none) | Override assertion count for complex pages (e.g. `25`). Used as default when the tool is invoked without `maxAssertions`; also used by run-genat.mjs. |
|
|
39
39
|
| **N8N_SCOPE_TO_REGIONS** | No | (none) | Comma-separated regions to focus tests on (e.g. `header,main,table`). Used as default when the tool is invoked without `scopeToRegions`; also used by run-genat.mjs. |
|
|
40
40
|
| **N8N_ANALYZE_STATES** | No | (off) | Set to `1`, `true`, or `yes` to analyze dropdown/combobox expanded states and include state-specific violations in generated tests. Used as default when the tool is invoked without `analyzeStates`; also used by run-genat.mjs. Increases analysis time. |
|
|
41
|
+
| **GENAT_PROJECT_ROOT** | No | (cwd) | Base path for resolving `parentProjectFolder`. When set, `parentProjectFolder` is resolved relative to this path. Use when your project is outside the MCP's working directory. Example: if your pytest project is at `/Users/me/projects/ill_tests`, set `GENAT_PROJECT_ROOT=/Users/me/projects` and use `parentProjectFolder ill_tests` in the prompt. |
|
|
41
42
|
|
|
42
43
|
## Cursor MCP config
|
|
43
44
|
|
|
@@ -84,6 +85,23 @@ npm install /path/to/n8n_playwright_tests/mcp-genat
|
|
|
84
85
|
}
|
|
85
86
|
```
|
|
86
87
|
|
|
88
|
+
**With GENAT_PROJECT_ROOT** (when project is outside MCP working directory):
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"mcpServers": {
|
|
93
|
+
"GenAT": {
|
|
94
|
+
"command": "npx",
|
|
95
|
+
"args": ["genat-mcp"],
|
|
96
|
+
"env": {
|
|
97
|
+
"GENAT_PROJECT_ROOT": "/Users/me/projects"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
Then use `parentProjectFolder ill_tests` in the prompt to target `/Users/me/projects/ill_tests`.
|
|
104
|
+
|
|
87
105
|
**With optional params for complex pages** (`N8N_MAX_ASSERTIONS`, `N8N_SCOPE_TO_REGIONS`, `N8N_ANALYZE_STATES`):
|
|
88
106
|
|
|
89
107
|
```json
|
|
@@ -110,7 +128,7 @@ If the global binary is not on PATH, use the full path, e.g. `node $(npm root -g
|
|
|
110
128
|
## Requirements
|
|
111
129
|
|
|
112
130
|
- **Node.js** 20+
|
|
113
|
-
- **n8n** with
|
|
131
|
+
- **n8n** with a GenAT workflow imported and activated. Use [genat-accessibility-tests-with-login-jira.json](../workflows/genat-accessibility-tests-with-login-jira.json) (path `webhook-test/webhook-genat-login-jira`) for JIRA support, or [genat-accessibility-tests-with-login.json](../workflows/genat-accessibility-tests-with-login.json) (path `webhook-test/webhook-genat-login`). Set **N8N_WEBHOOK_URL** to the workflow's webhook URL.
|
|
114
132
|
- **DOM Analyzer** and **Accessibility Analyzer** services running (see main README: `npm run services` from repo root)
|
|
115
133
|
|
|
116
134
|
## Standalone script: run-genat.mjs
|
|
@@ -134,7 +152,7 @@ N8N_WEBHOOK_URL='https://your-n8n/webhook-test/webhook-genat-login' N8N_INSECURE
|
|
|
134
152
|
N8N_MAX_ASSERTIONS=30 N8N_SCOPE_TO_REGIONS=header,main N8N_ANALYZE_STATES=1 node node_modules/genat-mcp/run-genat.mjs https://example.com .
|
|
135
153
|
```
|
|
136
154
|
|
|
137
|
-
**Important:** Use `webhook-genat-login` (not `webhook-genat`).
|
|
155
|
+
**Important:** Use `webhook-genat-login` or `webhook-genat-login-jira` (not `webhook-genat`). For JIRA support, import and activate [genat-accessibility-tests-with-login-jira.json](../workflows/genat-accessibility-tests-with-login-jira.json) and set N8N_WEBHOOK_URL to its webhook URL.
|
|
138
156
|
|
|
139
157
|
**Optional – Cursor rule:** Copy the rule so the AI uses the correct webhook when creating workarounds (the MCP error responses also include this hint):
|
|
140
158
|
```bash
|
|
@@ -168,6 +186,7 @@ When creating run-genat.mjs: Use webhook-genat-login, NOT webhook-genat. Prefer
|
|
|
168
186
|
- **loginUsername** (string, optional): Login username. Overrides .env when provided. Requires loginPassword.
|
|
169
187
|
- **loginPassword** (string, optional): Login password. Overrides .env when provided. Requires loginUsername.
|
|
170
188
|
- **loginUrl** (string, optional): Login page URL if different from target URL.
|
|
189
|
+
- **jiraNumber** (string, optional): JIRA issue key (e.g. PROJ-123). When provided, the workflow fetches the issue and injects acceptance criteria into the AI prompt.
|
|
171
190
|
|
|
172
191
|
Login credentials: provide in the prompt (loginUsername, loginPassword) or in project `.env` (TEST_USER, TEST_PASSWORD, LOGIN_USER, LOGIN_PASSWORD). Tool params override .env. For sensitive environments, prefer .env (gitignored) since credentials in the prompt are visible in chat history.
|
|
173
192
|
|
|
@@ -177,6 +196,8 @@ Generated tests include keyboard accessibility checks (Tab order, focus) by defa
|
|
|
177
196
|
|
|
178
197
|
## Sample prompts
|
|
179
198
|
|
|
199
|
+
See [prompts.md](prompts.md) for a full list of prompts including specific parent folders, login, JIRA, and combined options.
|
|
200
|
+
|
|
180
201
|
**With login credentials in the prompt:**
|
|
181
202
|
|
|
182
203
|
```
|
|
@@ -197,6 +218,16 @@ Use GenAT for https://myapp.example.com/dashboard. Credentials are in .env.
|
|
|
197
218
|
Use GenAT to generate accessibility tests for https://myapp.example.com/dashboard using this project folder: . Write the files to the project.
|
|
198
219
|
```
|
|
199
220
|
|
|
221
|
+
**With JIRA acceptance criteria:**
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
Use GenAT for https://myapp.example.com/dashboard with jiraNumber PROJ-123. Write the files to the project.
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
Generate accessibility tests for https://example.com using JIRA ticket A11Y-456. Use parentProjectFolder . and writeToProject true.
|
|
229
|
+
```
|
|
230
|
+
|
|
200
231
|
## Publishing to npm
|
|
201
232
|
|
|
202
233
|
Until the package is published, `npm install genat-mcp` returns 404. To publish:
|
package/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Detects framework (language, BDD, Page Object), POSTs to n8n webhook, returns generated files.
|
|
6
6
|
*/
|
|
7
7
|
import https from 'node:https';
|
|
8
|
+
import path from 'node:path';
|
|
8
9
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
10
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
11
|
import { z } from 'zod';
|
|
@@ -51,7 +52,7 @@ function insecureHttpsFetch(url, { method = 'GET', headers = {}, body }) {
|
|
|
51
52
|
const server = new McpServer(
|
|
52
53
|
{
|
|
53
54
|
name: 'GenAT',
|
|
54
|
-
version: '2.2.
|
|
55
|
+
version: '2.2.3',
|
|
55
56
|
},
|
|
56
57
|
{
|
|
57
58
|
capabilities: {
|
|
@@ -69,7 +70,7 @@ server.registerTool(
|
|
|
69
70
|
url: z.string().describe('Page URL to analyze for accessibility (e.g. https://example.com)'),
|
|
70
71
|
parentProjectFolder: z
|
|
71
72
|
.string()
|
|
72
|
-
.describe('Absolute or relative path to the project root
|
|
73
|
+
.describe('Absolute or relative path to the project root. When GENAT_PROJECT_ROOT is set, resolved relative to it; otherwise relative to process.cwd().'),
|
|
73
74
|
writeToProject: z
|
|
74
75
|
.boolean()
|
|
75
76
|
.optional()
|
|
@@ -98,9 +99,13 @@ server.registerTool(
|
|
|
98
99
|
.string()
|
|
99
100
|
.optional()
|
|
100
101
|
.describe('Login page URL if different from target URL'),
|
|
102
|
+
jiraNumber: z
|
|
103
|
+
.string()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe('JIRA issue key (e.g. PROJ-123, RB-40039). Extract from prompts like "JIRA RB-40039" or "JIRA ticket PROJ-123". Pass only the key (e.g. RB-40039), not "JIRA RB-40039".'),
|
|
101
106
|
},
|
|
102
107
|
},
|
|
103
|
-
async ({ url, parentProjectFolder, writeToProject, maxAssertions, scopeToRegions, analyzeStates, loginUsername, loginPassword, loginUrl }) => {
|
|
108
|
+
async ({ url, parentProjectFolder, writeToProject, maxAssertions, scopeToRegions, analyzeStates, loginUsername, loginPassword, loginUrl, jiraNumber }) => {
|
|
104
109
|
if (!url || typeof url !== 'string') {
|
|
105
110
|
return {
|
|
106
111
|
content: [{ type: 'text', text: JSON.stringify({ error: 'Missing or invalid "url"' }) }],
|
|
@@ -108,9 +113,12 @@ server.registerTool(
|
|
|
108
113
|
};
|
|
109
114
|
}
|
|
110
115
|
|
|
116
|
+
const base = process.env.GENAT_PROJECT_ROOT || process.cwd();
|
|
117
|
+
const resolvedPath = path.resolve(base, parentProjectFolder || '.');
|
|
118
|
+
|
|
111
119
|
let framework;
|
|
112
120
|
try {
|
|
113
|
-
framework = detectFramework(
|
|
121
|
+
framework = detectFramework(resolvedPath);
|
|
114
122
|
} catch (err) {
|
|
115
123
|
return {
|
|
116
124
|
content: [
|
|
@@ -129,7 +137,7 @@ server.registerTool(
|
|
|
129
137
|
|
|
130
138
|
let login = {};
|
|
131
139
|
try {
|
|
132
|
-
login = detectLogin(
|
|
140
|
+
login = detectLogin(resolvedPath) || {};
|
|
133
141
|
} catch (_) {}
|
|
134
142
|
|
|
135
143
|
// Tool params override .env
|
|
@@ -159,6 +167,7 @@ server.registerTool(
|
|
|
159
167
|
...(login.passwordSelector && { loginPasswordSelector: login.passwordSelector }),
|
|
160
168
|
...(login.submitSelector && { loginSubmitSelector: login.submitSelector }),
|
|
161
169
|
}),
|
|
170
|
+
...(jiraNumber && jiraNumber.trim() && { jiraNumber: jiraNumber.trim() }),
|
|
162
171
|
};
|
|
163
172
|
|
|
164
173
|
const useInsecureTls = N8N_INSECURE_TLS && N8N_WEBHOOK_URL.startsWith('https://');
|
|
@@ -221,9 +230,9 @@ server.registerTool(
|
|
|
221
230
|
};
|
|
222
231
|
}
|
|
223
232
|
|
|
224
|
-
if (writeToProject &&
|
|
233
|
+
if (writeToProject && resolvedPath && data) {
|
|
225
234
|
try {
|
|
226
|
-
const written = writeGeneratedFiles(
|
|
235
|
+
const written = writeGeneratedFiles(resolvedPath, data);
|
|
227
236
|
data._written = written;
|
|
228
237
|
} catch (err) {
|
|
229
238
|
data._writeError = err instanceof Error ? err.message : String(err);
|
package/package.json
CHANGED