@uarlouski/testrail-mcp-server 1.2.0 → 1.3.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/README.md +12 -2
- package/dist/client/testrail.js +167 -0
- package/{src/index.ts → dist/index.js} +35 -35
- package/dist/tools/add_attachment_to_run.js +52 -0
- package/dist/tools/add_results.js +24 -0
- package/dist/tools/add_run.js +19 -0
- package/dist/tools/create_case.js +23 -0
- package/{src/tools/get_case.ts → dist/tools/get_case.js} +3 -12
- package/{src/tools/get_case_fields.ts → dist/tools/get_case_fields.js} +8 -37
- package/{src/tools/get_cases.ts → dist/tools/get_cases.js} +10 -24
- package/{src/tools/get_projects.ts → dist/tools/get_projects.js} +3 -10
- package/{src/tools/get_sections.ts → dist/tools/get_sections.js} +4 -11
- package/dist/tools/get_statuses.js +13 -0
- package/dist/tools/get_templates.js +16 -0
- package/dist/tools/get_tests.js +17 -0
- package/{src/tools/update_case.ts → dist/tools/update_case.js} +2 -8
- package/{src/tools/update_cases.ts → dist/tools/update_cases.js} +4 -8
- package/dist/types/custom.js +1 -0
- package/{src/types/testrail.ts → dist/types/testrail.js} +37 -24
- package/{src/utils/mapper.ts → dist/utils/mapper.js} +16 -36
- package/{src/utils/sanitizer.ts → dist/utils/sanitizer.js} +4 -8
- package/package.json +10 -2
- package/.env.example +0 -3
- package/.github/workflows/ci.yml +0 -46
- package/.github/workflows/publish.yml +0 -35
- package/CHANGELOG.md +0 -27
- package/jest.config.js +0 -24
- package/src/client/testrail.ts +0 -161
- package/src/tools/create_case.ts +0 -29
- package/src/tools/get_templates.ts +0 -23
- package/src/types/custom.ts +0 -19
- package/test/client/testrail.test.ts +0 -430
- package/test/tools/create_case.test.ts +0 -101
- package/test/tools/get_case.test.ts +0 -185
- package/test/tools/get_case_fields.test.ts +0 -132
- package/test/tools/get_cases.test.ts +0 -104
- package/test/tools/get_projects.test.ts +0 -38
- package/test/tools/get_sections.test.ts +0 -39
- package/test/tools/get_templates.test.ts +0 -38
- package/test/tools/update_case.test.ts +0 -102
- package/test/tools/update_cases.test.ts +0 -61
- package/test/utils/mapper.test.ts +0 -112
- package/test/utils/sanitizer.test.ts +0 -143
- package/tsconfig.json +0 -24
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { TestRailClient } from "../client/testrail.js";
|
|
3
|
-
import { ToolDefinition } from "../types/custom.js";
|
|
4
2
|
import { SectionSchema } from "../types/testrail.js";
|
|
5
|
-
|
|
6
3
|
const parameters = {
|
|
7
|
-
project_id: z.string().describe("The ID of the project"),
|
|
4
|
+
project_id: z.string().describe("The ID of the project. Use get_projects to find available projects"),
|
|
8
5
|
};
|
|
9
|
-
|
|
10
|
-
export const getSectionsTool: ToolDefinition<typeof parameters, TestRailClient> = {
|
|
6
|
+
export const getSectionsTool = {
|
|
11
7
|
name: "get_sections",
|
|
12
|
-
description: "Get all sections for a project. Returns section IDs and names
|
|
8
|
+
description: "Get all sections for a project. Returns section IDs and names that can be used with create_case",
|
|
13
9
|
parameters,
|
|
14
10
|
handler: async ({ project_id }, client) => {
|
|
15
11
|
const sections = await client.getSections(project_id);
|
|
16
|
-
|
|
17
|
-
const response = {
|
|
12
|
+
return {
|
|
18
13
|
sections: sections.map(s => SectionSchema.parse(s)),
|
|
19
14
|
};
|
|
20
|
-
|
|
21
|
-
return response;
|
|
22
15
|
}
|
|
23
16
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StatusSchema } from "../types/testrail.js";
|
|
2
|
+
const parameters = {};
|
|
3
|
+
export const getStatusesTool = {
|
|
4
|
+
name: "get_statuses",
|
|
5
|
+
description: "Get all available test statuses (e.g. Passed, Failed, Blocked). Returns status IDs and names that can be used with add_result and get_tests",
|
|
6
|
+
parameters,
|
|
7
|
+
handler: async (args, client) => {
|
|
8
|
+
const statuses = await client.getStatuses();
|
|
9
|
+
return {
|
|
10
|
+
statuses: statuses.map(s => StatusSchema.parse(s)),
|
|
11
|
+
};
|
|
12
|
+
},
|
|
13
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { TemplateSchema } from "../types/testrail.js";
|
|
3
|
+
const parameters = {
|
|
4
|
+
project_id: z.string().describe("The ID of the project. Use get_projects to find available projects"),
|
|
5
|
+
};
|
|
6
|
+
export const getTemplatesTool = {
|
|
7
|
+
name: "get_templates",
|
|
8
|
+
description: "Get available test case templates for a project. Template IDs determine which fields are available when creating or updating test cases",
|
|
9
|
+
parameters,
|
|
10
|
+
handler: async ({ project_id }, client) => {
|
|
11
|
+
const templates = await client.getTemplates(project_id);
|
|
12
|
+
return {
|
|
13
|
+
templates: templates.map(t => TemplateSchema.parse(t)),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { TestSchema } from "../types/testrail.js";
|
|
3
|
+
const parameters = {
|
|
4
|
+
run_id: z.number().describe("The ID of the test run"),
|
|
5
|
+
status_id: z.array(z.number()).optional().describe("Optional array of status IDs to filter by. Use get_statuses to retrieve available status IDs"),
|
|
6
|
+
};
|
|
7
|
+
export const getTestsTool = {
|
|
8
|
+
name: "get_tests",
|
|
9
|
+
description: "Get tests for a test run, optionally filtered by status",
|
|
10
|
+
parameters,
|
|
11
|
+
handler: async ({ run_id, status_id }, client) => {
|
|
12
|
+
const tests = await client.getTests(run_id, status_id);
|
|
13
|
+
return {
|
|
14
|
+
tests: tests.map(test => TestSchema.parse(test)),
|
|
15
|
+
};
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { TestRailClient } from "../client/testrail.js";
|
|
3
|
-
import { ToolDefinition } from "../types/custom.js";
|
|
4
|
-
|
|
5
2
|
const parameters = {
|
|
6
3
|
case_id: z.string().describe("The ID of the test case to update (e.g. '123' or 'C123')"),
|
|
7
4
|
fields: z.record(z.string(), z.any()).describe("Object containing fields to update. Use get_case_fields to see available fields. Example: {\"title\": \"New title\", \"priority_id\": 2, \"custom_automation_priority\": 1}"),
|
|
8
5
|
};
|
|
9
|
-
|
|
10
|
-
export const updateCaseTool: ToolDefinition<typeof parameters, TestRailClient> = {
|
|
6
|
+
export const updateCaseTool = {
|
|
11
7
|
name: "update_case",
|
|
12
|
-
description: "Update a test case in TestRail. Supports partial updates - only specify the fields you want to change
|
|
8
|
+
description: "Update a test case in TestRail. Supports partial updates - only specify the fields you want to change",
|
|
13
9
|
parameters,
|
|
14
10
|
handler: async ({ case_id, fields }, client) => {
|
|
15
11
|
const id = case_id.toUpperCase().startsWith("C") ? case_id.substring(1) : case_id;
|
|
16
|
-
|
|
17
12
|
const updatedCase = await client.updateCase(id, fields);
|
|
18
|
-
|
|
19
13
|
return {
|
|
20
14
|
success: true,
|
|
21
15
|
case_id: updatedCase.id,
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { TestRailClient } from "../client/testrail.js";
|
|
3
|
-
import { ToolDefinition } from "../types/custom.js";
|
|
4
|
-
|
|
5
2
|
const parameters = {
|
|
6
3
|
case_ids: z.array(z.number()).describe("Array of case IDs to update (e.g. [123, 456, 789])"),
|
|
7
4
|
fields: z.record(z.string(), z.any()).describe("Object containing fields to update for ALL specified cases. Use get_case_fields to see available fields. Example: {\"priority_id\": 2, \"type_id\": 1}"),
|
|
8
5
|
};
|
|
9
|
-
|
|
10
|
-
export const updateCasesTool: ToolDefinition<typeof parameters, TestRailClient> = {
|
|
6
|
+
export const updateCasesTool = {
|
|
11
7
|
name: "update_cases",
|
|
12
|
-
description: "Bulk update multiple test cases with the same field values. More efficient than calling update_case multiple times
|
|
8
|
+
description: "Bulk update multiple test cases with the same field values. More efficient than calling update_case multiple times",
|
|
13
9
|
parameters,
|
|
14
10
|
handler: async ({ case_ids, fields }, client) => {
|
|
15
|
-
const
|
|
16
|
-
|
|
11
|
+
const caseData = await client.getCase(String(case_ids[0]));
|
|
12
|
+
const updatedCases = await client.updateCases(caseData.suite_id, case_ids, fields);
|
|
17
13
|
return {
|
|
18
14
|
success: true,
|
|
19
15
|
updated_count: updatedCases.length,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
|
|
3
2
|
export const CaseFieldConfigSchema = z.object({
|
|
4
3
|
options: z.object({
|
|
5
4
|
default_value: z.string().optional(),
|
|
@@ -7,9 +6,6 @@ export const CaseFieldConfigSchema = z.object({
|
|
|
7
6
|
items: z.string().optional(),
|
|
8
7
|
}),
|
|
9
8
|
});
|
|
10
|
-
|
|
11
|
-
export type CaseFieldConfig = z.infer<typeof CaseFieldConfigSchema>;
|
|
12
|
-
|
|
13
9
|
export const CaseFieldSchema = z.object({
|
|
14
10
|
id: z.number(),
|
|
15
11
|
name: z.string(),
|
|
@@ -22,9 +18,6 @@ export const CaseFieldSchema = z.object({
|
|
|
22
18
|
include_all: z.boolean(),
|
|
23
19
|
configs: z.array(CaseFieldConfigSchema),
|
|
24
20
|
});
|
|
25
|
-
|
|
26
|
-
export type CaseField = z.infer<typeof CaseFieldSchema>;
|
|
27
|
-
|
|
28
21
|
export const CaseSchema = z.object({
|
|
29
22
|
id: z.number(),
|
|
30
23
|
title: z.string(),
|
|
@@ -40,9 +33,6 @@ export const CaseSchema = z.object({
|
|
|
40
33
|
suite_id: z.number(),
|
|
41
34
|
labels: z.array(z.any()),
|
|
42
35
|
}).loose();
|
|
43
|
-
|
|
44
|
-
export type Case = z.infer<typeof CaseSchema>;
|
|
45
|
-
|
|
46
36
|
export const SectionSchema = z.object({
|
|
47
37
|
id: z.number(),
|
|
48
38
|
name: z.string(),
|
|
@@ -50,38 +40,61 @@ export const SectionSchema = z.object({
|
|
|
50
40
|
parent_id: z.number().nullish(),
|
|
51
41
|
suite_id: z.number(),
|
|
52
42
|
});
|
|
53
|
-
|
|
54
|
-
export type Section = z.infer<typeof SectionSchema>;
|
|
55
|
-
|
|
56
43
|
export const PrioritySchema = z.object({
|
|
57
44
|
id: z.number(),
|
|
58
45
|
is_default: z.boolean(),
|
|
59
46
|
name: z.string(),
|
|
60
47
|
});
|
|
61
|
-
|
|
62
|
-
export type Priority = z.infer<typeof PrioritySchema>;
|
|
63
|
-
|
|
64
48
|
export const CaseTypeSchema = z.object({
|
|
65
49
|
id: z.number(),
|
|
66
50
|
is_default: z.boolean(),
|
|
67
51
|
name: z.string(),
|
|
68
52
|
});
|
|
69
|
-
|
|
70
|
-
export type CaseType = z.infer<typeof CaseTypeSchema>;
|
|
71
|
-
|
|
72
53
|
export const TemplateSchema = z.object({
|
|
73
54
|
id: z.number(),
|
|
74
55
|
name: z.string(),
|
|
75
56
|
is_default: z.boolean(),
|
|
76
57
|
});
|
|
77
|
-
|
|
78
|
-
export type Template = z.infer<typeof TemplateSchema>;
|
|
79
|
-
|
|
80
58
|
export const ProjectSchema = z.object({
|
|
81
59
|
id: z.number(),
|
|
82
60
|
name: z.string(),
|
|
83
61
|
is_completed: z.boolean(),
|
|
84
62
|
suite_mode: z.number(),
|
|
85
63
|
});
|
|
86
|
-
|
|
87
|
-
|
|
64
|
+
export const RunSchema = z.object({
|
|
65
|
+
id: z.number(),
|
|
66
|
+
name: z.string(),
|
|
67
|
+
description: z.string().nullable(),
|
|
68
|
+
suite_id: z.number().nullable(),
|
|
69
|
+
project_id: z.number(),
|
|
70
|
+
is_completed: z.boolean(),
|
|
71
|
+
passed_count: z.number(),
|
|
72
|
+
blocked_count: z.number(),
|
|
73
|
+
untested_count: z.number(),
|
|
74
|
+
retest_count: z.number(),
|
|
75
|
+
failed_count: z.number(),
|
|
76
|
+
url: z.string(),
|
|
77
|
+
});
|
|
78
|
+
export const StatusSchema = z.object({
|
|
79
|
+
id: z.number(),
|
|
80
|
+
name: z.string(),
|
|
81
|
+
label: z.string(),
|
|
82
|
+
});
|
|
83
|
+
export const TestSchema = z.object({
|
|
84
|
+
id: z.number(),
|
|
85
|
+
case_id: z.number(),
|
|
86
|
+
status_id: z.number(),
|
|
87
|
+
title: z.string(),
|
|
88
|
+
run_id: z.number(),
|
|
89
|
+
});
|
|
90
|
+
export const TestsSchema = z.array(TestSchema);
|
|
91
|
+
export const ResultSchema = z.object({
|
|
92
|
+
id: z.number(),
|
|
93
|
+
test_id: z.number(),
|
|
94
|
+
status_id: z.number(),
|
|
95
|
+
comment: z.string().nullable(),
|
|
96
|
+
defects: z.string().nullable(),
|
|
97
|
+
});
|
|
98
|
+
export const AttachmentSchema = z.object({
|
|
99
|
+
attachment_id: z.number(),
|
|
100
|
+
});
|
|
@@ -1,73 +1,55 @@
|
|
|
1
|
-
import { Case, CaseField } from "../types/testrail.js";
|
|
2
1
|
import { sanitizeValue } from "./sanitizer.js";
|
|
3
|
-
|
|
4
2
|
/**
|
|
5
3
|
* Processes custom fields from a test case, converting system names to human-readable labels
|
|
6
4
|
* and mapping dropdown values to their display text.
|
|
7
5
|
*/
|
|
8
|
-
export function processCustomFields(
|
|
9
|
-
testCase: Case,
|
|
10
|
-
caseFields: CaseField[]
|
|
11
|
-
): Record<string, any> {
|
|
6
|
+
export function processCustomFields(testCase, caseFields) {
|
|
12
7
|
if (!testCase) {
|
|
13
8
|
throw new Error("Test case is undefined or null");
|
|
14
9
|
}
|
|
15
|
-
|
|
16
10
|
const templateId = testCase.template_id;
|
|
17
|
-
const result
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
const fieldNameMap = new Map<string, string>();
|
|
24
|
-
const dropdownOptionsMap = new Map<string, Map<string, string>>();
|
|
25
|
-
|
|
11
|
+
const result = {};
|
|
12
|
+
const applicableFields = caseFields.filter(field => field.include_all || field.template_ids.includes(templateId));
|
|
13
|
+
const fieldNameMap = new Map();
|
|
14
|
+
const dropdownOptionsMap = new Map();
|
|
26
15
|
for (const field of applicableFields) {
|
|
27
16
|
fieldNameMap.set(field.system_name, toSnakeCase(field.label));
|
|
28
|
-
|
|
29
17
|
const optionsMap = parseDropdownOptions(field);
|
|
30
18
|
if (optionsMap.size > 0) {
|
|
31
19
|
dropdownOptionsMap.set(field.system_name, optionsMap);
|
|
32
20
|
}
|
|
33
21
|
}
|
|
34
|
-
|
|
35
22
|
for (const [key, value] of Object.entries(testCase)) {
|
|
36
|
-
if (!key.startsWith("custom_"))
|
|
37
|
-
|
|
38
|
-
|
|
23
|
+
if (!key.startsWith("custom_"))
|
|
24
|
+
continue;
|
|
25
|
+
if (value === null || value === undefined)
|
|
26
|
+
continue;
|
|
39
27
|
if (!fieldNameMap.has(key)) {
|
|
40
28
|
console.error(`No field mapping found for: ${key}`);
|
|
41
29
|
result[key] = value;
|
|
42
30
|
continue;
|
|
43
31
|
}
|
|
44
|
-
|
|
45
|
-
const outputKey = fieldNameMap.get(key)!;
|
|
32
|
+
const outputKey = fieldNameMap.get(key);
|
|
46
33
|
let finalValue = value;
|
|
47
|
-
|
|
48
34
|
if (dropdownOptionsMap.has(key)) {
|
|
49
|
-
const options = dropdownOptionsMap.get(key)
|
|
35
|
+
const options = dropdownOptionsMap.get(key);
|
|
50
36
|
const optionKey = String(value);
|
|
51
37
|
finalValue = options.get(optionKey) || value;
|
|
52
38
|
}
|
|
53
|
-
|
|
54
39
|
result[outputKey] = sanitizeValue(finalValue);
|
|
55
40
|
}
|
|
56
|
-
|
|
57
41
|
return result;
|
|
58
42
|
}
|
|
59
|
-
|
|
60
43
|
/**
|
|
61
44
|
* Parse dropdown options from field configs.
|
|
62
45
|
* Format: "1, First\n2, Second\n3, Third"
|
|
63
46
|
*/
|
|
64
|
-
export function parseDropdownOptions(field
|
|
65
|
-
const options = new Map
|
|
66
|
-
|
|
47
|
+
export function parseDropdownOptions(field) {
|
|
48
|
+
const options = new Map();
|
|
67
49
|
for (const config of field.configs) {
|
|
68
50
|
const items = config.options?.items;
|
|
69
|
-
if (!items)
|
|
70
|
-
|
|
51
|
+
if (!items)
|
|
52
|
+
continue;
|
|
71
53
|
const lines = items.split('\n');
|
|
72
54
|
for (const line of lines) {
|
|
73
55
|
const commaIndex = line.indexOf(',');
|
|
@@ -78,11 +60,9 @@ export function parseDropdownOptions(field: CaseField): Map<string, string> {
|
|
|
78
60
|
}
|
|
79
61
|
}
|
|
80
62
|
}
|
|
81
|
-
|
|
82
63
|
return options;
|
|
83
64
|
}
|
|
84
|
-
|
|
85
|
-
function toSnakeCase(str: string): string {
|
|
65
|
+
function toSnakeCase(str) {
|
|
86
66
|
return str
|
|
87
67
|
.toLowerCase()
|
|
88
68
|
.replace(/[^a-z0-9]+/g, '_')
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* in an object or array. Useful for cleaning up TestRail markdown content before sending
|
|
4
4
|
* to LLMs.
|
|
5
5
|
*/
|
|
6
|
-
export function sanitizeValue(value
|
|
6
|
+
export function sanitizeValue(value) {
|
|
7
7
|
if (typeof value === 'string') {
|
|
8
8
|
return value.replace(/\s*style\s*=\s*["'][^"']*["']/gi, '');
|
|
9
9
|
}
|
|
@@ -11,7 +11,7 @@ export function sanitizeValue(value: any): any {
|
|
|
11
11
|
return value.map(sanitizeValue);
|
|
12
12
|
}
|
|
13
13
|
if (value !== null && typeof value === 'object') {
|
|
14
|
-
const result
|
|
14
|
+
const result = {};
|
|
15
15
|
for (const [key, val] of Object.entries(value)) {
|
|
16
16
|
result[key] = sanitizeValue(val);
|
|
17
17
|
}
|
|
@@ -19,24 +19,21 @@ export function sanitizeValue(value: any): any {
|
|
|
19
19
|
}
|
|
20
20
|
return value;
|
|
21
21
|
}
|
|
22
|
-
|
|
23
22
|
/**
|
|
24
23
|
* Recursively removes null and undefined values from objects and arrays.
|
|
25
24
|
* For arrays, filters nested object items as well.
|
|
26
25
|
*/
|
|
27
|
-
export function removeNullish(value
|
|
26
|
+
export function removeNullish(value) {
|
|
28
27
|
if (value == null) {
|
|
29
28
|
return value;
|
|
30
29
|
}
|
|
31
|
-
|
|
32
30
|
if (Array.isArray(value)) {
|
|
33
31
|
return value
|
|
34
32
|
.map(item => removeNullish(item))
|
|
35
33
|
.filter(item => item != null);
|
|
36
34
|
}
|
|
37
|
-
|
|
38
35
|
if (typeof value === 'object') {
|
|
39
|
-
const result
|
|
36
|
+
const result = {};
|
|
40
37
|
for (const [key, val] of Object.entries(value)) {
|
|
41
38
|
const cleanedVal = removeNullish(val);
|
|
42
39
|
if (cleanedVal != null) {
|
|
@@ -45,6 +42,5 @@ export function removeNullish(value: any): any {
|
|
|
45
42
|
}
|
|
46
43
|
return result;
|
|
47
44
|
}
|
|
48
|
-
|
|
49
45
|
return value;
|
|
50
46
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uarlouski/testrail-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server for TestRail integration, enabling LLMs to fetch test cases and metadata.",
|
|
5
|
-
"main": "index.js",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"testrail-mcp-server": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
6
12
|
"type": "module",
|
|
7
13
|
"scripts": {
|
|
8
14
|
"build": "rimraf dist && tsc",
|
|
@@ -34,10 +40,12 @@
|
|
|
34
40
|
"license": "Apache-2.0",
|
|
35
41
|
"dependencies": {
|
|
36
42
|
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
43
|
+
"archiver": "^7.0.1",
|
|
37
44
|
"dotenv": "^17.2.3",
|
|
38
45
|
"zod": "^4.3.5"
|
|
39
46
|
},
|
|
40
47
|
"devDependencies": {
|
|
48
|
+
"@types/archiver": "^7.0.0",
|
|
41
49
|
"@types/jest": "^30.0.0",
|
|
42
50
|
"@types/node": "^25.0.9",
|
|
43
51
|
"jest": "^30.2.0",
|
package/.env.example
DELETED
package/.github/workflows/ci.yml
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: ["main"]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: ["main"]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
build-and-test:
|
|
11
|
-
name: Build and Test (Node ${{ matrix.node-version }})
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
|
|
14
|
-
strategy:
|
|
15
|
-
matrix:
|
|
16
|
-
node-version: [18.x, 20.x, 22.x]
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- name: Checkout code
|
|
20
|
-
uses: actions/checkout@v4
|
|
21
|
-
|
|
22
|
-
- name: Setup Node.js ${{ matrix.node-version }}
|
|
23
|
-
uses: actions/setup-node@v4
|
|
24
|
-
with:
|
|
25
|
-
node-version: ${{ matrix.node-version }}
|
|
26
|
-
cache: "npm"
|
|
27
|
-
|
|
28
|
-
- name: Install dependencies
|
|
29
|
-
run: npm ci
|
|
30
|
-
|
|
31
|
-
- name: Run tests
|
|
32
|
-
run: npm test
|
|
33
|
-
|
|
34
|
-
- name: Run tests with coverage
|
|
35
|
-
run: npm run test:coverage
|
|
36
|
-
|
|
37
|
-
- name: Build project
|
|
38
|
-
run: npm run build
|
|
39
|
-
|
|
40
|
-
- name: Upload coverage reports
|
|
41
|
-
uses: actions/upload-artifact@v4
|
|
42
|
-
if: matrix.node-version == '20.x'
|
|
43
|
-
with:
|
|
44
|
-
name: coverage-report
|
|
45
|
-
path: coverage/
|
|
46
|
-
retention-days: 7
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
name: Publish to NPM
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
publish:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
permissions:
|
|
11
|
-
contents: read
|
|
12
|
-
id-token: write
|
|
13
|
-
steps:
|
|
14
|
-
- name: Checkout code
|
|
15
|
-
uses: actions/checkout@v4
|
|
16
|
-
|
|
17
|
-
- name: Setup Node.js
|
|
18
|
-
uses: actions/setup-node@v4
|
|
19
|
-
with:
|
|
20
|
-
node-version: "20.x"
|
|
21
|
-
registry-url: "https://registry.npmjs.org"
|
|
22
|
-
|
|
23
|
-
- name: Install dependencies
|
|
24
|
-
run: npm ci
|
|
25
|
-
|
|
26
|
-
- name: Run tests
|
|
27
|
-
run: npm test
|
|
28
|
-
|
|
29
|
-
- name: Build package
|
|
30
|
-
run: npm run build
|
|
31
|
-
|
|
32
|
-
- name: Publish to NPM
|
|
33
|
-
run: npm publish --provenance --access public
|
|
34
|
-
env:
|
|
35
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/CHANGELOG.md
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## [1.2.0] - 2026-02-14
|
|
4
|
-
|
|
5
|
-
### Changed
|
|
6
|
-
|
|
7
|
-
- Optimize MCP call responses by removing non-essential fields and nullish values
|
|
8
|
-
- Migrated from `axios` to native `fetch` API for reduced dependency footprint
|
|
9
|
-
|
|
10
|
-
## [1.1.0] - 2026-02-09
|
|
11
|
-
|
|
12
|
-
### Added
|
|
13
|
-
|
|
14
|
-
- **Configuration via environment variables**
|
|
15
|
-
- `TESTRAIL_INSTANCE_URL` - Your TestRail instance URL
|
|
16
|
-
- `TESTRAIL_USERNAME` - Your TestRail username
|
|
17
|
-
- `TESTRAIL_API_KEY` - [How to get your API key](https://support.testrail.com/hc/en-us/articles/7077039051412-Accessing-the-TestRail-API)
|
|
18
|
-
|
|
19
|
-
- **Test case management tools**
|
|
20
|
-
- `get_projects` - Discover available projects in your TestRail instance
|
|
21
|
-
- `get_case` - Fetch detailed test case info including custom fields
|
|
22
|
-
- `get_cases` - Query cases with filtering and pagination support
|
|
23
|
-
- `get_case_fields` - Explore available fields and dropdown options
|
|
24
|
-
- `get_templates` - List project templates to understand case structures
|
|
25
|
-
- `get_sections` - Navigate the test case hierarchy
|
|
26
|
-
- `create_case` - Create new test cases with full custom field support
|
|
27
|
-
- `update_case` / `update_cases` - Modify single or bulk update cases
|
package/jest.config.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
preset: 'ts-jest/presets/default-esm',
|
|
3
|
-
testEnvironment: 'node',
|
|
4
|
-
extensionsToTreatAsEsm: ['.ts'],
|
|
5
|
-
moduleNameMapper: {
|
|
6
|
-
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
7
|
-
},
|
|
8
|
-
transform: {
|
|
9
|
-
'^.+\\.tsx?$': [
|
|
10
|
-
'ts-jest',
|
|
11
|
-
{
|
|
12
|
-
useESM: true,
|
|
13
|
-
},
|
|
14
|
-
],
|
|
15
|
-
},
|
|
16
|
-
coverageThreshold: {
|
|
17
|
-
global: {
|
|
18
|
-
branches: 95,
|
|
19
|
-
functions: 95,
|
|
20
|
-
lines: 95,
|
|
21
|
-
statements: 95,
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
};
|