targetprocess-mcp-server 2.2.3 → 2.2.5

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
@@ -46,6 +46,7 @@ Features
46
46
  - `get_not_covered_user_stories_in_feature` — Get user stories in a feature not yet covered by tests, includes `covered` field based on "Test Automation" custom field (id)
47
47
 
48
48
  Cards — Read
49
+ - `get_card_current_status` — Get EntityState, TeamState, and assigned teams for a card (id, optional resourceType: UserStory | Bug | Feature, default: UserStory)
49
50
  - `get_bug_content` — Fetch full content of a bug by ID (id)
50
51
  - `get_user_story_content` — Fetch full content of a user story by ID (id)
51
52
  - `get_bug_comments` — Get comments on a bug (id, optional results)
@@ -55,7 +56,7 @@ Cards — Read
55
56
 
56
57
  Cards — Write
57
58
  - `add_comment` — Post a comment to any card (id, comment)
58
- - `create_bug` — Create a standalone bug (title, bugContent, optional origin, optional projectId, optional teamId)
59
+ - `create_bug` — Create a standalone bug (title, bugContent, optional origin, optional projectId, optional teamId, optional entityStateId)
59
60
  > `origin` accepted values: `Production - Customer`, `Production - Internal`, `Pre-Release - Customer`, `Pre-Release - Internal`, `Regression - Dev01`, `Regression - Team Env`, `Manual QA` *(default)*, `Developer Raised`, `Operations`
60
61
  > [!NOTE]
61
62
  > `projectId` and `teamId` are optional — fall back to `TP_PROJECT_ID` and `TP_TEAM_ID` from config
@@ -76,6 +77,10 @@ Test Case Workflows
76
77
  - `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 test cases covering happy path, edge cases, and error scenarios, creates a linked test plan via `create_test_plan`, then calls `add_test_cases_to_test_plan`. Each test case description contains Preconditions and Test Type as HTML; steps are passed as a structured array (resourceId, optional resourceType)
77
78
  - `add_test_cases_to_test_plan` — Add pre-generated test cases to an existing test plan. Each test case has a `name`, an HTML `description` (Preconditions and Test Type only), and a `steps` array of `{ description, result }` objects — steps are created via the TP test step API rather than embedded in the description (testPlanId, testCases array of {name, description, steps})
78
79
 
80
+ Processes
81
+ - `get_processes` — Get all Targetprocess processes (no params needed)
82
+ - `get_process_workflows` — Get workflows for a specific process (processId)
83
+
79
84
  Projects
80
85
  - `get_projects` — Get all Targetprocess projects (no params needed)
81
86
 
package/build/config.js CHANGED
@@ -6,5 +6,8 @@ export const config = {
6
6
  ownerId: process.env.TP_OWNER_ID || "1504",
7
7
  projectId: process.env.TP_PROJECT_ID || "",
8
8
  teamId: process.env.TP_TEAM_ID || "",
9
+ processId: process.env.TP_PROCESS_ID || "",
10
+ userStoryWorkflowId: process.env.TP_USER_STORY_WORKFLOW_ID || "",
11
+ bugWorkflowId: process.env.TP_BUG_WORKFLOW_ID || "",
9
12
  }
10
13
  };
package/build/index.js CHANGED
@@ -4,6 +4,7 @@ import { z } from "zod";
4
4
  import { JSDOM } from "jsdom";
5
5
  import { TpClient } from "./tp.js";
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { config } from "./config.js";
7
8
  const server = new McpServer({
8
9
  name: "tp",
9
10
  version: "1.0.0"
@@ -374,6 +375,7 @@ server.registerTool('search_tp_cards', {
374
375
  title: item.Name,
375
376
  id: item.Id,
376
377
  description: descriptionText,
378
+ url: `${config.tp.url}/entity/${item.Id}`,
377
379
  };
378
380
  });
379
381
  return {
@@ -598,11 +600,13 @@ server.registerTool('create_bug_based_on_card', {
598
600
  title: 'Create a new bug card based on provided card id',
599
601
  description: `Create a new bug card based on provided card id that summarizes the problem in concise, descriptive manner answering questions What? Where? When?, and content explaining what happened in detail.
600
602
  NOTE: this tool requires a user story or bug card as a reference (i.e. card ID).
601
- CRITICAL WORKFLOW: Before calling this tool, you MUST follow these steps:
603
+ CRITICAL WORKFLOW: Before calling this tool, you MUST follow these steps:
602
604
  1) IF you already have user story or bug card content, proceed to step 3 skipping step 2;
