@testomatio/mcp 1.0.6 → 1.0.8
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 +6 -6
- package/index.js +61 -43
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ A Model Context Protocol (MCP) server for Testomat.io API integration with AI as
|
|
|
13
13
|
### Run directly with npx
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npx @testomatio/mcp --token <your-token> --project <project-id>
|
|
16
|
+
npx @testomatio/mcp@latest --token <your-token> --project <project-id>
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
## Usage
|
|
@@ -26,13 +26,13 @@ The MCP server can be started using command line arguments or environment variab
|
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
28
|
# Using short flags
|
|
29
|
-
npx @testomatio/mcp -t testomat_YOUR_TOKEN_HERE -p your-project-id
|
|
29
|
+
npx @testomatio/mcp@latest -t testomat_YOUR_TOKEN_HERE -p your-project-id
|
|
30
30
|
|
|
31
31
|
# Using long flags
|
|
32
|
-
npx @testomatio/mcp --token testomat_YOUR_TOKEN_HERE --project your-project-id
|
|
32
|
+
npx @testomatio/mcp@latest --token testomat_YOUR_TOKEN_HERE --project your-project-id
|
|
33
33
|
|
|
34
34
|
# With custom base URL
|
|
35
|
-
npx @testomatio/mcp --token testomat_YOUR_TOKEN_HERE --project your-project-id --base-url https://your-instance.testomat.io
|
|
35
|
+
npx @testomatio/mcp@latest --token testomat_YOUR_TOKEN_HERE --project your-project-id --base-url https://your-instance.testomat.io
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
#### Using Environment Variables
|
|
@@ -43,10 +43,10 @@ export TESTOMATIO_API_TOKEN=testomat_YOUR_TOKEN_HERE
|
|
|
43
43
|
export TESTOMATIO_BASE_URL=https://app.testomat.io # Optional, defaults to https://app.testomat.io
|
|
44
44
|
|
|
45
45
|
# Run with project ID
|
|
46
|
-
npx @testomatio/mcp --project your-project-id
|
|
46
|
+
npx @testomatio/mcp@latest --project your-project-id
|
|
47
47
|
|
|
48
48
|
# Or run directly with environment variables
|
|
49
|
-
TESTOMATIO_API_TOKEN=testomat_YOUR_TOKEN_HERE npx @testomatio/mcp --project your-project-id
|
|
49
|
+
TESTOMATIO_API_TOKEN=testomat_YOUR_TOKEN_HERE npx @testomatio/mcp@latest --project your-project-id
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
### Getting Your API Token
|
package/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
ListToolsRequestSchema,
|
|
8
8
|
} from '@modelcontextprotocol/sdk/types.js';
|
|
9
9
|
import { program } from 'commander';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
10
11
|
|
|
11
12
|
function normalizeString(value) {
|
|
12
13
|
return typeof value === 'string' ? value.trim() : value;
|
|
@@ -642,7 +643,8 @@ class TestomatioMCPServer {
|
|
|
642
643
|
this.jwtToken = null;
|
|
643
644
|
return this.makePostRequest(path, data);
|
|
644
645
|
}
|
|
645
|
-
|
|
646
|
+
const errorText = await response.text();
|
|
647
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}. Details: ${errorText}`);
|
|
646
648
|
}
|
|
647
649
|
|
|
648
650
|
return await response.json();
|
|
@@ -666,7 +668,8 @@ class TestomatioMCPServer {
|
|
|
666
668
|
this.jwtToken = null;
|
|
667
669
|
return this.makePutRequest(path, data);
|
|
668
670
|
}
|
|
669
|
-
|
|
671
|
+
const errorText = await response.text();
|
|
672
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}. Details: ${errorText}`);
|
|
670
673
|
}
|
|
671
674
|
|
|
672
675
|
return await response.json();
|
|
@@ -1072,29 +1075,24 @@ class TestomatioMCPServer {
|
|
|
1072
1075
|
async createTest(args) {
|
|
1073
1076
|
const { suite_id, labels_ids, fields, ...attributes } = args;
|
|
1074
1077
|
|
|
1075
|
-
//
|
|
1076
|
-
const
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
attributes: {
|
|
1080
|
-
...Object.fromEntries(Object.entries(attributes).map(([k, v]) => [k.replace(/_/g, '-'), v])),
|
|
1081
|
-
...(fields && { 'custom-fields': fields })
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
};
|
|
1078
|
+
// Convert attributes to use hyphens instead of underscores for API compatibility
|
|
1079
|
+
const apiAttributes = Object.fromEntries(
|
|
1080
|
+
Object.entries(attributes).map(([k, v]) => [k.replace(/_/g, '-'), v])
|
|
1081
|
+
);
|
|
1085
1082
|
|
|
1083
|
+
// Add suite_id to attributes if provided
|
|
1086
1084
|
if (suite_id) {
|
|
1087
|
-
|
|
1088
|
-
suite: {
|
|
1089
|
-
data: {
|
|
1090
|
-
type: 'suites',
|
|
1091
|
-
id: suite_id
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
};
|
|
1085
|
+
apiAttributes['suite_id'] = suite_id;
|
|
1095
1086
|
}
|
|
1096
1087
|
|
|
1097
|
-
|
|
1088
|
+
// Handle fields parameter for custom fields
|
|
1089
|
+
const requestData = {
|
|
1090
|
+
test: {
|
|
1091
|
+
...apiAttributes,
|
|
1092
|
+
...(labels_ids && { labels_ids: labels_ids }),
|
|
1093
|
+
...(fields && { custom_fields: fields })
|
|
1094
|
+
}
|
|
1095
|
+
};
|
|
1098
1096
|
|
|
1099
1097
|
const data = await this.makePostRequest('/tests', requestData);
|
|
1100
1098
|
const formattedTest = this.formatModel(data.data, 'test', [
|
|
@@ -1115,31 +1113,43 @@ class TestomatioMCPServer {
|
|
|
1115
1113
|
async updateTest(args) {
|
|
1116
1114
|
const { test_id, suite_id, labels_ids, fields, ...attributes } = args;
|
|
1117
1115
|
|
|
1118
|
-
//
|
|
1119
|
-
const
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
attributes: {
|
|
1123
|
-
...Object.fromEntries(Object.entries(attributes).map(([k, v]) => [k.replace(/_/g, '-'), v])),
|
|
1124
|
-
...(fields && { 'custom-fields': fields })
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
};
|
|
1116
|
+
// Convert attributes to use hyphens instead of underscores for API compatibility
|
|
1117
|
+
const apiAttributes = Object.fromEntries(
|
|
1118
|
+
Object.entries(attributes).map(([k, v]) => [k.replace(/_/g, '-'), v])
|
|
1119
|
+
);
|
|
1128
1120
|
|
|
1121
|
+
// Add suite_id to attributes if provided
|
|
1129
1122
|
if (suite_id) {
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1123
|
+
apiAttributes['suite_id'] = suite_id;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
let data;
|
|
1127
|
+
|
|
1128
|
+
// Handle labels_ids using the bulk labels endpoint
|
|
1129
|
+
if (labels_ids && labels_ids.length > 0) {
|
|
1130
|
+
const labelsRequest = {
|
|
1131
|
+
items: {
|
|
1132
|
+
test: [test_id]
|
|
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: {
|
|
1145
|
+
...apiAttributes,
|
|
1146
|
+
...(fields && { custom_fields: fields })
|
|
1136
1147
|
}
|
|
1137
1148
|
};
|
|
1138
|
-
}
|
|
1139
1149
|
|
|
1140
|
-
|
|
1150
|
+
data = await this.makePutRequest(`/tests/${test_id}`, requestData);
|
|
1151
|
+
}
|
|
1141
1152
|
|
|
1142
|
-
const data = await this.makePutRequest(`/tests/${test_id}`, requestData);
|
|
1143
1153
|
const formattedTest = this.formatModel(data.data, 'test', [
|
|
1144
1154
|
'title', 'description', 'code', 'priority',
|
|
1145
1155
|
'state', 'suite-id', 'tags', 'file'
|
|
@@ -1338,7 +1348,15 @@ async function main() {
|
|
|
1338
1348
|
}
|
|
1339
1349
|
}
|
|
1340
1350
|
|
|
1341
|
-
//
|
|
1342
|
-
|
|
1343
|
-
|
|
1351
|
+
// Run main() when executed directly or as a bin script
|
|
1352
|
+
// Don't run when imported as a module for testing
|
|
1353
|
+
if (import.meta.url.startsWith('file://') && process.argv[1]) {
|
|
1354
|
+
const modulePath = fileURLToPath(import.meta.url);
|
|
1355
|
+
const isDirectExecution = process.argv[1].includes('index.js') ||
|
|
1356
|
+
process.argv[1] === modulePath ||
|
|
1357
|
+
process.argv[1].endsWith('/testomatio-mcp');
|
|
1358
|
+
|
|
1359
|
+
if (isDirectExecution) {
|
|
1360
|
+
main().catch(console.error);
|
|
1361
|
+
}
|
|
1344
1362
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testomatio/mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Model Context Protocol server for Testomatio API",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -13,11 +13,14 @@
|
|
|
13
13
|
"test": "node --experimental-vm-modules node_modules/.bin/jest",
|
|
14
14
|
"test:unit": "node --experimental-vm-modules node_modules/.bin/jest",
|
|
15
15
|
"test:integration": "node --experimental-vm-modules node_modules/.bin/jest --config jest.integration.config.js",
|
|
16
|
+
"test:e2e": "node --experimental-vm-modules node_modules/.bin/jest --config jest.e2e.config.js",
|
|
16
17
|
"test:watch": "node --experimental-vm-modules node_modules/.bin/jest --watch",
|
|
17
18
|
"test:integration:watch": "node --experimental-vm-modules node_modules/.bin/jest --config jest.integration.config.js --watch",
|
|
19
|
+
"test:e2e:watch": "node --experimental-vm-modules node_modules/.bin/jest --config jest.e2e.config.js --watch",
|
|
18
20
|
"test:coverage": "node --experimental-vm-modules node_modules/.bin/jest --coverage",
|
|
19
21
|
"test:coverage:integration": "node --experimental-vm-modules node_modules/.bin/jest --config jest.integration.config.js --coverage",
|
|
20
|
-
"test:
|
|
22
|
+
"test:coverage:e2e": "node --experimental-vm-modules node_modules/.bin/jest --config jest.e2e.config.js --coverage",
|
|
23
|
+
"test:all": "npm run test:unit && npm run test:integration && npm run test:e2e"
|
|
21
24
|
},
|
|
22
25
|
"keywords": [
|
|
23
26
|
"testomatio",
|