@testomatio/mcp-enterprise 2.0.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 ADDED
@@ -0,0 +1,22 @@
1
+ # Testomat.io MCP Enterprise
2
+
3
+ Enterprise Model Context Protocol server for Testomat.io API v2.
4
+
5
+ This package includes all tools from `@testomatio/mcp` plus enterprise analytics tools:
6
+
7
+ - `analytics_tests`
8
+ - `analytics_stats`
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install -g @testomatio/mcp-enterprise@latest
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ```bash
19
+ testomatio-mcp-enterprise --token <PROJECT_TOKEN> --project <PROJECT_ID>
20
+ ```
21
+
22
+ Analytics endpoints require the `api_analytics` subscription feature.
package/index.js ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from './src/main.js';
4
+
5
+ main(process.argv).catch((error) => {
6
+ console.error('Fatal startup error:', error.message || error);
7
+ process.exit(1);
8
+ });
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@testomatio/mcp-enterprise",
3
+ "version": "2.0.1",
4
+ "description": "Enterprise Model Context Protocol server for Testomat.io API with analytics tools",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "testomatio-mcp-enterprise": "index.js"
8
+ },
9
+ "type": "module",
10
+ "scripts": {
11
+ "prepack": "node ../../scripts/sync-enterprise-package.js"
12
+ },
13
+ "keywords": [
14
+ "testomatio",
15
+ "mcp",
16
+ "model-context-protocol",
17
+ "testing",
18
+ "api",
19
+ "analytics",
20
+ "enterprise"
21
+ ],
22
+ "author": "Testomatio Team",
23
+ "license": "MIT",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/testomatio/mcp",
27
+ "directory": "packages/enterprise"
28
+ },
29
+ "dependencies": {
30
+ "@testomatio/mcp": "2.0.1",
31
+ "commander": "^12.0.0"
32
+ },
33
+ "files": [
34
+ "index.js",
35
+ "src",
36
+ "README.md"
37
+ ],
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ }
41
+ }
@@ -0,0 +1,181 @@
1
+ import {
2
+ ANALYTICS_STATS_TQL_INPUT_DESCRIPTION,
3
+ ANALYTICS_STATS_TQL_REFERENCE,
4
+ ANALYTICS_TESTS_TQL_INPUT_DESCRIPTION,
5
+ ANALYTICS_TESTS_TQL_REFERENCE,
6
+ TOOL_DEFINITIONS,
7
+ } from './load-core.js';
8
+
9
+ const ANALYTICS_TEST_KINDS = [
10
+ 'flaky',
11
+ 'slow',
12
+ 'failing',
13
+ 'evergreen',
14
+ 'never-executed',
15
+ 'skipped',
16
+ 'failures',
17
+ 'defects',
18
+ 'issues',
19
+ ];
20
+
21
+ const ANALYTICS_STATS_KINDS = [
22
+ 'project-summary',
23
+ 'runs-summary',
24
+ 'success-rate-by-date',
25
+ 'automation-rate-by-date',
26
+ 'testruns-by-date',
27
+ 'priority-by-date',
28
+ ];
29
+
30
+ const commonAnalyticsProperties = {
31
+ days: {
32
+ type: 'integer',
33
+ minimum: 1,
34
+ description: 'Lookback window in days. Ignored when from/to are provided.',
35
+ },
36
+ from: {
37
+ type: 'string',
38
+ description: 'Inclusive start date in YYYY-MM-DD format. Takes precedence over days.',
39
+ },
40
+ to: {
41
+ type: 'string',
42
+ description: 'Inclusive end date in YYYY-MM-DD format.',
43
+ },
44
+ envs: {
45
+ type: 'string',
46
+ description: 'Comma-separated execution environments, for example: staging,production.',
47
+ },
48
+ };
49
+
50
+ export const ANALYTICS_TOOLS = [
51
+ {
52
+ name: 'analytics_tests',
53
+ description:
54
+ `Enterprise analytics: list tests matching an analytics report (/api/v2/{project_id}/analytics/tests/{kind}). Requires api_analytics subscription feature. ${ANALYTICS_TESTS_TQL_REFERENCE}`,
55
+ inputSchema: {
56
+ type: 'object',
57
+ properties: {
58
+ kind: {
59
+ type: 'string',
60
+ enum: ANALYTICS_TEST_KINDS,
61
+ description: 'Test-level analytics report kind.',
62
+ },
63
+ q: {
64
+ type: 'string',
65
+ description: ANALYTICS_TESTS_TQL_INPUT_DESCRIPTION,
66
+ },
67
+ ...commonAnalyticsProperties,
68
+ page: {
69
+ type: 'integer',
70
+ minimum: 1,
71
+ },
72
+ per_page: {
73
+ type: 'integer',
74
+ minimum: 1,
75
+ maximum: 100,
76
+ },
77
+ min: {
78
+ type: 'number',
79
+ minimum: 0,
80
+ maximum: 1,
81
+ description: 'Flaky rate lower bound. Applies only to kind=flaky.',
82
+ },
83
+ max: {
84
+ type: 'number',
85
+ minimum: 0,
86
+ maximum: 1,
87
+ description: 'Flaky rate upper bound. Applies only to kind=flaky.',
88
+ },
89
+ threshold_ms: {
90
+ type: 'integer',
91
+ minimum: 11,
92
+ description: 'Duration threshold in milliseconds. Applies only to kind=slow.',
93
+ },
94
+ maturity_days: {
95
+ type: 'integer',
96
+ minimum: 0,
97
+ description: 'Minimum test age in days. Applies only to kind=never-executed.',
98
+ },
99
+ run: {
100
+ type: 'string',
101
+ description: 'Scope results to one run UID. Applies only to kind=flaky or kind=slow.',
102
+ },
103
+ },
104
+ required: ['kind'],
105
+ additionalProperties: false,
106
+ },
107
+ },
108
+ {
109
+ name: 'analytics_stats',
110
+ description:
111
+ `Enterprise analytics: fetch an aggregated analytics report (/api/v2/{project_id}/analytics/stats/{kind}). Requires api_analytics subscription feature. ${ANALYTICS_STATS_TQL_REFERENCE}`,
112
+ inputSchema: {
113
+ type: 'object',
114
+ properties: {
115
+ kind: {
116
+ type: 'string',
117
+ enum: ANALYTICS_STATS_KINDS,
118
+ description: 'Aggregated analytics report kind.',
119
+ },
120
+ q: {
121
+ type: 'string',
122
+ description: ANALYTICS_STATS_TQL_INPUT_DESCRIPTION,
123
+ },
124
+ ...commonAnalyticsProperties,
125
+ },
126
+ required: ['kind'],
127
+ additionalProperties: false,
128
+ },
129
+ },
130
+ ];
131
+
132
+ export const ENTERPRISE_TOOL_DEFINITIONS = [
133
+ ...TOOL_DEFINITIONS,
134
+ ...ANALYTICS_TOOLS,
135
+ ];
136
+
137
+ export function registerAnalyticsHandlers(handlers) {
138
+ handlers.analytics_tests = async (args = {}) => this.asText(await analyticsTests.call(this, args));
139
+ handlers.analytics_stats = async (args = {}) => this.asText(await analyticsStats.call(this, args));
140
+ }
141
+
142
+ function analyticsTests({
143
+ kind,
144
+ q,
145
+ days,
146
+ from,
147
+ to,
148
+ envs,
149
+ page,
150
+ per_page: perPage,
151
+ min,
152
+ max,
153
+ threshold_ms: thresholdMs,
154
+ maturity_days: maturityDays,
155
+ run,
156
+ } = {}) {
157
+ return this.apiClient.list(`analytics/tests/${this.pickRequiredArg({ kind }, 'kind')}`, {
158
+ q,
159
+ days,
160
+ from,
161
+ to,
162
+ envs,
163
+ page,
164
+ per_page: perPage,
165
+ min,
166
+ max,
167
+ threshold_ms: thresholdMs,
168
+ maturity_days: maturityDays,
169
+ run,
170
+ });
171
+ }
172
+
173
+ function analyticsStats({ kind, q, days, from, to, envs } = {}) {
174
+ return this.apiClient.list(`analytics/stats/${this.pickRequiredArg({ kind }, 'kind')}`, {
175
+ q,
176
+ days,
177
+ from,
178
+ to,
179
+ envs,
180
+ });
181
+ }
@@ -0,0 +1,29 @@
1
+ async function loadCoreModule() {
2
+ try {
3
+ const installedCore = await import('@testomatio/mcp');
4
+ if (
5
+ installedCore &&
6
+ typeof installedCore.createApplication === 'function' &&
7
+ installedCore.ConfigurationError &&
8
+ Array.isArray(installedCore.TOOL_DEFINITIONS)
9
+ ) {
10
+ return installedCore;
11
+ }
12
+ } catch {
13
+ // Fall back to the local repo copy when testing from a checkout.
14
+ }
15
+
16
+ return import('../../../src/index.js');
17
+ }
18
+
19
+ const coreModule = await loadCoreModule();
20
+
21
+ export const {
22
+ ANALYTICS_STATS_TQL_INPUT_DESCRIPTION,
23
+ ANALYTICS_STATS_TQL_REFERENCE,
24
+ ANALYTICS_TESTS_TQL_INPUT_DESCRIPTION,
25
+ ANALYTICS_TESTS_TQL_REFERENCE,
26
+ ConfigurationError,
27
+ TOOL_DEFINITIONS,
28
+ createApplication,
29
+ } = coreModule;
package/src/main.js ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { ConfigurationError, createApplication } from './load-core.js';
5
+ import { ENTERPRISE_TOOL_DEFINITIONS, registerAnalyticsHandlers } from './analytics.js';
6
+ import { getPackageVersion } from './package-version.js';
7
+
8
+ export function parseArgs(argv = process.argv) {
9
+ const command = new Command();
10
+
11
+ command
12
+ .name('testomatio-mcp-enterprise')
13
+ .description('Enterprise Model Context Protocol server for Testomat.io API v2')
14
+ .version(getPackageVersion())
15
+ .option('-t, --token <token>', 'Testomatio Project token')
16
+ .option('-p, --project <project>', 'Project ID')
17
+ .option('--base-url <url>', 'Base URL for Testomat.io API')
18
+ .parse(argv);
19
+
20
+ return command.opts();
21
+ }
22
+
23
+ export function createEnterpriseApplication(argvOptions = {}) {
24
+ return createApplication(argvOptions, {
25
+ tools: ENTERPRISE_TOOL_DEFINITIONS,
26
+ name: 'testomatio-mcp-enterprise-server',
27
+ registryOptions: {
28
+ handlerRegistrars: [registerAnalyticsHandlers],
29
+ },
30
+ });
31
+ }
32
+
33
+ export async function main(argv = process.argv) {
34
+ try {
35
+ const options = parseArgs(argv);
36
+ const app = createEnterpriseApplication(options);
37
+ await app.mcpServer.run();
38
+ } catch (error) {
39
+ if (error instanceof ConfigurationError) {
40
+ console.error(`Configuration error: ${error.message}`);
41
+ process.exit(1);
42
+ }
43
+
44
+ console.error('Failed to start enterprise server:', error.message || error);
45
+ process.exit(1);
46
+ }
47
+ }
@@ -0,0 +1,19 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ let cachedVersion;
6
+
7
+ export function getPackageVersion() {
8
+ if (cachedVersion) {
9
+ return cachedVersion;
10
+ }
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+ const packageJsonPath = path.resolve(__dirname, '../package.json');
15
+ const raw = fs.readFileSync(packageJsonPath, 'utf8');
16
+ const pkg = JSON.parse(raw);
17
+ cachedVersion = pkg.version || '0.0.0';
18
+ return cachedVersion;
19
+ }