ai-test-process-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/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/resources/index.js +17 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/iso29119.js +114 -0
- package/dist/resources/iso29119.js.map +1 -0
- package/dist/server.js +11 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/generateTestPlan.js +143 -0
- package/dist/tools/generateTestPlan.js.map +1 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hashi_Kazu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# ai-test-process-mcp
|
|
2
|
+
|
|
3
|
+
AIによるテストプロセス支援MCPサーバー。
|
|
4
|
+
|
|
5
|
+
**Phase 1(実装済み)**: テスト計画書(ISO/IEC/IEEE 29119-3準拠)のドラフト生成のみ。
|
|
6
|
+
**将来構想**: テスト設計・レビュー・品質ゲート・テストメトリクス・改善提案を段階的に追加。
|
|
7
|
+
|
|
8
|
+
## セットアップ
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install
|
|
12
|
+
npm run build
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 提供する機能
|
|
16
|
+
|
|
17
|
+
### Resource: `iso29119://test-plan/structure`
|
|
18
|
+
|
|
19
|
+
ISO/IEC/IEEE 29119-3のテスト計画15章立て(Introduction〜Approvals)を構造化データ(JSON)として公開する。
|
|
20
|
+
|
|
21
|
+
### Tool: `generate_test_plan_draft`
|
|
22
|
+
|
|
23
|
+
プロジェクト情報(`projectName`, `scope` は必須。`objectives`, `risks`, `scheduleConstraints`, `team` など任意項目)を入力すると、ISO29119の章立てに沿ったMarkdown形式のテスト計画書ドラフトを生成する。未入力の項目は `_TBD — not provided by caller_` として明示される。
|
|
24
|
+
|
|
25
|
+
## コマンド
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm run dev # tsc --watch
|
|
29
|
+
npm start # node dist/server.js(stdio transport)
|
|
30
|
+
npm test # vitest run
|
|
31
|
+
npm run inspect # build後、MCP Inspectorを起動して動作確認
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 動作確認(CLI)
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx @modelcontextprotocol/inspector --cli node dist/server.js --method resources/list
|
|
38
|
+
npx @modelcontextprotocol/inspector --cli node dist/server.js --method tools/list
|
|
39
|
+
npx @modelcontextprotocol/inspector --cli node dist/server.js --method tools/call \
|
|
40
|
+
--tool-name generate_test_plan_draft \
|
|
41
|
+
--tool-arg projectName="ECサイト" \
|
|
42
|
+
--tool-arg scope="決済とログイン機能"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 実クライアントへの登録例(Claude Desktop / Claude Code)
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"ai-test-process-mcp": {
|
|
51
|
+
"command": "node",
|
|
52
|
+
"args": ["<repo-path>/dist/server.js"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
npm公開後は、リポジトリをローカルにcloneしなくても `npx` 経由で起動できる(`.vscode/mcp.json` の例)。
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"servers": {
|
|
63
|
+
"ai-test-process-mcp": {
|
|
64
|
+
"command": "npx",
|
|
65
|
+
"args": ["-y", "ai-test-process-mcp"]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 公開手順(メンテナ向け)
|
|
72
|
+
|
|
73
|
+
1. `npm login`(npmjs.comのアカウントで認証)
|
|
74
|
+
2. `npm run build`(`npm publish` 実行時は `prepublishOnly` フックにより自動実行されるため、手動実行は任意)
|
|
75
|
+
3. `npm publish`
|
|
76
|
+
|
|
77
|
+
公開後の接続方式(stdio)は変わらない。MCPレジストリ(`server.json` / `mcp-publisher`)への登録は本手順の対象外で、将来の別タスクとして扱う。
|
|
78
|
+
|
|
79
|
+
## 将来機能の追加方法
|
|
80
|
+
|
|
81
|
+
新しい機能(テスト設計・レビュー・品質ゲート・テストメトリクス・改善提案)を追加する際は、以下のパターンに従う:
|
|
82
|
+
|
|
83
|
+
1. `src/resources/<name>.ts` — 必要な参照データ(構造化データ)を定義
|
|
84
|
+
2. `src/tools/<name>.ts` — zod入力スキーマ + 純粋なレンダリング関数 + `registerXxxTool()`
|
|
85
|
+
3. `src/resources/index.ts` / `src/tools/index.ts` にそれぞれ1行登録を追加
|
|
86
|
+
4. `test/<name>.test.ts` でレンダリング関数を単体テスト
|
|
87
|
+
|
|
88
|
+
`server.ts` 本体は変更不要。プラグインローダーやレジストリのような抽象化は、モジュール数が増えて明示的な登録リストが煩雑になるまで導入しない。
|
|
89
|
+
|
|
90
|
+
詳細は [AGENTS.md](./AGENTS.md) と [docs/ai/project-overview.md](./docs/ai/project-overview.md) を参照。
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { iso29119TestPlanStructure } from "./iso29119.js";
|
|
2
|
+
export function registerResources(server) {
|
|
3
|
+
server.registerResource("iso29119-test-plan-structure", "iso29119://test-plan/structure", {
|
|
4
|
+
title: "ISO 29119 Test Plan Structure",
|
|
5
|
+
description: "Structural reference for ISO/IEC/IEEE 29119-3 conformant test plans: section list, standard references, and required fields per section.",
|
|
6
|
+
mimeType: "application/json",
|
|
7
|
+
}, async (uri) => ({
|
|
8
|
+
contents: [
|
|
9
|
+
{
|
|
10
|
+
uri: uri.href,
|
|
11
|
+
mimeType: "application/json",
|
|
12
|
+
text: JSON.stringify(iso29119TestPlanStructure, null, 2),
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAE1D,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,CAAC,gBAAgB,CACrB,8BAA8B,EAC9B,gCAAgC,EAChC;QACE,KAAK,EAAE,+BAA+B;QACtC,WAAW,EACT,0IAA0I;QAC5I,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACd,QAAQ,EAAE;YACR;gBACE,GAAG,EAAE,GAAG,CAAC,IAAI;gBACb,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,yBAAyB,EAAE,IAAI,EAAE,CAAC,CAAC;aACzD;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Section purposes are paraphrased summaries of ISO/IEC/IEEE 29119-3:2013 clause 4.2
|
|
2
|
+
// (Test Plan document), not verbatim standard text.
|
|
3
|
+
export const iso29119TestPlanStructure = {
|
|
4
|
+
standard: "ISO/IEC/IEEE 29119-3:2013",
|
|
5
|
+
documentType: "Test Plan",
|
|
6
|
+
sections: [
|
|
7
|
+
{
|
|
8
|
+
id: "introduction",
|
|
9
|
+
title: "Introduction",
|
|
10
|
+
standardRef: "§4.2.1",
|
|
11
|
+
description: "Purpose, background, and references for the test plan.",
|
|
12
|
+
requiredFields: ["purpose", "background", "references"],
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "test-items",
|
|
16
|
+
title: "Test Items",
|
|
17
|
+
standardRef: "§4.2.2",
|
|
18
|
+
description: "The items (software, systems, features) that are the object of testing.",
|
|
19
|
+
requiredFields: ["itemsUnderTest", "versionOrRelease"],
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "features-to-be-tested",
|
|
23
|
+
title: "Features to be Tested",
|
|
24
|
+
standardRef: "§4.2.3",
|
|
25
|
+
description: "Features or functions that are within scope of the testing effort.",
|
|
26
|
+
requiredFields: ["featureList"],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "features-not-to-be-tested",
|
|
30
|
+
title: "Features Not to be Tested",
|
|
31
|
+
standardRef: "§4.2.4",
|
|
32
|
+
description: "Features or functions explicitly excluded from testing, with rationale.",
|
|
33
|
+
requiredFields: ["excludedFeatureList", "exclusionRationale"],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "approach",
|
|
37
|
+
title: "Test Approach",
|
|
38
|
+
standardRef: "§4.2.5",
|
|
39
|
+
description: "The overall testing strategy, techniques, and levels to be applied.",
|
|
40
|
+
requiredFields: ["testLevels", "testTypes", "testTechniques"],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "item-pass-fail-criteria",
|
|
44
|
+
title: "Item Pass/Fail Criteria",
|
|
45
|
+
standardRef: "§4.2.6",
|
|
46
|
+
description: "Criteria used to determine whether a test item has passed or failed testing.",
|
|
47
|
+
requiredFields: ["passCriteria", "failCriteria"],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: "suspension-resumption-criteria",
|
|
51
|
+
title: "Suspension and Resumption Criteria",
|
|
52
|
+
standardRef: "§4.2.7",
|
|
53
|
+
description: "Conditions that would cause testing to be suspended, and conditions for resuming.",
|
|
54
|
+
requiredFields: ["suspensionCriteria", "resumptionCriteria"],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "test-deliverables",
|
|
58
|
+
title: "Test Deliverables",
|
|
59
|
+
standardRef: "§4.2.8",
|
|
60
|
+
description: "Documents and artifacts produced as output of the testing process.",
|
|
61
|
+
requiredFields: ["deliverableList"],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "testing-tasks",
|
|
65
|
+
title: "Testing Tasks",
|
|
66
|
+
standardRef: "§4.2.9",
|
|
67
|
+
description: "The set of tasks necessary to prepare for and perform testing.",
|
|
68
|
+
requiredFields: ["taskList", "taskDependencies"],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "environmental-needs",
|
|
72
|
+
title: "Environmental Needs",
|
|
73
|
+
standardRef: "§4.2.10",
|
|
74
|
+
description: "Hardware, software, data, tools, and facilities required for testing.",
|
|
75
|
+
requiredFields: ["hardware", "software", "testData", "tools"],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: "responsibilities",
|
|
79
|
+
title: "Responsibilities",
|
|
80
|
+
standardRef: "§4.2.11",
|
|
81
|
+
description: "Roles and responsibilities of individuals or groups involved in testing.",
|
|
82
|
+
requiredFields: ["roleAssignments"],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: "staffing-and-training-needs",
|
|
86
|
+
title: "Staffing and Training Needs",
|
|
87
|
+
standardRef: "§4.2.12",
|
|
88
|
+
description: "Staffing requirements and any training needed to carry out the test tasks.",
|
|
89
|
+
requiredFields: ["staffingNeeds", "trainingNeeds"],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: "schedule",
|
|
93
|
+
title: "Schedule",
|
|
94
|
+
standardRef: "§4.2.13",
|
|
95
|
+
description: "Key dates, milestones, and duration estimates for testing tasks.",
|
|
96
|
+
requiredFields: ["startDate", "endDate", "milestones"],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: "risks-and-contingencies",
|
|
100
|
+
title: "Risks and Contingencies",
|
|
101
|
+
standardRef: "§4.2.14",
|
|
102
|
+
description: "Risks that could affect the testing effort, along with mitigation/contingency plans.",
|
|
103
|
+
requiredFields: ["riskList"],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "approvals",
|
|
107
|
+
title: "Approvals",
|
|
108
|
+
standardRef: "§4.2.15",
|
|
109
|
+
description: "Names and roles of people who must approve the test plan.",
|
|
110
|
+
requiredFields: ["approverList"],
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=iso29119.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"iso29119.js","sourceRoot":"","sources":["../../src/resources/iso29119.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { registerResources } from "./resources/index.js";
|
|
5
|
+
import { registerTools } from "./tools/index.js";
|
|
6
|
+
const server = new McpServer({ name: "ai-test-process-mcp", version: "0.1.0" });
|
|
7
|
+
registerResources(server);
|
|
8
|
+
registerTools(server);
|
|
9
|
+
const transport = new StdioServerTransport();
|
|
10
|
+
await server.connect(transport);
|
|
11
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AAEhF,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,aAAa,CAAC,MAAM,CAAC,CAAC;AAEtB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { iso29119TestPlanStructure } from "../resources/iso29119.js";
|
|
3
|
+
const TBD = "_TBD — not provided by caller_";
|
|
4
|
+
export const generateTestPlanInputShape = {
|
|
5
|
+
projectName: z.string().describe("Name of the project or system under test"),
|
|
6
|
+
scope: z.string().describe("What is in scope for testing (features, systems, boundaries)"),
|
|
7
|
+
objectives: z.array(z.string()).optional().describe("Test objectives / goals"),
|
|
8
|
+
featuresToTest: z.array(z.string()).optional(),
|
|
9
|
+
featuresNotToTest: z.array(z.string()).optional(),
|
|
10
|
+
risks: z
|
|
11
|
+
.array(z.object({
|
|
12
|
+
description: z.string(),
|
|
13
|
+
impact: z.enum(["low", "medium", "high"]).optional(),
|
|
14
|
+
mitigation: z.string().optional(),
|
|
15
|
+
}))
|
|
16
|
+
.optional(),
|
|
17
|
+
scheduleConstraints: z
|
|
18
|
+
.object({
|
|
19
|
+
startDate: z.string().optional(),
|
|
20
|
+
endDate: z.string().optional(),
|
|
21
|
+
milestones: z.array(z.object({ name: z.string(), date: z.string() })).optional(),
|
|
22
|
+
})
|
|
23
|
+
.optional(),
|
|
24
|
+
team: z
|
|
25
|
+
.array(z.object({
|
|
26
|
+
role: z.string(),
|
|
27
|
+
name: z.string().optional(),
|
|
28
|
+
responsibilities: z.string().optional(),
|
|
29
|
+
}))
|
|
30
|
+
.optional(),
|
|
31
|
+
environment: z.string().optional().describe("Test environment needs (hardware, software, data, tools)"),
|
|
32
|
+
deliverables: z.array(z.string()).optional(),
|
|
33
|
+
passFailCriteria: z.string().optional(),
|
|
34
|
+
suspensionCriteria: z.string().optional(),
|
|
35
|
+
approvers: z.array(z.string()).optional(),
|
|
36
|
+
};
|
|
37
|
+
const generateTestPlanInputSchema = z.object(generateTestPlanInputShape);
|
|
38
|
+
function listOrTbd(items) {
|
|
39
|
+
if (!items || items.length === 0)
|
|
40
|
+
return TBD;
|
|
41
|
+
return items.map((item) => `- ${item}`).join("\n");
|
|
42
|
+
}
|
|
43
|
+
function risksOrTbd(risks) {
|
|
44
|
+
if (!risks || risks.length === 0)
|
|
45
|
+
return TBD;
|
|
46
|
+
return risks
|
|
47
|
+
.map((risk) => {
|
|
48
|
+
const parts = [`- ${risk.description}`];
|
|
49
|
+
if (risk.impact)
|
|
50
|
+
parts.push(`(impact: ${risk.impact})`);
|
|
51
|
+
if (risk.mitigation)
|
|
52
|
+
parts.push(`— mitigation: ${risk.mitigation}`);
|
|
53
|
+
return parts.join(" ");
|
|
54
|
+
})
|
|
55
|
+
.join("\n");
|
|
56
|
+
}
|
|
57
|
+
function teamOrTbd(team) {
|
|
58
|
+
if (!team || team.length === 0)
|
|
59
|
+
return TBD;
|
|
60
|
+
return team
|
|
61
|
+
.map((member) => {
|
|
62
|
+
const namePart = member.name ? ` (${member.name})` : "";
|
|
63
|
+
const respPart = member.responsibilities ? `: ${member.responsibilities}` : "";
|
|
64
|
+
return `- ${member.role}${namePart}${respPart}`;
|
|
65
|
+
})
|
|
66
|
+
.join("\n");
|
|
67
|
+
}
|
|
68
|
+
function scheduleOrTbd(schedule) {
|
|
69
|
+
if (!schedule || (!schedule.startDate && !schedule.endDate && !schedule.milestones?.length)) {
|
|
70
|
+
return TBD;
|
|
71
|
+
}
|
|
72
|
+
const lines = [];
|
|
73
|
+
lines.push(`- Start date: ${schedule.startDate ?? TBD}`);
|
|
74
|
+
lines.push(`- End date: ${schedule.endDate ?? TBD}`);
|
|
75
|
+
if (schedule.milestones && schedule.milestones.length > 0) {
|
|
76
|
+
lines.push("- Milestones:");
|
|
77
|
+
for (const milestone of schedule.milestones) {
|
|
78
|
+
lines.push(` - ${milestone.name}: ${milestone.date}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return lines.join("\n");
|
|
82
|
+
}
|
|
83
|
+
function sectionContent(sectionId, input) {
|
|
84
|
+
switch (sectionId) {
|
|
85
|
+
case "introduction":
|
|
86
|
+
return `**Purpose:** ${input.scope}\n\n**Objectives:**\n${listOrTbd(input.objectives)}`;
|
|
87
|
+
case "test-items":
|
|
88
|
+
return `**Project:** ${input.projectName}\n\n**Scope:** ${input.scope}`;
|
|
89
|
+
case "features-to-be-tested":
|
|
90
|
+
return listOrTbd(input.featuresToTest);
|
|
91
|
+
case "features-not-to-be-tested":
|
|
92
|
+
return listOrTbd(input.featuresNotToTest);
|
|
93
|
+
case "approach":
|
|
94
|
+
return TBD;
|
|
95
|
+
case "item-pass-fail-criteria":
|
|
96
|
+
return input.passFailCriteria ?? TBD;
|
|
97
|
+
case "suspension-resumption-criteria":
|
|
98
|
+
return input.suspensionCriteria ?? TBD;
|
|
99
|
+
case "test-deliverables":
|
|
100
|
+
return listOrTbd(input.deliverables);
|
|
101
|
+
case "testing-tasks":
|
|
102
|
+
return TBD;
|
|
103
|
+
case "environmental-needs":
|
|
104
|
+
return input.environment ?? TBD;
|
|
105
|
+
case "responsibilities":
|
|
106
|
+
return teamOrTbd(input.team);
|
|
107
|
+
case "staffing-and-training-needs":
|
|
108
|
+
return TBD;
|
|
109
|
+
case "schedule":
|
|
110
|
+
return scheduleOrTbd(input.scheduleConstraints);
|
|
111
|
+
case "risks-and-contingencies":
|
|
112
|
+
return risksOrTbd(input.risks);
|
|
113
|
+
case "approvals":
|
|
114
|
+
return listOrTbd(input.approvers);
|
|
115
|
+
default:
|
|
116
|
+
return TBD;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export function renderTestPlan(input, structure = iso29119TestPlanStructure) {
|
|
120
|
+
const lines = [];
|
|
121
|
+
lines.push(`# Test Plan: ${input.projectName}`);
|
|
122
|
+
lines.push("");
|
|
123
|
+
lines.push(`*Conforms to the structure of ${structure.standard}*`);
|
|
124
|
+
lines.push("");
|
|
125
|
+
structure.sections.forEach((section, index) => {
|
|
126
|
+
lines.push(`## ${index + 1}. ${section.title}`);
|
|
127
|
+
lines.push("");
|
|
128
|
+
lines.push(sectionContent(section.id, input));
|
|
129
|
+
lines.push("");
|
|
130
|
+
});
|
|
131
|
+
return lines.join("\n").trimEnd() + "\n";
|
|
132
|
+
}
|
|
133
|
+
export function registerGenerateTestPlanTool(server) {
|
|
134
|
+
server.registerTool("generate_test_plan_draft", {
|
|
135
|
+
title: "Generate Test Plan Draft",
|
|
136
|
+
description: "Generates an ISO/IEC/IEEE 29119-3 conformant test plan document draft in markdown from project information. Fields not provided are marked as TBD.",
|
|
137
|
+
inputSchema: generateTestPlanInputShape,
|
|
138
|
+
}, async (input) => {
|
|
139
|
+
const markdown = renderTestPlan(input);
|
|
140
|
+
return { content: [{ type: "text", text: markdown }] };
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=generateTestPlan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateTestPlan.js","sourceRoot":"","sources":["../../src/tools/generateTestPlan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAErE,MAAM,UAAU,aAAa,CAAC,MAAiB;IAC7C,4BAA4B,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ai-test-process-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "MCP server providing AI-assisted test process tools, starting with ISO/IEC/IEEE 29119-3 conformant test plan draft generation.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Hashi_Kazu <outsider.prs.0721@gmail.com>",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/Hashi-Kazu/ai-test-process-mcp.git"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"mcp",
|
|
14
|
+
"model-context-protocol",
|
|
15
|
+
"test-plan",
|
|
16
|
+
"iso29119",
|
|
17
|
+
"testing"
|
|
18
|
+
],
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"bin": {
|
|
23
|
+
"ai-test-process-mcp": "dist/server.js"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"dev": "tsc --watch",
|
|
28
|
+
"start": "node dist/server.js",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"inspect": "npm run build && npx @modelcontextprotocol/inspector node dist/server.js",
|
|
31
|
+
"prepublishOnly": "npm run build"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
35
|
+
"zod": "^4.4.3"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@modelcontextprotocol/inspector": "^0.22.0",
|
|
39
|
+
"@types/node": "^22.10.0",
|
|
40
|
+
"typescript": "^5.7.0",
|
|
41
|
+
"vitest": "^3.0.0"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
}
|
|
46
|
+
}
|