targetprocess-mcp-server 2.6.3 → 2.6.4

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.
@@ -0,0 +1,45 @@
1
+ import { JSDOM } from 'jsdom';
2
+ export async function handleGetFeatureComments(tp, id, results) {
3
+ const response = await tp.getFeatureComments(id, results);
4
+ if (!response) {
5
+ return {
6
+ content: [{
7
+ type: 'text',
8
+ text: `Failed to get comments for feature id: ${id}`
9
+ }],
10
+ };
11
+ }
12
+ const items = response.Items || [];
13
+ if (items.length === 0) {
14
+ return {
15
+ content: [{
16
+ type: 'text',
17
+ text: `No comments found for feature id: ${id}`,
18
+ }],
19
+ };
20
+ }
21
+ try {
22
+ const parsedItems = items.map((item) => {
23
+ const dom = new JSDOM(`<html><body><div id="content">${item.Description}</div></body></html>`);
24
+ const descriptionText = dom.window.document.getElementById('content')?.textContent;
25
+ return {
26
+ id: item.Id,
27
+ description: descriptionText,
28
+ createDate: item.CreateDate,
29
+ owner: item.Owner.FullName,
30
+ };
31
+ });
32
+ return {
33
+ content: [{ type: 'text', text: JSON.stringify(parsedItems) }],
34
+ };
35
+ }
36
+ catch (error) {
37
+ console.error('Error parsing feature comments:', error);
38
+ return {
39
+ content: [{
40
+ type: 'text',
41
+ text: `Failed to parse feature comments for feature id: ${id}`,
42
+ }],
43
+ };
44
+ }
45
+ }
package/build/index.js CHANGED
@@ -43,6 +43,7 @@ import { handleLogTime } from "./handlers/log_time.js";
43
43
  import { handleGetMyTimeLogs } from "./handlers/get_my_time_logs.js";
44
44
  import { handleGetFeatureUserStories } from "./handlers/get_feature_user_stories.js";
45
45
  import { handleGetFeatureContent } from "./handlers/get_feature_content.js";
46
+ import { handleGetFeatureComments } from "./handlers/get_feature_comments.js";
46
47
  import { handleGetUserStoryBugs } from "./handlers/get_user_story_bugs.js";
47
48
  import { handleGetCardCurrentStatus } from "./handlers/get_card_current_status.js";
48
49
  import { handleUpdateUserStorySubState } from "./handlers/update_user_story_sub_state.js";
@@ -449,7 +450,7 @@ server.registerTool('update_bug', {
449
450
  .describe('Optional Team ID — if user gave a team name, resolve it via "get_teams" first; defaults to TP_TEAM_ID from config'),
450
451
  entityStateId: z.string()
451
452
  .optional()
452
- .describe('Optional Entity State ID — if user gave a state name, resolve it via "get_bug_workflows" first; defaults to "Done"'),
453
+ .describe('Optional Entity State ID — if user gave a state name, resolve it via "get_bug_workflows" first; defaults to "Backlog"'),
453
454
  tags: z.string()
454
455
  .optional()
455
456
  .describe('Optional comma-separated tags to apply, e.g. "regression, mobile"'),
@@ -718,7 +719,12 @@ server.registerTool('create_formatted_feature', {
718
719
  1) Header — "businessBackground" is a 1-2 sentence value statement: who benefits and why;
719
720
  2) Definitions — cross-cutting terms used across multiple child stories, so they aren't redefined at every story level; if none apply, OMIT "definitions" entirely (do not send an empty section);
720
721
  3) Scope & Boundaries — what this feature explicitly includes/excludes, to stop child stories drifting into adjacent features; omit if genuinely trivial;
721
- 4) Non-Functional Requirements ("nonFunctionalRequirements") — every NFR category (Security, Compliance, Billing, Operational, etc.) MUST be converted from prose into one row with status "Covered" (link the child story/scenario that proves it in storyOrOwner), "Gap" (no story covers it yetstoryOrOwner names who should follow up), or "Decision needed" (genuinely still open, not testable until resolved). This is the core of the template never leave an NFR as untested prose;
722
+ 4) Non-Functional Requirements ("nonFunctionalRequirements") — this is the core of the template and doubles as ISO 27001:2022 audit evidence that NFRs (including information security, per Annex A Control 5.8) are considered at design time, not bolted on after. EVERY feature MUST include these four fixed rows, worded exactly as below (do not reword the questionsconsistency in the questions is what makes them auditable), each answered SPECIFICALLY for this feature in "storyOrOwner" a real, checkable answer (e.g. which systems/data/roles are involved), never a generic "considered" placeholder:
723
+ - area "System performance" / requirement "What does this feature add or change in terms of load, queries, polling, rendering etc., and what's the expected impact, if any?";
724
+ - area "Information security (ISO 27001:2022 Annex A 5.8)" / requirement "What personal or sensitive data does this feature touch, and what protects its privacy, confidentiality, integrity and availability?";
725
+ - area "Quality control" / requirement "How will this feature's behaviour and failures be measured or tested, and what happens when it fails?";
726
+ - area "Service logging" / requirement "What events or states should be logged so product support can diagnose an issue without reproducing it manually?";
727
+ For each row, set status to "Covered" (storyOrOwner holds the specific answer, or the child story/scenario that proves it), "Gap" (no answer/story yet — storyOrOwner names who should follow up), or "Decision needed" (genuinely open, not answerable yet). If any of the four is unclear, name Dave Sykes as the follow-up owner in storyOrOwner rather than guessing — he's the named escalation contact, not a mandatory sign-off gate. Additional NFR categories beyond these four (Compliance, Billing, Operational, etc.) can still be added as extra rows when relevant, using the same Covered/Gap/Decision-needed treatment;
722
728
  5) Cross-Cutting Scenarios — ONLY for behavior spanning multiple child stories that wouldn't naturally sit in any one of them (e.g. tenant isolation across all stories); do not duplicate per-story Gherkin here; omit if none apply;