603
605
  2) ELSE call "get_user_story_content" tool or "get_bug_content" tool to get user story or bug card content;
604
606
  3) format the new bug inside html <div> tags with Issue Description, Steps to Reproduce, Expected Behavior, Actual Behavior sections (note: section titles should be wrapped in <h3> tags, e.g. <h3>Issue Description</h3>);
605
- 4) add a comment to the card with created bug Id and its Title`,
607
+ 4) IF the user specified a team by name (not ID), call "get_teams" to find the matching team and use its ID as teamId;
608
+ 5) IF the user specified a project by name (not ID), call "get_projects" to find the matching project and use its ID as projectId;
609
+ 6) add a comment to the card with created bug Id and its Title`,
606
610
  inputSchema: {
607
611
  title: z.string()
608
612
  .describe('Bug card title that summarizes the problem in concise, descriptive, and actionable manner, enabling a developer to understand the issue without opening the report'),
@@ -635,10 +639,10 @@ server.registerTool('create_bug_based_on_card', {
635
639
  .describe('Where the bug was found, defaults to "Manual QA"'),
636
640
  projectId: z.string()
637
641
  .optional()
638
- .describe('Optional Project ID — defaults to TP_PROJECT_ID from config'),
642
+ .describe('Optional Project ID — if user gave a project name, resolve it via "get_projects" first; defaults to TP_PROJECT_ID from config'),
639
643
  teamId: z.string()
640
644
  .optional()
641
- .describe('Optional Team ID — defaults to TP_TEAM_ID from config'),
645
+ .describe('Optional Team ID — if user gave a team name, resolve it via "get_teams" first; defaults to TP_TEAM_ID from config'),
642
646
  },
643
647
  }, async ({ title, card, bugContent, origin, projectId, teamId }) => {
644
648
  const bugResponse = await tp.createBug({ title, card, bugContent, origin, projectId, teamId });
@@ -662,7 +666,9 @@ server.registerTool('create_bug', {
662
666
  description: `Create a new bug card that summarizes the problem in concise, descriptive manner answering questions "What? Where? When?" and content explaining what happened in detail.
663
667
  NOTE: this tool does not require a user story or bug card reference.
664
668
  CRITICAL WORKFLOW: Before calling this tool, you MUST follow these steps:
665
- 1) format the new bug inside html <div> tags with Issue Description, Steps to Reproduce, Expected Behavior, Actual Behavior sections (note: section titles should be wrapped in <h3> tags, e.g. <h3>Issue Description</h3>);`,
669
+ 1) format the new bug inside html <div> tags with Issue Description, Steps to Reproduce, Expected Behavior, Actual Behavior sections (note: section titles should be wrapped in <h3> tags, e.g. <h3>Issue Description</h3>, step to reproduce should be wrapped in <ol>);
670
+ 2) IF the user specified a team by name (not ID), call "get_teams" to find the matching team and use its ID as teamId;
671
+ 3) IF the user specified a project by name (not ID), call "get_projects" to find the matching project and use its ID as projectId;`,
666
672
  inputSchema: {
667
673
  title: z.string()
668
674
  .describe('Bug card title that summarizes the problem in concise, descriptive, and actionable manner, enabling a developer to understand the issue without opening the report'),
@@ -684,10 +690,10 @@ server.registerTool('create_bug', {
684
690
  .describe('Where the bug was found, defaults to "Manual QA"'),
685
691
  projectId: z.string()
686
692
  .optional()
687
- .describe('Optional Project ID — defaults to TP_PROJECT_ID from config'),
693
+ .describe('Optional Project ID — if user gave a project name, resolve it via "get_projects" first; defaults to TP_PROJECT_ID from config'),
688
694
  teamId: z.string()
689
695
  .optional()
690
- .describe('Optional Team ID — defaults to TP_TEAM_ID from config'),
696
+ .describe('Optional Team ID — if user gave a team name, resolve it via "get_teams" first; defaults to TP_TEAM_ID from config'),
691
697
  },
692
698
  }, async ({ title, bugContent, origin, projectId, teamId }) => {
693
699
  const bugResponse = await tp.createBugOnly({ title, bugContent, origin, projectId, teamId });
@@ -1238,63 +1244,106 @@ server.registerTool('add_test_cases_to_test_plan', {
1238
1244
  }]
1239
1245
  };
1240
1246
  });
1241
- server.registerTool('add_attached_file_to_card', {
1242
- title: 'Attach a file to a TP card',
1243
- description: `Upload and attach a file to a Targetprocess entity (UserStory, Bug, Feature, etc.) by its ID.
1244
- 1) fileContent + fileName — provide base64-encoded file content and a filename (use this when the file was uploaded directly into the chat)
1245
- WORKFLOW for chat-uploaded files: run \`base64 <path>\` via Bash to get the encoded content, then call this tool with fileContent + fileName.`,
1247
+ server.registerTool('get_process_workflows', {
1248
+ title: 'Get process workflows',
1249
+ description: 'Get all Targetprocess process workflows',
1250
+ inputSchema: {
1251
+ processId: z.string()
1252
+ .describe('Process ID (e.g. 145636)'),
1253
+ },
1254
+ }, async ({ processId }) => {
1255
+ const response = await tp.getProcessWorkflows({ processId });
1256
+ if (!response) {
1257
+ return {
1258
+ content: [{
1259
+ type: 'text',
1260
+ text: `Failed to get process workflows, JSON: ${JSON.stringify(response, null, 2)}`
1261
+ }],
1262
+ };
1263
+ }
1264
+ const items = response.items || [];
1265
+ if (items.length === 0) {
1266
+ return {
1267
+ content: [{
1268
+ type: 'text',
1269
+ text: `No process workflows found`,
1270
+ }],
1271
+ };
1272
+ }
1273
+ return {
1274
+ content: [{
1275
+ type: 'text',
1276
+ text: JSON.stringify(items)
1277
+ }],
1278
+ };
1279
+ });
1280
+ server.registerTool('get_processes', {
1281
+ title: 'Get processes',
1282
+ description: 'Get all Targetprocess processes',
1283
+ }, async ({}) => {
1284
+ const response = await tp.getProcesses();
1285
+ if (!response) {
1286
+ return {
1287
+ content: [{
1288
+ type: 'text',
1289
+ text: `Failed to get processes, JSON: ${JSON.stringify(response, null, 2)}`
1290
+ }],
1291
+ };
1292
+ }
1293
+ const items = response.items || [];
1294
+ if (items.length === 0) {
1295
+ return {
1296
+ content: [{
1297
+ type: 'text',
1298
+ text: `No processes found`,
1299
+ }],
1300
+ };
1301
+ }
1302
+ return {
1303
+ content: [{
1304
+ type: 'text',
1305
+ text: JSON.stringify(items)
1306
+ }],
1307
+ };
1308
+ });
1309
+ server.registerTool('get_card_current_status', {
1310
+ title: 'Get card status',
1311
+ description: 'Get the EntityState, TeamState, and assigned teams for a TP card (UserStory, Bug, or Feature) by ID',
1246
1312
  inputSchema: {
1247
- generalId: z.string()
1313
+ id: z.string()
1248
1314
  .min(5)
1249
1315
  .max(6)
1250
- .describe('TP entity ID to attach the file to (e.g. 145789)'),
1251
- filePath: z.string()
1252
- .optional()
1253
- .describe('Absolute path to a local file (mode 1). Mutually exclusive with fileContent/fileName.'),
1254
- fileContent: z.string()
1255
- .optional()
1256
- .describe('Base64-encoded file content (mode 2). Must be paired with fileName.'),
1257
- fileName: z.string()
1316
+ .describe('TP card ID (e.g. 146055)'),
1317
+ resourceType: z.enum(['UserStory', 'Bug', 'Feature'])
1318
+ .default('UserStory')
1258
1319
  .optional()
1259
- .describe('Filename including extension, required when using fileContent (e.g. screenshot.png).'),
1320
+ .describe('Type of the TP card — UserStory, Bug, or Feature (default: UserStory)'),
1260
1321
  },
1261
- }, async ({ generalId, filePath, fileContent, fileName }) => {
1262
- try {
1263
- if (!filePath && (!fileContent || !fileName)) {
1264
- return {
1265
- content: [{
1266
- type: 'text',
1267
- text: 'Provide either filePath, or both fileContent and fileName.'
1268
- }]
1269
- };
1270
- }
1271
- const source = filePath
1272
- ? { filePath }
1273
- : { fileContent: fileContent, fileName: fileName };
1274
- const result = await tp.addAttachedFile(generalId, source);
1275
- if (!result) {
1276
- return {
1277
- content: [{
1278
- type: 'text',
1279
- text: `Failed to attach file to card id: ${generalId}`
1280
- }]
1281
- };
1282
- }
1322
+ }, async ({ id, resourceType = 'UserStory' }) => {
1323
+ const response = await tp.getCardStatus(id, resourceType);
1324
+ if (!response) {
1283
1325
  return {
1284
1326
  content: [{
1285
1327
  type: 'text',
1286
- text: result
1287
- }]
1328
+ text: `Failed to get card status for ${resourceType} id: ${id}`
1329
+ }],
1288
1330
  };
1289
1331
  }
1290
- catch (error) {
1332
+ const items = response.items || [];
1333
+ if (items.length === 0) {
1291
1334
  return {
1292
1335
  content: [{
1293
1336
  type: 'text',
1294
- text: `Error attaching file to card ${generalId}: ${error}`
1295
- }]
1337
+ text: `No status data found for ${resourceType} id: ${id}`,
1338
+ }],
1296
1339
  };
1297
1340
  }
