@testomatio/mcp 2.1.0-beta → 2.1.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/index.js CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
  import { fileURLToPath } from 'url';
4
4
  import { main } from './src/cli/main.js';
5
-
6
- export { TestomatioMCPServer } from './src/mcp/server.js';
5
+ export * from './src/index.js';
7
6
 
8
7
  const modulePath = fileURLToPath(import.meta.url);
9
8
  const executedPath = process.argv[1] || '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/mcp",
3
- "version": "2.1.0-beta",
3
+ "version": "2.1.0",
4
4
  "description": "Model Context Protocol server for Testomatio API",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -60,14 +60,27 @@ export class TestomatioApiClient {
60
60
  }
61
61
 
62
62
  async mutate(method, path, options = {}) {
63
- const sessionHash = await this.ensureSession();
64
- return this.http.request(method, path, {
65
- ...options,
66
- headers: {
67
- ...options.headers,
68
- 'X-Session-Hash': sessionHash,
69
- },
70
- });
63
+ const runRequest = async () => {
64
+ const sessionHash = await this.ensureSession();
65
+ return this.http.request(method, path, {
66
+ ...options,
67
+ headers: {
68
+ ...options.headers,
69
+ 'X-Session-Hash': sessionHash,
70
+ },
71
+ });
72
+ };
73
+
74
+ try {
75
+ return await runRequest();
76
+ } catch (error) {
77
+ if (!this.shouldRefreshSession(error)) {
78
+ throw error;
79
+ }
80
+
81
+ await this.refreshSession();
82
+ return runRequest();
83
+ }
71
84
  }
72
85
 
73
86
  async ensureSession() {
@@ -124,4 +137,13 @@ export class TestomatioApiClient {
124
137
  }
125
138
  }
126
139
  }
140
+
141
+ shouldRefreshSession(error) {
142
+ return error?.status === 403 && Boolean(this.sessionHash);
143
+ }
144
+
145
+ async refreshSession() {
146
+ this.sessionHash = null;
147
+ return this.ensureSession();
148
+ }
127
149
  }
