targetprocess-mcp-server 2.0.0 → 2.0.2

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 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 user story"
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 user story (title, userStoryId)
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 for a user story',
696
- description: `Create a new test plan with provided title and user story id`,
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(`Test plan title that is taken from user story title`),
700
- userStoryId: z.string()
699
+ .describe('Test plan title use the linked card name'),
700
+ resourceId: z.string()
701
701
  .min(5)
702
702
  .max(6)
703
- .describe(`User story id, usually user story or bug ID (e.g. 145789)`),
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, userStoryId }) => {
706
- const testPlanResponse = await tp.createTestPlan(title, userStoryId);
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 testPlanResponse "${title}"\n JSON: ${JSON.stringify(testPlanResponse, null, 2)}`
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 createTestPlan(title, userStoryId) {
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": userStoryId,
201
+ "Id": resourceId,
181
202
  "Name": title,
182
203
  },
183
204
  "LinkedAssignable": {
184
205
  "ResourceType": "Assignable",
185
- "Id": userStoryId,
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" },
package/package.json CHANGED
@@ -25,7 +25,7 @@
25
25
  "engines": {
26
26
  "node": ">=20.x"
27
27
  },
28
- "version": "2.0.0",
28
+ "version": "2.0.2",
29
29
  "description": "MCP server for Tartget Process",
30
30
  "main": "build/index.js",
31
31
  "keywords": [