1341
+ return {
1342
+ content: [{
1343
+ type: 'text',
1344
+ text: JSON.stringify(items[0])
1345
+ }],
1346
+ };
1298
1347
  });
1299
1348
  async function main() {
1300
1349
  const transport = new StdioServerTransport();
package/build/tp.js CHANGED
@@ -15,8 +15,8 @@ export class TpClient {
15
15
  }
16
16
  params(params) {
17
17
  let _url = this.baseUrl + (params.apiVersion || this.v1);
18
- for (const [key, value] of Object.entries(params.pathParam)) {
19
- _url += value ? `/${key}/${value}` : `/${key}`;
18
+ for (const segment of params.pathParam) {
19
+ _url += `/${segment}`;
20
20
  }
21
21
  let _urlParams = [];
22
22
  for (const [key, value] of Object.entries(params.param)) {
@@ -83,21 +83,21 @@ export class TpClient {
83
83
  }
84
84
  async getUserStory(userStoryId) {
85
85
  const response = await this.get({
86
- pathParam: { "userStories": userStoryId },
86
+ pathParam: ["userStories", userStoryId],
87
87
  param: { "format": "json" },
88
88
  });
89
89
  return response;
90
90
  }
91
91
  async getBug(bugId) {
92
92
  const response = await this.get({
93
- pathParam: { "bugs": bugId },
93
+ pathParam: ["bugs", bugId],
94
94
  param: { "format": "json" }
95
95
  });
96
96
  return response;
97
97
  }
98
98
  async getFeature(featureId) {
99
99
  const response = await this.get({
100
- pathParam: { "features": featureId },
100
+ pathParam: ["features", featureId],
101
101
  param: { "format": "json" }
102
102
  });
103
103
  return response;
@@ -126,10 +126,34 @@ export class TpClient {
126
126
  };
127
127
  }
128
128
  return this.post({
129
- pathParam: { "bugs": '' },
129
+ pathParam: ["bugs"],
130
130
  param: { "format": "json" },
131
131
  }, bug);
132
132
  }
133
+ async updateUserStory({ title, description, projectId, teamId }) {
134
+ const userStory = {
135
+ "Name": title,
136
+ "Description": description,
137
+ "Project": {
138
+ "Id": projectId || config.tp.projectId
139
+ },
140
+ "assignedTeams": [
141
+ {
142
+ "entityState": {
143
+ "id": 7407
144
+ },
145
+ "id": 84252,
146
+ "team": {
147
+ "id": teamId || config.tp.teamId
148
+ }
149
+ }
150
+ ]
151
+ };
152
+ return this.post({
153
+ pathParam: ["UserStories"],
154
+ param: { "format": "json" },
155
+ }, userStory);
156
+ }
133
157
  async createBugOnly({ title, bugContent, origin = "Manual QA", projectId, teamId }) {
134
158
  const bug = {
135
159
  "Name": title,
@@ -149,7 +173,7 @@ export class TpClient {
149
173
  "Description": bugContent,
150
174
  };
151
175
  return this.post({
152
- pathParam: { "bugs": '' },
176
+ pathParam: ["bugs"],
153
177
  param: { "format": "json" },
154
178
  }, bug);
155
179
  }
@@ -166,7 +190,7 @@ export class TpClient {
166
190
  if (releaseId)
167
191
  userStory["Release"] = { "Id": releaseId };
168
192
  return this.post({
169
- pathParam: { "UserStories": '' },
193
+ pathParam: ["UserStories"],
170
194
  param: { "format": "json" },
171
195
  }, userStory);
172
196
  }
@@ -183,7 +207,7 @@ export class TpClient {
183
207
  if (releaseId)
184
208
  feature["Release"] = { "Id": releaseId };
185
209
  return this.post({
186
- pathParam: { "Features": '' },
210
+ pathParam: ["Features"],
187
211
  param: { "format": "json" },
188
212
  }, feature);
189
213
  }
@@ -209,7 +233,7 @@ export class TpClient {
209
233
  "Description": bugContent,
210
234
  };
211
235
  return this.post({
212
- pathParam: { "bugs": '' },
236
+ pathParam: ["bugs"],
213
237
  param: { "format": "json" },
214
238
  }, bug);
215
239
  }
@@ -223,7 +247,7 @@ export class TpClient {
223
247
  }],
224
248
  };
225
249
  return this.post({
226
- pathParam: { "testCases": '' },
250
+ pathParam: ["testCases"],
227
251
  param: { "format": "json" },
228
252
  }, testCase);
229
253
  }
