@uarlouski/testrail-mcp-server 1.10.0 → 2.0.0
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 +28 -12
- package/dist/client/testrail.js +55 -0
- package/dist/index.js +14 -53
- package/dist/tools/{add_case.js → cases/add_case.js} +2 -1
- package/dist/tools/{get_case.js → cases/get_case.js} +3 -2
- package/dist/tools/{get_case_fields.js → cases/get_case_fields.js} +6 -3
- package/dist/tools/{get_cases.js → cases/get_cases.js} +2 -1
- package/dist/tools/cases/index.js +14 -0
- package/dist/tools/cases/types.js +40 -0
- package/dist/tools/{update_case.js → cases/update_case.js} +2 -1
- package/dist/tools/{update_cases.js → cases/update_cases.js} +2 -1
- package/dist/tools/commons/delete_entity.js +24 -0
- package/dist/tools/commons/get_configurations.js +17 -0
- package/dist/tools/{get_labels.js → commons/get_labels.js} +2 -1
- package/dist/tools/{get_priorities.js → commons/get_priorities.js} +2 -1
- package/dist/tools/{get_statuses.js → commons/get_statuses.js} +2 -1
- package/dist/tools/{get_templates.js → commons/get_templates.js} +2 -1
- package/dist/tools/{get_tests.js → commons/get_tests.js} +2 -1
- package/dist/tools/commons/get_users.js +46 -0
- package/dist/tools/commons/index.js +18 -0
- package/dist/tools/commons/types.js +49 -0
- package/dist/tools/projects/index.js +4 -0
- package/dist/tools/projects/query_project.js +29 -0
- package/dist/tools/projects/types.js +14 -0
- package/dist/tools/registry.js +46 -0
- package/dist/tools/{add_results.js → results/add_results.js} +2 -1
- package/dist/tools/{add_results_for_cases.js → results/add_results_for_cases.js} +2 -1
- package/dist/tools/results/get_results.js +18 -0
- package/dist/tools/results/index.js +8 -0
- package/dist/tools/results/types.js +8 -0
- package/dist/tools/{add_attachment_to_run.js → runs/add_attachment_to_run.js} +2 -1
- package/dist/tools/runs/index.js +8 -0
- package/dist/tools/runs/mutate_run.js +40 -0
- package/dist/tools/runs/query_run.js +35 -0
- package/dist/tools/runs/types.js +43 -0
- package/dist/tools/{get_sections.js → sections/get_sections.js} +2 -1
- package/dist/tools/sections/index.js +6 -0
- package/dist/tools/sections/mutate_section.js +25 -0
- package/dist/tools/sections/types.js +21 -0
- package/dist/tools/shared_steps/add_shared_step.js +2 -1
- package/dist/tools/shared_steps/get_shared_step.js +2 -1
- package/dist/tools/shared_steps/get_shared_step_history.js +2 -1
- package/dist/tools/shared_steps/get_shared_steps.js +2 -1
- package/dist/tools/shared_steps/index.js +12 -0
- package/dist/tools/shared_steps/types.js +18 -0
- package/dist/tools/shared_steps/update_shared_step.js +2 -1
- package/dist/tools/suites/index.js +6 -0
- package/dist/tools/suites/mutate_suite.js +25 -0
- package/dist/tools/suites/query_suite.js +28 -0
- package/dist/tools/suites/types.js +28 -0
- package/dist/utils/mutate_handler.js +22 -0
- package/dist/utils/query_handler.js +20 -0
- package/dist/utils/sanitizer.js +11 -0
- package/dist/utils/validator.js +3 -2
- package/package.json +1 -1
- package/dist/tools/add_run.js +0 -19
- package/dist/tools/get_projects.js +0 -15
- package/dist/tools/shared_steps/delete_shared_step.js +0 -18
- package/dist/types/testrail.js +0 -125
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized utility to handle mutation actions (create or update) in a type-safe manner.
|
|
3
|
+
*
|
|
4
|
+
* @param payload The incoming payload containing the action discriminator
|
|
5
|
+
* @param onCreate Callback executed when action is "create"
|
|
6
|
+
* @param onUpdate Callback executed when action is "update"
|
|
7
|
+
* @returns The mutated entity wrapped in a record
|
|
8
|
+
*/
|
|
9
|
+
export async function handleMutate(payload, onCreate, onUpdate, schema) {
|
|
10
|
+
let result;
|
|
11
|
+
if (payload.action === "create") {
|
|
12
|
+
result = await onCreate(payload);
|
|
13
|
+
}
|
|
14
|
+
else if (payload.action === "update") {
|
|
15
|
+
result = await onUpdate(payload);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
const unknownAction = payload.action;
|
|
19
|
+
throw new Error(`Unsupported mutation action: ${unknownAction}`);
|
|
20
|
+
}
|
|
21
|
+
return schema ? schema.parse(result) : result;
|
|
22
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized utility to handle query actions (one or many) in a type-safe manner.
|
|
3
|
+
*
|
|
4
|
+
* @param payload The incoming payload containing the action discriminator
|
|
5
|
+
* @param onQueryOne Callback executed when action is "one"
|
|
6
|
+
* @param onQueryMany Callback executed when action is "many"
|
|
7
|
+
* @returns The queried entity or list of entities wrapped in a record
|
|
8
|
+
*/
|
|
9
|
+
export async function handleQuery(payload, onQueryOne, onQueryMany) {
|
|
10
|
+
if (payload.action === "one") {
|
|
11
|
+
return onQueryOne(payload);
|
|
12
|
+
}
|
|
13
|
+
else if (payload.action === "many") {
|
|
14
|
+
return onQueryMany(payload);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
const unknownAction = payload.action;
|
|
18
|
+
throw new Error(`Unsupported query action: ${unknownAction}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
package/dist/utils/sanitizer.js
CHANGED
|
@@ -44,3 +44,14 @@ export function removeNullish(value) {
|
|
|
44
44
|
}
|
|
45
45
|
return value;
|
|
46
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Checks if an entity is active by checking its active flag.
|
|
49
|
+
* Supports passing either the direct primitive value or the parent object containing `.is_active`.
|
|
50
|
+
*/
|
|
51
|
+
export function isActive(value) {
|
|
52
|
+
if (value == null) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const activeFlag = (typeof value === 'object') ? value.is_active : value;
|
|
56
|
+
return activeFlag === 1 || activeFlag === true || activeFlag === '1' || activeFlag === 'true';
|
|
57
|
+
}
|
package/dist/utils/validator.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { SYSTEM_FIELDS, mapToFieldSchema } from "../tools/get_case_fields.js";
|
|
1
|
+
import { SYSTEM_FIELDS, mapToFieldSchema } from "../tools/cases/get_case_fields.js";
|
|
2
|
+
import { isActive } from "./sanitizer.js";
|
|
2
3
|
/**
|
|
3
4
|
* Validates that the provided fields exist in the TestRail case schema.
|
|
4
5
|
* Throws an Error if any field is invalid.
|
|
@@ -11,7 +12,7 @@ export function validateCaseFields(fields, caseFields) {
|
|
|
11
12
|
if (fieldKeys.length === 0) {
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
|
-
const customFieldSchemas = caseFields.filter(
|
|
15
|
+
const customFieldSchemas = caseFields.filter(isActive).map(mapToFieldSchema);
|
|
15
16
|
const validFieldNames = new Set([...SYSTEM_FIELDS, ...customFieldSchemas].map(f => f.system_name));
|
|
16
17
|
validFieldNames.add('id');
|
|
17
18
|
validFieldNames.add('suite_id');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uarlouski/testrail-mcp-server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"mcpName": "io.github.uarlouski/testrail-mcp-server",
|
|
5
5
|
"description": "Model Context Protocol (MCP) server for TestRail integration, enabling LLMs to fetch test cases and metadata.",
|
|
6
6
|
"main": "dist/index.js",
|
package/dist/tools/add_run.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { RunSchema } from "../types/testrail.js";
|
|
3
|
-
const parameters = {
|
|
4
|
-
project_id: z.number().describe("The ID of the project. Use get_projects to find available projects"),
|
|
5
|
-
name: z.string().optional().describe("The name of the test run"),
|
|
6
|
-
description: z.string().optional().describe("The description of the test run"),
|
|
7
|
-
case_ids: z.array(z.number()).min(1).describe("Array of case IDs to include in the run. After creating the run, use get_tests with the returned run_id to retrieve test IDs for result submission")
|
|
8
|
-
};
|
|
9
|
-
export const addRunTool = {
|
|
10
|
-
name: "add_run",
|
|
11
|
-
description: "Create a new test run in TestRail",
|
|
12
|
-
parameters,
|
|
13
|
-
handler: async ({ project_id, ...fields }, client) => {
|
|
14
|
-
const caseData = await client.getCase(fields.case_ids[0]);
|
|
15
|
-
const params = { suite_id: caseData.suite_id, include_all: false, ...fields };
|
|
16
|
-
const run = await client.addRun(project_id, params);
|
|
17
|
-
return RunSchema.parse(run);
|
|
18
|
-
},
|
|
19
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ProjectSchema } from "../types/testrail.js";
|
|
2
|
-
const parameters = {};
|
|
3
|
-
export const getProjectsTool = {
|
|
4
|
-
name: "get_projects",
|
|
5
|
-
description: "Get all available projects in TestRail. Returns project IDs and names that can be used with get_sections, get_templates, get_cases, and add_run",
|
|
6
|
-
parameters,
|
|
7
|
-
handler: async (_args, client) => {
|
|
8
|
-
const projects = await client.getProjects();
|
|
9
|
-
return {
|
|
10
|
-
projects: projects
|
|
11
|
-
.filter(p => !p.is_completed)
|
|
12
|
-
.map(p => ProjectSchema.parse(p)),
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
const parameters = {
|
|
3
|
-
shared_step_id: z.number().describe("The ID of the shared test step to delete"),
|
|
4
|
-
};
|
|
5
|
-
const description = `
|
|
6
|
-
Deletes an existing shared step entity.
|
|
7
|
-
By default, this removes the shared step entity but keeps the steps in the test cases that used them.
|
|
8
|
-
`;
|
|
9
|
-
export const deleteSharedStepTool = {
|
|
10
|
-
name: "delete_shared_step",
|
|
11
|
-
description: description.trim(),
|
|
12
|
-
parameters,
|
|
13
|
-
handler: async (args, client) => {
|
|
14
|
-
const { shared_step_id } = args;
|
|
15
|
-
await client.deleteSharedStep(shared_step_id);
|
|
16
|
-
return { message: `Shared step ${shared_step_id} deleted successfully.` };
|
|
17
|
-
}
|
|
18
|
-
};
|
package/dist/types/testrail.js
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
export const CaseFieldConfigSchema = z.object({
|
|
3
|
-
context: z.object({
|
|
4
|
-
is_global: z.boolean(),
|
|
5
|
-
project_ids: z.array(z.number()),
|
|
6
|
-
}).optional(),
|
|
7
|
-
options: z.object({
|
|
8
|
-
default_value: z.string().optional(),
|
|
9
|
-
is_required: z.boolean().optional(),
|
|
10
|
-
items: z.string().optional(),
|
|
11
|
-
}),
|
|
12
|
-
});
|
|
13
|
-
export const CaseFieldSchema = z.object({
|
|
14
|
-
id: z.number(),
|
|
15
|
-
name: z.string(),
|
|
16
|
-
system_name: z.string(),
|
|
17
|
-
label: z.string(),
|
|
18
|
-
type_id: z.number(),
|
|
19
|
-
template_ids: z.array(z.number()),
|
|
20
|
-
is_active: z.boolean(),
|
|
21
|
-
description: z.string().nullable(),
|
|
22
|
-
include_all: z.boolean(),
|
|
23
|
-
configs: z.array(CaseFieldConfigSchema),
|
|
24
|
-
});
|
|
25
|
-
export const LabelSchema = z.object({
|
|
26
|
-
id: z.number(),
|
|
27
|
-
title: z.string(),
|
|
28
|
-
});
|
|
29
|
-
export const CaseSchema = z.object({
|
|
30
|
-
id: z.number(),
|
|
31
|
-
title: z.string(),
|
|
32
|
-
section_id: z.number(),
|
|
33
|
-
template_id: z.number(),
|
|
34
|
-
type_id: z.number(),
|
|
35
|
-
priority_id: z.number(),
|
|
36
|
-
milestone_id: z.number().nullable(),
|
|
37
|
-
refs: z.string().nullable(),
|
|
38
|
-
created_on: z.number(),
|
|
39
|
-
updated_on: z.number(),
|
|
40
|
-
estimate: z.string().nullable(),
|
|
41
|
-
suite_id: z.number(),
|
|
42
|
-
labels: z.array(LabelSchema),
|
|
43
|
-
}).loose();
|
|
44
|
-
export const SectionSchema = z.object({
|
|
45
|
-
id: z.number(),
|
|
46
|
-
name: z.string(),
|
|
47
|
-
description: z.string().nullish(),
|
|
48
|
-
parent_id: z.number().nullish(),
|
|
49
|
-
suite_id: z.number(),
|
|
50
|
-
});
|
|
51
|
-
export const PrioritySchema = z.object({
|
|
52
|
-
id: z.number(),
|
|
53
|
-
is_default: z.boolean(),
|
|
54
|
-
name: z.string(),
|
|
55
|
-
});
|
|
56
|
-
export const CaseTypeSchema = z.object({
|
|
57
|
-
id: z.number(),
|
|
58
|
-
is_default: z.boolean(),
|
|
59
|
-
name: z.string(),
|
|
60
|
-
});
|
|
61
|
-
export const TemplateSchema = z.object({
|
|
62
|
-
id: z.number(),
|
|
63
|
-
name: z.string(),
|
|
64
|
-
is_default: z.boolean(),
|
|
65
|
-
});
|
|
66
|
-
export const ProjectSchema = z.object({
|
|
67
|
-
id: z.number(),
|
|
68
|
-
name: z.string(),
|
|
69
|
-
is_completed: z.boolean(),
|
|
70
|
-
suite_mode: z.number(),
|
|
71
|
-
});
|
|
72
|
-
export const RunSchema = z.object({
|
|
73
|
-
id: z.number(),
|
|
74
|
-
name: z.string(),
|
|
75
|
-
description: z.string().nullable(),
|
|
76
|
-
suite_id: z.number().nullable(),
|
|
77
|
-
project_id: z.number(),
|
|
78
|
-
is_completed: z.boolean(),
|
|
79
|
-
passed_count: z.number(),
|
|
80
|
-
blocked_count: z.number(),
|
|
81
|
-
untested_count: z.number(),
|
|
82
|
-
retest_count: z.number(),
|
|
83
|
-
failed_count: z.number(),
|
|
84
|
-
url: z.string(),
|
|
85
|
-
});
|
|
86
|
-
export const StatusSchema = z.object({
|
|
87
|
-
id: z.number(),
|
|
88
|
-
name: z.string(),
|
|
89
|
-
label: z.string(),
|
|
90
|
-
});
|
|
91
|
-
export const TestSchema = z.object({
|
|
92
|
-
id: z.number(),
|
|
93
|
-
case_id: z.number(),
|
|
94
|
-
status_id: z.number(),
|
|
95
|
-
title: z.string(),
|
|
96
|
-
run_id: z.number(),
|
|
97
|
-
});
|
|
98
|
-
export const TestsSchema = z.array(TestSchema);
|
|
99
|
-
export const ResultSchema = z.object({
|
|
100
|
-
id: z.number(),
|
|
101
|
-
test_id: z.number(),
|
|
102
|
-
status_id: z.number(),
|
|
103
|
-
comment: z.string().nullable(),
|
|
104
|
-
defects: z.string().nullable(),
|
|
105
|
-
});
|
|
106
|
-
export const AttachmentSchema = z.object({
|
|
107
|
-
attachment_id: z.number(),
|
|
108
|
-
});
|
|
109
|
-
export const SharedStepContentSchema = z.object({
|
|
110
|
-
content: z.string(),
|
|
111
|
-
expected: z.string().nullable().optional(),
|
|
112
|
-
});
|
|
113
|
-
export const SharedStepSchema = z.object({
|
|
114
|
-
id: z.number(),
|
|
115
|
-
title: z.string(),
|
|
116
|
-
project_id: z.number().optional(),
|
|
117
|
-
custom_steps_separated: z.array(SharedStepContentSchema).optional(),
|
|
118
|
-
case_ids: z.array(z.number()).optional(),
|
|
119
|
-
});
|
|
120
|
-
export const SharedStepHistorySchema = z.object({
|
|
121
|
-
id: z.number(),
|
|
122
|
-
title: z.string(),
|
|
123
|
-
timestamp: z.number().optional(),
|
|
124
|
-
custom_steps_separated: z.array(SharedStepContentSchema).optional(),
|
|
125
|
-
});
|