cucumberstudio-mcp 1.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.
Files changed (130) hide show
  1. package/.env.example +36 -0
  2. package/.github/workflows/pr-checks.yml +41 -0
  3. package/.github/workflows/release.yml +194 -0
  4. package/.prettierignore +26 -0
  5. package/.prettierrc +14 -0
  6. package/CLAUDE.md +140 -0
  7. package/Dockerfile +50 -0
  8. package/Dockerfile.dev +31 -0
  9. package/LICENSE +21 -0
  10. package/README.md +395 -0
  11. package/build/api/client.d.ts +49 -0
  12. package/build/api/client.d.ts.map +1 -0
  13. package/build/api/client.js +204 -0
  14. package/build/api/client.js.map +1 -0
  15. package/build/api/types.d.ts +113 -0
  16. package/build/api/types.d.ts.map +1 -0
  17. package/build/api/types.js +2 -0
  18. package/build/api/types.js.map +1 -0
  19. package/build/config/settings.d.ts +123 -0
  20. package/build/config/settings.d.ts.map +1 -0
  21. package/build/config/settings.js +97 -0
  22. package/build/config/settings.js.map +1 -0
  23. package/build/constants.d.ts +16 -0
  24. package/build/constants.d.ts.map +1 -0
  25. package/build/constants.js +24 -0
  26. package/build/constants.js.map +1 -0
  27. package/build/generated/version.d.ts +3 -0
  28. package/build/generated/version.d.ts.map +1 -0
  29. package/build/generated/version.js +5 -0
  30. package/build/generated/version.js.map +1 -0
  31. package/build/index.d.ts +3 -0
  32. package/build/index.d.ts.map +1 -0
  33. package/build/index.js +81 -0
  34. package/build/index.js.map +1 -0
  35. package/build/mcp-server.d.ts +6 -0
  36. package/build/mcp-server.d.ts.map +1 -0
  37. package/build/mcp-server.js +263 -0
  38. package/build/mcp-server.js.map +1 -0
  39. package/build/tools/action-words.d.ts +18 -0
  40. package/build/tools/action-words.d.ts.map +1 -0
  41. package/build/tools/action-words.js +191 -0
  42. package/build/tools/action-words.js.map +1 -0
  43. package/build/tools/projects.d.ts +19 -0
  44. package/build/tools/projects.d.ts.map +1 -0
  45. package/build/tools/projects.js +123 -0
  46. package/build/tools/projects.js.map +1 -0
  47. package/build/tools/scenarios.d.ts +18 -0
  48. package/build/tools/scenarios.d.ts.map +1 -0
  49. package/build/tools/scenarios.js +194 -0
  50. package/build/tools/scenarios.js.map +1 -0
  51. package/build/tools/test-runs.d.ts +21 -0
  52. package/build/tools/test-runs.d.ts.map +1 -0
  53. package/build/tools/test-runs.js +324 -0
  54. package/build/tools/test-runs.js.map +1 -0
  55. package/build/transports/http.d.ts +38 -0
  56. package/build/transports/http.d.ts.map +1 -0
  57. package/build/transports/http.js +381 -0
  58. package/build/transports/http.js.map +1 -0
  59. package/build/transports/index.d.ts +22 -0
  60. package/build/transports/index.d.ts.map +1 -0
  61. package/build/transports/index.js +10 -0
  62. package/build/transports/index.js.map +1 -0
  63. package/build/transports/stdio.d.ts +13 -0
  64. package/build/transports/stdio.d.ts.map +1 -0
  65. package/build/transports/stdio.js +24 -0
  66. package/build/transports/stdio.js.map +1 -0
  67. package/build/utils/errors.d.ts +10 -0
  68. package/build/utils/errors.d.ts.map +1 -0
  69. package/build/utils/errors.js +35 -0
  70. package/build/utils/errors.js.map +1 -0
  71. package/build/utils/logger-constants.d.ts +15 -0
  72. package/build/utils/logger-constants.d.ts.map +1 -0
  73. package/build/utils/logger-constants.js +16 -0
  74. package/build/utils/logger-constants.js.map +1 -0
  75. package/build/utils/logger.d.ts +55 -0
  76. package/build/utils/logger.d.ts.map +1 -0
  77. package/build/utils/logger.js +113 -0
  78. package/build/utils/logger.js.map +1 -0
  79. package/build/utils/validation.d.ts +89 -0
  80. package/build/utils/validation.d.ts.map +1 -0
  81. package/build/utils/validation.js +78 -0
  82. package/build/utils/validation.js.map +1 -0
  83. package/docker-compose.yml +20 -0
  84. package/eslint.config.js +97 -0
  85. package/package.json +92 -0
  86. package/scripts/generate-version.js +31 -0
  87. package/src/api/client.ts +286 -0
  88. package/src/api/types.ts +137 -0
  89. package/src/config/settings.ts +113 -0
  90. package/src/constants.ts +29 -0
  91. package/src/index.ts +99 -0
  92. package/src/mcp-server.ts +342 -0
  93. package/src/tools/action-words.ts +240 -0
  94. package/src/tools/projects.ts +144 -0
  95. package/src/tools/scenarios.ts +231 -0
  96. package/src/tools/test-runs.ts +400 -0
  97. package/src/transports/http.ts +467 -0
  98. package/src/transports/index.ts +26 -0
  99. package/src/transports/stdio.ts +28 -0
  100. package/src/utils/errors.ts +45 -0
  101. package/src/utils/logger-constants.ts +18 -0
  102. package/src/utils/logger.ts +150 -0
  103. package/src/utils/validation.ts +94 -0
  104. package/test/api/client-with-msw.test.ts +122 -0
  105. package/test/api/client.test.ts +326 -0
  106. package/test/api/types.test.ts +88 -0
  107. package/test/config/settings.test.ts +204 -0
  108. package/test/mocks/data/action-words.ts +40 -0
  109. package/test/mocks/data/index.ts +13 -0
  110. package/test/mocks/data/projects.ts +38 -0
  111. package/test/mocks/data/scenarios.ts +53 -0
  112. package/test/mocks/data/test-runs.ts +101 -0
  113. package/test/mocks/handlers/action-words.ts +52 -0
  114. package/test/mocks/handlers/index.ts +10 -0
  115. package/test/mocks/handlers/projects.ts +45 -0
  116. package/test/mocks/handlers/scenarios.ts +72 -0
  117. package/test/mocks/handlers/test-runs.ts +106 -0
  118. package/test/mocks/server.ts +26 -0
  119. package/test/setup/vitest.setup.ts +18 -0
  120. package/test/tools/coverage-boost.test.ts +252 -0
  121. package/test/tools/projects.test.ts +290 -0
  122. package/test/tools/tools-basic.test.ts +146 -0
  123. package/test/transports/http-basic.test.ts +87 -0
  124. package/test/transports/http-simple.test.ts +33 -0
  125. package/test/transports/stdio.test.ts +73 -0
  126. package/test/utils/errors.test.ts +117 -0
  127. package/test/utils/validation.test.ts +261 -0
  128. package/tsconfig.build.json +8 -0
  129. package/tsconfig.json +27 -0
  130. package/vitest.config.ts +43 -0