@@ -260,7 +284,7 @@ export class TpClient {
260
284
  if (options?.endDate)
261
285
  testPlan["EndDate"] = options.endDate;
262
286
  return this.post({
263
- pathParam: { "testPlans": '' },
287
+ pathParam: ["testPlans"],
264
288
  param: { "format": "json" },
265
289
  }, testPlan);
266
290
  }
@@ -275,7 +299,7 @@ export class TpClient {
275
299
  },
276
300
  };
277
301
  return this.post({
278
- pathParam: { "comments": '' },
302
+ pathParam: ["comments"],
279
303
  param: { "format": "json" },
280
304
  }, commentData);
281
305
  }
@@ -286,16 +310,13 @@ export class TpClient {
286
310
  "TestCase": { "Id": testCaseId },
287
311
  };
288
312
  return this.post({
289
- pathParam: { "testSteps": '' },
313
+ pathParam: ["testSteps"],
290
314
  param: { "format": "json" },
291
315
  }, testStepData);
292
316
  }
293
317
  async getBugComments(bugId, results = 25) {
294
318
  const response = await this.get({
295
- pathParam: {
296
- "Bugs": bugId,
297
- "Comments": "",
298
- },
319
+ pathParam: ["Bugs", bugId, "Comments"],
299
320
  param: {
300
321
  "format": "json",
301
322
  "take": results,
@@ -305,10 +326,7 @@ export class TpClient {
305
326
  }
306
327
  async getUserStoryComments(userStoryId, results = 25) {
307
328
  const response = await this.get({
308
- pathParam: {
309
- "UserStories": userStoryId,
310
- "Comments": "",
311
- },
329
+ pathParam: ["UserStories", userStoryId, "Comments"],
312
330
  param: {
313
331
  "format": "json",
314
332
  "take": results,
@@ -318,7 +336,7 @@ export class TpClient {
318
336
  }
319
337
  async searchContainsNameText({ text, entityType }) {
320
338
  return this.get({
321
- pathParam: { [entityType]: '' },
339
+ pathParam: [entityType],
322
340
  param: {
323
341
  "format": "json",
324
342
  "take": "25",
@@ -329,7 +347,7 @@ export class TpClient {
329
347
  }
330
348
  async searchContainsDescriptionText({ text, entityType }) {
331
349
  return this.get({
332
- pathParam: { [entityType]: '' },
350
+ pathParam: [entityType],
333
351
  param: {
334
352
  "where": `Description contains '${text}' and EntityState.Name eq 'Done'`,
335
353
  "format": "json",
@@ -339,7 +357,7 @@ export class TpClient {
339
357
  }
340
358
  async getCurrentReleases() {
341
359
  return this.get({
342
- pathParam: { "Releases": '' },
360
+ pathParam: ["Releases"],
343
361
  param: {
344
362
  "format": "json",
345
363
  "where": `IsCurrent eq 'true'`,
@@ -349,7 +367,7 @@ export class TpClient {
349
367
  async getReleaseUserStories({ name, results = 50, withDescription = false }) {
350
368
  const includeFilter = withDescription ? "[Name, Description, Id]" : "[Name, Id]";
351
369
  return this.get({
352
- pathParam: { "UserStories": '' },
370
+ pathParam: ["UserStories"],
353
371
  param: {
354
372
  "format": "json",
355
373
  "take": results,
@@ -361,11 +379,11 @@ export class TpClient {
361
379
  async getReleaseOpenUserStories({ name, results = 100, withDescription = false }) {
362
380
  const includeFilter = withDescription ? "[Name, Description, Id]" : "[Name, Id]";
363
381
  return this.get({
364
- pathParam: { "UserStories": '' },
382
+ pathParam: ["UserStories"],
365
383
  param: {
366
384
  "format": "json",
367
385
  "take": results,
368
- "where": `Release.Name eq '${name}' and EntityState.Name ne 'Closed' and EntityState.Name ne 'Done' and EntityState.Name ne 'Passed Dev01  QA' and EntityState.Name ne 'Ready to Deploy to prod'`,
386
+ "where": `Release.Name eq '${name}' and EntityState.Name ne 'Closed' and EntityState.Name ne 'Done' and EntityState.Name ne 'Passed Dev01 QA' and EntityState.Name ne 'Ready to Deploy to prod'`,
369
387
  "include": includeFilter,
370
388
  }
371
389
  });
@@ -373,11 +391,11 @@ export class TpClient {
373
391
  async getReleaseOpenBugs({ name, results = 200, withDescription = false }) {
374
392
  const includeFilter = withDescription ? "[Name, Description, Id]" : "[Name, Id]";
375
393
  return this.get({
376
- pathParam: { "Bugs": '' },
394
+ pathParam: ["Bugs"],
377
395
  param: {
378
396
  "format": "json",
379
397
  "take": results,
380
- "where": `Release.Name eq '${name}' and EntityState.Name ne 'Closed' and EntityState.Name ne 'Done' and EntityState.Name ne 'Passed Dev01  QA' and EntityState.Name ne 'Ready to Deploy to prod'`,
398
+ "where": `Release.Name eq '${name}' and EntityState.Name ne 'Closed' and EntityState.Name ne 'Done' and EntityState.Name ne 'Passed Dev01 QA' and EntityState.Name ne 'Ready to Deploy to prod'`,
381
399
  "include": includeFilter,
382
400
  }
383
401
  });
@@ -385,7 +403,7 @@ export class TpClient {
385
403
  async getReleaseBugs({ name, results = 100, withDescription = false }) {
386
404
  const includeFilter = withDescription ? "[Name, Description, Id]" : "[Name, Id]";
387
405
  return this.get({
388
- pathParam: { "Bugs": '' },
406
+ pathParam: ["Bugs"],
389
407
  param: {
390
408
  "format": "json",
391
409
  "take": results,
@@ -397,7 +415,7 @@ export class TpClient {
397
415
  async getReleaseFeatures({ name, results = 50, withDescription = false }) {
398
416
  const includeFilter = withDescription ? "[Name, Description, Id]" : "[Name, Id]";
399
417
  return this.get({
400
- pathParam: { "Features": '' },
418
+ pathParam: ["Features"],
401
419
  param: {
402
420
  "format": "json",
403
421
  "take": results,
@@ -408,7 +426,7 @@ export class TpClient {
408
426
  }
409
427
  async getFeatureUserStories(featureId) {
410
428
  return this.get({
411
- pathParam: { "features": '' },
429
+ pathParam: ["features"],
412
430
  param: {
413
431
  "format": "json",
414
432
  "where": `(id==${featureId})`,
@@ -419,7 +437,7 @@ export class TpClient {
419
437
  }
420
438
  async getUserStoriesIdsByFeatureId(featureId) {
421
439
  return this.get({
422
- pathParam: { "userstories": '' },
440
+ pathParam: ["userstories"],
423
441
  param: {
424
442
  "format": "json",
425
443
  "where": `(Feature.Id==${featureId})`,
@@ -430,7 +448,7 @@ export class TpClient {
430
448
  }
431
449
  async getUserStoryTestPlan(userStoryId) {
432
450
  return this.get({
433
- pathParam: { "userStories": userStoryId },
451
+ pathParam: ["userStories", userStoryId],
434
452
  param: {
435
453
  "format": "json",
436
454
  "select": `{id,storyName:name,linkedtestplan}`,
@@ -439,18 +457,9 @@ export class TpClient {
439
457
  });
440
458
  }
441
459
  async getCardTestPlan(cardId, resourceType = 'UserStory') {
442
- let requestPath = "";
443
- if (resourceType === 'UserStory') {
444
- requestPath = "userStories";
445
- }
446
- else if (resourceType === 'Bug') {
447
- requestPath = "bugs";
448
- }
449
- else if (resourceType === 'Feature') {
450
- requestPath = "features";
451
- }
460
+ const pathMap = { UserStory: "userStories", Bug: "bugs", Feature: "features" };
452
461
  return this.get({
453
- pathParam: { [requestPath]: cardId },
462
+ pathParam: [pathMap[resourceType], cardId],
454
463
  param: {
455
464
  "format": "json",
456
465
  "select": `{id,linkedtestplan}`,
@@ -459,38 +468,71 @@ export class TpClient {
459
468
  }
460
469
  async getTestPlanTestCases(testPlanId) {
461
470
  return this.get({
462
- pathParam: {
463
- "testPlans": testPlanId,
464
- "testcases": "",
465
- },
471
+ pathParam: ["testPlans", testPlanId, "testcases"],
466
472
  param: { "format": "json" },
467
473
  });
468
474
  }
469
475
  async getTestCaseSteps(testCaseId) {
470
476
  return this.get({
471
- pathParam: {
472
- "testCases": testCaseId,
473
- "teststeps": "",
474
- },
475
- param: { "format": "json", },
477
+ pathParam: ["testCases", testCaseId, "teststeps"],
478
+ param: { "format": "json" },
476
479
  });
477
480
  }
478
481
  async getProjects() {
479
482
  return this.get({
480
- pathParam: { "Projects": '' },
483
+ pathParam: ["Projects"],
484
+ param: { "format": "json" },
485
+ });
486
+ }
487
+ async getProcessWorkflows({ processId }) {
488
+ return this.get({
489
+ pathParam: ["Process"],
490
+ param: {
491
+ "format": "json",
492
+ "where": `id=(${processId})`,
493
+ "select": `{Workflows}`
494
+ },
495
+ apiVersion: this.v2
496
+ });
497
+ }
498
+ async getUserStories({ take = 100 }) {
499
+ return this.get({
500
+ pathParam: ["userStories"],
501
+ param: {
502
+ "format": "json",
503
+ "take": take,
504
+ },
505
+ apiVersion: this.v2
506
+ });
507
+ }
508
+ async getProcesses() {
509
+ return this.get({
510
+ pathParam: ["Processes"],
481
511
  param: { "format": "json" },
482
512
  });
483
513
  }
484
514
  async getTeams() {
485
515
  return this.get({
486
- pathParam: { "Teams": '' },
516
+ pathParam: ["Teams"],
487
517
  param: { "format": "json" },
488
518
  });
489
519
  }
520
+ async getCardStatus(cardId, resourceType = 'UserStory') {
521
+ const pathMap = { UserStory: 'userStory', Bug: 'bug', Feature: 'feature' };
522
+ return this.get({
523
+ pathParam: [pathMap[resourceType]],
524
+ param: {
525
+ "select": `{Project:{Project.Id},EntityState:{EntityState.Id,EntityState.Name,EntityState.NextStates,EntityState.Workflow.Id as WorkflowId},TeamState:{ResponsibleTeam.Id,Team:{ResponsibleTeam.Team.Id,ResponsibleTeam.Team.Name},EntityState:{ResponsibleTeam.EntityState.Id,ResponsibleTeam.EntityState.Name,ResponsibleTeam.EntityState.Workflow.Id as WorkflowId}},AssignedTeams.Select({TeamAssignmentId:Id,Id:Team.Id,Name:Team.Name}) as Teams}`,
526
+ "where": `(id=${cardId})`,
527
+ "take": "1",
528
+ },
529
+ apiVersion: this.v2
530
+ });
531
+ }
490
532
  async getContext() {
491
533
  return this.get({
492
- pathParam: { "Context": '' },
493
- param: { "format": "json", }
534
+ pathParam: ["Context"],
535
+ param: { "format": "json" }
494
536
  });
495
537
  }
496
538
  async addAttachedFile(generalId, source) {
package/package.json CHANGED
@@ -25,7 +25,7 @@
25
25
  "engines": {
26
26
  "node": ">=20.x"
27
27
  },
28
- "version": "2.2.3",
28
+ "version": "2.2.5",
29
29
  "description": "MCP server for Tartget Process",
30
30
  "main": "build/index.js",
31
31
  "keywords": [