@testomatio/mcp 1.0.8 → 1.0.9
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/index.js +110 -25
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -480,6 +480,27 @@ class TestomatioMCPServer {
|
|
|
480
480
|
required: ['title'],
|
|
481
481
|
},
|
|
482
482
|
},
|
|
483
|
+
{
|
|
484
|
+
name: 'get_labels',
|
|
485
|
+
description: 'Get all available labels for the project with their IDs and configurations',
|
|
486
|
+
inputSchema: {
|
|
487
|
+
type: 'object',
|
|
488
|
+
properties: {
|
|
489
|
+
scope: {
|
|
490
|
+
type: 'array',
|
|
491
|
+
items: {
|
|
492
|
+
type: 'string',
|
|
493
|
+
enum: ['tests', 'suites']
|
|
494
|
+
},
|
|
495
|
+
description: 'Filter labels by scope (e.g., ["tests"], ["suites"], or ["tests", "suites"])',
|
|
496
|
+
},
|
|
497
|
+
page: {
|
|
498
|
+
type: 'number',
|
|
499
|
+
description: 'Page number for pagination',
|
|
500
|
+
},
|
|
501
|
+
},
|
|
502
|
+
},
|
|
503
|
+
},
|
|
483
504
|
{
|
|
484
505
|
name: 'create_label',
|
|
485
506
|
description: 'Create a new label with optional custom field configuration. Labels can be used to tag and categorize tests and suites',
|
|
@@ -561,6 +582,8 @@ class TestomatioMCPServer {
|
|
|
561
582
|
return await this.getPlans(args);
|
|
562
583
|
case 'get_plan':
|
|
563
584
|
return await this.getPlan(args.plan_id);
|
|
585
|
+
case 'get_labels':
|
|
586
|
+
return await this.getLabels(args);
|
|
564
587
|
case 'create_test':
|
|
565
588
|
return await this.createTest(args);
|
|
566
589
|
case 'update_test':
|
|
@@ -1072,6 +1095,41 @@ class TestomatioMCPServer {
|
|
|
1072
1095
|
};
|
|
1073
1096
|
}
|
|
1074
1097
|
|
|
1098
|
+
async getLabels(filters = {}) {
|
|
1099
|
+
const params = {};
|
|
1100
|
+
|
|
1101
|
+
// Handle scope filter
|
|
1102
|
+
if (filters.scope && Array.isArray(filters.scope)) {
|
|
1103
|
+
if (!params['scope[]']) {
|
|
1104
|
+
params['scope[]'] = [];
|
|
1105
|
+
}
|
|
1106
|
+
filters.scope.forEach(scope => {
|
|
1107
|
+
params['scope[]'].push(scope);
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// Handle pagination
|
|
1112
|
+
if (filters.page) {
|
|
1113
|
+
params.page = filters.page;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
const data = await this.makeRequest('/labels', params);
|
|
1117
|
+
const formattedLabels = data.data.map(label =>
|
|
1118
|
+
this.formatModel(label, 'label', [
|
|
1119
|
+
'title', 'color', 'scope', 'visibility', 'field'
|
|
1120
|
+
])
|
|
1121
|
+
).join('\n\n');
|
|
1122
|
+
|
|
1123
|
+
return {
|
|
1124
|
+
content: [
|
|
1125
|
+
{
|
|
1126
|
+
type: 'text',
|
|
1127
|
+
text: `Available labels for project ${this.config.projectId}:\n\n${formattedLabels || 'No labels found matching the criteria.'}`,
|
|
1128
|
+
},
|
|
1129
|
+
],
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1075
1133
|
async createTest(args) {
|
|
1076
1134
|
const { suite_id, labels_ids, fields, ...attributes } = args;
|
|
1077
1135
|
|
|
@@ -1085,12 +1143,15 @@ class TestomatioMCPServer {
|
|
|
1085
1143
|
apiAttributes['suite_id'] = suite_id;
|
|
1086
1144
|
}
|
|
1087
1145
|
|
|
1088
|
-
//
|
|
1146
|
+
// Build JSON-API request data
|
|
1089
1147
|
const requestData = {
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1148
|
+
data: {
|
|
1149
|
+
type: 'tests',
|
|
1150
|
+
attributes: {
|
|
1151
|
+
...apiAttributes,
|
|
1152
|
+
...(labels_ids && { labels_ids: labels_ids }),
|
|
1153
|
+
...(fields && { 'custom-fields': fields })
|
|
1154
|
+
}
|
|
1094
1155
|
}
|
|
1095
1156
|
};
|
|
1096
1157
|
|
|
@@ -1110,6 +1171,33 @@ class TestomatioMCPServer {
|
|
|
1110
1171
|
};
|
|
1111
1172
|
}
|
|
1112
1173
|
|
|
1174
|
+
async linkLabels(testId, labelsIds) {
|
|
1175
|
+
if (!labelsIds || labelsIds.length === 0) {
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
// Process each label individually using the label linking API
|
|
1180
|
+
for (const labelId of labelsIds) {
|
|
1181
|
+
// Parse label:value format if present
|
|
1182
|
+
let labelUid = labelId;
|
|
1183
|
+
let value = null;
|
|
1184
|
+
|
|
1185
|
+
if (labelId.includes(':')) {
|
|
1186
|
+
[labelUid, value] = labelId.split(':', 2);
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// Build URL with test_id query parameter
|
|
1190
|
+
let url = `/labels/${labelUid}/link?test_id=${testId}`;
|
|
1191
|
+
|
|
1192
|
+
// Add value as query parameter if present
|
|
1193
|
+
if (value) {
|
|
1194
|
+
url += `&value=${encodeURIComponent(value)}`;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
await this.makePostRequest(url, {});
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1113
1201
|
async updateTest(args) {
|
|
1114
1202
|
const { test_id, suite_id, labels_ids, fields, ...attributes } = args;
|
|
1115
1203
|
|
|
@@ -1125,29 +1213,26 @@ class TestomatioMCPServer {
|
|
|
1125
1213
|
|
|
1126
1214
|
let data;
|
|
1127
1215
|
|
|
1128
|
-
// Handle
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
add_labels: labels_ids
|
|
1135
|
-
};
|
|
1136
|
-
|
|
1137
|
-
await this.makePutRequest('/bulk/labels', labelsRequest);
|
|
1138
|
-
|
|
1139
|
-
// After updating labels, fetch the updated test
|
|
1140
|
-
data = await this.makeRequest(`/tests/${test_id}`);
|
|
1141
|
-
} else {
|
|
1142
|
-
// Handle regular test attributes update
|
|
1143
|
-
const requestData = {
|
|
1144
|
-
test: {
|
|
1216
|
+
// Handle regular test attributes update using JSON-API format
|
|
1217
|
+
const requestData = {
|
|
1218
|
+
data: {
|
|
1219
|
+
id: test_id,
|
|
1220
|
+
type: 'tests',
|
|
1221
|
+
attributes: {
|
|
1145
1222
|
...apiAttributes,
|
|
1146
|
-
...(fields && {
|
|
1223
|
+
...(fields && { 'custom-fields': fields })
|
|
1147
1224
|
}
|
|
1148
|
-
}
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1149
1227
|
|
|
1150
|
-
|
|
1228
|
+
data = await this.makePutRequest(`/tests/${test_id}`, requestData);
|
|
1229
|
+
|
|
1230
|
+
// Handle labels_ids using the label linking API
|
|
1231
|
+
if (labels_ids && labels_ids.length > 0) {
|
|
1232
|
+
await this.linkLabels(test_id, labels_ids);
|
|
1233
|
+
|
|
1234
|
+
// After linking labels, fetch the updated test to reflect changes
|
|
1235
|
+
data = await this.makeRequest(`/tests/${test_id}`);
|
|
1151
1236
|
}
|
|
1152
1237
|
|
|
1153
1238
|
const formattedTest = this.formatModel(data.data, 'test', [
|