@qase/mcp-server 1.0.0 → 1.1.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 +34 -0
- package/README.md +151 -2
- package/build/client/index.d.ts +50 -6
- package/build/client/index.d.ts.map +1 -1
- package/build/client/index.js +114 -18
- package/build/client/index.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +170 -62
- package/build/index.js.map +1 -1
- package/build/operations/attachments.js +35 -16
- package/build/operations/attachments.js.map +1 -1
- package/build/operations/authors.js +4 -4
- package/build/operations/authors.js.map +1 -1
- package/build/operations/cases.js +75 -34
- package/build/operations/cases.js.map +1 -1
- package/build/operations/configurations.d.ts +2 -0
- package/build/operations/configurations.d.ts.map +1 -1
- package/build/operations/configurations.js +28 -8
- package/build/operations/configurations.js.map +1 -1
- package/build/operations/custom-fields.js +7 -7
- package/build/operations/custom-fields.js.map +1 -1
- package/build/operations/defects.js +59 -29
- package/build/operations/defects.js.map +1 -1
- package/build/operations/environments.js +7 -7
- package/build/operations/environments.js.map +1 -1
- package/build/operations/milestones.js +6 -6
- package/build/operations/milestones.js.map +1 -1
- package/build/operations/plans.js +6 -6
- package/build/operations/plans.js.map +1 -1
- package/build/operations/projects.js +8 -8
- package/build/operations/projects.js.map +1 -1
- package/build/operations/results.js +7 -7
- package/build/operations/results.js.map +1 -1
- package/build/operations/runs.js +16 -10
- package/build/operations/runs.js.map +1 -1
- package/build/operations/search.js +10 -13
- package/build/operations/search.js.map +1 -1
- package/build/operations/shared-parameters.d.ts +2 -0
- package/build/operations/shared-parameters.d.ts.map +1 -1
- package/build/operations/shared-parameters.js +30 -78
- package/build/operations/shared-parameters.js.map +1 -1
- package/build/operations/shared-steps.js +6 -6
- package/build/operations/shared-steps.js.map +1 -1
- package/build/operations/suites.js +6 -6
- package/build/operations/suites.js.map +1 -1
- package/build/operations/system-fields.d.ts +2 -0
- package/build/operations/system-fields.d.ts.map +1 -1
- package/build/operations/system-fields.js +8 -2
- package/build/operations/system-fields.js.map +1 -1
- package/build/operations/users.d.ts +2 -0
- package/build/operations/users.d.ts.map +1 -1
- package/build/operations/users.js +19 -11
- package/build/operations/users.js.map +1 -1
- package/build/transports/sse.d.ts +10 -0
- package/build/transports/sse.d.ts.map +1 -0
- package/build/transports/sse.js +38 -0
- package/build/transports/sse.js.map +1 -0
- package/build/transports/streamableHttp.d.ts +9 -0
- package/build/transports/streamableHttp.d.ts.map +1 -0
- package/build/transports/streamableHttp.js +169 -0
- package/build/transports/streamableHttp.js.map +1 -0
- package/build/utils/auth-context.d.ts +8 -0
- package/build/utils/auth-context.d.ts.map +1 -0
- package/build/utils/auth-context.js +8 -0
- package/build/utils/auth-context.js.map +1 -0
- package/build/utils/case-enums.d.ts +6 -0
- package/build/utils/case-enums.d.ts.map +1 -0
- package/build/utils/case-enums.js +91 -0
- package/build/utils/case-enums.js.map +1 -0
- package/build/utils/errors.d.ts +25 -0
- package/build/utils/errors.d.ts.map +1 -1
- package/build/utils/errors.js +78 -0
- package/build/utils/errors.js.map +1 -1
- package/build/utils/registry.d.ts.map +1 -1
- package/build/utils/registry.js +4 -0
- package/build/utils/registry.js.map +1 -1
- package/build/utils/test-helpers.d.ts +2 -2
- package/build/utils/test-helpers.d.ts.map +1 -1
- package/build/utils/test-helpers.js +16 -0
- package/build/utils/test-helpers.js.map +1 -1
- package/package.json +17 -5
- package/server.json +36 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,39 @@ 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
|
+
## [1.1.0]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Per-request authentication: clients can pass `Authorization: Bearer <token>` to use their own Qase API token instead of the shared `QASE_API_TOKEN` environment variable (supported on both Streamable HTTP and SSE transports)
|
|
13
|
+
- `create_case`, `update_case`: Added `steps_type` field (`classic` / `gherkin`) ([#17](https://github.com/qase-tms/qase-mcp-server/issues/17))
|
|
14
|
+
- 87 schema-API contract tests to prevent future type drift between Zod schemas and SDK expectations
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **Breaking (internal):** Replaced deprecated `qaseio` SDK with `qase-api-client` — the new auto-generated OpenAPI client for Qase API v1
|
|
19
|
+
- `QaseApiClient` wrapper now instantiates all 18 API classes (`ProjectsApi`, `CasesApi`, `ConfigurationsApi`, `SystemFieldsApi`, `UsersApi`, `SharedParametersApi`, etc.) instead of relying on the old `QaseApi` facade
|
|
20
|
+
- `list_users`, `get_user`: Now use `UsersApi` from the SDK instead of direct HTTP calls
|
|
21
|
+
- `list_shared_parameters`, `get_shared_parameter`: Now use `SharedParametersApi` from the SDK instead of direct HTTP calls
|
|
22
|
+
- `list_system_fields`: Now uses `SystemFieldsApi` from the SDK instead of direct HTTP calls
|
|
23
|
+
- `list_configurations`, `create_configuration_group`: Now use `ConfigurationsApi` from the SDK instead of direct HTTP calls
|
|
24
|
+
- `qql_search`: Updated to positional arguments `search(query, limit, offset)` per new SDK signature
|
|
25
|
+
- Case enum resolution (`normalizeCaseEnums`): Now fetches system fields via `SystemFieldsApi` instead of direct HTTP calls
|
|
26
|
+
- `create_case`, `update_case`: Enum fields (`severity`, `priority`, `type`, `layer`, `behavior`, `status`) now accept human-readable string labels instead of numeric IDs; `normalizeCaseEnums` resolves labels to IDs via system fields ([#13](https://github.com/qase-tms/qase-mcp-server/issues/13))
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- `list_defects`: Corrected API call signature (status as single value, not array) and removed unsupported severity filter
|
|
31
|
+
- `list_custom_fields`: Fixed argument order — was passing `(limit, offset)` where SDK expects `(entity, type, limit, offset)`
|
|
32
|
+
- `list_environments`: Fixed argument order — was passing `(code, limit, offset)` where SDK expects `(code, search, slug, limit, offset)`
|
|
33
|
+
- `list_authors`: Fixed argument order — was passing `(limit, offset)` where SDK expects `(search, type, limit, offset)`
|
|
34
|
+
- `TestCaseexternalIssuesTypeEnum` → `TestCaseExternalIssuesTypeEnum`: Fixed enum name casing for the new SDK
|
|
35
|
+
- `upload_attachment`: Fixed "file.forEach is not a function" crash — now correctly converts base64 string or file path into the `[{name, value}]` array format expected by the SDK's multipart upload ([#14](https://github.com/qase-tms/qase-mcp-server/issues/14))
|
|
36
|
+
- `create_defect`, `update_defect`: `severity` now accepts human-readable labels (`blocker`, `critical`, `major`, `normal`, `minor`, `trivial`) instead of numeric IDs; converted to numbers internally ([#18](https://github.com/qase-tms/qase-mcp-server/issues/18))
|
|
37
|
+
- `create_run`: Changed `start_time` / `end_time` from number to string (RFC 3339 format) matching SDK type
|
|
38
|
+
- `qql_search`: Removed non-existent fields from response to prevent confusion
|
|
39
|
+
- `list_attachments`: Added default `limit=10` to prevent slow responses on accounts with large numbers of attachments
|
|
40
|
+
|
|
8
41
|
## [1.0.0] - 2025-10-08
|
|
9
42
|
|
|
10
43
|
### Added
|
|
@@ -162,4 +195,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
162
195
|
- Results are identified by hash, not numeric ID
|
|
163
196
|
- Custom fields accessed via bracket notation in QQL: `cf["Field Name"]`
|
|
164
197
|
|
|
198
|
+
[1.1.0]: https://github.com/qase-tms/qase-mcp-server/compare/v1.0.0...v1.1.0
|
|
165
199
|
[1.0.0]: https://github.com/qase-tms/qase-mcp-server/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -149,9 +149,47 @@ Or, if installed from source:
|
|
|
149
149
|
|
|
150
150
|
### Claude Code
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
You can add the Qase MCP server to Claude Code using the CLI command:
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
```bash
|
|
155
|
+
claude mcp add qase -- npx -y @qase/mcp-server
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Set the required environment variable:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
export QASE_API_TOKEN=your_api_token_here
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Alternatively, add a `.mcp.json` file to your project root for automatic project-scoped configuration:
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"mcpServers": {
|
|
169
|
+
"qase": {
|
|
170
|
+
"command": "npx",
|
|
171
|
+
"args": ["-y", "@qase/mcp-server"],
|
|
172
|
+
"env": {
|
|
173
|
+
"QASE_API_TOKEN": "your_api_token_here"
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
You can also use the `--scope` flag to choose where the configuration is stored:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# Project-scoped (saved in .mcp.json)
|
|
184
|
+
claude mcp add --scope project qase -- npx -y @qase/mcp-server
|
|
185
|
+
|
|
186
|
+
# User-scoped (available in all projects)
|
|
187
|
+
claude mcp add --scope user qase -- npx -y @qase/mcp-server
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### OpenAI Codex CLI
|
|
191
|
+
|
|
192
|
+
Add a `.codex/config.json` file to your project root:
|
|
155
193
|
|
|
156
194
|
```json
|
|
157
195
|
{
|
|
@@ -167,6 +205,32 @@ Add to your MCP configuration:
|
|
|
167
205
|
}
|
|
168
206
|
```
|
|
169
207
|
|
|
208
|
+
Set the required environment variable before running Codex:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
export QASE_API_TOKEN=your_api_token_here
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### OpenCode
|
|
215
|
+
|
|
216
|
+
Add an `opencode.json` file to your project root (or `~/.config/opencode/opencode.json` for global configuration):
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"mcp": {
|
|
221
|
+
"qase": {
|
|
222
|
+
"type": "local",
|
|
223
|
+
"command": ["npx", "-y", "@qase/mcp-server"],
|
|
224
|
+
"environment": {
|
|
225
|
+
"QASE_API_TOKEN": "your_api_token_here"
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
> **Note:** OpenCode uses a different format from other MCP clients — the command and args are combined into a single `command` array, env vars go under `environment`, and servers are nested under `mcp` (not `mcpServers`).
|
|
233
|
+
|
|
170
234
|
## Usage Examples
|
|
171
235
|
|
|
172
236
|
### Basic Operations
|
|
@@ -242,6 +306,13 @@ Create a test run in project DEMO called "Sprint 24 Regression" including all te
|
|
|
242
306
|
- `attach_external_issue` - Link external issue (Jira, etc.)
|
|
243
307
|
- `detach_external_issue` - Unlink external issue
|
|
244
308
|
|
|
309
|
+
### Case enum values
|
|
310
|
+
|
|
311
|
+
`create_case`, `bulk_create_cases`, and `update_case` automatically normalize friendly labels to whatever numeric IDs your workspace currently configures for the built-in system fields (`priority`, `severity`, `type`, `behavior`, `status`, `layer`). The server fetches `/v1/system_field` and caches the available options so you can keep using the titles or slugs you see in Qase while still satisfying the API’s numeric requirements.
|
|
312
|
+
|
|
313
|
+
The normalization does not touch `automation`/`is_flaky`, so pass those values as the API expects (strings or booleans).
|
|
314
|
+
The server keeps any existing label in place when it does not match a known enum so invalid values still bubble up as errors from Qase.
|
|
315
|
+
|
|
245
316
|
### Test Runs (7 tools)
|
|
246
317
|
- `list_runs` - List test runs
|
|
247
318
|
- `get_run` - Get run details
|
|
@@ -365,6 +436,52 @@ npm run inspector
|
|
|
365
436
|
|
|
366
437
|
Set your API token when prompted, then interact with tools in the inspector UI.
|
|
367
438
|
|
|
439
|
+
### Transport Options
|
|
440
|
+
|
|
441
|
+
The server supports multiple transport types for different use cases:
|
|
442
|
+
|
|
443
|
+
#### Stdio Transport (Default)
|
|
444
|
+
|
|
445
|
+
Used by MCP clients like Claude Desktop and Cursor:
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
npm start
|
|
449
|
+
# or
|
|
450
|
+
npm run start:stdio
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
#### SSE Transport
|
|
454
|
+
|
|
455
|
+
Server-Sent Events for web-based clients:
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
npm run start:sse
|
|
459
|
+
# Server runs on http://localhost:3000/sse
|
|
460
|
+
# Health check: http://localhost:3000/health
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
#### Streamable HTTP Transport
|
|
464
|
+
|
|
465
|
+
Full HTTP-based transport with session management:
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
npm run start:http
|
|
469
|
+
# Server runs on http://localhost:3000/mcp
|
|
470
|
+
# Health check: http://localhost:3000/health
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
#### Custom Configuration
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
# Custom port and host
|
|
477
|
+
node build/index.js --transport streamable-http --port 8080 --host 0.0.0.0
|
|
478
|
+
|
|
479
|
+
# Available options:
|
|
480
|
+
# --transport: stdio | sse | streamable-http (default: stdio)
|
|
481
|
+
# --port: Port number (default: 3000)
|
|
482
|
+
# --host: Host address (default: 0.0.0.0)
|
|
483
|
+
```
|
|
484
|
+
|
|
368
485
|
## Troubleshooting
|
|
369
486
|
|
|
370
487
|
### Authentication Errors
|
|
@@ -385,6 +502,38 @@ Set your API token when prompted, then interact with tools in the inspector UI.
|
|
|
385
502
|
2. Verify the API domain is correct (especially for enterprise customers)
|
|
386
503
|
3. Check if Qase is accessible: https://api.qase.io/v1/
|
|
387
504
|
|
|
505
|
+
### SSL Certificate Errors
|
|
506
|
+
|
|
507
|
+
**Error**: `unable to get local issuer certificate`
|
|
508
|
+
|
|
509
|
+
This error typically occurs in corporate environments with:
|
|
510
|
+
- SSL-intercepting proxy servers
|
|
511
|
+
- Self-signed certificates
|
|
512
|
+
- Internal Certificate Authorities (CA)
|
|
513
|
+
|
|
514
|
+
**Solution**: Add the `NODE_EXTRA_CA_CERTS` environment variable pointing to your CA certificate file:
|
|
515
|
+
|
|
516
|
+
```json
|
|
517
|
+
{
|
|
518
|
+
"mcpServers": {
|
|
519
|
+
"qase": {
|
|
520
|
+
"command": "npx",
|
|
521
|
+
"args": ["-y", "@qase/mcp-server"],
|
|
522
|
+
"env": {
|
|
523
|
+
"QASE_API_TOKEN": "your_api_token_here",
|
|
524
|
+
"NODE_EXTRA_CA_CERTS": "/path/to/your/certificate.pem"
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
To find your certificate:
|
|
532
|
+
- **Corporate environments**: Contact your IT department for the CA certificate
|
|
533
|
+
- **macOS**: Export from Keychain Access (System Roots → your CA → Export as .pem)
|
|
534
|
+
- **Windows**: Export from Certificate Manager (certmgr.msc)
|
|
535
|
+
- **Linux**: Usually in `/etc/ssl/certs/` or `/etc/pki/tls/certs/`
|
|
536
|
+
|
|
388
537
|
### Custom Domain Issues
|
|
389
538
|
|
|
390
539
|
**Error**: `Invalid domain` or connection errors with custom domain
|
package/build/client/index.d.ts
CHANGED
|
@@ -3,21 +3,65 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Provides a singleton instance of the Qase API client with support for:
|
|
5
5
|
* - Token-based authentication
|
|
6
|
+
* - Per-request Bearer token authentication
|
|
6
7
|
* - Custom enterprise domains
|
|
7
8
|
* - Environment-based configuration
|
|
8
9
|
*/
|
|
9
|
-
import {
|
|
10
|
+
import { ProjectsApi, CasesApi, SuitesApi, RunsApi, ResultsApi, PlansApi, MilestonesApi, DefectsApi, EnvironmentsApi, AttachmentsApi, SharedStepsApi, AuthorsApi, CustomFieldsApi, SearchApi, ConfigurationsApi, SystemFieldsApi, UsersApi, SharedParametersApi } from 'qase-api-client';
|
|
11
|
+
import { AxiosRequestConfig } from 'axios';
|
|
10
12
|
/**
|
|
11
|
-
*
|
|
13
|
+
* Configuration for the Qase API client
|
|
14
|
+
*/
|
|
15
|
+
interface ApiClientConfig {
|
|
16
|
+
token: string;
|
|
17
|
+
host: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Wrapper around qase-api-client that preserves the `client.resource.method()` interface.
|
|
21
|
+
*/
|
|
22
|
+
declare class QaseApiClient {
|
|
23
|
+
readonly projects: ProjectsApi;
|
|
24
|
+
readonly cases: CasesApi;
|
|
25
|
+
readonly suites: SuitesApi;
|
|
26
|
+
readonly runs: RunsApi;
|
|
27
|
+
readonly results: ResultsApi;
|
|
28
|
+
readonly plans: PlansApi;
|
|
29
|
+
readonly milestones: MilestonesApi;
|
|
30
|
+
readonly defects: DefectsApi;
|
|
31
|
+
readonly environment: EnvironmentsApi;
|
|
32
|
+
readonly attachments: AttachmentsApi;
|
|
33
|
+
readonly sharedSteps: SharedStepsApi;
|
|
34
|
+
readonly authors: AuthorsApi;
|
|
35
|
+
readonly customFields: CustomFieldsApi;
|
|
36
|
+
readonly search: SearchApi;
|
|
37
|
+
readonly configurations: ConfigurationsApi;
|
|
38
|
+
readonly systemFields: SystemFieldsApi;
|
|
39
|
+
readonly users: UsersApi;
|
|
40
|
+
readonly sharedParameters: SharedParametersApi;
|
|
41
|
+
private readonly token;
|
|
42
|
+
private readonly host;
|
|
43
|
+
constructor(config: ApiClientConfig);
|
|
44
|
+
/**
|
|
45
|
+
* Make a direct API call for endpoints not fully covered by the SDK.
|
|
46
|
+
*/
|
|
47
|
+
request<T = any>(path: string, options?: AxiosRequestConfig): Promise<T>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get or create the Qase API client instance.
|
|
51
|
+
*
|
|
52
|
+
* Auth priority:
|
|
53
|
+
* 1. Per-request Bearer token from Authorization header (set via AsyncLocalStorage)
|
|
54
|
+
* → creates a fresh QaseApiClient instance with the user's own token
|
|
55
|
+
* 2. Shared QASE_API_TOKEN env var (singleton, read-only fallback)
|
|
12
56
|
*
|
|
13
|
-
* @returns Configured
|
|
14
|
-
* @throws Error if QASE_API_TOKEN is
|
|
57
|
+
* @returns Configured QaseApiClient instance
|
|
58
|
+
* @throws Error if neither a request token nor QASE_API_TOKEN is available
|
|
15
59
|
*/
|
|
16
|
-
export declare function getApiClient():
|
|
60
|
+
export declare function getApiClient(): QaseApiClient;
|
|
17
61
|
/**
|
|
18
62
|
* Reset the client instance (useful for testing)
|
|
19
63
|
* @internal
|
|
20
64
|
*/
|
|
21
65
|
export declare function resetClientInstance(): void;
|
|
22
|
-
export type {
|
|
66
|
+
export type { QaseApiClient };
|
|
23
67
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAEL,WAAW,EACX,QAAQ,EACR,SAAS,EACT,OAAO,EACP,UAAU,EACV,QAAQ,EACR,aAAa,EACb,UAAU,EACV,eAAe,EACf,cAAc,EACd,cAAc,EACd,UAAU,EACV,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,QAAQ,EACR,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AACzB,OAAc,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAIlD;;GAEG;AACH,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,cAAM,aAAa;IACjB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,iBAAiB,CAAC;IAC3C,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,gBAAgB,EAAE,mBAAmB,CAAC;IAE/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,MAAM,EAAE,eAAe;IA8BnC;;OAEG;IACG,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,CAAC,CAAC;CAcnF;AAqDD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,IAAI,aAAa,CAY5C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,YAAY,EAAE,aAAa,EAAE,CAAC"}
|
package/build/client/index.js
CHANGED
|
@@ -3,45 +3,141 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Provides a singleton instance of the Qase API client with support for:
|
|
5
5
|
* - Token-based authentication
|
|
6
|
+
* - Per-request Bearer token authentication
|
|
6
7
|
* - Custom enterprise domains
|
|
7
8
|
* - Environment-based configuration
|
|
8
9
|
*/
|
|
9
|
-
import {
|
|
10
|
+
import { Configuration, ProjectsApi, CasesApi, SuitesApi, RunsApi, ResultsApi, PlansApi, MilestonesApi, DefectsApi, EnvironmentsApi, AttachmentsApi, SharedStepsApi, AuthorsApi, CustomFieldsApi, SearchApi, ConfigurationsApi, SystemFieldsApi, UsersApi, SharedParametersApi, } from 'qase-api-client';
|
|
11
|
+
import axios from 'axios';
|
|
12
|
+
import FormData from 'form-data';
|
|
13
|
+
import { requestTokenStorage } from '../utils/auth-context.js';
|
|
10
14
|
/**
|
|
11
|
-
*
|
|
15
|
+
* Wrapper around qase-api-client that preserves the `client.resource.method()` interface.
|
|
12
16
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
class QaseApiClient {
|
|
18
|
+
projects;
|
|
19
|
+
cases;
|
|
20
|
+
suites;
|
|
21
|
+
runs;
|
|
22
|
+
results;
|
|
23
|
+
plans;
|
|
24
|
+
milestones;
|
|
25
|
+
defects;
|
|
26
|
+
environment;
|
|
27
|
+
attachments;
|
|
28
|
+
sharedSteps;
|
|
29
|
+
authors;
|
|
30
|
+
customFields;
|
|
31
|
+
search;
|
|
32
|
+
configurations;
|
|
33
|
+
systemFields;
|
|
34
|
+
users;
|
|
35
|
+
sharedParameters;
|
|
36
|
+
token;
|
|
37
|
+
host;
|
|
38
|
+
constructor(config) {
|
|
39
|
+
this.token = config.token;
|
|
40
|
+
this.host = config.host;
|
|
41
|
+
const cfg = new Configuration({
|
|
42
|
+
apiKey: config.token,
|
|
43
|
+
basePath: `${config.host}/v1`,
|
|
44
|
+
formDataCtor: FormData,
|
|
45
|
+
});
|
|
46
|
+
this.projects = new ProjectsApi(cfg);
|
|
47
|
+
this.cases = new CasesApi(cfg);
|
|
48
|
+
this.suites = new SuitesApi(cfg);
|
|
49
|
+
this.runs = new RunsApi(cfg);
|
|
50
|
+
this.results = new ResultsApi(cfg);
|
|
51
|
+
this.plans = new PlansApi(cfg);
|
|
52
|
+
this.milestones = new MilestonesApi(cfg);
|
|
53
|
+
this.defects = new DefectsApi(cfg);
|
|
54
|
+
this.environment = new EnvironmentsApi(cfg);
|
|
55
|
+
this.attachments = new AttachmentsApi(cfg);
|
|
56
|
+
this.sharedSteps = new SharedStepsApi(cfg);
|
|
57
|
+
this.authors = new AuthorsApi(cfg);
|
|
58
|
+
this.customFields = new CustomFieldsApi(cfg);
|
|
59
|
+
this.search = new SearchApi(cfg);
|
|
60
|
+
this.configurations = new ConfigurationsApi(cfg);
|
|
61
|
+
this.systemFields = new SystemFieldsApi(cfg);
|
|
62
|
+
this.users = new UsersApi(cfg);
|
|
63
|
+
this.sharedParameters = new SharedParametersApi(cfg);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Make a direct API call for endpoints not fully covered by the SDK.
|
|
67
|
+
*/
|
|
68
|
+
async request(path, options = {}) {
|
|
69
|
+
const response = await axios({
|
|
70
|
+
method: options.method || 'GET',
|
|
71
|
+
url: `${this.host}${path}`,
|
|
72
|
+
headers: {
|
|
73
|
+
Token: this.token,
|
|
74
|
+
'Content-Type': 'application/json',
|
|
75
|
+
...options.headers,
|
|
76
|
+
},
|
|
77
|
+
...options,
|
|
78
|
+
});
|
|
79
|
+
return response.data;
|
|
18
80
|
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get validated API host from QASE_API_DOMAIN env var.
|
|
84
|
+
*/
|
|
85
|
+
function getHost() {
|
|
19
86
|
const domain = process.env.QASE_API_DOMAIN || 'api.qase.io';
|
|
20
|
-
// Validate domain format (should not include protocol or path)
|
|
21
87
|
if (domain.includes('://') || domain.includes('/')) {
|
|
22
88
|
throw new Error('QASE_API_DOMAIN should only contain the domain name (e.g., api.qase.io), ' +
|
|
23
89
|
'not the full URL with protocol or path');
|
|
24
90
|
}
|
|
25
|
-
|
|
26
|
-
|
|
91
|
+
return `https://${domain}`;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get the effective API token for the current request.
|
|
95
|
+
*
|
|
96
|
+
* Priority:
|
|
97
|
+
* 1. Per-request Bearer token from Authorization header (AsyncLocalStorage)
|
|
98
|
+
* 2. Shared QASE_API_TOKEN environment variable
|
|
99
|
+
*/
|
|
100
|
+
function getEffectiveToken() {
|
|
101
|
+
const requestToken = requestTokenStorage.getStore();
|
|
102
|
+
if (requestToken) {
|
|
103
|
+
return requestToken;
|
|
104
|
+
}
|
|
105
|
+
const envToken = process.env.QASE_API_TOKEN;
|
|
106
|
+
if (!envToken) {
|
|
107
|
+
throw new Error('QASE_API_TOKEN environment variable is required. ' +
|
|
108
|
+
'Get your token from: https://app.qase.io/user/api/token');
|
|
109
|
+
}
|
|
110
|
+
return envToken;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get full API client config (token + host).
|
|
114
|
+
*/
|
|
115
|
+
function getConfig() {
|
|
116
|
+
return { token: getEffectiveToken(), host: getHost() };
|
|
27
117
|
}
|
|
28
118
|
/**
|
|
29
|
-
* Singleton API client instance
|
|
119
|
+
* Singleton API client instance (used for shared QASE_API_TOKEN fallback).
|
|
30
120
|
*/
|
|
31
121
|
let clientInstance = null;
|
|
32
122
|
/**
|
|
33
|
-
* Get or create the Qase API client instance
|
|
123
|
+
* Get or create the Qase API client instance.
|
|
34
124
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
125
|
+
* Auth priority:
|
|
126
|
+
* 1. Per-request Bearer token from Authorization header (set via AsyncLocalStorage)
|
|
127
|
+
* → creates a fresh QaseApiClient instance with the user's own token
|
|
128
|
+
* 2. Shared QASE_API_TOKEN env var (singleton, read-only fallback)
|
|
129
|
+
*
|
|
130
|
+
* @returns Configured QaseApiClient instance
|
|
131
|
+
* @throws Error if neither a request token nor QASE_API_TOKEN is available
|
|
37
132
|
*/
|
|
38
133
|
export function getApiClient() {
|
|
134
|
+
const requestToken = requestTokenStorage.getStore();
|
|
135
|
+
if (requestToken) {
|
|
136
|
+
return new QaseApiClient({ token: requestToken, host: getHost() });
|
|
137
|
+
}
|
|
39
138
|
if (!clientInstance) {
|
|
40
139
|
const config = getConfig();
|
|
41
|
-
clientInstance = new
|
|
42
|
-
token: config.token,
|
|
43
|
-
host: config.host,
|
|
44
|
-
});
|
|
140
|
+
clientInstance = new QaseApiClient({ token: config.token, host: config.host });
|
|
45
141
|
}
|
|
46
142
|
return clientInstance;
|
|
47
143
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* It exposes 90+ tools for managing projects, test cases, runs, results, defects, and more.
|
|
7
7
|
*
|
|
8
8
|
* Architecture:
|
|
9
|
-
* -
|
|
9
|
+
* - Supports multiple transports: stdio, sse, streamable-http
|
|
10
10
|
* - Tools are registered via the global tool registry
|
|
11
11
|
* - Operation modules self-register their tools on import
|
|
12
12
|
* - All API errors are handled gracefully with user-friendly messages
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;GAWG;AAWH,OAAO,0BAA0B,CAAC;AAClC,OAAO,uBAAuB,CAAC;AAC/B,OAAO,wBAAwB,CAAC;AAChC,OAAO,sBAAsB,CAAC;AAC9B,OAAO,yBAAyB,CAAC;AACjC,OAAO,uBAAuB,CAAC;AAC/B,OAAO,8BAA8B,CAAC;AACtC,OAAO,mCAAmC,CAAC;AAC3C,OAAO,4BAA4B,CAAC;AACpC,OAAO,yBAAyB,CAAC;AACjC,OAAO,8BAA8B,CAAC;AACtC,OAAO,6BAA6B,CAAC;AACrC,OAAO,yBAAyB,CAAC;AACjC,OAAO,+BAA+B,CAAC;AACvC,OAAO,+BAA+B,CAAC;AACvC,OAAO,gCAAgC,CAAC;AACxC,OAAO,uBAAuB,CAAC;AAC/B,OAAO,wBAAwB,CAAC"}
|