@@ -1,3 +1,5 @@
1
+ import { PLANS_TQL_INPUT_DESCRIPTION, PLANS_TQL_REFERENCE } from './tql-reference.js';
2
+
1
3
  export const PLANS_TOOLS = [
2
4
  {
3
5
  "name": "plans_list",
@@ -56,7 +58,7 @@ export const PLANS_TOOLS = [
56
58
  },
57
59
  {
58
60
  "name": "plans_create",
59
- "description": "Create plan (/api/v2/{project_id}/plans)",
61
+ "description": `Create plan (/api/v2/{project_id}/plans). ${PLANS_TQL_REFERENCE}`,
60
62
  "inputSchema": {
61
63
  "type": "object",
62
64
  "properties": {
@@ -94,6 +96,10 @@ export const PLANS_TOOLS = [
94
96
  },
95
97
  "description": "List of suite IDs (8-char) to include in the plan. If omitted, all suites are considered."
96
98
  },
99
+ "tql": {
100
+ "type": "string",
101
+ "description": PLANS_TQL_INPUT_DESCRIPTION
102
+ },
97
103
  "link": {
98
104
  "type": "array",
99
105
  "items": {
@@ -138,7 +144,7 @@ export const PLANS_TOOLS = [
138
144
  },
139
145
  {
140
146
  "name": "plans_update",
141
- "description": "Update plan (/api/v2/{project_id}/plans/{id})",
147
+ "description": `Update plan (/api/v2/{project_id}/plans/{id}). ${PLANS_TQL_REFERENCE}`,
142
148
  "inputSchema": {
143
149
  "type": "object",
144
150
  "properties": {
@@ -179,6 +185,10 @@ export const PLANS_TOOLS = [
179
185
  },
180
186
  "description": "List of suite IDs (8-char) to include in the plan. If omitted, all suites are considered."
181
187
  },
188
+ "tql": {
189
+ "type": "string",
190
+ "description": PLANS_TQL_INPUT_DESCRIPTION
191
+ },
182
192
  "link": {
183
193
  "type": "array",
184
194
  "items": {
@@ -15,6 +15,8 @@ const TESTS_TQL_VARIABLES = [
15
15
  'assigned_to',
16
16
  'suite',
17
17
  'test',
18
+ 'shared',
19
+ 'milestone',
18
20
  ];
19
21
 
20
22
  const RUNS_TQL_VARIABLES = [
@@ -57,16 +59,20 @@ const RUNS_TQL_VARIABLES = [
57
59
  'updated_at',
58
60
  'launched_at',
59
61
  'finished_at',
62
+ 'milestone',
60
63
  ];
61
64
 
62
65
  const TESTS_TQL_EXAMPLES = [
63
66
  "priority == 'high'",
67
+ "priority >= 'normal'",
64
68
  "state == 'automated'",
65
69
  "tag in ['smoke', 'stage1'] and status == 'failed'",
66
70
  "suite % 'Checkout'",
67
71
  "test % 'User login'",
72
+ "custom_status % 'issue'",
68
73
  "created_at < 1.month_ago",
69
74
  "jira in ['JST-1', 'JST-2']",
75
+ "milestone == 'Sprint 1'",
70
76
  ];
71
77
 
72
78
  const RUNS_TQL_EXAMPLES = [
@@ -81,7 +87,7 @@ const RUNS_TQL_EXAMPLES = [
81
87
  ];
82
88
 
83
89
  const COMMON_TQL_SYNTAX =
84
- "Supported syntax includes `==`, `!=`, `>`, `<`, `>=`, `<=`, `in [...]`, `%` for partial text match, `and`, `or`, `not`, and parentheses for grouping. Use quotes for string values, for example `state == 'automated'`.";
90
+ "Supported syntax includes logical operators `and`, `or`, `not`, equality operators `==` and `!=`, list membership `in [...]`, `%` for partial text match on supported text fields, and parentheses for grouping. Ordered comparisons `>`, `<`, `>=`, `<=` are for ordered fields such as `priority`, dates, and numeric counters/durations. Use quotes for string values, for example `state == 'automated'`.";
85
91
 
86
92
  export const TESTS_TQL_REFERENCE =
87
93
  `TQL (Testomat.io Query Language) is a string expression passed in \`tql\` to filter tests. ${COMMON_TQL_SYNTAX} ` +
@@ -104,6 +110,17 @@ export const RUNS_TQL_INPUT_DESCRIPTION =
104
110
  `TQL filter for runs. Documented variables: ${RUNS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
105
111
  `Examples: ${RUNS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}.`;
106
112
 
113
+ export const PLANS_TQL_REFERENCE =
114
+ `TQL (Testomat.io Query Language) is a string expression passed in \`tql\` to select tests included in a plan. ${COMMON_TQL_SYNTAX} ` +
115
+ `Plan TQL uses documented test variables: ${TESTS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
116
+ `Documented examples: ${TESTS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}. ` +
117
+ 'Use `tql` when you want the API to resolve matching tests automatically instead of sending explicit `test_ids`. Do not invent undocumented fields or syntax. If a query fails, simplify it to one documented predicate.';
118
+
119
+ export const PLANS_TQL_INPUT_DESCRIPTION =
120
+ 'TQL filter for selecting tests included in the plan. ' +
121
+ `Documented test variables: ${TESTS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
122
+ `Examples: ${TESTS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}.`;
123
+
107
124
  export const ANALYTICS_TESTS_TQL_REFERENCE =
108
125
  `TQL (Testomat.io Query Language) is a string expression passed in \`q\` to filter enterprise analytics test reports. ${COMMON_TQL_SYNTAX} ` +
109
126
  'For analytics tools, the API parameter name is `q`, not `tql`. ' +
@@ -316,6 +316,7 @@ export const payloadMethods = {
316
316
  as_manual: asManual,
317
317
  test_ids: testIds,
318
318
  suite_ids: suiteIds,
319
+ tql,
319
320
  link,
320
321
  } = {}) {
321
322
  return {
@@ -326,6 +327,7 @@ export const payloadMethods = {
326
327
  as_manual: asManual,
327
328
  test_ids: testIds,
328
329
  suite_ids: suiteIds,
330
+ tql,
329
331
  link,
330
332
  };
331
333
  },