targetprocess-mcp-server 2.4.3 → 2.5.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 +3 -0
- package/build/handlers/create_epic.js +14 -0
- package/build/handlers/get_epic_content.js +38 -0
- package/build/handlers/get_epic_features.js +24 -0
- package/build/handlers/update_epic.js +14 -0
- package/build/index.js +69 -2
- package/build/tp.js +46 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -96,6 +96,9 @@ Cards — Write
|
|
|
96
96
|
> `projectId` and `teamId` are optional — fall back to `TP_PROJECT_ID` and `TP_TEAM_ID` from config
|
|
97
97
|
- `format_existing_user_story` — Re-format the description of an existing user story using the structured template (id, header object with asA/iWant/soThat, acceptanceCriteria array, scenarios array with Gherkin steps, optional title, definitions, examplesTable, edgeCases, references, notes)
|
|
98
98
|
> Call `get_user_story_content` first to read the current content, then reconstruct the structured fields before calling this tool
|
|
99
|
+
- `get_epic_content` — Get a Targetprocess Epic by ID, including description, state, and progress (id)
|
|
100
|
+
- `update_epic` — Update an epic's title, description, release, or project (id, optional title, optional description, optional releaseId, optional projectId)
|
|
101
|
+
- `get_epic_features` — Get all features belonging to an epic (id)
|
|
99
102
|
- `create_feature` — Create a new feature (title, optional description, optional epicId, optional releaseId, optional projectId, optional teamId)
|
|
100
103
|
> [!NOTE]
|
|
101
104
|
> `projectId` and `teamId` are optional — fall back to `TP_PROJECT_ID` and `TP_TEAM_ID` from config
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export async function handleCreateEpic(tp, params) {
|
|
2
|
+
const response = await tp.createEpic(params);
|
|
3
|
+
if (!response) {
|
|
4
|
+
return {
|
|
5
|
+
content: [{
|
|
6
|
+
type: 'text',
|
|
7
|
+
text: `Failed to create epic "${params.title}"\n JSON: ${JSON.stringify(response, null, 2)}`
|
|
8
|
+
}],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
content: [{ type: 'text', text: JSON.stringify(response) }],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { JSDOM } from 'jsdom';
|
|
2
|
+
export async function handleGetEpicContent(tp, id) {
|
|
3
|
+
const epic = await tp.getEpic(id);
|
|
4
|
+
if (!epic) {
|
|
5
|
+
return {
|
|
6
|
+
content: [{
|
|
7
|
+
type: 'text',
|
|
8
|
+
text: `Failed to get epic, id: ${id}\n JSON: ${JSON.stringify(epic, null, 2)}`
|
|
9
|
+
}],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const result = {
|
|
13
|
+
name: epic.Name,
|
|
14
|
+
id: epic.Id,
|
|
15
|
+
description: '',
|
|
16
|
+
entityState: epic.EntityState?.Name,
|
|
17
|
+
release: epic.Release?.Name,
|
|
18
|
+
portfolioEpic: epic.PortfolioEpic?.Name,
|
|
19
|
+
progress: epic.Progress,
|
|
20
|
+
effort: epic.Effort,
|
|
21
|
+
customFields: epic.CustomFields,
|
|
22
|
+
};
|
|
23
|
+
const description = epic.Description || '';
|
|
24
|
+
if (description) {
|
|
25
|
+
try {
|
|
26
|
+
const dom = new JSDOM(`<html><body><div id="content">${description}</div></body></html>`);
|
|
27
|
+
const text = dom.window.document.getElementById('content')?.textContent;
|
|
28
|
+
if (text)
|
|
29
|
+
result.description = text;
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error('Error parsing epic description:', error);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export async function handleGetEpicFeatures(tp, epicId) {
|
|
2
|
+
const response = await tp.getEpicFeatures(epicId);
|
|
3
|
+
if (!response) {
|
|
4
|
+
return {
|
|
5
|
+
content: [{
|
|
6
|
+
type: 'text',
|
|
7
|
+
text: `Failed to get features for epic id: ${epicId}`
|
|
8
|
+
}],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const features = response.Items ?? [];
|
|
12
|
+
const result = features.map(f => ({
|
|
13
|
+
id: f.Id,
|
|
14
|
+
name: f.Name,
|
|
15
|
+
entityState: f.EntityState?.Name,
|
|
16
|
+
team: f.Team?.Name,
|
|
17
|
+
release: f.Release?.Name,
|
|
18
|
+
progress: f.Progress,
|
|
19
|
+
effort: f.Effort,
|
|
20
|
+
}));
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text', text: JSON.stringify({ total: result.length, features: result }) }],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export async function handleUpdateEpic(tp, params) {
|
|
2
|
+
const response = await tp.updateEpic(params);
|
|
3
|
+
if (!response) {
|
|
4
|
+
return {
|
|
5
|
+
content: [{
|
|
6
|
+
type: 'text',
|
|
7
|
+
text: `Failed to update epic id: ${params.id}\n JSON: ${JSON.stringify(response, null, 2)}`
|
|
8
|
+
}],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
content: [{ type: 'text', text: JSON.stringify(response) }],
|
|
13
|
+
};
|
|
14
|
+
}
|
package/build/index.js
CHANGED
|
@@ -25,6 +25,10 @@ import { handleGetBugComments } from "./handlers/get_bug_comments.js";
|
|
|
25
25
|
import { handleCreateBug } from "./handlers/create_bug.js";
|
|
26
26
|
import { handleCreateUserStory } from "./handlers/create_user_story.js";
|
|
27
27
|
import { handleCreateFeature } from "./handlers/create_feature.js";
|
|
28
|
+
import { handleCreateEpic } from "./handlers/create_epic.js";
|
|
29
|
+
import { handleGetEpicContent } from "./handlers/get_epic_content.js";
|
|
30
|
+
import { handleUpdateEpic } from "./handlers/update_epic.js";
|
|
31
|
+
import { handleGetEpicFeatures } from "./handlers/get_epic_features.js";
|
|
28
32
|
import { handleCreateTask } from "./handlers/create_task.js";
|
|
29
33
|
import { handleUpdateBug } from "./handlers/update_bug.js";
|
|
30
34
|
import { handleGetInProgressTasksAndBugs } from "./handlers/get_in_progress_tasks_and_bugs.js";
|
|
@@ -635,12 +639,12 @@ server.registerTool('create_formatted_user_story', {
|
|
|
635
639
|
.describe('Optional Team ID — defaults to TP_TEAM_ID from config'),
|
|
636
640
|
},
|
|
637
641
|
}, async ({ title, header, definitions, acceptanceCriteria, scenarios, examplesTable, edgeCases, references, notes, featureId, releaseId, projectId, teamId }) => {
|
|
638
|
-
const gherkinBlock = (items) => items.map((s, indx) => `<div><strong>Scenario ${indx + 1} - ${s.name}:</strong></div><div>${s.steps.map(step => `<div>\t${step}</div>`).join('\n')}</div>`).join('
|
|
642
|
+
const gherkinBlock = (items) => items.map((s, indx) => `<div><strong>Scenario ${indx + 1} - ${s.name}:</strong></div><div>${s.steps.map(step => `<div>\t${step}</div>`).join('\n')}</div>`).join('<br>');
|
|
639
643
|
const parts = ['<div>'];
|
|
640
644
|
parts.push('<h3>Header</h3>');
|
|
641
645
|
if (header.storyId)
|
|
642
646
|
parts.push(`<p><strong>Story ID:</strong> ${header.storyId}</p>`);
|
|
643
|
-
parts.push(`<p>As a ${header.asA}
|
|
647
|
+
parts.push(`<p>As a ${header.asA} <br> I want ${header.iWant} <br> so that ${header.soThat}</p>`);
|
|
644
648
|
if (definitions) {
|
|
645
649
|
parts.push('<h3>Definitions</h3>');
|
|
646
650
|
parts.push(`<div>`);
|
|
@@ -718,6 +722,69 @@ server.registerTool('create_feature', {
|
|
|
718
722
|
.describe('Optional Team ID — defaults to TP_TEAM_ID from config'),
|
|
719
723
|
},
|
|
720
724
|
}, async ({ title, description, epicId, releaseId, projectId, teamId }) => handleCreateFeature(tp, { title, description, epicId, releaseId, projectId, teamId }));
|
|
725
|
+
server.registerTool('create_epic', {
|
|
726
|
+
title: 'Create a new epic',
|
|
727
|
+
description: `Create a new Epic in Targetprocess.`,
|
|
728
|
+
inputSchema: {
|
|
729
|
+
title: z.string()
|
|
730
|
+
.describe('Epic title'),
|
|
731
|
+
description: z.string()
|
|
732
|
+
.optional()
|
|
733
|
+
.describe('Optional epic description (when provided, format as HTML)'),
|
|
734
|
+
releaseId: z.string()
|
|
735
|
+
.min(5)
|
|
736
|
+
.max(6)
|
|
737
|
+
.optional()
|
|
738
|
+
.describe('Optional Release ID to link this epic to (e.g. 145200)'),
|
|
739
|
+
projectId: z.string()
|
|
740
|
+
.optional()
|
|
741
|
+
.describe('Optional Project ID -- defaults to TP_PROJECT_ID from config'),
|
|
742
|
+
},
|
|
743
|
+
}, async ({ title, description, releaseId, projectId }) => handleCreateEpic(tp, { title, description, releaseId, projectId }));
|
|
744
|
+
server.registerTool('get_epic_content', {
|
|
745
|
+
title: 'Get epic content',
|
|
746
|
+
description: 'Get a Targetprocess Epic by ID, including its description, state, and progress.',
|
|
747
|
+
inputSchema: {
|
|
748
|
+
id: z.string()
|
|
749
|
+
.min(5)
|
|
750
|
+
.max(6)
|
|
751
|
+
.describe('Epic ID (e.g. 148813)'),
|
|
752
|
+
},
|
|
753
|
+
}, async ({ id }) => handleGetEpicContent(tp, id));
|
|
754
|
+
server.registerTool('update_epic', {
|
|
755
|
+
title: 'Update an epic',
|
|
756
|
+
description: 'Update a Targetprocess Epic. Pass only the fields to change.',
|
|
757
|
+
inputSchema: {
|
|
758
|
+
id: z.string()
|
|
759
|
+
.min(5)
|
|
760
|
+
.max(6)
|
|
761
|
+
.describe('Epic ID (e.g. 148813)'),
|
|
762
|
+
title: z.string()
|
|
763
|
+
.optional()
|
|
764
|
+
.describe('Updated epic title'),
|
|
765
|
+
description: z.string()
|
|
766
|
+
.optional()
|
|
767
|
+
.describe('Updated epic description (format as HTML)'),
|
|
768
|
+
releaseId: z.string()
|
|
769
|
+
.min(5)
|
|
770
|
+
.max(6)
|
|
771
|
+
.optional()
|
|
772
|
+
.describe('Optional Release ID to link this epic to'),
|
|
773
|
+
projectId: z.string()
|
|
774
|
+
.optional()
|
|
775
|
+
.describe('Optional Project ID'),
|
|
776
|
+
},
|
|
777
|
+
}, async ({ id, title, description, releaseId, projectId }) => handleUpdateEpic(tp, { id, title, description, releaseId, projectId }));
|
|
778
|
+
server.registerTool('get_epic_features', {
|
|
779
|
+
title: 'Get features in an epic',
|
|
780
|
+
description: 'Get all Features belonging to a Targetprocess Epic.',
|
|
781
|
+
inputSchema: {
|
|
782
|
+
id: z.string()
|
|
783
|
+
.min(5)
|
|
784
|
+
.max(6)
|
|
785
|
+
.describe('Epic ID (e.g. 148813)'),
|
|
786
|
+
},
|
|
787
|
+
}, async ({ id }) => handleGetEpicFeatures(tp, id));
|
|
721
788
|
server.registerTool('create_test_plan', {
|
|
722
789
|
title: 'Create a new test plan linked to a TP card',
|
|
723
790
|
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.`,
|
package/build/tp.js
CHANGED
|
@@ -283,6 +283,52 @@ export class TpClient {
|
|
|
283
283
|
param: { "format": "json" },
|
|
284
284
|
}, userStory);
|
|
285
285
|
}
|
|
286
|
+
async getEpic(epicId) {
|
|
287
|
+
return this.get({
|
|
288
|
+
pathParam: ["Epics", epicId],
|
|
289
|
+
param: { "format": "json" },
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
async updateEpic({ id, title, description, releaseId, projectId }) {
|
|
293
|
+
const epic = { "Id": id };
|
|
294
|
+
if (title)
|
|
295
|
+
epic["Name"] = title;
|
|
296
|
+
if (description)
|
|
297
|
+
epic["Description"] = description;
|
|
298
|
+
if (projectId)
|
|
299
|
+
epic["Project"] = { "Id": projectId };
|
|
300
|
+
if (releaseId)
|
|
301
|
+
epic["Release"] = { "Id": releaseId };
|
|
302
|
+
return this.post({
|
|
303
|
+
pathParam: ["Epics"],
|
|
304
|
+
param: { "format": "json" },
|
|
305
|
+
}, epic);
|
|
306
|
+
}
|
|
307
|
+
async getEpicFeatures(epicId) {
|
|
308
|
+
return this.get({
|
|
309
|
+
pathParam: ["Features"],
|
|
310
|
+
param: {
|
|
311
|
+
"format": "json",
|
|
312
|
+
"where": `Epic.Id eq ${epicId}`,
|
|
313
|
+
"include": "[Id,Name,Description,EntityState[Name],Team[Name],Release[Name],Progress,Effort]",
|
|
314
|
+
"take": 100,
|
|
315
|
+
},
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
async createEpic({ title, description, releaseId, projectId }) {
|
|
319
|
+
const epic = {
|
|
320
|
+
"Name": title,
|
|
321
|
+
"Project": { "Id": projectId || config.tp.projectId },
|
|
322
|
+
};
|
|
323
|
+
if (description)
|
|
324
|
+
epic["Description"] = description;
|
|
325
|
+
if (releaseId)
|
|
326
|
+
epic["Release"] = { "Id": releaseId };
|
|
327
|
+
return this.post({
|
|
328
|
+
pathParam: ["Epics"],
|
|
329
|
+
param: { "format": "json" },
|
|
330
|
+
}, epic);
|
|
331
|
+
}
|
|
286
332
|
async createFeature({ title, description, epicId, releaseId, projectId, teamId }) {
|
|
287
333
|
const feature = {
|
|
288
334
|
"Name": title,
|