723
729
  6) Child Stories ("childStories") — pull this from "get_feature_user_stories" / "get_not_covered_user_stories_in_feature" rather than retyping it; keep it as a live pointer, not a duplicate spec; normally empty when first creating the feature;
724
730
  7) Open Questions / Risks ("openQuestions") — anything raised at feature conception that hasn't been resolved into either a Covered NFR row or a child story; this is the section most likely to get silently dropped — treat it as the running "not done yet" list until each line is promoted to a Covered NFR row;
@@ -770,7 +776,7 @@ server.registerTool('create_formatted_feature', {
770
776
  .describe('If Covered, the child story ID/scenario that proves it; if Gap or Decision needed, who owns the follow-up (e.g. "Needs legal/BA follow-up")'),
771
777
  }))
772
778
  .min(1)
773
- .describe('Every NFR category converted from prose into a testable/decided row — the core of this template. Do not leave requirements as untested prose'),
779
+ .describe('Every NFR category converted from prose into a testable/decided row — the core of this template. MUST include the four fixed rows required for ISO 27001:2022 audit evidence: "System performance", "Information security (ISO 27001:2022 Annex A 5.8)", "Quality control", and "Service logging" — worded exactly, each answered specifically for this feature (escalate unclear items to Dave Sykes via storyOrOwner). Additional categories may be added beyond these four. Do not leave requirements as untested prose'),
774
780
  crossCuttingScenarios: z.array(z.object({
775
781
  name: z.string()
776
782
  .describe('Scenario name'),
@@ -1099,6 +1105,58 @@ server.registerTool('get_feature_content', {
1099
1105
  .describe('TP feature ID (e.g. 145636)'),
1100
1106
  },
1101
1107
  }, async ({ id }) => handleGetFeatureContent(tp, id));
1108
+ server.registerTool('get_feature_comments', {
1109
+ title: 'Get feature comments',
1110
+ description: 'Get comments for a TP feature by its ID',
1111
+ inputSchema: {
1112
+ id: z.string()
1113
+ .min(5)
1114
+ .max(9)
1115
+ .describe('TP feature ID (e.g. 145636)'),
1116
+ results: z.number()
1117
+ .default(25)
1118
+ .optional()
1119
+ .describe('Number of comments to return, default is 25'),
1120
+ },
1121
+ }, async ({ id, results }) => handleGetFeatureComments(tp, id, results));
1122
+ server.registerTool('get_assignment_roles', {
1123
+ title: 'Get assignment roles',
1124
+ description: 'Returns all available assignment roles (e.g. Business Analyst, Developer) with their IDs.',
1125
+ inputSchema: {},
1126
+ }, async () => {
1127
+ const result = await tp.getAssignmentRoles();
1128
+ return {
1129
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1130
+ };
1131
+ });
1132
+ server.registerTool('assign_role', {
1133
+ title: 'Assign a role to a user on a card',
1134
+ description: 'Assigns a user to a specific role on a single TP card (User Story, Bug, etc.).',
1135
+ inputSchema: {
1136
+ cardId: z.string().describe('TP card ID (e.g. 149350)'),
1137
+ userId: z.string().describe('TP user ID'),
1138
+ roleId: z.string().describe('TP role ID — use get_assignment_roles to find the right ID'),
1139
+ },
1140
+ }, async ({ cardId, userId, roleId }) => {
1141
+ const result = await tp.assignRole(cardId, userId, roleId);
1142
+ return {
1143
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1144
+ };
1145
+ });
1146
+ server.registerTool('assign_role_to_feature', {
1147
+ title: 'Assign a role to a user on all user stories in a feature',
1148
+ description: 'Assigns a user to a specific role on every user story within a given feature.',
1149
+ inputSchema: {
1150
+ featureId: z.string().describe('TP feature ID (e.g. 149341)'),
1151
+ userId: z.string().describe('TP user ID'),
1152
+ roleId: z.string().describe('TP role ID — use get_assignment_roles to find the right ID'),
1153
+ },
1154
+ }, async ({ featureId, userId, roleId }) => {
1155
+ const result = await tp.assignRoleToAllStoriesInFeature(featureId, userId, roleId);
1156
+ return {
1157
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1158
+ };
1159
+ });
1102
1160
  server.registerTool('get_user_story_bugs', {
1103
1161
  title: 'Get user story bugs',
1104
1162
  description: 'Get bugs linked to a TP user story by its ID',
package/build/tp.js CHANGED
@@ -586,6 +586,16 @@ export class TpClient {
586
586
  });
587
587
  return response;
588
588
  }
589
+ async getFeatureComments(featureId, results = 25) {
590
+ const response = await this.get({
591
+ pathParam: ["Features", featureId, "Comments"],
592
+ param: {
593
+ "format": "json",
594
+ "take": results,
595
+ }
596
+ });
597
+ return response;
598
+ }
589
599
  async searchContainsNameText({ text, entityType }) {
590
600
  return this.get({
591
601
  pathParam: [entityType],
package/package.json CHANGED
@@ -27,7 +27,7 @@
27
27
  "engines": {
28
28
  "node": ">=20.x"
29
29
  },
30
- "version": "2.6.3",
30
+ "version": "2.6.4",
31
31
  "description": "MCP server for Tartget Process",
32
32
  "main": "build/index.js",
33
33
  "keywords": [