@@ -0,0 +1,113 @@
1
+ import { DEFAULT_LOG_LEVEL } from '../constants.js';
2
+ import { LOG_COLORS as ANSI_COLORS } from './logger-constants.js';
3
+ const LOG_LEVELS = {
4
+ error: 0,
5
+ warn: 1,
6
+ info: 2,
7
+ debug: 3,
8
+ trace: 4,
9
+ };
10
+ const LOG_COLORS = {
11
+ error: ANSI_COLORS.ERROR,
12
+ warn: ANSI_COLORS.WARN,
13
+ info: ANSI_COLORS.INFO,
14
+ debug: ANSI_COLORS.DEBUG,
15
+ trace: ANSI_COLORS.DEBUG, // Using same as debug
16
+ };
17
+ const RESET_COLOR = ANSI_COLORS.RESET;
18
+ /**
19
+ * No-operation logger for testing - discards all log messages
20
+ */
21
+ export class NoOpLogger {
22
+ error() { }
23
+ warn() { }
24
+ info() { }
25
+ debug() { }
26
+ trace() { }
27
+ }
28
+ /**
29
+ * Logger implementation that outputs to stderr
30
+ * Safe for use with STDIO MCP transport as it won't interfere with stdout protocol
31
+ */
32
+ export class StderrLogger {
33
+ config;
34
+ constructor(config) {
35
+ this.config = {
36
+ enableTimestamp: true,
37
+ enableColors: true,
38
+ ...config,
39
+ };
40
+ }
41
+ shouldLog(level) {
42
+ return LOG_LEVELS[level] <= LOG_LEVELS[this.config.level];
43
+ }
44
+ formatMessage(level, message, meta) {
45
+ let formatted = '';
46
+ // Add timestamp if enabled
47
+ if (this.config.enableTimestamp) {
48
+ formatted += `[${new Date().toISOString()}] `;
49
+ }
50
+ // Add level with color if enabled
51
+ const levelUpper = level.toUpperCase().padEnd(5);
52
+ if (this.config.enableColors) {
53
+ formatted += `${LOG_COLORS[level]}${levelUpper}${RESET_COLOR} `;
54
+ }
55
+ else {
56
+ formatted += `${levelUpper} `;
57
+ }
58
+ // Add prefix if configured
59
+ if (this.config.prefix) {
60
+ formatted += `${this.config.prefix} `;
61
+ }
62
+ // Add message
63
+ formatted += message;
64
+ // Add metadata
65
+ if (meta !== undefined) {
66
+ if (typeof meta === 'object') {
67
+ formatted += ` ${JSON.stringify(meta)}`;
68
+ }
69
+ else {
70
+ formatted += ` ${String(meta)}`;
71
+ }
72
+ }
73
+ return formatted;
74
+ }
75
+ writeLog(level, message, meta) {
76
+ if (!this.shouldLog(level))
77
+ return;
78
+ const formatted = this.formatMessage(level, message, meta);
79
+ console.error(formatted);
80
+ }
81
+ error(message, meta) {
82
+ this.writeLog('error', message, meta);
83
+ }
84
+ warn(message, meta) {
85
+ this.writeLog('warn', message, meta);
86
+ }
87
+ info(message, meta) {
88
+ this.writeLog('info', message, meta);
89
+ }
90
+ debug(message, meta) {
91
+ this.writeLog('debug', message, meta);
92
+ }
93
+ trace(message, meta) {
94
+ this.writeLog('trace', message, meta);
95
+ }
96
+ }
97
+ /**
98
+ * No-op logger for testing or when logging is disabled
99
+ */
100
+ export class NoopLogger {
101
+ error() { }
102
+ warn() { }
103
+ info() { }
104
+ debug() { }
105
+ trace() { }
106
+ }
107
+ /**
108
+ * Helper to get log level from environment
109
+ */
110
+ export function getLogLevel() {
111
+ return process.env.LOG_LEVEL || DEFAULT_LOG_LEVEL;
112
+ }
113
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ import { z } from 'zod';
2
+ export declare const ProjectIdSchema: z.ZodString;
3
+ export declare const ScenarioIdSchema: z.ZodString;
4
+ export declare const ActionWordIdSchema: z.ZodString;
5
+ export declare const FolderIdSchema: z.ZodString;
6
+ export declare const TestRunIdSchema: z.ZodString;
7
+ export declare const BuildIdSchema: z.ZodString;
8
+ export declare const PaginationSchema: z.ZodOptional<z.ZodObject<{
9
+ page: z.ZodOptional<z.ZodNumber>;
10
+ pageSize: z.ZodOptional<z.ZodNumber>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ page?: number | undefined;
13
+ pageSize?: number | undefined;
14
+ }, {
15
+ page?: number | undefined;
16
+ pageSize?: number | undefined;
17
+ }>>;
18
+ export declare const FilterSchema: z.ZodOptional<z.ZodObject<{
19
+ name: z.ZodOptional<z.ZodString>;
20
+ tags: z.ZodOptional<z.ZodString>;
21
+ }, "strip", z.ZodTypeAny, {
22
+ name?: string | undefined;
23
+ tags?: string | undefined;
24
+ }, {
25
+ name?: string | undefined;
26
+ tags?: string | undefined;
27
+ }>>;
28
+ export declare const ListParamsSchema: z.ZodOptional<z.ZodObject<{
29
+ pagination: z.ZodOptional<z.ZodObject<{
30
+ page: z.ZodOptional<z.ZodNumber>;
31
+ pageSize: z.ZodOptional<z.ZodNumber>;
32
+ }, "strip", z.ZodTypeAny, {
33
+ page?: number | undefined;
34
+ pageSize?: number | undefined;
35
+ }, {
36
+ page?: number | undefined;
37
+ pageSize?: number | undefined;
38
+ }>>;
39
+ filter: z.ZodOptional<z.ZodObject<{
40
+ name: z.ZodOptional<z.ZodString>;
41
+ tags: z.ZodOptional<z.ZodString>;
42
+ }, "strip", z.ZodTypeAny, {
43
+ name?: string | undefined;
44
+ tags?: string | undefined;
45
+ }, {
46
+ name?: string | undefined;
47
+ tags?: string | undefined;
48
+ }>>;
49
+ }, "strip", z.ZodTypeAny, {
50
+ filter?: {
51
+ name?: string | undefined;
52
+ tags?: string | undefined;
53
+ } | undefined;
54
+ pagination?: {
55
+ page?: number | undefined;
56
+ pageSize?: number | undefined;
57
+ } | undefined;
58
+ }, {
59
+ filter?: {
60
+ name?: string | undefined;
61
+ tags?: string | undefined;
62
+ } | undefined;
63
+ pagination?: {
64
+ page?: number | undefined;
65
+ pageSize?: number | undefined;
66
+ } | undefined;
67
+ }>>;
68
+ /**
69
+ * Convert pagination and filter parameters to API format
70
+ */
71
+ export declare function convertToApiParams(params?: {
72
+ pagination?: {
73
+ page?: number;
74
+ pageSize?: number;
75
+ };
76
+ filter?: {
77
+ name?: string;
78
+ tags?: string;
79
+ };
80
+ }): Record<string, unknown>;
81
+ /**
82
+ * Validate input against a schema and throw MCP error if invalid
83
+ */
84
+ export declare function validateInput<T>(schema: z.ZodSchema<T>, input: unknown, context?: string): T;
85
+ /**
86
+ * Validate that required environment variables are present
87
+ */
88
+ export declare function validateEnvironment(): void;
89
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAKvB,eAAO,MAAM,eAAe,aAA8C,CAAA;AAC1E,eAAO,MAAM,gBAAgB,aAA+C,CAAA;AAC5E,eAAO,MAAM,kBAAkB,aAAkD,CAAA;AACjF,eAAO,MAAM,cAAc,aAA6C,CAAA;AACxE,eAAO,MAAM,eAAe,aAA+C,CAAA;AAC3E,eAAO,MAAM,aAAa,aAA4C,CAAA;AAGtE,eAAO,MAAM,gBAAgB;;;;;;;;;GAKhB,CAAA;AAGb,eAAO,MAAM,YAAY;;;;;;;;;GAKZ,CAAA;AAGb,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAKhB,CAAA;AAEb;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE;IAC1C,UAAU,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACjD,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC1C,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsB1B;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAU5F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAQ1C"}
@@ -0,0 +1,78 @@
1
+ import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
2
+ import { z } from 'zod';
3
+ import { MAX_PAGE_SIZE } from '../constants.js';
4
+ // Common validation schemas
5
+ export const ProjectIdSchema = z.string().min(1, 'Project ID is required');
6
+ export const ScenarioIdSchema = z.string().min(1, 'Scenario ID is required');
7
+ export const ActionWordIdSchema = z.string().min(1, 'Action Word ID is required');
8
+ export const FolderIdSchema = z.string().min(1, 'Folder ID is required');
9
+ export const TestRunIdSchema = z.string().min(1, 'Test Run ID is required');
10
+ export const BuildIdSchema = z.string().min(1, 'Build ID is required');
11
+ // Pagination schema
12
+ export const PaginationSchema = z
13
+ .object({
14
+ page: z.number().int().min(1).optional(),
15
+ pageSize: z.number().int().min(1).max(MAX_PAGE_SIZE).optional(),
16
+ })
17
+ .optional();
18
+ // Filter schema
19
+ export const FilterSchema = z
20
+ .object({
21
+ name: z.string().optional(),
22
+ tags: z.string().optional(),
23
+ })
24
+ .optional();
25
+ // List parameters schema
26
+ export const ListParamsSchema = z
27
+ .object({
28
+ pagination: PaginationSchema,
29
+ filter: FilterSchema,
30
+ })
31
+ .optional();
32
+ /**
33
+ * Convert pagination and filter parameters to API format
34
+ */
35
+ export function convertToApiParams(params) {
36
+ if (!params)
37
+ return {};
38
+ const apiParams = {};
39
+ if (params.pagination?.page) {
40
+ apiParams['page[number]'] = params.pagination.page;
41
+ }
42
+ if (params.pagination?.pageSize) {
43
+ apiParams['page[size]'] = params.pagination.pageSize;
44
+ }
45
+ if (params.filter?.name) {
46
+ apiParams['filter[name]'] = params.filter.name;
47
+ }
48
+ if (params.filter?.tags) {
49
+ apiParams['filter[tags]'] = params.filter.tags;
50
+ }
51
+ return apiParams;
52
+ }
53
+ /**
54
+ * Validate input against a schema and throw MCP error if invalid
55
+ */
56
+ export function validateInput(schema, input, context) {
57
+ try {
58
+ return schema.parse(input);
59
+ }
60
+ catch (error) {
61
+ if (error instanceof z.ZodError) {
62
+ const issues = error.errors.map((e) => `${e.path.join('.')}: ${e.message}`).join(', ');
63
+ throw new McpError(ErrorCode.InvalidParams, `Invalid parameters${context ? ` for ${context}` : ''}: ${issues}`);
64
+ }
65
+ throw error;
66
+ }
67
+ }
68
+ /**
69
+ * Validate that required environment variables are present
70
+ */
71
+ export function validateEnvironment() {
72
+ const required = ['CUCUMBERSTUDIO_ACCESS_TOKEN', 'CUCUMBERSTUDIO_CLIENT_ID', 'CUCUMBERSTUDIO_UID'];
73
+ const missing = required.filter((envVar) => !process.env[envVar]);
74
+ if (missing.length > 0) {
75
+ throw new McpError(ErrorCode.InvalidRequest, `Missing required environment variables: ${missing.join(', ')}`);
76
+ }
77
+ }
78
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE/C,4BAA4B;AAC5B,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAA;AAC1E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,yBAAyB,CAAC,CAAA;AAC5E,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,4BAA4B,CAAC,CAAA;AACjF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,uBAAuB,CAAC,CAAA;AACxE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,yBAAyB,CAAC,CAAA;AAC3E,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAA;AAEtE,oBAAoB;AACpB,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC;KAC9B,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACxC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE;CAChE,CAAC;KACD,QAAQ,EAAE,CAAA;AAEb,gBAAgB;AAChB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC;KAC1B,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC;KACD,QAAQ,EAAE,CAAA;AAEb,yBAAyB;AACzB,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC;KAC9B,MAAM,CAAC;IACN,UAAU,EAAE,gBAAgB;IAC5B,MAAM,EAAE,YAAY;CACrB,CAAC;KACD,QAAQ,EAAE,CAAA;AAEb;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAGlC;IACC,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAA;IAEtB,MAAM,SAAS,GAA4B,EAAE,CAAA;IAE7C,IAAI,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;QAC5B,SAAS,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAA;IACpD,CAAC;IAED,IAAI,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE,CAAC;QAChC,SAAS,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAA;IACtD,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;QACxB,SAAS,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAA;IAChD,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;QACxB,SAAS,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAA;IAChD,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAI,MAAsB,EAAE,KAAc,EAAE,OAAgB;IACvF,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACtF,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,qBAAqB,OAAO,CAAC,CAAC,CAAC,QAAQ,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC,CAAA;QACjH,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,QAAQ,GAAG,CAAC,6BAA6B,EAAE,0BAA0B,EAAE,oBAAoB,CAAC,CAAA;IAElG,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;IAEjE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,2CAA2C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC/G,CAAC;AACH,CAAC"}
@@ -0,0 +1,20 @@
1
+ version: '3.8'
2
+
3
+ services:
4
+ cucumberstudio-mcp:
5
+ build: .
6
+ env_file:
7
+ - .env
8
+ restart: unless-stopped
9
+ ports:
10
+ - "${MCP_PORT:-3000}:3000"
11
+ healthcheck:
12
+ test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/health", "||", "exit", "1"]
13
+ interval: 30s
14
+ timeout: 10s
15
+ retries: 3
16
+ start_period: 40s
17
+
18
+ networks:
19
+ default:
20
+ name: cucumberstudio-mcp-network
@@ -0,0 +1,97 @@
1
+ import tseslint from '@typescript-eslint/eslint-plugin'
2
+ import tsparser from '@typescript-eslint/parser'
3
+ import importPlugin from 'eslint-plugin-import'
4
+
5
+ export default [
6
+ {
7
+ files: ['**/*.ts', '**/*.tsx'],
8
+ languageOptions: {
9
+ parser: tsparser,
10
+ parserOptions: {
11
+ ecmaVersion: 2022,
12
+ sourceType: 'module',
13
+ project: './tsconfig.json',
14
+ },
15
+ },
16
+ plugins: {
17
+ '@typescript-eslint': tseslint,
18
+ import: importPlugin,
19
+ },
20
+ settings: {
21
+ 'import/resolver': {
22
+ typescript: {
23
+ alwaysTryTypes: true,
24
+ project: './tsconfig.json',
25
+ },
26
+ },
27
+ },
28
+ rules: {
29
+ // TypeScript-specific rules
30
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
31
+ '@typescript-eslint/explicit-function-return-type': 'off',
32
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
33
+ '@typescript-eslint/no-explicit-any': 'error',
34
+ '@typescript-eslint/no-non-null-assertion': 'off', // Allow ! in Result pattern
35
+
36
+ // Import organization rules
37
+ 'import/order': [
38
+ 'error',
39
+ {
40
+ groups: [
41
+ 'builtin', // Node.js built-in modules
42
+ 'external', // External libraries
43
+ 'internal', // Internal modules (using path mapping)
44
+ 'parent', // Parent directories
45
+ 'sibling', // Same directory
46
+ 'index', // Index files
47
+ ],
48
+ 'newlines-between': 'always',
49
+ alphabetize: {
50
+ order: 'asc',
51
+ caseInsensitive: true,
52
+ },
53
+ pathGroups: [
54
+ {
55
+ pattern: '@/**',
56
+ group: 'internal',
57
+ position: 'before',
58
+ },
59
+ ],
60
+ pathGroupsExcludedImportTypes: ['builtin'],
61
+ },
62
+ ],
63
+ 'import/newline-after-import': 'error',
64
+ 'import/no-duplicates': 'error',
65
+ 'import/no-unused-modules': 'off', // Can be enabled for stricter checking
66
+
67
+ // General code quality rules
68
+ 'no-console': 'off', // Allow console for this MCP server
69
+ 'no-debugger': 'error',
70
+ 'no-unused-vars': 'off', // Use TypeScript version instead
71
+ 'prefer-const': 'error',
72
+ 'no-var': 'error',
73
+ 'object-shorthand': 'error',
74
+ 'prefer-arrow-callback': 'error',
75
+ },
76
+ },
77
+ {
78
+ files: ['**/*.test.ts', '**/*.spec.ts', 'test/**/*.ts'],
79
+ rules: {
80
+ // Relax some rules for test files
81
+ '@typescript-eslint/no-explicit-any': 'off',
82
+ '@typescript-eslint/no-non-null-assertion': 'off',
83
+ '@typescript-eslint/no-unused-vars': 'off',
84
+ },
85
+ },
86
+ {
87
+ // Ignore patterns
88
+ ignores: [
89
+ 'build/**',
90
+ 'node_modules/**',
91
+ 'coverage/**',
92
+ '*.js', // Ignore JS files in root (like this config file)
93
+ 'vitest.config.ts', // Vitest config not in main tsconfig
94
+ '**/*.d.ts', // Ignore generated TypeScript declaration files
95
+ ],
96
+ },
97
+ ]
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "cucumberstudio-mcp",
3
+ "version": "1.1.0",
4
+ "description": "MCP server for Cucumber Studio API integration",
5
+ "main": "build/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "cucumberstudio-mcp": "./build/index.js"
9
+ },
10
+ "scripts": {
11
+ "prepare": "node scripts/generate-version.js",
12
+ "prebuild": "node scripts/generate-version.js",
13
+ "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
14
+ "start": "node build/index.js",
15
+ "start:http": "MCP_TRANSPORT=http node build/index.js",
16
+ "dev": "tsx --watch -r tsconfig-paths/register src/index.ts",
17
+ "dev:http": "MCP_TRANSPORT=http tsx --watch -r tsconfig-paths/register src/index.ts",
18
+ "test": "vitest run",
19
+ "test:watch": "vitest",
20
+ "test:ui": "vitest --ui",
21
+ "test:coverage": "vitest run --coverage",
22
+ "test:ui-coverage": "vitest --ui --coverage",
23
+ "lint": "eslint src test --ext .ts",
24
+ "lint:fix": "eslint src test --ext .ts --fix",
25
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
26
+ "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
27
+ "typecheck": "tsc --noEmit",
28
+ "docker:build": "docker build -t cucumberstudio-mcp .",
29
+ "docker:build:dev": "docker build -f Dockerfile.dev -t cucumberstudio-mcp:dev .",
30
+ "docker:run": "docker run --env-file .env cucumberstudio-mcp",
31
+ "docker:run:dev": "docker run --env-file .env -v $(pwd)/src:/app/src cucumberstudio-mcp:dev",
32
+ "docker:compose:up": "docker-compose up",
33
+ "docker:compose:up:dev": "docker-compose --profile dev up cucumberstudio-mcp-dev",
34
+ "docker:compose:down": "docker-compose down",
35
+ "docker:compose:build": "docker-compose build"
36
+ },
37
+ "keywords": [
38
+ "mcp",
39
+ "cucumber",
40
+ "testing",
41
+ "api",
42
+ "automation",
43
+ "model-context-protocol",
44
+ "cucumber-studio",
45
+ "ai",
46
+ "llm"
47
+ ],
48
+ "author": "",
49
+ "license": "MIT",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/HeroSizy/cucumberstudio-mcp.git"
53
+ },
54
+ "bugs": {
55
+ "url": "https://github.com/HeroSizy/cucumberstudio-mcp/issues"
56
+ },
57
+ "homepage": "https://github.com/HeroSizy/cucumberstudio-mcp#readme",
58
+ "preferGlobal": true,
59
+ "dependencies": {
60
+ "@modelcontextprotocol/sdk": "^1.12.3",
61
+ "axios": "^1.6.0",
62
+ "cors": "^2.8.5",
63
+ "dotenv": "^16.5.0",
64
+ "express": "^4.18.0",
65
+ "zod": "^3.22.0"
66
+ },
67
+ "devDependencies": {
68
+ "@types/cors": "^2.8.0",
69
+ "@types/express": "^4.17.0",
70
+ "@types/node": "^22.15.30",
71
+ "@typescript-eslint/eslint-plugin": "^8.34.0",
72
+ "@typescript-eslint/parser": "^8.34.0",
73
+ "@vitest/coverage-v8": "^3.2.2",
74
+ "@vitest/ui": "^3.2.2",
75
+ "eslint": "^9.28.0",
76
+ "eslint-config-prettier": "^9.0.0",
77
+ "eslint-import-resolver-typescript": "^4.4.3",
78
+ "eslint-plugin-import": "^2.31.0",
79
+ "eslint-plugin-prettier": "^5.0.0",
80
+ "msw": "^2.10.2",
81
+ "prettier": "^3.5.3",
82
+ "tsc-alias": "^1.8.16",
83
+ "tsconfig-paths": "^4.2.0",
84
+ "tsx": "^4.0.0",
85
+ "typescript": "^5.8.3",
86
+ "vite-tsconfig-paths": "^5.1.4",
87
+ "vitest": "^3.2.2"
88
+ },
89
+ "engines": {
90
+ "node": ">=20.0.0"
91
+ }
92
+ }
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync, writeFileSync, mkdirSync } from 'fs'
4
+ import { join, dirname } from 'path'
5
+ import { fileURLToPath } from 'url'
6
+
7
+ // Get current directory for ES modules
8
+ const __filename = fileURLToPath(import.meta.url)
9
+ const __dirname = dirname(__filename)
10
+
11
+ // Read package.json
12
+ const packagePath = join(__dirname, '..', 'package.json')
13
+ const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'))
14
+
15
+ // Generate version constants file
16
+ const versionContent = `// Auto-generated version info - DO NOT EDIT
17
+ // Generated at build time from package.json
18
+
19
+ export const PACKAGE_VERSION = '${packageJson.version}'
20
+ export const PACKAGE_NAME = '${packageJson.name}'
21
+ `
22
+
23
+ // Ensure the generated directory exists
24
+ const generatedDir = join(__dirname, '..', 'src', 'generated')
25
+ mkdirSync(generatedDir, { recursive: true })
26
+
27
+ // Write to src/generated/version.ts
28
+ const outputPath = join(generatedDir, 'version.ts')
29
+ writeFileSync(outputPath, versionContent)
30
+
31
+ console.log(`✅ Generated version constants: ${packageJson.name}@${packageJson.version}`)