@qase/mcp-server 2.0.0 → 2.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 +14 -1
- package/README.md +5 -5
- package/build/operations-v2/index.d.ts +2 -0
- package/build/operations-v2/index.d.ts.map +1 -1
- package/build/operations-v2/index.js +2 -0
- package/build/operations-v2/index.js.map +1 -1
- package/build/operations-v2/meta/discover.js +4 -1
- package/build/operations-v2/meta/discover.js.map +1 -1
- package/build/operations-v2/read/get.js +28 -4
- package/build/operations-v2/read/get.js.map +1 -1
- package/build/operations-v2/write/case-fields.d.ts +206 -0
- package/build/operations-v2/write/case-fields.d.ts.map +1 -0
- package/build/operations-v2/write/case-fields.js +79 -0
- package/build/operations-v2/write/case-fields.js.map +1 -0
- package/build/operations-v2/write/cases-bulk.d.ts +2 -0
- package/build/operations-v2/write/cases-bulk.d.ts.map +1 -0
- package/build/operations-v2/write/cases-bulk.js +54 -0
- package/build/operations-v2/write/cases-bulk.js.map +1 -0
- package/build/operations-v2/write/cases.js +1 -70
- package/build/operations-v2/write/cases.js.map +1 -1
- package/build/operations-v2/write/external-issues.d.ts +2 -0
- package/build/operations-v2/write/external-issues.d.ts.map +1 -0
- package/build/operations-v2/write/external-issues.js +96 -0
- package/build/operations-v2/write/external-issues.js.map +1 -0
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/docs/migration.md +1 -1
- package/docs/tools.md +6 -4
- package/docs/troubleshooting.md +1 -1
- package/package.json +2 -2
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,11 +5,24 @@ All notable changes to this 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
|
+
## [2.0.1]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`qase_external_issue_link`** — Link or unlink test cases and test runs to issues in an external tracker (Jira Cloud / Jira Server), wrapping `POST /v1/case/{code}/external-issue/attach`, `.../detach`, and `POST /v1/run/{code}/external-issue`. A case can hold several links; a run holds one, and detaching clears it. ([#64](https://github.com/qase-tms/qase-mcp-server/issues/64))
|
|
13
|
+
- **`qase_get`** now requests external issue links for cases and runs by default (`include=external_issues` / `include=external_issue`), so a link created via `qase_external_issue_link` can be verified without leaving the MCP client. The new `include` parameter overrides the default; if a deployment rejects the value, the request is retried without it. ([#65](https://github.com/qase-tms/qase-mcp-server/issues/65))
|
|
14
|
+
|
|
15
|
+
- **`qase_case_bulk_create`** — Create up to 100 test cases in a single request, restoring the bulk creation that v1 offered as `bulk_create_cases`. Unlike the v1 tool it normalises enum labels per case, so `priority: "high"` works the same as in `qase_case_upsert`.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- `qase_discover_tools` no longer skips activation when the `activate` argument is omitted. Tool handlers receive raw MCP arguments, so the schema default never applied and matched tools stayed hidden from the client's tool list.
|
|
20
|
+
|
|
8
21
|
## [2.0.0]
|
|
9
22
|
|
|
10
23
|
### Breaking Changes
|
|
11
24
|
|
|
12
|
-
- **All 83 v1 tool names have been removed.** The tool set has been consolidated from 83 tools to 29. See [
|
|
25
|
+
- **All 83 v1 tool names have been removed.** The tool set has been consolidated from 83 tools to 29. See [docs/migration.md](docs/migration.md) for a complete v1→v2 tool mapping table.
|
|
13
26
|
- Response format is now compact JSON with null values stripped (no indentation). This reduces token usage but changes the raw string format of responses.
|
|
14
27
|
|
|
15
28
|
### Added
|
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ The Qase MCP Server lets AI assistants (Claude, Cursor, Codex, and any other MCP
|
|
|
27
27
|
|
|
28
28
|
**Features:**
|
|
29
29
|
|
|
30
|
-
- **
|
|
30
|
+
- **31 task-oriented tools** (32 total, including `qase_discover_tools`) — consolidated from 83 v1 tools for lower token usage and better LLM accuracy
|
|
31
31
|
- **Composite tools** — multi-step workflows in a single call: CI reporting, defect triage, regression run setup
|
|
32
32
|
- **QQL support** — Qase Query Language for advanced searches across cases, runs, results, defects, and plans
|
|
33
33
|
- **Project context bootstrap** — one call returns full project structure (suites, milestones, environments, users, custom fields)
|
|
@@ -76,17 +76,17 @@ Then point your MCP client's stdio config at the `@qase/mcp-server` binary. Full
|
|
|
76
76
|
|
|
77
77
|
## Upgrading from v1
|
|
78
78
|
|
|
79
|
-
v2 consolidates 83 v1 tools into **29 task-oriented tools** (30 total, including a discovery tool). Tool names and response shapes have changed. See **[
|
|
79
|
+
v2 consolidates 83 v1 tools into **29 task-oriented tools** (30 total, including a discovery tool). Tool names and response shapes have changed. See **[docs/migration.md](docs/migration.md)** for the complete tool mapping table, response format changes, and before/after examples.
|
|
80
80
|
|
|
81
81
|
## Tools
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
32 tools across 6 groups (31 task-oriented tools plus `qase_discover_tools` for on-demand activation of secondary tools):
|
|
84
84
|
|
|
85
85
|
| Group | Count | Description |
|
|
86
86
|
| --- | --- | --- |
|
|
87
87
|
| Read | 2 | Fetch any entity by type/ID, or bootstrap full project context in one call |
|
|
88
88
|
| QQL | 2 | Search across cases, runs, results, defects, and plans with Qase Query Language |
|
|
89
|
-
| Write |
|
|
89
|
+
| Write | 23 | Create, update, and delete cases (single or up to 100 at once), runs, results, defects, suites, milestones, plans, shared steps, environments, and attachments; link cases and runs to Jira issues |
|
|
90
90
|
| Composite | 3 | Multi-step workflows in one call: CI reporting, defect triage, regression run setup |
|
|
91
91
|
| Escape hatch | 1 | Direct REST API access for any endpoint not covered by the tools above |
|
|
92
92
|
| Meta | 1 | `qase_discover_tools` — find and activate secondary tools on demand |
|
|
@@ -99,7 +99,7 @@ Full tool-by-tool reference with parameters and the discovery model: **[docs/too
|
|
|
99
99
|
- **[docs/self-run.md](docs/self-run.md)** — install and run the server yourself (config, clients, transports)
|
|
100
100
|
- **[docs/tools.md](docs/tools.md)** — full tool reference, groups, and the discovery model
|
|
101
101
|
- **[docs/troubleshooting.md](docs/troubleshooting.md)** — auth, OAuth/connector, and SSL issues
|
|
102
|
-
- **[
|
|
102
|
+
- **[docs/migration.md](docs/migration.md)** — v1 → v2 tool mapping and migration guide
|
|
103
103
|
|
|
104
104
|
## Contributing
|
|
105
105
|
|
|
@@ -2,6 +2,7 @@ import './read/project-context.js';
|
|
|
2
2
|
import './read/get.js';
|
|
3
3
|
import './qql/index.js';
|
|
4
4
|
import './write/cases.js';
|
|
5
|
+
import './write/cases-bulk.js';
|
|
5
6
|
import './write/runs.js';
|
|
6
7
|
import './write/results.js';
|
|
7
8
|
import './write/defects.js';
|
|
@@ -11,6 +12,7 @@ import './write/plans.js';
|
|
|
11
12
|
import './write/shared-steps.js';
|
|
12
13
|
import './write/environments.js';
|
|
13
14
|
import './write/attachments.js';
|
|
15
|
+
import './write/external-issues.js';
|
|
14
16
|
import './composites/ci-report.js';
|
|
15
17
|
import './composites/triage-defect.js';
|
|
16
18
|
import './composites/regression-run.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/operations-v2/index.ts"],"names":[],"mappings":"AACA,OAAO,2BAA2B,CAAC;AACnC,OAAO,eAAe,CAAC;AAGvB,OAAO,gBAAgB,CAAC;AAGxB,OAAO,kBAAkB,CAAC;AAC1B,OAAO,iBAAiB,CAAC;AACzB,OAAO,oBAAoB,CAAC;AAC5B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,yBAAyB,CAAC;AACjC,OAAO,yBAAyB,CAAC;AACjC,OAAO,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/operations-v2/index.ts"],"names":[],"mappings":"AACA,OAAO,2BAA2B,CAAC;AACnC,OAAO,eAAe,CAAC;AAGvB,OAAO,gBAAgB,CAAC;AAGxB,OAAO,kBAAkB,CAAC;AAC1B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,iBAAiB,CAAC;AACzB,OAAO,oBAAoB,CAAC;AAC5B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,yBAAyB,CAAC;AACjC,OAAO,yBAAyB,CAAC;AACjC,OAAO,wBAAwB,CAAC;AAChC,OAAO,4BAA4B,CAAC;AAGpC,OAAO,2BAA2B,CAAC;AACnC,OAAO,+BAA+B,CAAC;AACvC,OAAO,gCAAgC,CAAC;AAGxC,OAAO,oBAAoB,CAAC;AAG5B,OAAO,iBAAiB,CAAC"}
|
|
@@ -5,6 +5,7 @@ import './read/get.js';
|
|
|
5
5
|
import './qql/index.js';
|
|
6
6
|
// Write tools
|
|
7
7
|
import './write/cases.js';
|
|
8
|
+
import './write/cases-bulk.js';
|
|
8
9
|
import './write/runs.js';
|
|
9
10
|
import './write/results.js';
|
|
10
11
|
import './write/defects.js';
|
|
@@ -14,6 +15,7 @@ import './write/plans.js';
|
|
|
14
15
|
import './write/shared-steps.js';
|
|
15
16
|
import './write/environments.js';
|
|
16
17
|
import './write/attachments.js';
|
|
18
|
+
import './write/external-issues.js';
|
|
17
19
|
// Composites
|
|
18
20
|
import './composites/ci-report.js';
|
|
19
21
|
import './composites/triage-defect.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/operations-v2/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,2BAA2B,CAAC;AACnC,OAAO,eAAe,CAAC;AAEvB,YAAY;AACZ,OAAO,gBAAgB,CAAC;AAExB,cAAc;AACd,OAAO,kBAAkB,CAAC;AAC1B,OAAO,iBAAiB,CAAC;AACzB,OAAO,oBAAoB,CAAC;AAC5B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,yBAAyB,CAAC;AACjC,OAAO,yBAAyB,CAAC;AACjC,OAAO,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/operations-v2/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,2BAA2B,CAAC;AACnC,OAAO,eAAe,CAAC;AAEvB,YAAY;AACZ,OAAO,gBAAgB,CAAC;AAExB,cAAc;AACd,OAAO,kBAAkB,CAAC;AAC1B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,iBAAiB,CAAC;AACzB,OAAO,oBAAoB,CAAC;AAC5B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,mBAAmB,CAAC;AAC3B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,yBAAyB,CAAC;AACjC,OAAO,yBAAyB,CAAC;AACjC,OAAO,wBAAwB,CAAC;AAChC,OAAO,4BAA4B,CAAC;AAEpC,aAAa;AACb,OAAO,2BAA2B,CAAC;AACnC,OAAO,+BAA+B,CAAC;AACvC,OAAO,gCAAgC,CAAC;AAExC,aAAa;AACb,OAAO,oBAAoB,CAAC;AAE5B,eAAe;AACf,OAAO,iBAAiB,CAAC"}
|
|
@@ -25,7 +25,10 @@ const Schema = z.object({
|
|
|
25
25
|
.describe('If true (default), found tools are activated and become available for use'),
|
|
26
26
|
});
|
|
27
27
|
async function handler(args) {
|
|
28
|
-
const { query, category
|
|
28
|
+
const { query, category } = args;
|
|
29
|
+
// Handlers receive raw MCP arguments, so the schema default never runs —
|
|
30
|
+
// apply it here or discovery silently stops activating anything.
|
|
31
|
+
const activate = args.activate ?? true;
|
|
29
32
|
let matches = query ? toolRegistry.searchTools(query) : toolRegistry.getAllTools();
|
|
30
33
|
// Filter by category based on tool annotations
|
|
31
34
|
if (category && category !== 'all') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/operations-v2/meta/discover.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEpE,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,qDAAqD;QACnD,wDAAwD,CAC3D;IACH,QAAQ,EAAE,CAAC;SACR,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;SACrD,QAAQ,EAAE;SACV,QAAQ,CAAC,yBAAyB,CAAC;IACtC,QAAQ,EAAE,CAAC;SACR,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,2EAA2E,CAAC;CACzF,CAAC,CAAC;AAEH,KAAK,UAAU,OAAO,CAAC,IAA4B;IACjD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/operations-v2/meta/discover.ts"],"names":[],"mappings":"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"}
|
|
@@ -43,11 +43,26 @@ const Schema = z.object({
|
|
|
43
43
|
.array(z.string())
|
|
44
44
|
.optional()
|
|
45
45
|
.describe('Optional field projection — only return these top-level fields. Pass ["*"] for all fields.'),
|
|
46
|
+
include: z
|
|
47
|
+
.string()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe('Comma-separated list of related entities to include in the response. ' +
|
|
50
|
+
'Cases and runs already request their external issue links by default ' +
|
|
51
|
+
'("external_issues" / "external_issue"); pass this only to override that.'),
|
|
46
52
|
});
|
|
53
|
+
/**
|
|
54
|
+
* Related entities requested automatically so linked issues are visible without
|
|
55
|
+
* the caller knowing about the `include` query parameter. The Qase API omits
|
|
56
|
+
* these fields entirely unless they are asked for.
|
|
57
|
+
*/
|
|
58
|
+
const DEFAULT_INCLUDE = {
|
|
59
|
+
case: 'external_issues',
|
|
60
|
+
run: 'external_issue',
|
|
61
|
+
};
|
|
47
62
|
const FETCHERS = {
|
|
48
|
-
case: (c, code, id) => c.cases.getCase(code, id),
|
|
63
|
+
case: (c, code, id, include) => c.cases.getCase(code, id, include),
|
|
49
64
|
suite: (c, code, id) => c.suites.getSuite(code, id),
|
|
50
|
-
run: (c, code, id) => c.runs.getRun(code, id),
|
|
65
|
+
run: (c, code, id, include) => c.runs.getRun(code, id, include),
|
|
51
66
|
result: (c, code, id) => c.results.getResult(code, id),
|
|
52
67
|
plan: (c, code, id) => c.plans.getPlan(code, id),
|
|
53
68
|
defect: (c, code, id) => c.defects.getDefect(code, id),
|
|
@@ -62,7 +77,7 @@ const FETCHERS = {
|
|
|
62
77
|
custom_field: (c, _code, id) => c.customFields.getCustomField(id),
|
|
63
78
|
};
|
|
64
79
|
async function handler(args) {
|
|
65
|
-
const { entity, code, id, fields: fieldList } = args;
|
|
80
|
+
const { entity, code, id, fields: fieldList, include } = args;
|
|
66
81
|
if (ENTITIES_REQUIRING_CODE.has(entity) && !code) {
|
|
67
82
|
throw createToolError(`Project code is required for entity type "${entity}"`, 'get operation');
|
|
68
83
|
}
|
|
@@ -70,7 +85,16 @@ async function handler(args) {
|
|
|
70
85
|
const fetcher = FETCHERS[entity];
|
|
71
86
|
if (!fetcher)
|
|
72
87
|
throw createToolError(`Unknown entity type: ${entity}`, 'get operation');
|
|
73
|
-
const
|
|
88
|
+
const effectiveInclude = include ?? DEFAULT_INCLUDE[entity];
|
|
89
|
+
const isDefaultInclude = !include && effectiveInclude !== undefined;
|
|
90
|
+
let result = await toResultAsync(fetcher(client, code || '', id, effectiveInclude));
|
|
91
|
+
// Deployments that don't know the `include` value (older self-hosted
|
|
92
|
+
// instances) reject the request outright — retry without it rather than
|
|
93
|
+
// failing a plain get. An explicit `include` from the caller is never
|
|
94
|
+
// silently dropped.
|
|
95
|
+
if (result.isErr() && isDefaultInclude) {
|
|
96
|
+
result = await toResultAsync(fetcher(client, code || '', id, undefined));
|
|
97
|
+
}
|
|
74
98
|
return result.match((response) => {
|
|
75
99
|
const data = response.data.result;
|
|
76
100
|
return fieldList ? projectFields(data, fieldList) : data;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get.js","sourceRoot":"","sources":["../../../src/operations-v2/read/get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAE9D,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC;IACtC,MAAM;IACN,OAAO;IACP,KAAK;IACL,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,WAAW;IACX,aAAa;IACb,aAAa;IACb,kBAAkB;IAClB,eAAe;CAChB,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,MAAM,EAAE,CAAC;SACN,IAAI,CAAC;QACJ,MAAM;QACN,OAAO;QACP,KAAK;QACL,QAAQ;QACR,MAAM;QACN,QAAQ;QACR,WAAW;QACX,aAAa;QACb,aAAa;QACb,kBAAkB;QAClB,eAAe;QACf,YAAY;QACZ,QAAQ;QACR,MAAM;QACN,cAAc;KACf,CAAC;SACD,QAAQ,CAAC,sBAAsB,CAAC;IACnC,IAAI,EAAE,iBAAiB,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;IACxF,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,qCAAqC,CAAC;IACnF,MAAM,EAAE,CAAC;SACN,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CACP,4FAA4F,CAC7F;CACJ,CAAC,CAAC;AAEH,MAAM,QAAQ,
|
|
1
|
+
{"version":3,"file":"get.js","sourceRoot":"","sources":["../../../src/operations-v2/read/get.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test case field definitions.
|
|
3
|
+
*
|
|
4
|
+
* `qase_case_upsert` and `qase_case_bulk_create` accept the same case body, so
|
|
5
|
+
* the schema and the automation mapping live here instead of being duplicated
|
|
6
|
+
* — a new case field only has to be added once.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
export declare const TestStepSchema: z.ZodObject<{
|
|
10
|
+
steps: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
11
|
+
action: z.ZodOptional<z.ZodString>;
|
|
12
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
13
|
+
data: z.ZodOptional<z.ZodString>;
|
|
14
|
+
value: z.ZodOptional<z.ZodString>;
|
|
15
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
16
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
17
|
+
action: z.ZodOptional<z.ZodString>;
|
|
18
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
19
|
+
data: z.ZodOptional<z.ZodString>;
|
|
20
|
+
value: z.ZodOptional<z.ZodString>;
|
|
21
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
22
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
23
|
+
action: z.ZodOptional<z.ZodString>;
|
|
24
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
25
|
+
data: z.ZodOptional<z.ZodString>;
|
|
26
|
+
value: z.ZodOptional<z.ZodString>;
|
|
27
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
28
|
+
}, z.ZodTypeAny, "passthrough">>, "many">>;
|
|
29
|
+
action: z.ZodOptional<z.ZodString>;
|
|
30
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
31
|
+
data: z.ZodOptional<z.ZodString>;
|
|
32
|
+
value: z.ZodOptional<z.ZodString>;
|
|
33
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
value?: string | undefined;
|
|
36
|
+
data?: string | undefined;
|
|
37
|
+
action?: string | undefined;
|
|
38
|
+
expected_result?: string | undefined;
|
|
39
|
+
attachments?: string[] | undefined;
|
|
40
|
+
steps?: z.objectOutputType<{
|
|
41
|
+
action: z.ZodOptional<z.ZodString>;
|
|
42
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
43
|
+
data: z.ZodOptional<z.ZodString>;
|
|
44
|
+
value: z.ZodOptional<z.ZodString>;
|
|
45
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
46
|
+
}, z.ZodTypeAny, "passthrough">[] | undefined;
|
|
47
|
+
}, {
|
|
48
|
+
value?: string | undefined;
|
|
49
|
+
data?: string | undefined;
|
|
50
|
+
action?: string | undefined;
|
|
51
|
+
expected_result?: string | undefined;
|
|
52
|
+
attachments?: string[] | undefined;
|
|
53
|
+
steps?: z.objectInputType<{
|
|
54
|
+
action: z.ZodOptional<z.ZodString>;
|
|
55
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
56
|
+
data: z.ZodOptional<z.ZodString>;
|
|
57
|
+
value: z.ZodOptional<z.ZodString>;
|
|
58
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
59
|
+
}, z.ZodTypeAny, "passthrough">[] | undefined;
|
|
60
|
+
}>;
|
|
61
|
+
export declare const CaseFieldsSchema: z.ZodObject<{
|
|
62
|
+
title: z.ZodString;
|
|
63
|
+
description: z.ZodOptional<z.ZodString>;
|
|
64
|
+
preconditions: z.ZodOptional<z.ZodString>;
|
|
65
|
+
postconditions: z.ZodOptional<z.ZodString>;
|
|
66
|
+
severity: z.ZodOptional<z.ZodString>;
|
|
67
|
+
priority: z.ZodOptional<z.ZodString>;
|
|
68
|
+
type: z.ZodOptional<z.ZodString>;
|
|
69
|
+
layer: z.ZodOptional<z.ZodString>;
|
|
70
|
+
behavior: z.ZodOptional<z.ZodString>;
|
|
71
|
+
automation: z.ZodOptional<z.ZodString>;
|
|
72
|
+
status: z.ZodOptional<z.ZodString>;
|
|
73
|
+
is_flaky: z.ZodOptional<z.ZodBoolean>;
|
|
74
|
+
suite_id: z.ZodOptional<z.ZodNumber>;
|
|
75
|
+
milestone_id: z.ZodOptional<z.ZodNumber>;
|
|
76
|
+
steps: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
77
|
+
steps: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
78
|
+
action: z.ZodOptional<z.ZodString>;
|
|
79
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
80
|
+
data: z.ZodOptional<z.ZodString>;
|
|
81
|
+
value: z.ZodOptional<z.ZodString>;
|
|
82
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
83
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
84
|
+
action: z.ZodOptional<z.ZodString>;
|
|
85
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
86
|
+
data: z.ZodOptional<z.ZodString>;
|
|
87
|
+
value: z.ZodOptional<z.ZodString>;
|
|
88
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
89
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
90
|
+
action: z.ZodOptional<z.ZodString>;
|
|
91
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
92
|
+
data: z.ZodOptional<z.ZodString>;
|
|
93
|
+
value: z.ZodOptional<z.ZodString>;
|
|
94
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
95
|
+
}, z.ZodTypeAny, "passthrough">>, "many">>;
|
|
96
|
+
action: z.ZodOptional<z.ZodString>;
|
|
97
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
98
|
+
data: z.ZodOptional<z.ZodString>;
|
|
99
|
+
value: z.ZodOptional<z.ZodString>;
|
|
100
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
101
|
+
}, "strip", z.ZodTypeAny, {
|
|
102
|
+
value?: string | undefined;
|
|
103
|
+
data?: string | undefined;
|
|
104
|
+
action?: string | undefined;
|
|
105
|
+
expected_result?: string | undefined;
|
|
106
|
+
attachments?: string[] | undefined;
|
|
107
|
+
steps?: z.objectOutputType<{
|
|
108
|
+
action: z.ZodOptional<z.ZodString>;
|
|
109
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
110
|
+
data: z.ZodOptional<z.ZodString>;
|
|
111
|
+
value: z.ZodOptional<z.ZodString>;
|
|
112
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
113
|
+
}, z.ZodTypeAny, "passthrough">[] | undefined;
|
|
114
|
+
}, {
|
|
115
|
+
value?: string | undefined;
|
|
116
|
+
data?: string | undefined;
|
|
117
|
+
action?: string | undefined;
|
|
118
|
+
expected_result?: string | undefined;
|
|
119
|
+
attachments?: string[] | undefined;
|
|
120
|
+
steps?: z.objectInputType<{
|
|
121
|
+
action: z.ZodOptional<z.ZodString>;
|
|
122
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
123
|
+
data: z.ZodOptional<z.ZodString>;
|
|
124
|
+
value: z.ZodOptional<z.ZodString>;
|
|
125
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
126
|
+
}, z.ZodTypeAny, "passthrough">[] | undefined;
|
|
127
|
+
}>, "many">>;
|
|
128
|
+
steps_type: z.ZodOptional<z.ZodEnum<["classic", "gherkin"]>>;
|
|
129
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
130
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
131
|
+
custom_field: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
132
|
+
}, "strip", z.ZodTypeAny, {
|
|
133
|
+
title: string;
|
|
134
|
+
type?: string | undefined;
|
|
135
|
+
status?: string | undefined;
|
|
136
|
+
description?: string | undefined;
|
|
137
|
+
priority?: string | undefined;
|
|
138
|
+
custom_field?: Record<string, any> | undefined;
|
|
139
|
+
behavior?: string | undefined;
|
|
140
|
+
severity?: string | undefined;
|
|
141
|
+
layer?: string | undefined;
|
|
142
|
+
automation?: string | undefined;
|
|
143
|
+
attachments?: string[] | undefined;
|
|
144
|
+
steps?: {
|
|
145
|
+
value?: string | undefined;
|
|
146
|
+
data?: string | undefined;
|
|
147
|
+
action?: string | undefined;
|
|
148
|
+
expected_result?: string | undefined;
|
|
149
|
+
attachments?: string[] | undefined;
|
|
150
|
+
steps?: z.objectOutputType<{
|
|
151
|
+
action: z.ZodOptional<z.ZodString>;
|
|
152
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
153
|
+
data: z.ZodOptional<z.ZodString>;
|
|
154
|
+
value: z.ZodOptional<z.ZodString>;
|
|
155
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
156
|
+
}, z.ZodTypeAny, "passthrough">[] | undefined;
|
|
157
|
+
}[] | undefined;
|
|
158
|
+
preconditions?: string | undefined;
|
|
159
|
+
postconditions?: string | undefined;
|
|
160
|
+
is_flaky?: boolean | undefined;
|
|
161
|
+
suite_id?: number | undefined;
|
|
162
|
+
milestone_id?: number | undefined;
|
|
163
|
+
steps_type?: "classic" | "gherkin" | undefined;
|
|
164
|
+
tags?: string[] | undefined;
|
|
165
|
+
}, {
|
|
166
|
+
title: string;
|
|
167
|
+
type?: string | undefined;
|
|
168
|
+
status?: string | undefined;
|
|
169
|
+
description?: string | undefined;
|
|
170
|
+
priority?: string | undefined;
|
|
171
|
+
custom_field?: Record<string, any> | undefined;
|
|
172
|
+
behavior?: string | undefined;
|
|
173
|
+
severity?: string | undefined;
|
|
174
|
+
layer?: string | undefined;
|
|
175
|
+
automation?: string | undefined;
|
|
176
|
+
attachments?: string[] | undefined;
|
|
177
|
+
steps?: {
|
|
178
|
+
value?: string | undefined;
|
|
179
|
+
data?: string | undefined;
|
|
180
|
+
action?: string | undefined;
|
|
181
|
+
expected_result?: string | undefined;
|
|
182
|
+
attachments?: string[] | undefined;
|
|
183
|
+
steps?: z.objectInputType<{
|
|
184
|
+
action: z.ZodOptional<z.ZodString>;
|
|
185
|
+
expected_result: z.ZodOptional<z.ZodString>;
|
|
186
|
+
data: z.ZodOptional<z.ZodString>;
|
|
187
|
+
value: z.ZodOptional<z.ZodString>;
|
|
188
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
189
|
+
}, z.ZodTypeAny, "passthrough">[] | undefined;
|
|
190
|
+
}[] | undefined;
|
|
191
|
+
preconditions?: string | undefined;
|
|
192
|
+
postconditions?: string | undefined;
|
|
193
|
+
is_flaky?: boolean | undefined;
|
|
194
|
+
suite_id?: number | undefined;
|
|
195
|
+
milestone_id?: number | undefined;
|
|
196
|
+
steps_type?: "classic" | "gherkin" | undefined;
|
|
197
|
+
tags?: string[] | undefined;
|
|
198
|
+
}>;
|
|
199
|
+
/**
|
|
200
|
+
* Map the user-facing `automation` enum (0=Manual, 1=To be automated,
|
|
201
|
+
* 2=Automated) to the current API contract (`isManual` + `isToBeAutomated`).
|
|
202
|
+
* The legacy `automation` field is deprecated in qase-api-client and dropped
|
|
203
|
+
* from the outbound payload.
|
|
204
|
+
*/
|
|
205
|
+
export declare function applyAutomationMapping(caseData: Record<string, unknown>): Record<string, unknown>;
|
|
206
|
+
//# sourceMappingURL=case-fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case-fields.d.ts","sourceRoot":"","sources":["../../../src/operations-v2/write/case-fields.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMzB,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4B3B,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA0BjG"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test case field definitions.
|
|
3
|
+
*
|
|
4
|
+
* `qase_case_upsert` and `qase_case_bulk_create` accept the same case body, so
|
|
5
|
+
* the schema and the automation mapping live here instead of being duplicated
|
|
6
|
+
* — a new case field only has to be added once.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
const stepFields = {
|
|
10
|
+
action: z.string().optional().describe('Step action (classic steps)'),
|
|
11
|
+
expected_result: z.string().optional().describe('Expected result'),
|
|
12
|
+
data: z.string().optional().describe('Test data'),
|
|
13
|
+
value: z.string().optional().describe('Gherkin scenario text (when steps_type is "gherkin")'),
|
|
14
|
+
attachments: z.array(z.string()).optional().describe('Attachment hashes'),
|
|
15
|
+
};
|
|
16
|
+
export const TestStepSchema = z.object({
|
|
17
|
+
...stepFields,
|
|
18
|
+
steps: z
|
|
19
|
+
.array(z.object(stepFields).passthrough())
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Nested substeps. Same structure as parent steps, supports further nesting.'),
|
|
22
|
+
});
|
|
23
|
+
export const CaseFieldsSchema = z.object({
|
|
24
|
+
title: z.string().min(1).max(255).describe('Test case title'),
|
|
25
|
+
description: z.string().optional(),
|
|
26
|
+
preconditions: z.string().optional(),
|
|
27
|
+
postconditions: z.string().optional(),
|
|
28
|
+
severity: z.string().optional().describe('Severity label or numeric ID'),
|
|
29
|
+
priority: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe('Priority label or numeric ID (0=not set, 1=high, 2=medium, 3=low)'),
|
|
33
|
+
type: z.string().optional().describe('Type label or numeric ID'),
|
|
34
|
+
layer: z.string().optional().describe('Layer label or numeric ID'),
|
|
35
|
+
behavior: z.string().optional().describe('Behavior label or numeric ID'),
|
|
36
|
+
automation: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe('Automation status (label, slug, or numeric ID: 0=Manual / is-not-automated, 1=To be automated, 2=Automated)'),
|
|
40
|
+
status: z.string().optional().describe('Status label or numeric ID'),
|
|
41
|
+
is_flaky: z.boolean().optional(),
|
|
42
|
+
suite_id: z.number().int().positive().optional(),
|
|
43
|
+
milestone_id: z.number().int().positive().optional(),
|
|
44
|
+
steps: z.array(TestStepSchema).optional(),
|
|
45
|
+
steps_type: z.enum(['classic', 'gherkin']).optional(),
|
|
46
|
+
tags: z.array(z.string()).optional(),
|
|
47
|
+
attachments: z.array(z.string()).optional(),
|
|
48
|
+
custom_field: z.record(z.any()).optional(),
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* Map the user-facing `automation` enum (0=Manual, 1=To be automated,
|
|
52
|
+
* 2=Automated) to the current API contract (`isManual` + `isToBeAutomated`).
|
|
53
|
+
* The legacy `automation` field is deprecated in qase-api-client and dropped
|
|
54
|
+
* from the outbound payload.
|
|
55
|
+
*/
|
|
56
|
+
export function applyAutomationMapping(caseData) {
|
|
57
|
+
const automationId = caseData.automation;
|
|
58
|
+
if (typeof automationId !== 'number') {
|
|
59
|
+
return caseData;
|
|
60
|
+
}
|
|
61
|
+
const { automation: _drop, ...rest } = caseData;
|
|
62
|
+
const mapped = rest;
|
|
63
|
+
switch (automationId) {
|
|
64
|
+
case 2: // Automated
|
|
65
|
+
mapped.isManual = 0;
|
|
66
|
+
break;
|
|
67
|
+
case 1: // To be automated
|
|
68
|
+
mapped.isManual = 1;
|
|
69
|
+
mapped.isToBeAutomated = 1;
|
|
70
|
+
break;
|
|
71
|
+
case 0: // Manual
|
|
72
|
+
default:
|
|
73
|
+
mapped.isManual = 1;
|
|
74
|
+
mapped.isToBeAutomated = 0;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
return mapped;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=case-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case-fields.js","sourceRoot":"","sources":["../../../src/operations-v2/write/case-fields.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cases-bulk.d.ts","sourceRoot":"","sources":["../../../src/operations-v2/write/cases-bulk.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getApiClient } from '../../client/index.js';
|
|
3
|
+
import { toolRegistry, CreateAnnotation } from '../../utils/registry.js';
|
|
4
|
+
import { toResultAsync, createToolError } from '../../utils/errors.js';
|
|
5
|
+
import { ProjectCodeSchema } from '../../utils/validation.js';
|
|
6
|
+
import { normalizeCaseEnums } from '../../utils/case-enums.js';
|
|
7
|
+
import { CaseFieldsSchema, applyAutomationMapping } from './case-fields.js';
|
|
8
|
+
const CONTEXT = 'bulk case creation';
|
|
9
|
+
/** Qase creates the whole batch in one transaction; 100 keeps the request sane. */
|
|
10
|
+
const MAX_CASES = 100;
|
|
11
|
+
const Schema = z.object({
|
|
12
|
+
code: ProjectCodeSchema,
|
|
13
|
+
cases: z
|
|
14
|
+
.array(CaseFieldsSchema)
|
|
15
|
+
.min(1)
|
|
16
|
+
.max(MAX_CASES, `A single call creates at most ${MAX_CASES} test cases — split larger batches.`)
|
|
17
|
+
.describe(`Test cases to create, 1 to ${MAX_CASES} per call`),
|
|
18
|
+
});
|
|
19
|
+
async function handler(rawArgs) {
|
|
20
|
+
// Tool handlers get raw MCP arguments — validate here so a malformed call
|
|
21
|
+
// returns a readable error instead of a TypeError from deeper in the code.
|
|
22
|
+
const parsed = Schema.safeParse(rawArgs);
|
|
23
|
+
if (!parsed.success) {
|
|
24
|
+
const details = parsed.error.issues
|
|
25
|
+
.map((issue) => `${issue.path.join('.') || 'arguments'}: ${issue.message}`)
|
|
26
|
+
.join('; ');
|
|
27
|
+
throw createToolError(`Invalid arguments — ${details}`, CONTEXT);
|
|
28
|
+
}
|
|
29
|
+
const { code, cases } = parsed.data;
|
|
30
|
+
// Same enum handling as qase_case_upsert, so "high" and "blocker" work here
|
|
31
|
+
// too. System fields are cached, so this does not fan out into N API calls.
|
|
32
|
+
const normalized = await Promise.all(cases.map(async (testCase) => applyAutomationMapping(await normalizeCaseEnums(testCase))));
|
|
33
|
+
const client = getApiClient();
|
|
34
|
+
const result = await toResultAsync(client.cases.bulk(code, { cases: normalized }));
|
|
35
|
+
return result.match((r) => {
|
|
36
|
+
const ids = r.data.result?.ids ?? [];
|
|
37
|
+
return { created: ids.length, ids };
|
|
38
|
+
}, (e) => {
|
|
39
|
+
throw createToolError(e, CONTEXT);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
toolRegistry.register({
|
|
43
|
+
name: 'qase_case_bulk_create',
|
|
44
|
+
description: `Create up to ${MAX_CASES} test cases in a single request. Use this instead of calling ` +
|
|
45
|
+
'`qase_case_upsert` repeatedly when importing or generating several cases at once. ' +
|
|
46
|
+
'Enum fields (priority, severity, type, etc.) accept both labels ("high", "blocker") and ' +
|
|
47
|
+
'numeric IDs. Creates only — use `qase_case_upsert` with an `id` to update an existing case. ' +
|
|
48
|
+
'Returns the IDs of the created cases in the order they were submitted.',
|
|
49
|
+
schema: Schema,
|
|
50
|
+
handler,
|
|
51
|
+
annotations: CreateAnnotation,
|
|
52
|
+
visibility: 'discoverable',
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=cases-bulk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cases-bulk.js","sourceRoot":"","sources":["../../../src/operations-v2/write/cases-bulk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE5E,MAAM,OAAO,GAAG,oBAAoB,CAAC;AAErC,mFAAmF;AACnF,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,IAAI,EAAE,iBAAiB;IACvB,KAAK,EAAE,CAAC;SACL,KAAK,CAAC,gBAAgB,CAAC;SACvB,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,SAAS,EAAE,iCAAiC,SAAS,qCAAqC,CAAC;SAC/F,QAAQ,CAAC,8BAA8B,SAAS,WAAW,CAAC;CAChE,CAAC,CAAC;AAEH,KAAK,UAAU,OAAO,CAAC,OAAgB;IACrC,0EAA0E;IAC1E,2EAA2E;IAC3E,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM;aAChC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,WAAW,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;aAC1E,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,eAAe,CAAC,uBAAuB,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;IAEpC,4EAA4E;IAC5E,4EAA4E;IAC5E,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAClC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,sBAAsB,CAAC,MAAM,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAC1F,CAAC;IAEF,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,UAAU,EAAS,CAAC,CAAC,CAAC;IAE1F,OAAO,MAAM,CAAC,KAAK,CACjB,CAAC,CAAC,EAAE,EAAE;QACJ,MAAM,GAAG,GAAa,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC;QAC/C,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;IACtC,CAAC,EACD,CAAC,CAAC,EAAE,EAAE;QACJ,MAAM,eAAe,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC,CACF,CAAC;AACJ,CAAC;AAED,YAAY,CAAC,QAAQ,CAAC;IACpB,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACT,gBAAgB,SAAS,+DAA+D;QACxF,oFAAoF;QACpF,0FAA0F;QAC1F,8FAA8F;QAC9F,wEAAwE;IAC1E,MAAM,EAAE,MAAM;IACd,OAAO;IACP,WAAW,EAAE,gBAAgB;IAC7B,UAAU,EAAE,cAAc;CAC3B,CAAC,CAAC"}
|
|
@@ -4,47 +4,7 @@ import { toolRegistry, CreateAnnotation, DeleteAnnotation } from '../../utils/re
|
|
|
4
4
|
import { toResultAsync, createToolError } from '../../utils/errors.js';
|
|
5
5
|
import { ProjectCodeSchema, IdSchema } from '../../utils/validation.js';
|
|
6
6
|
import { normalizeCaseEnums } from '../../utils/case-enums.js';
|
|
7
|
-
|
|
8
|
-
action: z.string().optional().describe('Step action (classic steps)'),
|
|
9
|
-
expected_result: z.string().optional().describe('Expected result'),
|
|
10
|
-
data: z.string().optional().describe('Test data'),
|
|
11
|
-
value: z.string().optional().describe('Gherkin scenario text (when steps_type is "gherkin")'),
|
|
12
|
-
attachments: z.array(z.string()).optional().describe('Attachment hashes'),
|
|
13
|
-
};
|
|
14
|
-
const TestStepSchema = z.object({
|
|
15
|
-
...stepFields,
|
|
16
|
-
steps: z
|
|
17
|
-
.array(z.object(stepFields).passthrough())
|
|
18
|
-
.optional()
|
|
19
|
-
.describe('Nested substeps. Same structure as parent steps, supports further nesting.'),
|
|
20
|
-
});
|
|
21
|
-
const CaseFieldsSchema = z.object({
|
|
22
|
-
title: z.string().min(1).max(255).describe('Test case title'),
|
|
23
|
-
description: z.string().optional(),
|
|
24
|
-
preconditions: z.string().optional(),
|
|
25
|
-
postconditions: z.string().optional(),
|
|
26
|
-
severity: z.string().optional().describe('Severity label or numeric ID'),
|
|
27
|
-
priority: z
|
|
28
|
-
.string()
|
|
29
|
-
.optional()
|
|
30
|
-
.describe('Priority label or numeric ID (0=not set, 1=high, 2=medium, 3=low)'),
|
|
31
|
-
type: z.string().optional().describe('Type label or numeric ID'),
|
|
32
|
-
layer: z.string().optional().describe('Layer label or numeric ID'),
|
|
33
|
-
behavior: z.string().optional().describe('Behavior label or numeric ID'),
|
|
34
|
-
automation: z
|
|
35
|
-
.string()
|
|
36
|
-
.optional()
|
|
37
|
-
.describe('Automation status (label, slug, or numeric ID: 0=Manual / is-not-automated, 1=To be automated, 2=Automated)'),
|
|
38
|
-
status: z.string().optional().describe('Status label or numeric ID'),
|
|
39
|
-
is_flaky: z.boolean().optional(),
|
|
40
|
-
suite_id: z.number().int().positive().optional(),
|
|
41
|
-
milestone_id: z.number().int().positive().optional(),
|
|
42
|
-
steps: z.array(TestStepSchema).optional(),
|
|
43
|
-
steps_type: z.enum(['classic', 'gherkin']).optional(),
|
|
44
|
-
tags: z.array(z.string()).optional(),
|
|
45
|
-
attachments: z.array(z.string()).optional(),
|
|
46
|
-
custom_field: z.record(z.any()).optional(),
|
|
47
|
-
});
|
|
7
|
+
import { CaseFieldsSchema, applyAutomationMapping } from './case-fields.js';
|
|
48
8
|
const UpsertSchema = z.object({
|
|
49
9
|
code: ProjectCodeSchema,
|
|
50
10
|
id: IdSchema.optional().describe('Case ID — if provided, updates the case; if omitted, creates a new one'),
|
|
@@ -54,35 +14,6 @@ const DeleteSchema = z.object({
|
|
|
54
14
|
code: ProjectCodeSchema,
|
|
55
15
|
id: IdSchema,
|
|
56
16
|
});
|
|
57
|
-
/**
|
|
58
|
-
* Map the user-facing `automation` enum (0=Manual, 1=To be automated,
|
|
59
|
-
* 2=Automated) to the current API contract (`isManual` + `isToBeAutomated`).
|
|
60
|
-
* The legacy `automation` field is deprecated in qase-api-client and dropped
|
|
61
|
-
* from the outbound payload.
|
|
62
|
-
*/
|
|
63
|
-
function applyAutomationMapping(caseData) {
|
|
64
|
-
const automationId = caseData.automation;
|
|
65
|
-
if (typeof automationId !== 'number') {
|
|
66
|
-
return caseData;
|
|
67
|
-
}
|
|
68
|
-
const { automation: _drop, ...rest } = caseData;
|
|
69
|
-
const mapped = rest;
|
|
70
|
-
switch (automationId) {
|
|
71
|
-
case 2: // Automated
|
|
72
|
-
mapped.isManual = 0;
|
|
73
|
-
break;
|
|
74
|
-
case 1: // To be automated
|
|
75
|
-
mapped.isManual = 1;
|
|
76
|
-
mapped.isToBeAutomated = 1;
|
|
77
|
-
break;
|
|
78
|
-
case 0: // Manual
|
|
79
|
-
default:
|
|
80
|
-
mapped.isManual = 1;
|
|
81
|
-
mapped.isToBeAutomated = 0;
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
return mapped;
|
|
85
|
-
}
|
|
86
17
|
async function upsert(args) {
|
|
87
18
|
const client = getApiClient();
|
|
88
19
|
const { code, id, ...data } = args;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cases.js","sourceRoot":"","sources":["../../../src/operations-v2/write/cases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"cases.js","sourceRoot":"","sources":["../../../src/operations-v2/write/cases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE5E,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,IAAI,EAAE,iBAAiB;IACvB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAC9B,wEAAwE,CACzE;IACD,GAAG,gBAAgB,CAAC,KAAK;CAC1B,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,IAAI,EAAE,iBAAiB;IACvB,EAAE,EAAE,QAAQ;CACb,CAAC,CAAC;AAEH,KAAK,UAAU,MAAM,CAAC,IAAkC;IACtD,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACnC,MAAM,UAAU,GAAG,sBAAsB,CAAC,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;IAE1E,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,EAAE;QACA,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,EAAE,UAAiB,CAAC;QACtD,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,UAAiB,CAAC,CACrD,CAAC;IAEF,OAAO,MAAM,CAAC,KAAK,CACjB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EACpB,CAAC,CAAC,EAAE,EAAE;QACJ,MAAM,eAAe,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAC7C,CAAC,CACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,GAAG,CAAC,IAAkC;IACnD,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAChF,OAAO,MAAM,CAAC,KAAK,CACjB,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,EACtC,CAAC,CAAC,EAAE,EAAE;QACJ,MAAM,eAAe,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAC7C,CAAC,CACF,CAAC;AACJ,CAAC;AAED,YAAY,CAAC,QAAQ,CAAC;IACpB,IAAI,EAAE,kBAAkB;IACxB,WAAW,EACT,gFAAgF;QAChF,qFAAqF;QACrF,wFAAwF;IAC1F,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,MAAM;IACf,WAAW,EAAE,gBAAgB;CAC9B,CAAC,CAAC;AAEH,YAAY,CAAC,QAAQ,CAAC;IACpB,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,iDAAiD;IAC9D,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,gBAAgB;IAC7B,UAAU,EAAE,cAAc;CAC3B,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-issues.d.ts","sourceRoot":"","sources":["../../../src/operations-v2/write/external-issues.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getApiClient } from '../../client/index.js';
|
|
3
|
+
import { toolRegistry, UpdateAnnotation } from '../../utils/registry.js';
|
|
4
|
+
import { toResultAsync, createToolError } from '../../utils/errors.js';
|
|
5
|
+
import { ProjectCodeSchema, IdSchema } from '../../utils/validation.js';
|
|
6
|
+
const CONTEXT = 'external issue link operation';
|
|
7
|
+
const LinkSchema = z.object({
|
|
8
|
+
id: IdSchema.describe('Test case ID (entity="case") or test run ID (entity="run")'),
|
|
9
|
+
issues: z
|
|
10
|
+
.array(z.string().min(1))
|
|
11
|
+
.optional()
|
|
12
|
+
.describe('External issue keys, e.g. ["PROJ-1234"]. Required for cases (attach and detach) and ' +
|
|
13
|
+
'for attaching to a run — a run accepts exactly one issue. Omit when detaching a run.'),
|
|
14
|
+
});
|
|
15
|
+
const Schema = z.object({
|
|
16
|
+
code: ProjectCodeSchema,
|
|
17
|
+
entity: z.enum(['case', 'run']).describe('Entity to link — test case or test run'),
|
|
18
|
+
action: z
|
|
19
|
+
.enum(['attach', 'detach'])
|
|
20
|
+
.describe('attach creates the link, detach removes it (for runs, clears the single link)'),
|
|
21
|
+
type: z
|
|
22
|
+
.enum(['jira-cloud', 'jira-server'])
|
|
23
|
+
.describe('Issue tracker integration configured for the project'),
|
|
24
|
+
links: z.array(LinkSchema).min(1).describe('Entities to link, processed in a single API request'),
|
|
25
|
+
});
|
|
26
|
+
function requireIssues(link, entity) {
|
|
27
|
+
if (!link.issues?.length) {
|
|
28
|
+
throw createToolError(`No issues provided for ${entity} ${link.id} — "issues" must contain at least one external issue key (e.g. "PROJ-1234").`, CONTEXT);
|
|
29
|
+
}
|
|
30
|
+
return link.issues;
|
|
31
|
+
}
|
|
32
|
+
async function linkCases(args) {
|
|
33
|
+
const client = getApiClient();
|
|
34
|
+
const payload = {
|
|
35
|
+
type: args.type,
|
|
36
|
+
links: args.links.map((link) => ({
|
|
37
|
+
case_id: link.id,
|
|
38
|
+
external_issues: requireIssues(link, 'case'),
|
|
39
|
+
})),
|
|
40
|
+
};
|
|
41
|
+
const call = args.action === 'attach'
|
|
42
|
+
? client.cases.caseAttachExternalIssue(args.code, payload)
|
|
43
|
+
: client.cases.caseDetachExternalIssue(args.code, payload);
|
|
44
|
+
return toResultAsync(call);
|
|
45
|
+
}
|
|
46
|
+
async function linkRuns(args) {
|
|
47
|
+
const client = getApiClient();
|
|
48
|
+
const payload = {
|
|
49
|
+
type: args.type,
|
|
50
|
+
links: args.links.map((link) => {
|
|
51
|
+
if (args.action === 'detach') {
|
|
52
|
+
return { run_id: link.id, external_issue: null };
|
|
53
|
+
}
|
|
54
|
+
const issues = requireIssues(link, 'run');
|
|
55
|
+
if (issues.length > 1) {
|
|
56
|
+
throw createToolError(`A test run can have only one external issue link — ${issues.length} issues provided for run ${link.id}.`, CONTEXT);
|
|
57
|
+
}
|
|
58
|
+
return { run_id: link.id, external_issue: issues[0] };
|
|
59
|
+
}),
|
|
60
|
+
};
|
|
61
|
+
return toResultAsync(client.runs.runUpdateExternalIssue(args.code, payload));
|
|
62
|
+
}
|
|
63
|
+
async function handler(rawArgs) {
|
|
64
|
+
// Tool handlers get raw MCP arguments — validate here so a malformed call
|
|
65
|
+
// returns a readable error instead of a TypeError from deeper in the code.
|
|
66
|
+
const parsed = Schema.safeParse(rawArgs);
|
|
67
|
+
if (!parsed.success) {
|
|
68
|
+
const details = parsed.error.issues
|
|
69
|
+
.map((issue) => `${issue.path.join('.') || 'arguments'}: ${issue.message}`)
|
|
70
|
+
.join('; ');
|
|
71
|
+
throw createToolError(`Invalid arguments — ${details}`, CONTEXT);
|
|
72
|
+
}
|
|
73
|
+
const args = parsed.data;
|
|
74
|
+
const result = args.entity === 'case' ? await linkCases(args) : await linkRuns(args);
|
|
75
|
+
return result.match(() => ({
|
|
76
|
+
success: true,
|
|
77
|
+
entity: args.entity,
|
|
78
|
+
action: args.action,
|
|
79
|
+
linked: args.links.length,
|
|
80
|
+
}), (e) => {
|
|
81
|
+
throw createToolError(e, CONTEXT);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
toolRegistry.register({
|
|
85
|
+
name: 'qase_external_issue_link',
|
|
86
|
+
description: 'Link or unlink test cases and test runs to issues in an external tracker (Jira Cloud or ' +
|
|
87
|
+
'Jira Server). Use `entity` to choose between cases and runs and `action` to attach or ' +
|
|
88
|
+
'detach. A test case can be linked to several issues; a test run can have only one link, ' +
|
|
89
|
+
'and attaching a new issue replaces the previous one. Read linked issues back with ' +
|
|
90
|
+
'`qase_get` (entity "case" or "run").',
|
|
91
|
+
schema: Schema,
|
|
92
|
+
handler,
|
|
93
|
+
annotations: UpdateAnnotation,
|
|
94
|
+
visibility: 'discoverable',
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=external-issues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-issues.js","sourceRoot":"","sources":["../../../src/operations-v2/write/external-issues.ts"],"names":[],"mappings":"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"}
|
package/build/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "2.0.
|
|
1
|
+
export declare const VERSION = "2.0.1";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/build/version.js
CHANGED
package/docs/migration.md
CHANGED
|
@@ -41,7 +41,7 @@ All 83 v1 tools mapped to their v2 equivalents.
|
|
|
41
41
|
| `create_case` | `qase_case_upsert` (omit `id`) | Pass all case fields; no `id` = create |
|
|
42
42
|
| `update_case` | `qase_case_upsert` (include `id`) | Include `id` to update existing case |
|
|
43
43
|
| `delete_case` | `qase_case_delete` | — |
|
|
44
|
-
| `bulk_create_cases` | `
|
|
44
|
+
| `bulk_create_cases` | `qase_case_bulk_create` | Same shape: `cases` array, up to 100 per call |
|
|
45
45
|
| `attach_external_issue` | `qase_api` | Use escape hatch: `POST /case/{code}/{id}/external-issues` |
|
|
46
46
|
| `detach_external_issue` | `qase_api` | Use escape hatch: `DELETE /case/{code}/{id}/external-issues` |
|
|
47
47
|
|
package/docs/tools.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Tool Reference
|
|
2
2
|
|
|
3
|
-
The Qase MCP Server exposes **
|
|
3
|
+
The Qase MCP Server exposes **32 tools** across 6 groups: Read, QQL, Write, Composite, Escape hatch, and Meta.
|
|
4
4
|
|
|
5
5
|
## Discovery model
|
|
6
6
|
|
|
7
7
|
To keep context-token usage low, tools are split into two visibility tiers:
|
|
8
8
|
|
|
9
9
|
- **`core`** — always listed to the MCP client, no activation needed (13 tools).
|
|
10
|
-
- **`discoverable`** — hidden by default; the LLM finds and activates them on demand via `qase_discover_tools`, which searches tool names/descriptions and activates matches for the rest of the session (
|
|
10
|
+
- **`discoverable`** — hidden by default; the LLM finds and activates them on demand via `qase_discover_tools`, which searches tool names/descriptions and activates matches for the rest of the session (19 tools, mostly deletes and secondary write operations).
|
|
11
11
|
|
|
12
12
|
If a tool you need isn't showing up in your client's tool list, call `qase_discover_tools` with a query (e.g. `"delete"`, `"milestone"`, `"attachment"`) to activate it first.
|
|
13
13
|
|
|
@@ -17,7 +17,7 @@ Every tool's schema uses "label or numeric ID" strings for Qase's configurable e
|
|
|
17
17
|
|
|
18
18
|
| Tool | Description | Key params | Visibility |
|
|
19
19
|
| --- | --- | --- | --- |
|
|
20
|
-
| `qase_get` | Get any Qase entity by type and ID. Supports field projection via `fields`. `code` is required for project-scoped entities (case, suite, run, result, plan, defect, milestone, environment, shared_step, shared_parameter, configuration); optional for global entities (user, author, attachment, custom_field). | `entity` (enum: case, suite, run, result, plan, defect, milestone, environment, shared_step, shared_parameter, configuration, attachment, author, user, custom_field), `code` (optional), `id` (number or hash string), `fields` (optional string array — pass `["*"]` for all) | core |
|
|
20
|
+
| `qase_get` | Get any Qase entity by type and ID. Supports field projection via `fields`. `code` is required for project-scoped entities (case, suite, run, result, plan, defect, milestone, environment, shared_step, shared_parameter, configuration); optional for global entities (user, author, attachment, custom_field). Cases and runs automatically request their external issue links (`external_issues` / `external_issue`); override with `include`. | `entity` (enum: case, suite, run, result, plan, defect, milestone, environment, shared_step, shared_parameter, configuration, attachment, author, user, custom_field), `code` (optional), `id` (number or hash string), `fields` (optional string array — pass `["*"]` for all), `include` (optional string) | core |
|
|
21
21
|
| `qase_project_context` | Get full project context in one call: project details, suites tree, milestones, environments, custom fields, and users. Cached for 5 minutes. Recommended as the first call when starting work with a project. | `code` | core |
|
|
22
22
|
|
|
23
23
|
## QQL tools
|
|
@@ -30,11 +30,12 @@ Every tool's schema uses "label or numeric ID" strings for Qase's configurable e
|
|
|
30
30
|
## Write tools
|
|
31
31
|
|
|
32
32
|
<details>
|
|
33
|
-
<summary>Write tools (
|
|
33
|
+
<summary>Write tools (23)</summary>
|
|
34
34
|
|
|
35
35
|
| Tool | Description | Key params | Visibility |
|
|
36
36
|
| --- | --- | --- | --- |
|
|
37
37
|
| `qase_case_upsert` | Create or update a test case. If `id` is provided, updates the existing case; if omitted, creates a new one. Enum fields (priority, severity, type, etc.) accept both labels ("high", "blocker") and numeric IDs — the server normalizes automatically. | `code`, `id` (optional), `title` (1-255 chars), `description`, `preconditions`, `postconditions`, `severity`, `priority`, `type`, `layer`, `behavior`, `automation`, `status` (all label-or-ID strings), `is_flaky`, `suite_id`, `milestone_id`, `steps` (array, supports nesting), `steps_type` (enum: classic, gherkin), `tags`, `attachments`, `custom_field` | core |
|
|
38
|
+
| `qase_case_bulk_create` | Create up to 100 test cases in a single request. Use instead of calling `qase_case_upsert` repeatedly when importing or generating several cases at once. Enum fields accept labels or numeric IDs. Creates only — use `qase_case_upsert` with an `id` to update. Returns the IDs of the created cases in submission order. | `code`, `cases` (array, 1-100 — same fields as `qase_case_upsert` without `id`) | discoverable |
|
|
38
39
|
| `qase_case_delete` | Delete a test case by project code and case ID. | `code`, `id` | discoverable |
|
|
39
40
|
| `qase_defect_upsert` | Create or update a defect. If `id` is provided, updates (including status changes and resolve). If omitted, creates a new defect. Set `status: "resolved"` to resolve an existing defect. | `code`, `id` (optional), `title` (1-255 chars), `actual_result`, `severity` (enum, see [below](#case-enum-values)), `status` (enum: open, in_progress, resolved, invalid), `tags`, `attachments`, `custom_field` | core |
|
|
40
41
|
| `qase_defect_delete` | Delete a defect by project code and defect ID. | `code`, `id` | discoverable |
|
|
@@ -55,6 +56,7 @@ Every tool's schema uses "label or numeric ID" strings for Qase's configurable e
|
|
|
55
56
|
| `qase_environment_delete` | Delete a test environment by project code and environment ID. | `code`, `id` | discoverable |
|
|
56
57
|
| `qase_attachment_upload` | Upload a file attachment. Accepts the file as a base64 encoded string or an absolute path. Returns the attachment hash that can be referenced in test cases and results. | `code`, `file` (base64 string or absolute path), `filename` | discoverable |
|
|
57
58
|
| `qase_attachment_delete` | Delete an attachment by its hash. | `hash` | discoverable |
|
|
59
|
+
| `qase_external_issue_link` | Link or unlink test cases and test runs to issues in an external tracker (Jira Cloud or Jira Server). A case can be linked to several issues; a run can have only one link, and attaching a new issue replaces the previous one. Detaching a run clears its link. Read linked issues back with `qase_get`. | `code`, `entity` (enum: case, run), `action` (enum: attach, detach), `type` (enum: jira-cloud, jira-server), `links` (array: `id`, `issues` — issue keys such as `PROJ-1234`) | discoverable |
|
|
58
60
|
|
|
59
61
|
</details>
|
|
60
62
|
|
package/docs/troubleshooting.md
CHANGED
|
@@ -134,7 +134,7 @@ To find your certificate:
|
|
|
134
134
|
|
|
135
135
|
**Solution**:
|
|
136
136
|
1. Ensure you're using the latest version: `npm update -g @qase/mcp-server` (self-run) — the hosted connector always runs the latest version
|
|
137
|
-
2. If upgrading from v1, tool names have changed — see [
|
|
137
|
+
2. If upgrading from v1, tool names have changed — see [docs/migration.md](migration.md)
|
|
138
138
|
3. Restart your MCP client after updating
|
|
139
139
|
|
|
140
140
|
## Still stuck?
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qase/mcp-server",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"mcpName": "io.qase/mcp-server",
|
|
5
5
|
"description": "Official MCP server for Qase Test Management Platform",
|
|
6
6
|
"type": "module",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"jose": "^6.1.3",
|
|
75
75
|
"lru-cache": "^11.3.5",
|
|
76
76
|
"neverthrow": "^8.2.0",
|
|
77
|
-
"npm": "^12.0.
|
|
77
|
+
"npm": "^12.0.2",
|
|
78
78
|
"qase-api-client": "^1.1.10",
|
|
79
79
|
"zod": "^3.24.2",
|
|
80
80
|
"zod-to-json-schema": "^3.24.3"
|
package/server.json
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"url": "https://github.com/qase-tms/qase-mcp-server",
|
|
9
9
|
"source": "github"
|
|
10
10
|
},
|
|
11
|
-
"version": "2.0.
|
|
11
|
+
"version": "2.0.1",
|
|
12
12
|
"packages": [
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
15
|
"identifier": "@qase/mcp-server",
|
|
16
|
-
"version": "2.0.
|
|
16
|
+
"version": "2.0.1",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|
|
19
19
|
},
|