@debugg-ai/debugg-ai-mcp 2.9.7 → 3.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/CHANGELOG.md +42 -0
- package/README.md +61 -22
- package/dist/handlers/environmentHandler.js +27 -0
- package/dist/handlers/executionsHandler.js +9 -0
- package/dist/handlers/index.js +7 -2
- package/dist/handlers/projectHandler.js +14 -0
- package/dist/handlers/testCaseHandler.js +22 -0
- package/dist/handlers/testSuiteHandler.js +34 -0
- package/dist/handlers/triggerCrawlHandler.js +1 -2
- package/dist/tools/environment.js +51 -0
- package/dist/tools/executions.js +34 -0
- package/dist/tools/index.js +21 -46
- package/dist/tools/project.js +40 -0
- package/dist/tools/testCase.js +39 -0
- package/dist/tools/testSuite.js +47 -0
- package/dist/tools/triggerCrawl.js +0 -4
- package/dist/types/index.js +55 -1
- package/dist/utils/confirmDestructive.js +48 -0
- package/package.json +1 -1
- package/dist/handlers/deleteProjectHandler.js +0 -39
- package/dist/handlers/updateProjectHandler.js +0 -45
- package/dist/tools/createEnvironment.js +0 -46
- package/dist/tools/createProject.js +0 -27
- package/dist/tools/deleteEnvironment.js +0 -23
- package/dist/tools/deleteProject.js +0 -22
- package/dist/tools/searchEnvironments.js +0 -35
- package/dist/tools/searchExecutions.js +0 -31
- package/dist/tools/searchProjects.js +0 -30
- package/dist/tools/testSuiteTools.js +0 -183
- package/dist/tools/updateEnvironment.js +0 -74
- package/dist/tools/updateProject.js +0 -24
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,48 @@ All notable changes to the DebuggAI MCP project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.0.1]
|
|
9
|
+
|
|
10
|
+
### Fixed — 5 action tools were invisible in Claude Code (and any Anthropic-API client)
|
|
11
|
+
|
|
12
|
+
3.0.0's action tools (`project`, `environment`, `test_suite`, `test_case`,
|
|
13
|
+
`executions`) declared a top-level `oneOf` in their JSON Schema to express
|
|
14
|
+
per-action required fields. The Anthropic tool `input_schema` does not accept
|
|
15
|
+
top-level `oneOf`/`anyOf`/`allOf`, so clients **silently dropped all 5 tools** —
|
|
16
|
+
only the 3 browser tools showed up (the server still advertised all 8). Removed
|
|
17
|
+
the `oneOf`; per-action required fields remain enforced by the Zod discriminated
|
|
18
|
+
unions at call time and documented in each tool's description. Added a registry
|
|
19
|
+
regression test asserting no tool schema uses top-level `oneOf`/`anyOf`/`allOf`.
|
|
20
|
+
|
|
21
|
+
## [3.0.0]
|
|
22
|
+
|
|
23
|
+
### Changed — Tool surface consolidated to 8 action-based tools (BREAKING)
|
|
24
|
+
|
|
25
|
+
The 20 per-verb tools were consolidated into **8** tools: three browser tools
|
|
26
|
+
(`check_app_in_browser`, `probe_page`, `trigger_crawl`) plus one action-based
|
|
27
|
+
tool per entity — `project`, `environment`, `test_suite`, `test_case`,
|
|
28
|
+
`executions` — each taking an `action` discriminator. Clients pick up the new
|
|
29
|
+
surface on MCP restart.
|
|
30
|
+
|
|
31
|
+
Migration (old tool → new tool + action):
|
|
32
|
+
|
|
33
|
+
- `search_projects` → `project {action:"get"|"list"}`
|
|
34
|
+
- `create_project` → `project {action:"create"}`
|
|
35
|
+
- `search_environments` → `environment {action:"get"|"list"}`
|
|
36
|
+
- `create_environment` / `update_environment` / `delete_environment` → `environment {action:"create"|"update"|"delete"}`
|
|
37
|
+
- `create_test_suite` / `search_test_suites` / `run_test_suite` / `get_test_suite_results` / `delete_test_suite` → `test_suite {action:"create"|"list"|"run"|"results"|"delete"}`
|
|
38
|
+
- `create_test_case` / `update_test_case` / `delete_test_case` → `test_case {action:"create"|"update"|"delete"}`
|
|
39
|
+
- `search_executions` → `executions {action:"get"|"list"}`
|
|
40
|
+
|
|
41
|
+
### Removed
|
|
42
|
+
|
|
43
|
+
- `update_project` and `delete_project` — rename/delete a project from the DebuggAI web app (both were effectively unused).
|
|
44
|
+
- `trigger_crawl`'s `headless` parameter — the MCP now always runs headless (no opt-out).
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- Destructive `delete` actions require confirmation: an elicitation prompt when the client supports it, otherwise a required `confirm: true` argument.
|
|
49
|
+
|
|
8
50
|
## [Unreleased]
|
|
9
51
|
|
|
10
52
|
### Added — E2E test suite management (8 new MCP tools)
|
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ docker run -i --rm --init -e DEBUGGAI_API_KEY=your_api_key quinnosha/debugg-ai-m
|
|
|
34
34
|
|
|
35
35
|
## Tools
|
|
36
36
|
|
|
37
|
-
The server exposes **
|
|
37
|
+
The server exposes **8** tools: three **Browser** tools plus one **action-based** tool per managed entity. The headline tools are `check_app_in_browser` (full AI agent) and `probe_page` (lightweight no-LLM page probe). The rest — `project`, `environment`, `test_suite`, `test_case`, `executions` — each take an `action` discriminator (e.g. `{"action":"list"}`) that selects the operation. Destructive `delete` actions require confirmation (an elicitation prompt where supported, otherwise `confirm: true`).
|
|
38
38
|
|
|
39
39
|
### Browser
|
|
40
40
|
|
|
@@ -69,7 +69,7 @@ Every successful run returns a `browserSession` block alongside the screenshot
|
|
|
69
69
|
}
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
URLs are short-lived presigned S3 — refetch the parent execution via `
|
|
72
|
+
URLs are short-lived presigned S3 — refetch the parent execution via `executions {action:"get", uuid}` to renew. `harStatus` / `consoleLogStatus` disambiguate `'downloaded'` (URL fetchable), `'not_available'` (page emitted nothing), `'failed'` (capture broke). On a fresh run the URLs are commonly `null` because capture uploads async after the agent finishes — poll `executions {action:"get", uuid: executionId}` until status reaches `'downloaded'`. Authorization / Cookie / `token`/`secret`/`api_key` headers are scrubbed server-side before the artifacts are persisted.
|
|
73
73
|
|
|
74
74
|
#### `trigger_crawl`
|
|
75
75
|
|
|
@@ -95,33 +95,54 @@ The whole batch shares a single backend execution + browser session + tunnel —
|
|
|
95
95
|
|
|
96
96
|
Performance budget: <10s for 1 URL, <25s for 20. Localhost dead-port returns `LocalServerUnreachable` in <2s without burning a workflow execution.
|
|
97
97
|
|
|
98
|
-
###
|
|
98
|
+
### `project`
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
| Action | Params | Result |
|
|
101
|
+
|--------|--------|--------|
|
|
102
|
+
| `get` | `{uuid}` | Curated project detail |
|
|
103
|
+
| `list` | `{q?, page?, pageSize?}` | Paginated summaries |
|
|
104
|
+
| `create` | `{name, platform, (teamUuid\|teamName), (repoUuid\|repoName)}` | Created project |
|
|
101
105
|
|
|
102
|
-
|
|
103
|
-
|------|-----------|-------------|
|
|
104
|
-
| `search_projects` | `{uuid}` → curated project detail | `{q?, page?, pageSize?}` → paginated summaries |
|
|
105
|
-
| `search_environments` | `{uuid, projectUuid}` → env with credentials inlined | `{projectUuid?, q?, page?, pageSize?}` → paginated envs, each with credentials array |
|
|
106
|
-
| `search_executions` | `{uuid}` → full detail with `nodeExecutions` + state | `{status?, projectUuid?, page?, pageSize?}` → paginated summaries |
|
|
106
|
+
Team and repo resolve by **either** uuid **or** name (case-insensitive exact match; `NotFound` if none, `AmbiguousMatch` if multiple). There is **no** `update`/`delete` — rename or delete a project from the DebuggAI web app.
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
### `environment`
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
| Action | Params | Result |
|
|
111
|
+
|--------|--------|--------|
|
|
112
|
+
| `get` | `{uuid, projectUuid?}` | Env with credentials inlined (passwords never returned) |
|
|
113
|
+
| `list` | `{projectUuid?, q?, page?, pageSize?}` | Paginated envs, each with a credentials array |
|
|
114
|
+
| `create` | `{name, url, description?, projectUuid?, credentials?}` | Created env (optionally seeds credentials) |
|
|
115
|
+
| `update` | `{uuid, name?, url?, description?, addCredentials?, updateCredentials?, removeCredentialIds?}` | Patched env; credential ops run **remove → update → add** |
|
|
116
|
+
| `delete` | `{uuid, projectUuid?, confirm?}` | Deletes env (cascades credentials) — **requires confirmation** |
|
|
111
117
|
|
|
112
|
-
|
|
113
|
-
|------|---------|
|
|
114
|
-
| `create_project` | Requires `name` + `platform`. Team and repo resolve by **either** uuid **or** name: pass `teamUuid` OR `teamName`, and `repoUuid` OR `repoName`. Name resolution is case-insensitive exact match; `NotFound` if none, `AmbiguousMatch` with candidates if multiple. |
|
|
115
|
-
| `update_project` | PATCH `name`, `description`. |
|
|
116
|
-
| `delete_project` | Destructive — cascades environments, credentials, and execution history. |
|
|
118
|
+
`projectUuid` auto-resolves from the git repo when omitted. Per-cred failures surface in `credentialWarnings[]` without blocking the env op.
|
|
117
119
|
|
|
118
|
-
###
|
|
120
|
+
### `test_suite`
|
|
119
121
|
|
|
120
|
-
|
|
|
121
|
-
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
122
|
+
| Action | Params | Result |
|
|
123
|
+
|--------|--------|--------|
|
|
124
|
+
| `list` | `{projectUuid\|projectName, search?, page?, pageSize?}` | Paginated suites with status + pass rate |
|
|
125
|
+
| `create` | `{name, description, projectUuid\|projectName}` | Created suite |
|
|
126
|
+
| `run` | `{suiteUuid\|(suiteName+project), targetUrl?}` | Triggers all tests async |
|
|
127
|
+
| `results` | `{suiteUuid\|(suiteName+project)}` | Suite + per-test outcomes |
|
|
128
|
+
| `delete` | `{suiteUuid\|(suiteName+project), confirm?}` | Soft-delete — **requires confirmation** |
|
|
129
|
+
|
|
130
|
+
### `test_case`
|
|
131
|
+
|
|
132
|
+
| Action | Params | Result |
|
|
133
|
+
|--------|--------|--------|
|
|
134
|
+
| `create` | `{name, description, agentTaskDescription, suiteUuid\|(suiteName+project), relativeUrl?, maxSteps?}` | Created test case (not auto-run) |
|
|
135
|
+
| `update` | `{testUuid, name?, description?, agentTaskDescription?}` | Patched test case |
|
|
136
|
+
| `delete` | `{testUuid, confirm?}` | Soft-delete — **requires confirmation** |
|
|
137
|
+
|
|
138
|
+
### `executions`
|
|
139
|
+
|
|
140
|
+
| Action | Params | Result |
|
|
141
|
+
|--------|--------|--------|
|
|
142
|
+
| `get` | `{uuid}` | Full detail (`nodeExecutions` + state + errorInfo) + screenshot/gif artifacts |
|
|
143
|
+
| `list` | `{status?, projectUuid?, page?, pageSize?}` | Paginated summaries |
|
|
144
|
+
|
|
145
|
+
404 from the backend surfaces as `isError: true` with `{error: 'NotFound', message, uuid}`. Credentials are **always** returned without passwords.
|
|
125
146
|
|
|
126
147
|
### Pagination
|
|
127
148
|
|
|
@@ -144,6 +165,24 @@ Pass optional `page` (1-indexed, default 1) and `pageSize` (default 20, max 200;
|
|
|
144
165
|
- 404s from the backend surface as `isError: true` with `{error: 'NotFound', ...}`, never as thrown exceptions.
|
|
145
166
|
- Missing `DEBUGGAI_API_KEY` surfaces as a structured tool error on first invocation — the server still registers and lists tools normally.
|
|
146
167
|
|
|
168
|
+
## Migration to v3.0.0 (action-based tools)
|
|
169
|
+
|
|
170
|
+
v3 consolidated the 20 per-verb tools into 8 action-based tools. Old tool → new `tool {action}`:
|
|
171
|
+
|
|
172
|
+
| Removed | Replacement |
|
|
173
|
+
|---------|-------------|
|
|
174
|
+
| `search_projects` | `project {action:"get"}` / `project {action:"list"}` |
|
|
175
|
+
| `create_project` | `project {action:"create"}` |
|
|
176
|
+
| `update_project`, `delete_project` | **Dropped** — use the DebuggAI web app |
|
|
177
|
+
| `search_environments` | `environment {action:"get"}` / `{action:"list"}` |
|
|
178
|
+
| `create_environment` / `update_environment` / `delete_environment` | `environment {action:"create"\|"update"\|"delete"}` |
|
|
179
|
+
| `create_test_suite` / `search_test_suites` / `run_test_suite` / `get_test_suite_results` / `delete_test_suite` | `test_suite {action:"create"\|"list"\|"run"\|"results"\|"delete"}` |
|
|
180
|
+
| `create_test_case` / `update_test_case` / `delete_test_case` | `test_case {action:"create"\|"update"\|"delete"}` |
|
|
181
|
+
| `search_executions` | `executions {action:"get"\|"list"}` |
|
|
182
|
+
| `trigger_crawl` `headless` param | **Dropped** — always headless |
|
|
183
|
+
|
|
184
|
+
`delete` actions now require confirmation (elicitation prompt, or `confirm: true`). Clients pick up the new surface on MCP restart.
|
|
185
|
+
|
|
147
186
|
## Migration from v1.x (breaking change in v2.0.0)
|
|
148
187
|
|
|
149
188
|
v2 collapsed a 22-tool surface to 11. Old-tool → new-tool mapping:
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ensureConfirmed } from '../utils/confirmDestructive.js';
|
|
2
|
+
import { searchEnvironmentsHandler } from './searchEnvironmentsHandler.js';
|
|
3
|
+
import { createEnvironmentHandler } from './createEnvironmentHandler.js';
|
|
4
|
+
import { updateEnvironmentHandler } from './updateEnvironmentHandler.js';
|
|
5
|
+
import { deleteEnvironmentHandler } from './deleteEnvironmentHandler.js';
|
|
6
|
+
export async function environmentHandler(input, ctx) {
|
|
7
|
+
switch (input.action) {
|
|
8
|
+
case 'get':
|
|
9
|
+
return searchEnvironmentsHandler({ uuid: input.uuid, projectUuid: input.projectUuid }, ctx);
|
|
10
|
+
case 'list':
|
|
11
|
+
return searchEnvironmentsHandler({ projectUuid: input.projectUuid, q: input.q, page: input.page, pageSize: input.pageSize }, ctx);
|
|
12
|
+
case 'create': {
|
|
13
|
+
const { action, ...rest } = input;
|
|
14
|
+
return createEnvironmentHandler(rest, ctx);
|
|
15
|
+
}
|
|
16
|
+
case 'update': {
|
|
17
|
+
const { action, ...rest } = input;
|
|
18
|
+
return updateEnvironmentHandler(rest, ctx);
|
|
19
|
+
}
|
|
20
|
+
case 'delete': {
|
|
21
|
+
const refusal = await ensureConfirmed('delete', `environment ${input.uuid}`, input, ctx);
|
|
22
|
+
if (refusal)
|
|
23
|
+
return refusal;
|
|
24
|
+
return deleteEnvironmentHandler({ uuid: input.uuid, projectUuid: input.projectUuid }, ctx);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { searchExecutionsHandler } from './searchExecutionsHandler.js';
|
|
2
|
+
export async function executionsHandler(input, ctx) {
|
|
3
|
+
switch (input.action) {
|
|
4
|
+
case 'get':
|
|
5
|
+
return searchExecutionsHandler({ uuid: input.uuid }, ctx);
|
|
6
|
+
case 'list':
|
|
7
|
+
return searchExecutionsHandler({ projectUuid: input.projectUuid, status: input.status, page: input.page, pageSize: input.pageSize }, ctx);
|
|
8
|
+
}
|
|
9
|
+
}
|
package/dist/handlers/index.js
CHANGED
|
@@ -8,9 +8,14 @@ export * from './createEnvironmentHandler.js';
|
|
|
8
8
|
export * from './updateEnvironmentHandler.js';
|
|
9
9
|
export * from './deleteEnvironmentHandler.js';
|
|
10
10
|
// Credential mutations are folded into create_environment + update_environment.
|
|
11
|
-
|
|
12
|
-
export * from './deleteProjectHandler.js';
|
|
11
|
+
// update_project + delete_project were cut (epic yg7o6, D8).
|
|
13
12
|
export * from './createProjectHandler.js';
|
|
13
|
+
// Action-tool dispatchers (the registered surface).
|
|
14
|
+
export * from './projectHandler.js';
|
|
15
|
+
export * from './environmentHandler.js';
|
|
16
|
+
export * from './testSuiteHandler.js';
|
|
17
|
+
export * from './testCaseHandler.js';
|
|
18
|
+
export * from './executionsHandler.js';
|
|
14
19
|
export * from './createTestSuiteHandler.js';
|
|
15
20
|
export * from './searchTestSuitesHandler.js';
|
|
16
21
|
export * from './deleteTestSuiteHandler.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { searchProjectsHandler } from './searchProjectsHandler.js';
|
|
2
|
+
import { createProjectHandler } from './createProjectHandler.js';
|
|
3
|
+
export async function projectHandler(input, ctx) {
|
|
4
|
+
switch (input.action) {
|
|
5
|
+
case 'get':
|
|
6
|
+
return searchProjectsHandler({ uuid: input.uuid }, ctx);
|
|
7
|
+
case 'list':
|
|
8
|
+
return searchProjectsHandler({ q: input.q, page: input.page, pageSize: input.pageSize }, ctx);
|
|
9
|
+
case 'create': {
|
|
10
|
+
const { action, ...rest } = input;
|
|
11
|
+
return createProjectHandler(rest, ctx);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ensureConfirmed } from '../utils/confirmDestructive.js';
|
|
2
|
+
import { createTestCaseHandler } from './createTestCaseHandler.js';
|
|
3
|
+
import { updateTestCaseHandler } from './updateTestCaseHandler.js';
|
|
4
|
+
import { deleteTestCaseHandler } from './deleteTestCaseHandler.js';
|
|
5
|
+
export async function testCaseHandler(input, ctx) {
|
|
6
|
+
switch (input.action) {
|
|
7
|
+
case 'create': {
|
|
8
|
+
const { action, ...rest } = input;
|
|
9
|
+
return createTestCaseHandler(rest, ctx);
|
|
10
|
+
}
|
|
11
|
+
case 'update': {
|
|
12
|
+
const { action, ...rest } = input;
|
|
13
|
+
return updateTestCaseHandler(rest, ctx);
|
|
14
|
+
}
|
|
15
|
+
case 'delete': {
|
|
16
|
+
const refusal = await ensureConfirmed('delete', `test case ${input.testUuid}`, input, ctx);
|
|
17
|
+
if (refusal)
|
|
18
|
+
return refusal;
|
|
19
|
+
return deleteTestCaseHandler({ testUuid: input.testUuid }, ctx);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ensureConfirmed } from '../utils/confirmDestructive.js';
|
|
2
|
+
import { searchTestSuitesHandler } from './searchTestSuitesHandler.js';
|
|
3
|
+
import { createTestSuiteHandler } from './createTestSuiteHandler.js';
|
|
4
|
+
import { runTestSuiteHandler } from './runTestSuiteHandler.js';
|
|
5
|
+
import { getTestSuiteResultsHandler } from './getTestSuiteResultsHandler.js';
|
|
6
|
+
import { deleteTestSuiteHandler } from './deleteTestSuiteHandler.js';
|
|
7
|
+
export async function testSuiteHandler(input, ctx) {
|
|
8
|
+
switch (input.action) {
|
|
9
|
+
case 'list': {
|
|
10
|
+
const { action, ...rest } = input;
|
|
11
|
+
return searchTestSuitesHandler(rest, ctx);
|
|
12
|
+
}
|
|
13
|
+
case 'create': {
|
|
14
|
+
const { action, ...rest } = input;
|
|
15
|
+
return createTestSuiteHandler(rest, ctx);
|
|
16
|
+
}
|
|
17
|
+
case 'run': {
|
|
18
|
+
const { action, ...rest } = input;
|
|
19
|
+
return runTestSuiteHandler(rest, ctx);
|
|
20
|
+
}
|
|
21
|
+
case 'results': {
|
|
22
|
+
const { action, ...rest } = input;
|
|
23
|
+
return getTestSuiteResultsHandler(rest, ctx);
|
|
24
|
+
}
|
|
25
|
+
case 'delete': {
|
|
26
|
+
const label = `test suite ${input.suiteUuid ?? input.suiteName ?? ''}`.trim();
|
|
27
|
+
const refusal = await ensureConfirmed('delete', label, input, ctx);
|
|
28
|
+
if (refusal)
|
|
29
|
+
return refusal;
|
|
30
|
+
const { action, confirm, ...rest } = input;
|
|
31
|
+
return deleteTestSuiteHandler(rest, ctx);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -150,8 +150,7 @@ export async function triggerCrawlHandler(input, context, rawProgressCallback) {
|
|
|
150
150
|
};
|
|
151
151
|
if (input.projectUuid)
|
|
152
152
|
contextData.projectId = input.projectUuid;
|
|
153
|
-
|
|
154
|
-
contextData.headless = input.headless;
|
|
153
|
+
contextData.headless = true; // D7: the MCP always runs headless — no opt-out.
|
|
155
154
|
if (typeof input.timeoutSeconds === 'number')
|
|
156
155
|
contextData.timeoutSeconds = input.timeoutSeconds;
|
|
157
156
|
const env = {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { EnvironmentInputSchema } from '../types/index.js';
|
|
2
|
+
import { environmentHandler } from '../handlers/environmentHandler.js';
|
|
3
|
+
const CRED_ITEM = {
|
|
4
|
+
type: 'object',
|
|
5
|
+
properties: {
|
|
6
|
+
label: { type: 'string' }, username: { type: 'string' }, password: { type: 'string', description: 'Write-only — never returned.' }, role: { type: 'string' },
|
|
7
|
+
},
|
|
8
|
+
required: ['label', 'username', 'password'],
|
|
9
|
+
additionalProperties: false,
|
|
10
|
+
};
|
|
11
|
+
const DESCRIPTION = `Manage environments (and their login credentials) under a project. Pass an "action":
|
|
12
|
+
- "get" {uuid, projectUuid?} → one environment with credentials inline (passwords never returned).
|
|
13
|
+
- "list" {projectUuid?, q?, page?, pageSize?} → paginated environments. projectUuid auto-resolves from the git repo if omitted.
|
|
14
|
+
- "create" {name, url, description?, projectUuid?, credentials?} → create an env, optionally seeding credentials.
|
|
15
|
+
- "update" {uuid, name?, url?, description?, addCredentials?, updateCredentials?, removeCredentialIds?} → patch env + manage credentials.
|
|
16
|
+
- "delete" {uuid, projectUuid?, confirm?} → delete env (DESTRUCTIVE; requires confirmation).`;
|
|
17
|
+
export function buildEnvironmentTool() {
|
|
18
|
+
return {
|
|
19
|
+
name: 'environment',
|
|
20
|
+
title: 'Environment',
|
|
21
|
+
description: DESCRIPTION,
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
action: { type: 'string', enum: ['get', 'list', 'create', 'update', 'delete'], description: 'Operation to perform.' },
|
|
26
|
+
uuid: { type: 'string', description: '[get/update/delete] Environment UUID.' },
|
|
27
|
+
projectUuid: { type: 'string', description: 'Target project (defaults to git auto-detect).' },
|
|
28
|
+
q: { type: 'string', description: '[list] Free-text search over env name.' },
|
|
29
|
+
page: { type: 'number', description: '[list] Page (1-indexed).' },
|
|
30
|
+
pageSize: { type: 'number', description: '[list] Page size (1..200).' },
|
|
31
|
+
name: { type: 'string', description: '[create/update] Environment name.' },
|
|
32
|
+
url: { type: 'string', description: '[create/update] Base URL.' },
|
|
33
|
+
description: { type: 'string', description: '[create/update] Free-text description.' },
|
|
34
|
+
credentials: { type: 'array', items: CRED_ITEM, description: '[create] Seed login credentials.' },
|
|
35
|
+
addCredentials: { type: 'array', items: CRED_ITEM, description: '[update] Add credentials.' },
|
|
36
|
+
updateCredentials: { type: 'array', items: { type: 'object', properties: { uuid: { type: 'string' }, label: { type: 'string' }, username: { type: 'string' }, password: { type: 'string' }, role: { type: 'string' } }, required: ['uuid'], additionalProperties: false }, description: '[update] Patch credentials by UUID.' },
|
|
37
|
+
removeCredentialIds: { type: 'array', items: { type: 'string' }, description: '[update] Delete credentials by UUID.' },
|
|
38
|
+
confirm: { type: 'boolean', description: '[delete] Set true to confirm deletion (when the client cannot prompt).' },
|
|
39
|
+
},
|
|
40
|
+
required: ['action'],
|
|
41
|
+
// No top-level oneOf/anyOf/allOf: the Anthropic tool input_schema rejects
|
|
42
|
+
// them and clients (Claude Code) silently drop the tool. Per-action required
|
|
43
|
+
// fields are enforced by the Zod discriminated union in types/index.ts and
|
|
44
|
+
// documented in DESCRIPTION above.
|
|
45
|
+
additionalProperties: false,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function buildValidatedEnvironmentTool() {
|
|
50
|
+
return { ...buildEnvironmentTool(), inputSchema: EnvironmentInputSchema, handler: environmentHandler };
|
|
51
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ExecutionsInputSchema } from '../types/index.js';
|
|
2
|
+
import { executionsHandler } from '../handlers/executionsHandler.js';
|
|
3
|
+
const DESCRIPTION = `Look up workflow executions (history of check_app_in_browser, trigger_crawl, and test-suite runs). Pass an "action":
|
|
4
|
+
- "get" {uuid} → one execution with FULL detail (nodeExecutions, state, errorInfo) + any screenshot/gif artifacts.
|
|
5
|
+
- "list" {projectUuid?, status?, page?, pageSize?} → paginated execution summaries. status ∈ completed|running|failed|cancelled|pending.
|
|
6
|
+
|
|
7
|
+
Tip: after a fresh check_app_in_browser run, poll action:"get" with the returned executionId until artifact URLs are available.`;
|
|
8
|
+
export function buildExecutionsTool() {
|
|
9
|
+
return {
|
|
10
|
+
name: 'executions',
|
|
11
|
+
title: 'Workflow Executions',
|
|
12
|
+
description: DESCRIPTION,
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
action: { type: 'string', enum: ['get', 'list'], description: 'Operation to perform.' },
|
|
17
|
+
uuid: { type: 'string', description: '[get] Execution UUID.' },
|
|
18
|
+
projectUuid: { type: 'string', description: '[list] Filter by project UUID.' },
|
|
19
|
+
status: { type: 'string', description: '[list] Filter by status.' },
|
|
20
|
+
page: { type: 'number', description: '[list] Page (1-indexed).' },
|
|
21
|
+
pageSize: { type: 'number', description: '[list] Page size (1..200).' },
|
|
22
|
+
},
|
|
23
|
+
required: ['action'],
|
|
24
|
+
// No top-level oneOf/anyOf/allOf: the Anthropic tool input_schema rejects
|
|
25
|
+
// them and clients (Claude Code) silently drop the tool. Per-action required
|
|
26
|
+
// fields are enforced by the Zod discriminated union in types/index.ts and
|
|
27
|
+
// documented in DESCRIPTION above.
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function buildValidatedExecutionsTool() {
|
|
33
|
+
return { ...buildExecutionsTool(), inputSchema: ExecutionsInputSchema, handler: executionsHandler };
|
|
34
|
+
}
|
package/dist/tools/index.js
CHANGED
|
@@ -1,66 +1,41 @@
|
|
|
1
1
|
import { buildTestPageChangesTool, buildValidatedTestPageChangesTool } from './testPageChanges.js';
|
|
2
2
|
import { buildTriggerCrawlTool, buildValidatedTriggerCrawlTool } from './triggerCrawl.js';
|
|
3
3
|
import { buildProbePageTool, buildValidatedProbePageTool } from './probePage.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { buildDeleteEnvironmentTool, buildValidatedDeleteEnvironmentTool } from './deleteEnvironment.js';
|
|
10
|
-
import { buildUpdateProjectTool, buildValidatedUpdateProjectTool } from './updateProject.js';
|
|
11
|
-
import { buildDeleteProjectTool, buildValidatedDeleteProjectTool } from './deleteProject.js';
|
|
12
|
-
import { buildCreateProjectTool, buildValidatedCreateProjectTool } from './createProject.js';
|
|
13
|
-
import { buildCreateTestSuiteTool, buildValidatedCreateTestSuiteTool, buildSearchTestSuitesTool, buildValidatedSearchTestSuitesTool, buildDeleteTestSuiteTool, buildValidatedDeleteTestSuiteTool, buildCreateTestCaseTool, buildValidatedCreateTestCaseTool, buildUpdateTestCaseTool, buildValidatedUpdateTestCaseTool, buildDeleteTestCaseTool, buildValidatedDeleteTestCaseTool, buildRunTestSuiteTool, buildValidatedRunTestSuiteTool, buildGetTestSuiteResultsTool, buildValidatedGetTestSuiteResultsTool, } from './testSuiteTools.js';
|
|
4
|
+
import { buildProjectTool, buildValidatedProjectTool } from './project.js';
|
|
5
|
+
import { buildEnvironmentTool, buildValidatedEnvironmentTool } from './environment.js';
|
|
6
|
+
import { buildExecutionsTool, buildValidatedExecutionsTool } from './executions.js';
|
|
7
|
+
import { buildTestSuiteTool, buildValidatedTestSuiteTool } from './testSuite.js';
|
|
8
|
+
import { buildTestCaseTool, buildValidatedTestCaseTool } from './testCase.js';
|
|
14
9
|
let _tools = null;
|
|
15
10
|
let _validatedTools = null;
|
|
16
11
|
const toolRegistry = new Map();
|
|
17
12
|
/**
|
|
18
13
|
* Initialize tools with project context (call once after resolveProjectContext).
|
|
14
|
+
*
|
|
15
|
+
* The surface is 8 action-based tools (epic yg7o6): 3 browser tools plus one
|
|
16
|
+
* tool per managed entity (project/environment/test_suite/test_case/executions),
|
|
17
|
+
* each routing an `action` discriminator to its handler.
|
|
19
18
|
*/
|
|
20
19
|
export function initTools(ctx) {
|
|
21
20
|
const tools = [
|
|
22
21
|
buildTestPageChangesTool(ctx),
|
|
23
|
-
buildTriggerCrawlTool(ctx),
|
|
24
22
|
buildProbePageTool(),
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
buildDeleteProjectTool(),
|
|
32
|
-
buildSearchExecutionsTool(),
|
|
33
|
-
buildCreateProjectTool(),
|
|
34
|
-
buildCreateTestSuiteTool(),
|
|
35
|
-
buildSearchTestSuitesTool(),
|
|
36
|
-
buildDeleteTestSuiteTool(),
|
|
37
|
-
buildCreateTestCaseTool(),
|
|
38
|
-
buildUpdateTestCaseTool(),
|
|
39
|
-
buildDeleteTestCaseTool(),
|
|
40
|
-
buildRunTestSuiteTool(),
|
|
41
|
-
buildGetTestSuiteResultsTool(),
|
|
23
|
+
buildTriggerCrawlTool(ctx),
|
|
24
|
+
buildProjectTool(),
|
|
25
|
+
buildEnvironmentTool(),
|
|
26
|
+
buildTestSuiteTool(),
|
|
27
|
+
buildTestCaseTool(),
|
|
28
|
+
buildExecutionsTool(),
|
|
42
29
|
];
|
|
43
30
|
const validated = [
|
|
44
31
|
buildValidatedTestPageChangesTool(ctx),
|
|
45
|
-
buildValidatedTriggerCrawlTool(ctx),
|
|
46
32
|
buildValidatedProbePageTool(),
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
buildValidatedDeleteProjectTool(),
|
|
54
|
-
buildValidatedSearchExecutionsTool(),
|
|
55
|
-
buildValidatedCreateProjectTool(),
|
|
56
|
-
buildValidatedCreateTestSuiteTool(),
|
|
57
|
-
buildValidatedSearchTestSuitesTool(),
|
|
58
|
-
buildValidatedDeleteTestSuiteTool(),
|
|
59
|
-
buildValidatedCreateTestCaseTool(),
|
|
60
|
-
buildValidatedUpdateTestCaseTool(),
|
|
61
|
-
buildValidatedDeleteTestCaseTool(),
|
|
62
|
-
buildValidatedRunTestSuiteTool(),
|
|
63
|
-
buildValidatedGetTestSuiteResultsTool(),
|
|
33
|
+
buildValidatedTriggerCrawlTool(ctx),
|
|
34
|
+
buildValidatedProjectTool(),
|
|
35
|
+
buildValidatedEnvironmentTool(),
|
|
36
|
+
buildValidatedTestSuiteTool(),
|
|
37
|
+
buildValidatedTestCaseTool(),
|
|
38
|
+
buildValidatedExecutionsTool(),
|
|
64
39
|
];
|
|
65
40
|
_tools = tools;
|
|
66
41
|
_validatedTools = validated;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ProjectInputSchema } from '../types/index.js';
|
|
2
|
+
import { projectHandler } from '../handlers/projectHandler.js';
|
|
3
|
+
const DESCRIPTION = `Manage DebuggAI projects. Pass an "action":
|
|
4
|
+
- "get" {uuid} → one project with full detail.
|
|
5
|
+
- "list" {q?, page?, pageSize?} → paginated project summaries.
|
|
6
|
+
- "create" {name, platform, (teamUuid|teamName), (repoUuid|repoName)} → create a project. The repo must be GitHub-linked; names resolve by case-insensitive exact match.
|
|
7
|
+
|
|
8
|
+
Note: there is no update/delete here — rename/delete a project from the DebuggAI web app.`;
|
|
9
|
+
export function buildProjectTool() {
|
|
10
|
+
return {
|
|
11
|
+
name: 'project',
|
|
12
|
+
title: 'Project',
|
|
13
|
+
description: DESCRIPTION,
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
action: { type: 'string', enum: ['get', 'list', 'create'], description: 'Operation to perform.' },
|
|
18
|
+
uuid: { type: 'string', description: '[get] Project UUID.' },
|
|
19
|
+
q: { type: 'string', description: '[list] Free-text search.' },
|
|
20
|
+
page: { type: 'number', description: '[list] Page (1-indexed).' },
|
|
21
|
+
pageSize: { type: 'number', description: '[list] Page size (1..200).' },
|
|
22
|
+
name: { type: 'string', description: '[create] Project name.' },
|
|
23
|
+
platform: { type: 'string', description: '[create] Platform, e.g. "web".' },
|
|
24
|
+
teamUuid: { type: 'string', description: '[create] Team UUID (or teamName).' },
|
|
25
|
+
teamName: { type: 'string', description: '[create] Team name (or teamUuid).' },
|
|
26
|
+
repoUuid: { type: 'string', description: '[create] GitHub repo UUID (or repoName).' },
|
|
27
|
+
repoName: { type: 'string', description: '[create] GitHub repo name "org/repo" (or repoUuid).' },
|
|
28
|
+
},
|
|
29
|
+
required: ['action'],
|
|
30
|
+
// No top-level oneOf/anyOf/allOf: the Anthropic tool input_schema rejects
|
|
31
|
+
// them and clients (Claude Code) silently drop the tool. Per-action required
|
|
32
|
+
// fields are enforced by the Zod discriminated union in types/index.ts and
|
|
33
|
+
// documented in DESCRIPTION above.
|
|
34
|
+
additionalProperties: false,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function buildValidatedProjectTool() {
|
|
39
|
+
return { ...buildProjectTool(), inputSchema: ProjectInputSchema, handler: projectHandler };
|
|
40
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { TestCaseInputSchema } from '../types/index.js';
|
|
2
|
+
import { testCaseHandler } from '../handlers/testCaseHandler.js';
|
|
3
|
+
const DESCRIPTION = `Manage individual test cases within a suite. Pass an "action":
|
|
4
|
+
- "create" {name, description, agentTaskDescription, suiteUuid|(suiteName+project), relativeUrl?, maxSteps?} → add a test case (NOT auto-run).
|
|
5
|
+
- "update" {testUuid, name?, description?, agentTaskDescription?} → patch a test case.
|
|
6
|
+
- "delete" {testUuid, confirm?} → soft-delete (DESTRUCTIVE; requires confirmation).`;
|
|
7
|
+
export function buildTestCaseTool() {
|
|
8
|
+
return {
|
|
9
|
+
name: 'test_case',
|
|
10
|
+
title: 'Test Case',
|
|
11
|
+
description: DESCRIPTION,
|
|
12
|
+
inputSchema: {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
action: { type: 'string', enum: ['create', 'update', 'delete'], description: 'Operation to perform.' },
|
|
16
|
+
testUuid: { type: 'string', description: '[update/delete] Test case UUID.' },
|
|
17
|
+
name: { type: 'string', description: 'Test case name.' },
|
|
18
|
+
description: { type: 'string', description: 'Test case description.' },
|
|
19
|
+
agentTaskDescription: { type: 'string', description: "What the AI agent should do and verify." },
|
|
20
|
+
suiteUuid: { type: 'string', description: '[create] Suite UUID.' },
|
|
21
|
+
suiteName: { type: 'string', description: '[create] Suite name (requires a project identifier).' },
|
|
22
|
+
projectUuid: { type: 'string', description: '[create] Project UUID (or projectName).' },
|
|
23
|
+
projectName: { type: 'string', description: '[create] Project name (or projectUuid).' },
|
|
24
|
+
relativeUrl: { type: 'string', description: '[create] Starting path, must start with "/".' },
|
|
25
|
+
maxSteps: { type: 'number', description: '[create] Max agent steps (1..100).' },
|
|
26
|
+
confirm: { type: 'boolean', description: '[delete] Set true to confirm deletion (when the client cannot prompt).' },
|
|
27
|
+
},
|
|
28
|
+
required: ['action'],
|
|
29
|
+
// No top-level oneOf/anyOf/allOf: the Anthropic tool input_schema rejects
|
|
30
|
+
// them and clients (Claude Code) silently drop the tool. Per-action required
|
|
31
|
+
// fields are enforced by the Zod discriminated union in types/index.ts and
|
|
32
|
+
// documented in DESCRIPTION above.
|
|
33
|
+
additionalProperties: false,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function buildValidatedTestCaseTool() {
|
|
38
|
+
return { ...buildTestCaseTool(), inputSchema: TestCaseInputSchema, handler: testCaseHandler };
|
|
39
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { TestSuiteInputSchema } from '../types/index.js';
|
|
2
|
+
import { testSuiteHandler } from '../handlers/testSuiteHandler.js';
|
|
3
|
+
const DESCRIPTION = `Manage and run test suites. Identify a suite by suiteUuid, or suiteName + a project identifier (projectUuid|projectName). Pass an "action":
|
|
4
|
+
- "list" {projectUuid|projectName, search?, page?, pageSize?} → paginated suites with status/pass-rate.
|
|
5
|
+
- "create" {name, description, projectUuid|projectName} → create a suite.
|
|
6
|
+
- "run" {suiteUuid|(suiteName+project), targetUrl?} → run all tests async. Poll with action:"results".
|
|
7
|
+
- "results" {suiteUuid|(suiteName+project)} → suite + per-test outcomes.
|
|
8
|
+
- "delete" {suiteUuid|(suiteName+project), confirm?} → soft-delete (DESTRUCTIVE; requires confirmation).`;
|
|
9
|
+
const PROJECT_PROPS = {
|
|
10
|
+
projectUuid: { type: 'string', description: 'Project UUID (or projectName).' },
|
|
11
|
+
projectName: { type: 'string', description: 'Project name (or projectUuid).' },
|
|
12
|
+
};
|
|
13
|
+
const SUITE_PROPS = {
|
|
14
|
+
suiteUuid: { type: 'string', description: 'Test suite UUID.' },
|
|
15
|
+
suiteName: { type: 'string', description: 'Test suite name (requires a project identifier).' },
|
|
16
|
+
};
|
|
17
|
+
export function buildTestSuiteTool() {
|
|
18
|
+
return {
|
|
19
|
+
name: 'test_suite',
|
|
20
|
+
title: 'Test Suite',
|
|
21
|
+
description: DESCRIPTION,
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
action: { type: 'string', enum: ['list', 'create', 'run', 'results', 'delete'], description: 'Operation to perform.' },
|
|
26
|
+
...SUITE_PROPS,
|
|
27
|
+
...PROJECT_PROPS,
|
|
28
|
+
name: { type: 'string', description: '[create] Suite name.' },
|
|
29
|
+
description: { type: 'string', description: '[create] Suite description.' },
|
|
30
|
+
search: { type: 'string', description: '[list] Text filter over name/description.' },
|
|
31
|
+
page: { type: 'number', description: '[list] Page (1-indexed).' },
|
|
32
|
+
pageSize: { type: 'number', description: '[list] Page size (1..100).' },
|
|
33
|
+
targetUrl: { type: 'string', description: '[run] Override the default test target (full URL).' },
|
|
34
|
+
confirm: { type: 'boolean', description: '[delete] Set true to confirm deletion (when the client cannot prompt).' },
|
|
35
|
+
},
|
|
36
|
+
required: ['action'],
|
|
37
|
+
// No top-level oneOf/anyOf/allOf: the Anthropic tool input_schema rejects
|
|
38
|
+
// them and clients (Claude Code) silently drop the tool. Per-action required
|
|
39
|
+
// fields are enforced by the Zod discriminated union in types/index.ts and
|
|
40
|
+
// documented in DESCRIPTION above.
|
|
41
|
+
additionalProperties: false,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function buildValidatedTestSuiteTool() {
|
|
46
|
+
return { ...buildTestSuiteTool(), inputSchema: TestSuiteInputSchema, handler: testSuiteHandler };
|
|
47
|
+
}
|
|
@@ -71,10 +71,6 @@ export function buildTriggerCrawlTool(ctx) {
|
|
|
71
71
|
type: 'string',
|
|
72
72
|
description: 'The real password for the username above. Do NOT guess.',
|
|
73
73
|
},
|
|
74
|
-
headless: {
|
|
75
|
-
type: 'boolean',
|
|
76
|
-
description: 'Run the browser in headless mode. Defaults to backend configuration.',
|
|
77
|
-
},
|
|
78
74
|
timeoutSeconds: {
|
|
79
75
|
type: 'number',
|
|
80
76
|
description: 'Maximum wall-time the crawl may run, in seconds (1..1800). Backend enforces this per workflow execution.',
|