targetprocess-mcp-server 2.2.7 → 2.2.9-b
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/index.js +163 -5
- package/build/tp.js +62 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,6 +45,9 @@ Features
|
|
|
45
45
|
- `get_feature_user_stories` — Get all user stories for a feature by its ID (id)
|
|
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
|
+
User Stories
|
|
49
|
+
- `get_user_story_bugs` — Get all bugs linked to a user story by its ID (id)
|
|
50
|
+
|
|
48
51
|
Cards — Read
|
|
49
52
|
- `get_card_current_status` — Get EntityState, TeamState, and assigned teams for a card (id, optional resourceType: UserStory | Bug | Feature, default: UserStory)
|
|
50
53
|
- `get_bug_content` — Fetch full content of a bug by ID (id)
|
package/build/index.js
CHANGED
|
@@ -603,7 +603,7 @@ server.registerTool('create_bug_based_on_card', {
|
|
|
603
603
|
CRITICAL WORKFLOW: Before calling this tool, you MUST follow these steps:
|
|
604
604
|
1) IF you already have user story or bug card content, proceed to step 3 skipping step 2;
|
|
605
605
|
2) ELSE call "get_user_story_content" tool or "get_bug_content" tool to get user story or bug card content;
|
|
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>);
|
|
606
|
+
3) format the new bug inside html <div> tags with Environment, Issue Description, Steps to Reproduce, Expected Behavior, Actual Behavior and Attachments sections (note: section titles should be wrapped in <h3> tags, e.g. <h3>Issue Description</h3>);
|
|
607
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
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
609
|
6) add a comment to the card with created bug Id and its Title`,
|
|
@@ -771,7 +771,7 @@ server.registerTool('create_bug', {
|
|
|
771
771
|
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.
|
|
772
772
|
NOTE: this tool does not require a user story or bug card reference.
|
|
773
773
|
CRITICAL WORKFLOW: Before calling this tool, you MUST follow these steps:
|
|
774
|
-
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>);
|
|
774
|
+
1) format the new bug inside html <div> tags with Environment, Issue Description, Steps to Reproduce, Expected Behavior, Actual Behavior and Attachments sections (note: section titles should be wrapped in <h3> tags, e.g. <h3>Issue Description</h3>, step to reproduce should be wrapped in <ol>);
|
|
775
775
|
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;
|
|
776
776
|
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;`,
|
|
777
777
|
inputSchema: {
|
|
@@ -1058,19 +1058,45 @@ server.registerTool('get_feature_user_stories', {
|
|
|
1058
1058
|
}],
|
|
1059
1059
|
};
|
|
1060
1060
|
}
|
|
1061
|
-
|
|
1061
|
+
return {
|
|
1062
|
+
content: [{
|
|
1063
|
+
type: 'text',
|
|
1064
|
+
text: JSON.stringify(items)
|
|
1065
|
+
}],
|
|
1066
|
+
};
|
|
1067
|
+
});
|
|
1068
|
+
server.registerTool('get_user_story_bugs', {
|
|
1069
|
+
title: 'Get user story bugs',
|
|
1070
|
+
description: 'Get bugs linked to a TP user story by its ID',
|
|
1071
|
+
inputSchema: {
|
|
1072
|
+
id: z.string()
|
|
1073
|
+
.min(5)
|
|
1074
|
+
.max(6)
|
|
1075
|
+
.describe('TP user story ID (e.g. 145789)'),
|
|
1076
|
+
},
|
|
1077
|
+
}, async ({ id }) => {
|
|
1078
|
+
const response = await tp.getUserStoryBugs(id);
|
|
1079
|
+
if (!response) {
|
|
1080
|
+
return {
|
|
1081
|
+
content: [{
|
|
1082
|
+
type: 'text',
|
|
1083
|
+
text: `Failed to get bugs for user story id: ${id}`
|
|
1084
|
+
}],
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
const items = response.items || [];
|
|
1062
1088
|
if (items.length === 0) {
|
|
1063
1089
|
return {
|
|
1064
1090
|
content: [{
|
|
1065
1091
|
type: 'text',
|
|
1066
|
-
text: `No
|
|
1092
|
+
text: `No bugs found for user story id: ${id}`,
|
|
1067
1093
|
}],
|
|
1068
1094
|
};
|
|
1069
1095
|
}
|
|
1070
1096
|
return {
|
|
1071
1097
|
content: [{
|
|
1072
1098
|
type: 'text',
|
|
1073
|
-
text: JSON.stringify(
|
|
1099
|
+
text: JSON.stringify(items)
|
|
1074
1100
|
}],
|
|
1075
1101
|
};
|
|
1076
1102
|
});
|
|
@@ -1531,6 +1557,138 @@ server.registerTool('get_card_current_status', {
|
|
|
1531
1557
|
}],
|
|
1532
1558
|
};
|
|
1533
1559
|
});
|
|
1560
|
+
server.registerTool('get_in_progress_tasks_and_bugs', {
|
|
1561
|
+
title: 'Get in-progress tasks and bugs for a user',
|
|
1562
|
+
description: 'Get all Tasks and Bugs currently in "In Progress" state assigned to a given user ID',
|
|
1563
|
+
inputSchema: {
|
|
1564
|
+
userId: z.string()
|
|
1565
|
+
.describe('Targetprocess user ID (e.g. 123)'),
|
|
1566
|
+
},
|
|
1567
|
+
}, async ({ userId }) => {
|
|
1568
|
+
const result = await tp.getInProgressTasksAndBugs(userId);
|
|
1569
|
+
const tasks = result.tasks.map((t) => ({
|
|
1570
|
+
type: 'Task',
|
|
1571
|
+
id: t.Id,
|
|
1572
|
+
name: t.Name,
|
|
1573
|
+
state: t.EntityState?.Name,
|
|
1574
|
+
userStoryId: t.UserStory?.Id,
|
|
1575
|
+
userStoryName: t.UserStory?.Name,
|
|
1576
|
+
featureId: t.UserStory?.Feature?.Id,
|
|
1577
|
+
featureName: t.UserStory?.Feature?.Name,
|
|
1578
|
+
}));
|
|
1579
|
+
const bugs = result.bugs.map((b) => ({
|
|
1580
|
+
type: 'Bug',
|
|
1581
|
+
id: b.Id,
|
|
1582
|
+
name: b.Name,
|
|
1583
|
+
state: b.EntityState?.Name,
|
|
1584
|
+
userStoryId: b.UserStory?.Id,
|
|
1585
|
+
userStoryName: b.UserStory?.Name,
|
|
1586
|
+
featureId: b.UserStory?.Feature?.Id ?? b.Feature?.Id,
|
|
1587
|
+
featureName: b.UserStory?.Feature?.Name ?? b.Feature?.Name,
|
|
1588
|
+
}));
|
|
1589
|
+
const items = [...tasks, ...bugs];
|
|
1590
|
+
if (items.length === 0) {
|
|
1591
|
+
return {
|
|
1592
|
+
content: [{
|
|
1593
|
+
type: 'text',
|
|
1594
|
+
text: `No in-progress tasks or bugs found for user ID: ${userId}`,
|
|
1595
|
+
}],
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1598
|
+
return {
|
|
1599
|
+
content: [{
|
|
1600
|
+
type: 'text',
|
|
1601
|
+
text: JSON.stringify(items),
|
|
1602
|
+
}],
|
|
1603
|
+
};
|
|
1604
|
+
});
|
|
1605
|
+
server.registerTool('create_task', {
|
|
1606
|
+
title: 'Create a new task',
|
|
1607
|
+
description: 'Create a new task linked to a user story.',
|
|
1608
|
+
inputSchema: {
|
|
1609
|
+
title: z.string()
|
|
1610
|
+
.describe('Task title'),
|
|
1611
|
+
userStoryId: z.string()
|
|
1612
|
+
.min(5)
|
|
1613
|
+
.max(6)
|
|
1614
|
+
.describe('User story ID to link the task to (e.g. 145789)'),
|
|
1615
|
+
description: z.string()
|
|
1616
|
+
.optional()
|
|
1617
|
+
.describe('Task description (optional)'),
|
|
1618
|
+
},
|
|
1619
|
+
}, async ({ title, userStoryId, description }) => {
|
|
1620
|
+
const taskResponse = await tp.createTask({ title, userStoryId, description });
|
|
1621
|
+
if (!taskResponse) {
|
|
1622
|
+
return {
|
|
1623
|
+
content: [{
|
|
1624
|
+
type: 'text',
|
|
1625
|
+
text: `Failed to create task "${title}"\n JSON: ${JSON.stringify(taskResponse, null, 2)}`
|
|
1626
|
+
}]
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
return {
|
|
1630
|
+
content: [{
|
|
1631
|
+
type: 'text',
|
|
1632
|
+
text: JSON.stringify(taskResponse)
|
|
1633
|
+
}],
|
|
1634
|
+
};
|
|
1635
|
+
});
|
|
1636
|
+
server.registerTool('get_commit_message', {
|
|
1637
|
+
title: 'Get commit message for a task or bug',
|
|
1638
|
+
description: `Returns the formatted commit message string for a given task or bug ID.
|
|
1639
|
+
Formats:
|
|
1640
|
+
- Task on a user story: "F#<featureId> US#<userStoryId> T#<taskId> <title>"
|
|
1641
|
+
- Bug on a user story: "F#<featureId> US#<userStoryId> B#<bugId> <title>"
|
|
1642
|
+
- Standalone bug (no user story): "B#<bugId> <title>"`,
|
|
1643
|
+
inputSchema: {
|
|
1644
|
+
id: z.string()
|
|
1645
|
+
.describe('The task or bug ID (e.g. 145789)'),
|
|
1646
|
+
type: z.enum(['task', 'bug'])
|
|
1647
|
+
.describe('Whether the ID refers to a task or a bug'),
|
|
1648
|
+
},
|
|
1649
|
+
}, async ({ id, type }) => {
|
|
1650
|
+
if (type === 'task') {
|
|
1651
|
+
const task = await tp.getTask(id);
|
|
1652
|
+
if (!task) {
|
|
1653
|
+
return {
|
|
1654
|
+
content: [{ type: 'text', text: `Failed to get task with id: ${id}` }],
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
const userStory = task.UserStory;
|
|
1658
|
+
const feature = userStory?.Feature;
|
|
1659
|
+
if (!userStory) {
|
|
1660
|
+
return {
|
|
1661
|
+
content: [{ type: 'text', text: `Task ${id} has no linked user story` }],
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
const prefix = feature
|
|
1665
|
+
? `F#${feature.Id} US#${userStory.Id} T#${task.Id}`
|
|
1666
|
+
: `US#${userStory.Id} T#${task.Id}`;
|
|
1667
|
+
return {
|
|
1668
|
+
content: [{ type: 'text', text: `${prefix} ${task.Name}` }],
|
|
1669
|
+
};
|
|
1670
|
+
}
|
|
1671
|
+
// type === 'bug'
|
|
1672
|
+
const bug = await tp.getBugWithRelations(id);
|
|
1673
|
+
if (!bug) {
|
|
1674
|
+
return {
|
|
1675
|
+
content: [{ type: 'text', text: `Failed to get bug with id: ${id}` }],
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
const userStory = bug.UserStory;
|
|
1679
|
+
const feature = userStory?.Feature ?? bug.Feature;
|
|
1680
|
+
if (!userStory) {
|
|
1681
|
+
return {
|
|
1682
|
+
content: [{ type: 'text', text: `B#${bug.Id} ${bug.Name}` }],
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
const prefix = feature
|
|
1686
|
+
? `F#${feature.Id} US#${userStory.Id} B#${bug.Id}`
|
|
1687
|
+
: `US#${userStory.Id} B#${bug.Id}`;
|
|
1688
|
+
return {
|
|
1689
|
+
content: [{ type: 'text', text: `${prefix} ${bug.Name}` }],
|
|
1690
|
+
};
|
|
1691
|
+
});
|
|
1534
1692
|
async function main() {
|
|
1535
1693
|
const transport = new StdioServerTransport();
|
|
1536
1694
|
await server.connect(transport);
|
package/build/tp.js
CHANGED
|
@@ -45,7 +45,6 @@ export class TpClient {
|
|
|
45
45
|
async get(params) {
|
|
46
46
|
params.param["access_token"] = this.token;
|
|
47
47
|
let _url = this.params(params);
|
|
48
|
-
console.error(JSON.stringify({ "TP_URL": _url }, null, 2));
|
|
49
48
|
try {
|
|
50
49
|
const response = await fetch(_url, {
|
|
51
50
|
method: "GET",
|
|
@@ -457,6 +456,17 @@ export class TpClient {
|
|
|
457
456
|
apiVersion: this.v2
|
|
458
457
|
});
|
|
459
458
|
}
|
|
459
|
+
async getUserStoryBugs(userStoryId) {
|
|
460
|
+
return this.get({
|
|
461
|
+
pathParam: ["userstories"],
|
|
462
|
+
param: {
|
|
463
|
+
"format": "json",
|
|
464
|
+
"where": `(id==${userStoryId})`,
|
|
465
|
+
"select": `{bugs}`,
|
|
466
|
+
},
|
|
467
|
+
apiVersion: this.v2
|
|
468
|
+
});
|
|
469
|
+
}
|
|
460
470
|
async getUserStoriesIdsByFeatureId(featureId) {
|
|
461
471
|
return this.get({
|
|
462
472
|
pathParam: ["userstories"],
|
|
@@ -581,6 +591,57 @@ export class TpClient {
|
|
|
581
591
|
param: { "format": "json" }
|
|
582
592
|
});
|
|
583
593
|
}
|
|
594
|
+
async getInProgressTasksAndBugs(userId) {
|
|
595
|
+
const where = `(EntityState.Name eq 'In Progress') and (AssignedUser.Id eq ${userId})`;
|
|
596
|
+
const include = "[Id,Name,EntityState[Name],UserStory[Id,Name,Feature[Id,Name]]]";
|
|
597
|
+
const param = { "format": "json", "where": where, "include": include, "orderByDesc": "ModifyDate" };
|
|
598
|
+
const [tasks, bugs] = await Promise.all([
|
|
599
|
+
this.get({ pathParam: ["Tasks"], param }),
|
|
600
|
+
this.get({ pathParam: ["Bugs"], param }),
|
|
601
|
+
]);
|
|
602
|
+
return {
|
|
603
|
+
tasks: tasks?.Items ?? [],
|
|
604
|
+
bugs: bugs?.Items ?? [],
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
async getTask(taskId) {
|
|
608
|
+
const response = await this.get({
|
|
609
|
+
pathParam: ["Tasks", taskId],
|
|
610
|
+
param: {
|
|
611
|
+
"format": "json",
|
|
612
|
+
"include": "[Id,Name,UserStory[Id,Name,Feature[Id,Name]]]",
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
return response;
|
|
616
|
+
}
|
|
617
|
+
async getBugWithRelations(bugId) {
|
|
618
|
+
const response = await this.get({
|
|
619
|
+
pathParam: ["Bugs", bugId],
|
|
620
|
+
param: {
|
|
621
|
+
"format": "json",
|
|
622
|
+
"include": "[Id,Name,UserStory[Id,Name,Feature[Id,Name]]]",
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
return response;
|
|
626
|
+
}
|
|
627
|
+
async createTask({ title, description, userStoryId }) {
|
|
628
|
+
const task = {
|
|
629
|
+
"Name": title,
|
|
630
|
+
"Project": {
|
|
631
|
+
"Id": config.tp.projectId
|
|
632
|
+
},
|
|
633
|
+
"UserStory": {
|
|
634
|
+
"Id": userStoryId
|
|
635
|
+
},
|
|
636
|
+
};
|
|
637
|
+
if (description) {
|
|
638
|
+
task["Description"] = description;
|
|
639
|
+
}
|
|
640
|
+
return this.post({
|
|
641
|
+
pathParam: ["Tasks"],
|
|
642
|
+
param: { "format": "json" },
|
|
643
|
+
}, task);
|
|
644
|
+
}
|
|
584
645
|
async addAttachedFile(generalId, source) {
|
|
585
646
|
let blob;
|
|
586
647
|
let fileName;
|