targetprocess-mcp-server 2.0.0 → 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 +8 -3
- package/build/index.js +119 -8
- package/build/tp.js +39 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,9 +24,9 @@ It acts as a **bridge between LLM agents and the Targetprocess API**, providing:
|
|
|
24
24
|
|
|
25
25
|
- "Show me currently active release"
|
|
26
26
|
- "write me test cases based on 145322 tp user story"
|
|
27
|
+
- "write detailed test cases based on 145642 bug, format them inside html <div> element, create a test plan and add test cases to it"
|
|
27
28
|
- "add a comment to 145155 card saying 'test'"
|
|
28
|
-
- "write test cases based on 145640
|
|
29
|
-
- "write detailed test cases based on 145642 user story, format them inside html <div> element and add them as a comment"
|
|
29
|
+
- "write test cases based on 145640 feature"
|
|
30
30
|
- "create a bug based on 145637 user story where Add Tile flyout (for a Static Tile) not show"
|
|
31
31
|
- "search for a card with 'Text Element' title"
|
|
32
32
|
|
|
@@ -56,7 +56,12 @@ Cards — Write
|
|
|
56
56
|
- `add_comment` — Post a comment to any card (id, comment)
|
|
57
57
|
- `create_bug` — Create a standalone bug (title, bugContent, optional origin)
|
|
58
58
|
- `create_bug_based_on_card` — Create a bug linked to an existing user story or bug card (card object with id+type, title, bugContent, optional origin)
|
|
59
|
-
- `create_test_plan` — Create a test plan linked to a
|
|
59
|
+
- `create_test_plan` — Create a test plan linked to a UserStory, Bug, or Feature (title, resourceId, optional resourceType, optional description/startDate/endDate)
|
|
60
|
+
- `add_test_cases` — Create a test plan and add generated test cases to it in one call (resourceId, testPlanTitle, testCases array of {name, description}, optional resourceType)
|
|
61
|
+
|
|
62
|
+
Test Case Workflows
|
|
63
|
+
- `write_test_cases` — Fetch a card (UserStory, Bug, or Feature) by ID and trigger the full test case writing workflow: Claude analyzes the card, generates detailed HTML-formatted test cases covering happy path, edge cases, and error scenarios, creates a linked test plan, then calls `add_test_cases_to_test_plan` (resourceId, optional resourceType)
|
|
64
|
+
- `add_test_cases_to_test_plan` — Add an array of pre-generated test cases to an existing test plan by its ID (testPlanId, testCases array of {name, description})
|
|
60
65
|
|
|
61
66
|
Projects
|
|
62
67
|
- `get_projects` — Get all Targetprocess projects (no params needed)
|
package/build/index.js
CHANGED
|
@@ -692,23 +692,30 @@ server.registerTool('create_bug', {
|
|
|
692
692
|
};
|
|
693
693
|
});
|
|
694
694
|
server.registerTool('create_test_plan', {
|
|
695
|
-
title: 'Create a new test plan
|
|
696
|
-
description: `Create a new test plan
|
|
695
|
+
title: 'Create a new test plan linked to a TP card',
|
|
696
|
+
description: `Create a new test plan linked to a UserStory, Bug, or Feature. Name and Project are required by the API; Description, StartDate, and EndDate are optional.`,
|
|
697
697
|
inputSchema: {
|
|
698
698
|
title: z.string()
|
|
699
|
-
.describe(
|
|
700
|
-
|
|
699
|
+
.describe('Test plan title — use the linked card name with a prefix (e.g. "Test Plan: User story title")'),
|
|
700
|
+
resourceId: z.string()
|
|
701
701
|
.min(5)
|
|
702
702
|
.max(6)
|
|
703
|
-
.describe(
|
|
703
|
+
.describe('ID of the card to link this test plan to (e.g. 145789)'),
|
|
704
|
+
resourceType: z.enum(['UserStory', 'Bug', 'Feature'])
|
|
705
|
+
.default('UserStory')
|
|
706
|
+
.optional()
|
|
707
|
+
.describe('Type of the linked card — UserStory, Bug, or Feature (default: UserStory)'),
|
|
708
|
+
description: z.string()
|
|
709
|
+
.optional()
|
|
710
|
+
.describe('Optional description of the test plan scope or goals')
|
|
704
711
|
},
|
|
705
|
-
}, async ({ title,
|
|
706
|
-
const testPlanResponse = await tp.createTestPlan(title,
|
|
712
|
+
}, async ({ title, resourceId, resourceType, description }) => {
|
|
713
|
+
const testPlanResponse = await tp.createTestPlan(title, resourceId, resourceType, { description });
|
|
707
714
|
if (!testPlanResponse) {
|
|
708
715
|
return {
|
|
709
716
|
content: [{
|
|
710
717
|
type: 'text',
|
|
711
|
-
text: `Failed to create
|
|
718
|
+
text: `Failed to create test plan "${title}" for ${resourceType} id: ${resourceId}`
|
|
712
719
|
}]
|
|
713
720
|
};
|
|
714
721
|
}
|
|
@@ -939,6 +946,110 @@ server.registerTool('get_logged_in_user', {
|
|
|
939
946
|
}],
|
|
940
947
|
};
|
|
941
948
|
});
|
|
949
|
+
server.registerTool('write_test_cases', {
|
|
950
|
+
title: 'Write test cases for a TP card (UserStory, Bug, or Feature)',
|
|
951
|
+
description: `Fetches a TP card (UserStory, Bug, or Feature) content by ID.
|
|
952
|
+
CRITICAL WORKFLOW — after receiving the card content, you MUST:
|
|
953
|
+
1) Thoroughly analyze the card name and description to understand the feature or issue being tested
|
|
954
|
+
2) Write detailed test cases covering: happy path, edge cases, boundary conditions, and error scenarios
|
|
955
|
+
3) Format each test case description inside an html <div> element structured as:
|
|
956
|
+
<div>
|
|
957
|
+
<p><strong>Preconditions:</strong> ...</p>
|
|
958
|
+
<p><strong>Test Steps:</strong><ol><li>...</li></ol></p>
|
|
959
|
+
<p><strong>Expected Result:</strong> ...</p>
|
|
960
|
+
<p><strong>Test Type:</strong> ...</p>
|
|
961
|
+
</div>
|
|
962
|
+
4) Call "create_test_plan" tool passing: resourceId (the card id), resourceType, testPlanTitle (use the card name prefixed with "Test Plan: "), and the testCases array
|
|
963
|
+
5) Call "add_test_case_to_test_plan" tool passing: testPlanId (the test plan id), and the testCases array`,
|
|
964
|
+
inputSchema: {
|
|
965
|
+
resourceId: z.string()
|
|
966
|
+
.min(5)
|
|
967
|
+
.max(6)
|
|
968
|
+
.describe('TP card ID (e.g. 145789)'),
|
|
969
|
+
resourceType: z.enum(['UserStory', 'Bug', 'Feature'])
|
|
970
|
+
.default('UserStory')
|
|
971
|
+
.optional()
|
|
972
|
+
.describe('Type of the TP card — UserStory, Bug, or Feature (default: UserStory)'),
|
|
973
|
+
},
|
|
974
|
+
}, async ({ resourceId, resourceType = 'UserStory' }) => {
|
|
975
|
+
let card = null;
|
|
976
|
+
if (resourceType === 'Bug') {
|
|
977
|
+
card = await tp.getBug(resourceId);
|
|
978
|
+
}
|
|
979
|
+
else if (resourceType === 'Feature') {
|
|
980
|
+
card = await tp.getFeature(resourceId);
|
|
981
|
+
}
|
|
982
|
+
else {
|
|
983
|
+
card = await tp.getUserStory(resourceId);
|
|
984
|
+
}
|
|
985
|
+
if (!card) {
|
|
986
|
+
return {
|
|
987
|
+
content: [{
|
|
988
|
+
type: 'text',
|
|
989
|
+
text: `Failed to get ${resourceType} with id: ${resourceId}`
|
|
990
|
+
}],
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
let description = '';
|
|
994
|
+
try {
|
|
995
|
+
const dom = new JSDOM(`<html><body><div id="content">${card.Description}</div></body></html>`);
|
|
996
|
+
description = dom.window.document.getElementById('content')?.textContent || '';
|
|
997
|
+
}
|
|
998
|
+
catch (error) {
|
|
999
|
+
console.error("Error parsing card description:", error);
|
|
1000
|
+
}
|
|
1001
|
+
return {
|
|
1002
|
+
content: [{
|
|
1003
|
+
type: 'text',
|
|
1004
|
+
text: JSON.stringify({
|
|
1005
|
+
id: card.Id,
|
|
1006
|
+
name: card.Name,
|
|
1007
|
+
resourceType,
|
|
1008
|
+
description,
|
|
1009
|
+
customFields: card.CustomFields,
|
|
1010
|
+
})
|
|
1011
|
+
}],
|
|
1012
|
+
};
|
|
1013
|
+
});
|
|
1014
|
+
server.registerTool('add_test_cases_to_test_plan', {
|
|
1015
|
+
title: 'Adds generated test cases to a test plan linked to a TP card (UserStory, Bug, or Feature).',
|
|
1016
|
+
description: `Adds generated test cases to a test plan linked to a TP card (UserStory, Bug, or Feature).`,
|
|
1017
|
+
inputSchema: {
|
|
1018
|
+
testPlanId: z.string()
|
|
1019
|
+
.min(5)
|
|
1020
|
+
.max(6)
|
|
1021
|
+
.describe('TP card ID to link the test plan to (e.g. 145789)'),
|
|
1022
|
+
testCases: z.array(z.object({
|
|
1023
|
+
name: z.string()
|
|
1024
|
+
.describe('Test case title (concise, action-oriented)'),
|
|
1025
|
+
description: z.string()
|
|
1026
|
+
.describe('Test case steps and expected results formatted as HTML'),
|
|
1027
|
+
}))
|
|
1028
|
+
.min(1)
|
|
1029
|
+
.describe('Array of test cases to create in the new test plan'),
|
|
1030
|
+
},
|
|
1031
|
+
}, async ({ testPlanId, testCases }) => {
|
|
1032
|
+
const created = [];
|
|
1033
|
+
const failed = [];
|
|
1034
|
+
for (const tc of testCases) {
|
|
1035
|
+
const result = await tp.createTestCase(tc.name, tc.description, String(testPlanId));
|
|
1036
|
+
if (result) {
|
|
1037
|
+
created.push({ id: result.Id, name: result.Name });
|
|
1038
|
+
}
|
|
1039
|
+
else {
|
|
1040
|
+
failed.push(tc.name);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
return {
|
|
1044
|
+
content: [{
|
|
1045
|
+
type: 'text',
|
|
1046
|
+
text: JSON.stringify({
|
|
1047
|
+
created,
|
|
1048
|
+
failed,
|
|
1049
|
+
})
|
|
1050
|
+
}]
|
|
1051
|
+
};
|
|
1052
|
+
});
|
|
942
1053
|
async function main() {
|
|
943
1054
|
const transport = new StdioServerTransport();
|
|
944
1055
|
await server.connect(transport);
|
package/build/tp.js
CHANGED
|
@@ -92,6 +92,13 @@ export class TpClient {
|
|
|
92
92
|
});
|
|
93
93
|
return response;
|
|
94
94
|
}
|
|
95
|
+
async getFeature(featureId) {
|
|
96
|
+
const response = await this.get({
|
|
97
|
+
pathParam: { "features": featureId },
|
|
98
|
+
param: { "format": "json" }
|
|
99
|
+
});
|
|
100
|
+
return response;
|
|
101
|
+
}
|
|
95
102
|
async createBug({ title, card, bugContent, origin = "Manual QA" }) {
|
|
96
103
|
const bug = {
|
|
97
104
|
"Name": title,
|
|
@@ -169,7 +176,21 @@ export class TpClient {
|
|
|
169
176
|
param: { "format": "json" },
|
|
170
177
|
}, bug);
|
|
171
178
|
}
|
|
172
|
-
async
|
|
179
|
+
async createTestCase(name, description, testPlanId) {
|
|
180
|
+
const testCase = {
|
|
181
|
+
"Name": name,
|
|
182
|
+
"Project": { "Id": config.tp.projectId },
|
|
183
|
+
"Description": description,
|
|
184
|
+
"TestPlans": [{
|
|
185
|
+
"Id": testPlanId
|
|
186
|
+
}],
|
|
187
|
+
};
|
|
188
|
+
return this.post({
|
|
189
|
+
pathParam: { "testCases": '' },
|
|
190
|
+
param: { "format": "json" },
|
|
191
|
+
}, testCase);
|
|
192
|
+
}
|
|
193
|
+
async createTestPlan(title, resourceId, resourceType = 'UserStory', options) {
|
|
173
194
|
const testPlan = {
|
|
174
195
|
"Name": title,
|
|
175
196
|
"Project": {
|
|
@@ -177,20 +198,30 @@ export class TpClient {
|
|
|
177
198
|
},
|
|
178
199
|
"LinkedGeneral": {
|
|
179
200
|
"ResourceType": "General",
|
|
180
|
-
"Id":
|
|
201
|
+
"Id": resourceId,
|
|
181
202
|
"Name": title,
|
|
182
203
|
},
|
|
183
204
|
"LinkedAssignable": {
|
|
184
205
|
"ResourceType": "Assignable",
|
|
185
|
-
"Id":
|
|
186
|
-
"Name": title,
|
|
187
|
-
},
|
|
188
|
-
"LinkedUserStory": {
|
|
189
|
-
"ResourceType": "UserStory",
|
|
190
|
-
"Id": userStoryId,
|
|
206
|
+
"Id": resourceId,
|
|
191
207
|
"Name": title,
|
|
192
208
|
},
|
|
193
209
|
};
|
|
210
|
+
if (resourceType === 'UserStory') {
|
|
211
|
+
testPlan["LinkedUserStory"] = { "ResourceType": "UserStory", "Id": resourceId, "Name": title };
|
|
212
|
+
}
|
|
213
|
+
else if (resourceType === 'Bug') {
|
|
214
|
+
testPlan["LinkedBug"] = { "ResourceType": "Bug", "Id": resourceId, "Name": title };
|
|
215
|
+
}
|
|
216
|
+
else if (resourceType === 'Feature') {
|
|
217
|
+
testPlan["LinkedFeature"] = { "ResourceType": "Feature", "Id": resourceId, "Name": title };
|
|
218
|
+
}
|
|
219
|
+
if (options?.description)
|
|
220
|
+
testPlan["Description"] = options.description;
|
|
221
|
+
if (options?.startDate)
|
|
222
|
+
testPlan["StartDate"] = options.startDate;
|
|
223
|
+
if (options?.endDate)
|
|
224
|
+
testPlan["EndDate"] = options.endDate;
|
|
194
225
|
return this.post({
|
|
195
226
|
pathParam: { "testPlans": '' },
|
|
196
227
|
param: { "format": "json" },
|