@auto-docs-test-code/test-code-mcp 0.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/README.md +78 -0
- package/index.mjs +267 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# @auto-docs/test-code-mcp
|
|
2
|
+
|
|
3
|
+
Auto Docs 백엔드의 `POST /api/ai/api-tests/generate`를 MCP tool로 노출하는 패키지입니다.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @auto-docs/test-code-mcp
|
|
9
|
+
# or
|
|
10
|
+
yarn add @auto-docs/test-code-mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
개발 중 로컬 테스트:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install ./tools/auto-docs-test-code-mcp
|
|
17
|
+
# or
|
|
18
|
+
yarn add file:./tools/auto-docs-test-code-mcp
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Environment
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
export AUTO_DOCS_API_BASE_URL=http://localhost:8080/api
|
|
25
|
+
export AUTO_DOCS_ACCESS_TOKEN=<your-jwt>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## MCP Server command
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
auto-docs-test-code-mcp
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Tool
|
|
35
|
+
|
|
36
|
+
### `generate_api_tests_and_qa`
|
|
37
|
+
|
|
38
|
+
입력 파라미터:
|
|
39
|
+
- `projectId` (required, number)
|
|
40
|
+
- `request` (required, string)
|
|
41
|
+
- `baseUrl` (optional)
|
|
42
|
+
- `token` (optional)
|
|
43
|
+
- `apiSpec` (optional)
|
|
44
|
+
- `implementationContext` (optional)
|
|
45
|
+
- `framework` (optional)
|
|
46
|
+
- `targetFilePathHint` (optional)
|
|
47
|
+
- `maxQaItems` (optional)
|
|
48
|
+
- `createQaTickets` (optional, default: `false`)
|
|
49
|
+
- `qaLabels` (optional, string[])
|
|
50
|
+
- `assignees` (optional, string[])
|
|
51
|
+
|
|
52
|
+
반환:
|
|
53
|
+
- Auto Docs API `data` payload(JSON text)
|
|
54
|
+
|
|
55
|
+
## Example MCP config
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"mcpServers": {
|
|
60
|
+
"auto-docs-test-code": {
|
|
61
|
+
"command": "auto-docs-test-code-mcp",
|
|
62
|
+
"env": {
|
|
63
|
+
"AUTO_DOCS_API_BASE_URL": "http://localhost:8080/api",
|
|
64
|
+
"AUTO_DOCS_ACCESS_TOKEN": "<JWT>"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Publish
|
|
72
|
+
|
|
73
|
+
패키지 퍼블리시는 이 디렉터리에서 실행:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cd tools/auto-docs-test-code-mcp
|
|
77
|
+
npm publish --access public
|
|
78
|
+
```
|
package/index.mjs
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import {
|
|
6
|
+
CallToolRequestSchema,
|
|
7
|
+
ListToolsRequestSchema,
|
|
8
|
+
McpError,
|
|
9
|
+
ErrorCode,
|
|
10
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
11
|
+
|
|
12
|
+
const TOOL_NAME = 'generate_api_tests_and_qa';
|
|
13
|
+
const DEFAULT_BASE_URL = 'http://localhost:8080/api';
|
|
14
|
+
|
|
15
|
+
function normalizeBaseUrl(raw) {
|
|
16
|
+
const value = `${raw || DEFAULT_BASE_URL}`.trim();
|
|
17
|
+
if (!value) {
|
|
18
|
+
return DEFAULT_BASE_URL;
|
|
19
|
+
}
|
|
20
|
+
return value.replace(/\/+$/, '');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function assertString(value, name, required = false) {
|
|
24
|
+
if (value === undefined || value === null) {
|
|
25
|
+
if (required) {
|
|
26
|
+
throw new McpError(ErrorCode.InvalidParams, `${name} is required.`);
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (typeof value !== 'string') {
|
|
32
|
+
throw new McpError(ErrorCode.InvalidParams, `${name} must be a string.`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const normalized = value.trim();
|
|
36
|
+
if (!normalized && required) {
|
|
37
|
+
throw new McpError(ErrorCode.InvalidParams, `${name} cannot be empty.`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return normalized || undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function assertNumber(value, name, required = false) {
|
|
44
|
+
if (value === undefined || value === null) {
|
|
45
|
+
if (required) {
|
|
46
|
+
throw new McpError(ErrorCode.InvalidParams, `${name} is required.`);
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const parsed = Number(value);
|
|
52
|
+
if (!Number.isFinite(parsed)) {
|
|
53
|
+
throw new McpError(ErrorCode.InvalidParams, `${name} must be a number.`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return parsed;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function assertBoolean(value, name, defaultValue) {
|
|
60
|
+
if (value === undefined || value === null) {
|
|
61
|
+
return defaultValue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (typeof value !== 'boolean') {
|
|
65
|
+
throw new McpError(ErrorCode.InvalidParams, `${name} must be a boolean.`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function assertStringArray(value, name) {
|
|
72
|
+
if (value === undefined || value === null) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
|
|
77
|
+
throw new McpError(
|
|
78
|
+
ErrorCode.InvalidParams,
|
|
79
|
+
`${name} must be an array of strings.`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return value.map((item) => item.trim()).filter(Boolean);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function callGenerateApiTests(payload) {
|
|
87
|
+
const baseUrl = normalizeBaseUrl(payload.baseUrl || process.env.AUTO_DOCS_API_BASE_URL);
|
|
88
|
+
const token = assertString(
|
|
89
|
+
payload.token || process.env.AUTO_DOCS_ACCESS_TOKEN,
|
|
90
|
+
'token',
|
|
91
|
+
true,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const response = await fetch(`${baseUrl}/ai/api-tests/generate`, {
|
|
95
|
+
method: 'POST',
|
|
96
|
+
headers: {
|
|
97
|
+
'Content-Type': 'application/json',
|
|
98
|
+
Authorization: `Bearer ${token}`,
|
|
99
|
+
},
|
|
100
|
+
body: JSON.stringify({
|
|
101
|
+
projectId: payload.projectId,
|
|
102
|
+
request: payload.request,
|
|
103
|
+
apiSpec: payload.apiSpec,
|
|
104
|
+
implementationContext: payload.implementationContext,
|
|
105
|
+
framework: payload.framework,
|
|
106
|
+
targetFilePathHint: payload.targetFilePathHint,
|
|
107
|
+
maxQaItems: payload.maxQaItems,
|
|
108
|
+
createQaTickets: payload.createQaTickets,
|
|
109
|
+
qaLabels: payload.qaLabels,
|
|
110
|
+
assignees: payload.assignees,
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const json = await response.json().catch(() => null);
|
|
115
|
+
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const reason =
|
|
118
|
+
json?.message ||
|
|
119
|
+
json?.error?.message ||
|
|
120
|
+
`Request failed with status ${response.status}`;
|
|
121
|
+
|
|
122
|
+
throw new McpError(ErrorCode.InternalError, `Auto Docs API error: ${reason}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return json;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function createServer() {
|
|
129
|
+
const server = new Server(
|
|
130
|
+
{
|
|
131
|
+
name: '@auto-docs/test-code-mcp',
|
|
132
|
+
version: '0.1.0',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
capabilities: {
|
|
136
|
+
tools: {},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
142
|
+
tools: [
|
|
143
|
+
{
|
|
144
|
+
name: TOOL_NAME,
|
|
145
|
+
description:
|
|
146
|
+
'Generate API test draft and optional QA tickets via Auto Docs backend.',
|
|
147
|
+
inputSchema: {
|
|
148
|
+
type: 'object',
|
|
149
|
+
additionalProperties: false,
|
|
150
|
+
properties: {
|
|
151
|
+
baseUrl: {
|
|
152
|
+
type: 'string',
|
|
153
|
+
description:
|
|
154
|
+
'Auto Docs API base URL. Default: AUTO_DOCS_API_BASE_URL or http://localhost:8080/api',
|
|
155
|
+
},
|
|
156
|
+
token: {
|
|
157
|
+
type: 'string',
|
|
158
|
+
description:
|
|
159
|
+
'Access token. Default: AUTO_DOCS_ACCESS_TOKEN environment variable.',
|
|
160
|
+
},
|
|
161
|
+
projectId: {
|
|
162
|
+
type: 'number',
|
|
163
|
+
description: 'Project ID',
|
|
164
|
+
},
|
|
165
|
+
request: {
|
|
166
|
+
type: 'string',
|
|
167
|
+
description: 'Natural-language request for API test generation',
|
|
168
|
+
},
|
|
169
|
+
apiSpec: {
|
|
170
|
+
type: 'string',
|
|
171
|
+
description: 'API specification summary',
|
|
172
|
+
},
|
|
173
|
+
implementationContext: {
|
|
174
|
+
type: 'string',
|
|
175
|
+
description: 'Implementation context summary',
|
|
176
|
+
},
|
|
177
|
+
framework: {
|
|
178
|
+
type: 'string',
|
|
179
|
+
description: 'Testing framework hint (e.g., jest + supertest)',
|
|
180
|
+
},
|
|
181
|
+
targetFilePathHint: {
|
|
182
|
+
type: 'string',
|
|
183
|
+
description: 'Target test file path hint',
|
|
184
|
+
},
|
|
185
|
+
maxQaItems: {
|
|
186
|
+
type: 'number',
|
|
187
|
+
description: 'Maximum number of QA tickets to generate',
|
|
188
|
+
},
|
|
189
|
+
createQaTickets: {
|
|
190
|
+
type: 'boolean',
|
|
191
|
+
description: 'Whether to create QA tickets in backend (default: false)',
|
|
192
|
+
},
|
|
193
|
+
qaLabels: {
|
|
194
|
+
type: 'array',
|
|
195
|
+
items: { type: 'string' },
|
|
196
|
+
description: 'Labels for generated QA tickets',
|
|
197
|
+
},
|
|
198
|
+
assignees: {
|
|
199
|
+
type: 'array',
|
|
200
|
+
items: { type: 'string' },
|
|
201
|
+
description: 'Assignees for generated QA tickets',
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
required: ['projectId', 'request'],
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
}));
|
|
209
|
+
|
|
210
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
211
|
+
const { name, arguments: args = {} } = request.params;
|
|
212
|
+
|
|
213
|
+
if (name !== TOOL_NAME) {
|
|
214
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const projectId = assertNumber(args.projectId, 'projectId', true);
|
|
218
|
+
if (!Number.isInteger(projectId) || projectId <= 0) {
|
|
219
|
+
throw new McpError(
|
|
220
|
+
ErrorCode.InvalidParams,
|
|
221
|
+
'projectId must be a positive integer.',
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const payload = {
|
|
226
|
+
baseUrl: assertString(args.baseUrl, 'baseUrl'),
|
|
227
|
+
token: assertString(args.token, 'token'),
|
|
228
|
+
projectId,
|
|
229
|
+
request: assertString(args.request, 'request', true),
|
|
230
|
+
apiSpec: assertString(args.apiSpec, 'apiSpec'),
|
|
231
|
+
implementationContext: assertString(
|
|
232
|
+
args.implementationContext,
|
|
233
|
+
'implementationContext',
|
|
234
|
+
),
|
|
235
|
+
framework: assertString(args.framework, 'framework'),
|
|
236
|
+
targetFilePathHint: assertString(args.targetFilePathHint, 'targetFilePathHint'),
|
|
237
|
+
maxQaItems: assertNumber(args.maxQaItems, 'maxQaItems'),
|
|
238
|
+
createQaTickets: assertBoolean(args.createQaTickets, 'createQaTickets', false),
|
|
239
|
+
qaLabels: assertStringArray(args.qaLabels, 'qaLabels'),
|
|
240
|
+
assignees: assertStringArray(args.assignees, 'assignees'),
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const result = await callGenerateApiTests(payload);
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
content: [
|
|
247
|
+
{
|
|
248
|
+
type: 'text',
|
|
249
|
+
text: JSON.stringify(result?.data ?? result, null, 2),
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
return server;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function main() {
|
|
259
|
+
const server = createServer();
|
|
260
|
+
const transport = new StdioServerTransport();
|
|
261
|
+
await server.connect(transport);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
main().catch((error) => {
|
|
265
|
+
console.error('[auto-docs-test-code-mcp] fatal error:', error);
|
|
266
|
+
process.exit(1);
|
|
267
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@auto-docs-test-code/test-code-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Auto Docs AI API test generation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.mjs",
|
|
7
|
+
"bin": {
|
|
8
|
+
"auto-docs-test-code-mcp": "index.mjs"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"index.mjs",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"mcp",
|
|
16
|
+
"model-context-protocol",
|
|
17
|
+
"auto-docs",
|
|
18
|
+
"api-test",
|
|
19
|
+
"qa"
|
|
20
|
+
],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.18.1"
|
|
27
|
+
}
|
|
28
|
+
}
|