targetprocess-mcp-server 2.3.0 → 2.4.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.
Files changed (37) hide show
  1. package/README.md +46 -0
  2. package/build/config.js +0 -0
  3. package/build/handlers/add_comment.js +14 -0
  4. package/build/handlers/create_bug.js +14 -0
  5. package/build/handlers/create_feature.js +14 -0
  6. package/build/handlers/create_task.js +14 -0
  7. package/build/handlers/create_user_story.js +14 -0
  8. package/build/handlers/get_bug_comments.js +45 -0
  9. package/build/handlers/get_bug_content.js +37 -0
  10. package/build/handlers/get_card_current_status.js +23 -0
  11. package/build/handlers/get_commit_message.js +42 -0
  12. package/build/handlers/get_current_releases.js +20 -0
  13. package/build/handlers/get_feature_user_stories.js +23 -0
  14. package/build/handlers/get_in_progress_tasks_and_bugs.js +35 -0
  15. package/build/handlers/get_logged_in_user.js +23 -0
  16. package/build/handlers/get_my_time_logs.js +20 -0
  17. package/build/handlers/get_projects.js +23 -0
  18. package/build/handlers/get_release_bugs.js +20 -0
  19. package/build/handlers/get_release_features.js +20 -0
  20. package/build/handlers/get_release_open_bugs.js +20 -0
  21. package/build/handlers/get_release_open_user_stories.js +20 -0
  22. package/build/handlers/get_release_user_stories.js +20 -0
  23. package/build/handlers/get_teams.js +41 -0
  24. package/build/handlers/get_user_by_id.js +14 -0
  25. package/build/handlers/get_user_story_bugs.js +23 -0
  26. package/build/handlers/get_user_story_comments.js +45 -0
  27. package/build/handlers/get_user_story_content.js +44 -0
  28. package/build/handlers/get_users.js +20 -0
  29. package/build/handlers/list_my_bugs.js +23 -0
  30. package/build/handlers/list_my_user_stories.js +23 -0
  31. package/build/handlers/log_time.js +14 -0
  32. package/build/handlers/update_bug.js +14 -0
  33. package/build/handlers/update_user_story_sub_state.js +14 -0
  34. package/build/index.js +94 -859
  35. package/build/tp.js +25 -0
  36. package/build/types.js +0 -0
  37. package/package.json +12 -7
package/README.md CHANGED
@@ -51,6 +51,8 @@ User Stories
51
51
  Tasks
52
52
  - `get_in_progress_tasks_and_bugs` — Get all Tasks and Bugs currently in "In Progress" state assigned to a given user (userId)
53
53
  - `create_task` — Create a new task linked to a user story (title, userStoryId, optional description)
54
+ - `list_my_user_stories` — List User Stories assigned to the current user, optionally filtered by state (optional state, optional take, optional skip)
55
+ - `list_my_bugs` — List Bugs assigned to the current user, optionally filtered by state (optional state, optional take, optional skip)
54
56
 
55
57
  Cards — Read
56
58
  - `get_card_current_status` — Get EntityState, TeamState, and assigned teams for a card (id, optional resourceType: UserStory | Bug | Feature, default: UserStory)
@@ -59,6 +61,8 @@ Cards — Read
59
61
  - `get_bug_comments` — Get comments on a bug (id, optional results)
60
62
  - `get_user_story_comments` — Get comments on a user story (id, optional results)
61
63
  - `get_user_story_test_cases` — Fetch the linked test plan and all its test cases (with steps) for a user story (resourceId)
64
+ - `get_card_relations` — Get all relations (Dependency, Blocker, Relation, Link, Duplicate) for a card, with direction and the related card (id)
65
+ - `get_relation_types` — List the relation types available in this instance (id + name); use to find the `relationType` name for `create_card_relation` (no params)
62
66
  - `search_tp_cards` — Search TP cards by keyword or phrase in description (keyword, optional entityType: UserStories | Bugs, default: UserStories)
63
67
 
64
68
  Cards — Write
@@ -68,6 +72,14 @@ Cards — Write
68
72
  > Resolve state name → ID via `get_bug_workflows` before passing `entityStateId`
69
73
  - `update_user_story` — Update an existing user story (id, optional title, optional description, optional projectId, optional teamId, optional entityStateId)
70
74
  > Resolve state name → ID via `get_user_story_workflows` before passing `entityStateId`
75
+ - `create_card_relation` — Create a relation between two cards (masterId, slaveId, optional relationType name, default: "Depends on")
76
+ > The Slave depends on the Master — the Master must be done first
77
+ > `relationType` is matched by name against this instance's types; resolve exact names via `get_relation_types` (it's resolved to an ID before the API call, since TP rejects relation types passed by name)
78
+ - `delete_card_relation` — Remove a relation by its relation ID (relationId)
79
+ > Get the `relationId` from `get_card_relations` first — it's the relation's own ID, not a card ID
80
+ - `update_user_story_state` — Update the sub-state (team assignment entity state) for a user story (id, optional entityStateId, optional teamId, optional teamAssignmentId)
81
+ > 1. Call `get_user_story_content` first to find the assigned team and `teamAssignmentId`
82
+ > 2. Call `get_user_story_workflows` to resolve the target state name → `entityStateId`
71
83
  - `create_bug` — Create a standalone bug (title, bugContent, optional origin, optional projectId, optional teamId, optional entityStateName)
72
84
  > `origin` accepted values: `Production - Customer`, `Production - Internal`, `Pre-Release - Customer`, `Pre-Release - Internal`, `Regression - Dev01`, `Regression - Team Env`, `Manual QA` *(default)*, `Developer Raised`, `Operations`
73
85
  > `entityStateName` accepted values: `Backlog`, `In Triage`, `Ready for Dev`, `In Dev`, `Blocked`, `PR Raised`, `Ready for Feature PCH`, `Ready for Feature QA`, `In Feature QA`, `Failed Feature QA`, `Ready for Merge`, `Ready to Deploy to Dev01`, `Ready for Dev01 QA`, `In Dev01 QA`, `Failed Dev01 QA`, `Ready to Deploy to prod`, `Closed`
@@ -101,12 +113,17 @@ Projects
101
113
 
102
114
  Teams
103
115
  - `get_teams` — Get all Targetprocess teams returning id and name (no params needed)
116
+ - `get_teams_and_team_assignments` — Get all teams and team assignments (id and name for each) (no params needed)
104
117
 
105
118
  User
106
119
  - `get_logged_in_user` — Get the currently logged-in user's info (no params needed)
107
120
  - `get_users` — Get all Targetprocess users (no params needed)
108
121
  - `get_user_by_id` — Get a single Targetprocess user by their ID (id)
109
122
 
123
+ Time Tracking
124
+ - `log_time` — Log time spent on a Task, User Story, or Bug (entityId, entityType: Task | UserStory | Bug, hours, optional description, optional date)
125
+ - `get_my_time_logs` — Get recent time log entries submitted by the current user (optional take)
126
+
110
127
  Developer Tools
111
128
  - `get_commit_message` — Returns a formatted commit message string for a task or bug ID (id, type: task | bug)
112
129
  > Format for task on a user story: `F#<featureId> US#<userStoryId> T#<taskId> <title>`
@@ -177,3 +194,32 @@ cd targetprocess-mcp-server
177
194
  npm install
178
195
  npm run build
179
196
  ```
197
+
198
+ ## Testing
199
+
200
+ Tests live in `tests/` and use [Vitest](https://vitest.dev/). All tool handlers are extracted to `src/handlers/` and tested with mocked `TpClient` instances — no network calls are made.
201
+
202
+ ```bash
203
+ npx vitest run # run all tests once
204
+ npx vitest # watch mode
205
+ ```
206
+
207
+ ### Coverage
208
+
209
+ **33 of 46 tools (72%) are covered by unit tests.**
210
+
211
+ | Test file | Handlers covered |
212
+ |---|---|
213
+ | `get_bug_content.test.ts` | `get_bug_content` |
214
+ | `get_user_story_content.test.ts` | `get_user_story_content` |
215
+ | `get_commit_message.test.ts` | `get_commit_message` |
216
+ | `get_current_releases.test.ts` | `get_current_releases` |
217
+ | `get_projects.test.ts` | `get_projects` |
218
+ | `get_logged_in_user.test.ts` | `get_logged_in_user` |
219
+ | `get_user_by_id.test.ts` | `get_user_by_id` |
220
+ | `release_tools.test.ts` | `get_release_user_stories`, `get_release_bugs`, `get_release_features`, `get_release_open_bugs`, `get_release_open_user_stories` |
221
+ | `user_team_tools.test.ts` | `get_users`, `get_teams`, `get_teams_and_team_assignments` |
222
+ | `comment_tools.test.ts` | `add_comment`, `get_user_story_comments`, `get_bug_comments` |
223
+ | `creation_tools.test.ts` | `create_bug`, `create_user_story`, `create_feature`, `create_task`, `update_bug`, `update_user_story_state` |
224
+ | `my_work_tools.test.ts` | `get_in_progress_tasks_and_bugs`, `list_my_user_stories`, `list_my_bugs`, `log_time`, `get_my_time_logs` |
225
+ | `entity_tools.test.ts` | `get_feature_user_stories`, `get_user_story_bugs`, `get_card_current_status` |
package/build/config.js CHANGED
File without changes
@@ -0,0 +1,14 @@
1
+ export async function handleAddComment(tp, id, comment) {
2
+ const response = await tp.addComment(id, comment);
3
+ if (!response) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to add comment to user story, id: ${id}\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,14 @@
1
+ export async function handleCreateBug(tp, params) {
2
+ const bugResponse = await tp.createBugOnly(params);
3
+ if (!bugResponse) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to create bug "${params.title}"\n JSON: ${JSON.stringify(bugResponse, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ return {
12
+ content: [{ type: 'text', text: JSON.stringify(bugResponse) }],
13
+ };
14
+ }
@@ -0,0 +1,14 @@
1
+ export async function handleCreateFeature(tp, params) {
2
+ const response = await tp.createFeature(params);
3
+ if (!response) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to create feature "${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,14 @@
1
+ export async function handleCreateTask(tp, params) {
2
+ const response = await tp.createTask(params);
3
+ if (!response) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to create task "${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,14 @@
1
+ export async function handleCreateUserStory(tp, params) {
2
+ const response = await tp.createUserStory(params);
3
+ if (!response) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to create user story "${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,45 @@
1
+ import { JSDOM } from 'jsdom';
2
+ export async function handleGetBugComments(tp, id, results) {
3
+ const response = await tp.getBugComments(id, results);
4
+ if (!response) {
5
+ return {
6
+ content: [{
7
+ type: 'text',
8
+ text: `Failed to get comments for bug 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 bug 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 bug comments:', error);
38
+ return {
39
+ content: [{
40
+ type: 'text',
41
+ text: `Failed to parse bug comments for bug id: ${id}`,
42
+ }],
43
+ };
44
+ }
45
+ }
@@ -0,0 +1,37 @@
1
+ import { JSDOM } from 'jsdom';
2
+ export async function handleGetBugContent(tp, id) {
3
+ const bug = await tp.getBug(id);
4
+ if (!bug) {
5
+ return {
6
+ content: [{
7
+ type: 'text',
8
+ text: `Failed to get bug, id: ${id}\n JSON: ${JSON.stringify(bug, null, 2)}`
9
+ }],
10
+ };
11
+ }
12
+ const bugResult = {
13
+ name: bug.Name,
14
+ id: bug.Id,
15
+ description: '',
16
+ origin: '',
17
+ };
18
+ try {
19
+ const dom = new JSDOM(`<html><body><div id="content">${bug.Description}</div></body></html>`);
20
+ const descriptionText = dom.window.document.getElementById('content')?.textContent;
21
+ if (descriptionText) {
22
+ bugResult.description = descriptionText;
23
+ }
24
+ }
25
+ catch (error) {
26
+ console.error('Error parsing bug description:', error);
27
+ }
28
+ try {
29
+ bugResult.origin = bug.CustomFields?.find((field) => field?.Value === 'Origin')?.Value;
30
+ }
31
+ catch (error) {
32
+ console.error('Error parsing bug origin:', error);
33
+ }
34
+ return {
35
+ content: [{ type: 'text', text: JSON.stringify(bugResult) }],
36
+ };
37
+ }
@@ -0,0 +1,23 @@
1
+ export async function handleGetCardCurrentStatus(tp, id, resourceType = 'UserStory') {
2
+ const response = await tp.getCardStatus(id, resourceType);
3
+ if (!response) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get card status for ${resourceType} id: ${id}`
8
+ }],
9
+ };
10
+ }
11
+ const items = response.items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{
15
+ type: 'text',
16
+ text: `No status data found for ${resourceType} id: ${id}`,
17
+ }],
18
+ };
19
+ }
20
+ return {
21
+ content: [{ type: 'text', text: JSON.stringify(items[0]) }],
22
+ };
23
+ }
@@ -0,0 +1,42 @@
1
+ export async function handleGetCommitMessage(tp, id, type) {
2
+ if (type === 'task') {
3
+ const task = await tp.getTask(id);
4
+ if (!task) {
5
+ return {
6
+ content: [{ type: 'text', text: `Failed to get task with id: ${id}` }],
7
+ };
8
+ }
9
+ const userStory = task.UserStory;
10
+ if (!userStory) {
11
+ return {
12
+ content: [{ type: 'text', text: `Task ${id} has no linked user story` }],
13
+ };
14
+ }
15
+ const feature = userStory.Feature;
16
+ const prefix = feature
17
+ ? `F#${feature.Id} US#${userStory.Id} T#${task.Id}`
18
+ : `US#${userStory.Id} T#${task.Id}`;
19
+ return {
20
+ content: [{ type: 'text', text: `${prefix} ${task.Name}` }],
21
+ };
22
+ }
23
+ const bug = await tp.getBugWithRelations(id);
24
+ if (!bug) {
25
+ return {
26
+ content: [{ type: 'text', text: `Failed to get bug with id: ${id}` }],
27
+ };
28
+ }
29
+ const userStory = bug.UserStory;
30
+ const feature = userStory?.Feature ?? bug.Feature;
31
+ if (!userStory) {
32
+ return {
33
+ content: [{ type: 'text', text: `B#${bug.Id} ${bug.Name}` }],
34
+ };
35
+ }
36
+ const prefix = feature
37
+ ? `F#${feature.Id} US#${userStory.Id} B#${bug.Id}`
38
+ : `US#${userStory.Id} B#${bug.Id}`;
39
+ return {
40
+ content: [{ type: 'text', text: `${prefix} ${bug.Name}` }],
41
+ };
42
+ }
@@ -0,0 +1,20 @@
1
+ export async function handleGetCurrentReleases(tp) {
2
+ const releases = await tp.getCurrentReleases();
3
+ if (!releases) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get current releases, JSON: ${JSON.stringify(releases, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ const items = releases.Items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{ type: 'text', text: 'No releases found' }],
15
+ };
16
+ }
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify(items) }],
19
+ };
20
+ }
@@ -0,0 +1,23 @@
1
+ export async function handleGetFeatureUserStories(tp, id) {
2
+ const response = await tp.getFeatureUserStories(id);
3
+ if (!response) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get user stories for feature id: ${id}`
8
+ }],
9
+ };
10
+ }
11
+ const items = response.items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{
15
+ type: 'text',
16
+ text: `No user stories found in outer items for feature id: ${id}`,
17
+ }],
18
+ };
19
+ }
20
+ return {
21
+ content: [{ type: 'text', text: JSON.stringify(items) }],
22
+ };
23
+ }
@@ -0,0 +1,35 @@
1
+ export async function handleGetInProgressTasksAndBugs(tp, userId) {
2
+ const result = await tp.getInProgressTasksAndBugs(userId);
3
+ const tasks = result.tasks.map((t) => ({
4
+ type: 'Task',
5
+ id: t.Id,
6
+ name: t.Name,
7
+ state: t.EntityState?.Name,
8
+ userStoryId: t.UserStory?.Id,
9
+ userStoryName: t.UserStory?.Name,
10
+ featureId: t.UserStory?.Feature?.Id,
11
+ featureName: t.UserStory?.Feature?.Name,
12
+ }));
13
+ const bugs = result.bugs.map((b) => ({
14
+ type: 'Bug',
15
+ id: b.Id,
16
+ name: b.Name,
17
+ state: b.EntityState?.Name,
18
+ userStoryId: b.UserStory?.Id,
19
+ userStoryName: b.UserStory?.Name,
20
+ featureId: b.UserStory?.Feature?.Id ?? b.Feature?.Id,
21
+ featureName: b.UserStory?.Feature?.Name ?? b.Feature?.Name,
22
+ }));
23
+ const items = [...tasks, ...bugs];
24
+ if (items.length === 0) {
25
+ return {
26
+ content: [{
27
+ type: 'text',
28
+ text: `No in-progress tasks or bugs found for user ID: ${userId}`,
29
+ }],
30
+ };
31
+ }
32
+ return {
33
+ content: [{ type: 'text', text: JSON.stringify(items) }],
34
+ };
35
+ }
@@ -0,0 +1,23 @@
1
+ export async function handleGetLoggedInUser(tp) {
2
+ const ctx = await tp.getContext();
3
+ if (!ctx) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get context, JSON: ${JSON.stringify(ctx, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ const loggedInUser = ctx.LoggedUser;
12
+ if (!loggedInUser) {
13
+ return {
14
+ content: [{
15
+ type: 'text',
16
+ text: `Failed to get logged in user in this context, JSON: ${JSON.stringify(ctx, null, 2)}`
17
+ }],
18
+ };
19
+ }
20
+ return {
21
+ content: [{ type: 'text', text: JSON.stringify(loggedInUser) }],
22
+ };
23
+ }
@@ -0,0 +1,20 @@
1
+ export async function handleGetMyTimeLogs(tp, take) {
2
+ const response = await tp.getMyTimeLogs(take);
3
+ if (!response) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get time logs, JSON: ${JSON.stringify(response, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ const items = response.Items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{ type: 'text', text: 'No time logs found' }],
15
+ };
16
+ }
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify(items) }],
19
+ };
20
+ }
@@ -0,0 +1,23 @@
1
+ export async function handleGetProjects(tp) {
2
+ const response = await tp.getProjects();
3
+ if (!response) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get projects, JSON: ${JSON.stringify(response, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ const items = response.Items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{ type: 'text', text: 'No projects found' }],
15
+ };
16
+ }
17
+ return {
18
+ content: [{
19
+ type: 'text',
20
+ text: JSON.stringify(items.map((p) => ({ id: p.Id, name: p.Name })))
21
+ }],
22
+ };
23
+ }
@@ -0,0 +1,20 @@
1
+ export async function handleGetReleaseBugs(tp, name, results) {
2
+ const release = await tp.getReleaseBugs({ name, results });
3
+ if (!release) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get ${name} release bugs, JSON: ${JSON.stringify(release, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ const items = release.Items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{ type: 'text', text: 'No release bugs found' }],
15
+ };
16
+ }
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify(items) }],
19
+ };
20
+ }
@@ -0,0 +1,20 @@
1
+ export async function handleGetReleaseFeatures(tp, name, results) {
2
+ const release = await tp.getReleaseFeatures({ name, results });
3
+ if (!release) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get ${name} release features, JSON: ${JSON.stringify(release, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ const items = release.Items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{ type: 'text', text: 'No release features found' }],
15
+ };
16
+ }
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify(items) }],
19
+ };
20
+ }
@@ -0,0 +1,20 @@
1
+ export async function handleGetReleaseOpenBugs(tp, name, results, withDescription) {
2
+ const release = await tp.getReleaseOpenBugs({ name, results, withDescription });
3
+ if (!release) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get ${name} release bugs, JSON: ${JSON.stringify(release, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ const items = release.Items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{ type: 'text', text: 'No release bugs found' }],
15
+ };
16
+ }
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify(items) }],
19
+ };
20
+ }
@@ -0,0 +1,20 @@
1
+ export async function handleGetReleaseOpenUserStories(tp, name, results, withDescription) {
2
+ const release = await tp.getReleaseOpenUserStories({ name, results, withDescription });
3
+ if (!release) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get ${name} release user stories, JSON: ${JSON.stringify(release, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ const items = release.Items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{ type: 'text', text: 'No release user stories found' }],
15
+ };
16
+ }
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify(items) }],
19
+ };
20
+ }
@@ -0,0 +1,20 @@
1
+ export async function handleGetReleaseUserStories(tp, name, results, withDescription) {
2
+ const release = await tp.getReleaseUserStories({ name, results, withDescription });
3
+ if (!release) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get ${name} release user stories, JSON: ${JSON.stringify(release, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ const items = release.Items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{ type: 'text', text: 'No release user stories found' }],
15
+ };
16
+ }
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify(items) }],
19
+ };
20
+ }
@@ -0,0 +1,41 @@
1
+ export async function handleGetTeams(tp) {
2
+ const response = await tp.getTeams();
3
+ if (!response) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get teams, JSON: ${JSON.stringify(response, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ const items = response.Items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{ type: 'text', text: 'No teams found' }],
15
+ };
16
+ }
17
+ return {
18
+ content: [{ type: 'text', text: JSON.stringify(items.map((t) => ({ id: t.Id, name: t.Name }))) }],
19
+ };
20
+ }
21
+ export async function handleGetTeamsAndTeamAssignments(tp) {
22
+ const teams = await tp.getTeams();
23
+ const teamAssignments = await tp.getTeamAssignments();
24
+ if (!teams || !teamAssignments) {
25
+ return {
26
+ content: [{
27
+ type: 'text',
28
+ text: `Failed to get teams and team assignments, JSON: ${JSON.stringify({ teams, teamAssignments }, null, 2)}`
29
+ }],
30
+ };
31
+ }
32
+ return {
33
+ content: [{
34
+ type: 'text',
35
+ text: JSON.stringify({
36
+ teams: teams.Items.map((t) => ({ id: t.Id, name: t.Name })),
37
+ teamAssignments: teamAssignments.Items.map((t) => ({ id: t.Id, name: t.Team.Name })),
38
+ }),
39
+ }],
40
+ };
41
+ }
@@ -0,0 +1,14 @@
1
+ export async function handleGetUserById(tp, id) {
2
+ const user = await tp.getUser(id);
3
+ if (!user) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get user, id: ${id}\n JSON: ${JSON.stringify(user, null, 2)}`
8
+ }],
9
+ };
10
+ }
11
+ return {
12
+ content: [{ type: 'text', text: JSON.stringify(user) }],
13
+ };
14
+ }
@@ -0,0 +1,23 @@
1
+ export async function handleGetUserStoryBugs(tp, id) {
2
+ const response = await tp.getUserStoryBugs(id);
3
+ if (!response) {
4
+ return {
5
+ content: [{
6
+ type: 'text',
7
+ text: `Failed to get bugs for user story id: ${id}`
8
+ }],
9
+ };
10
+ }
11
+ const items = response.items || [];
12
+ if (items.length === 0) {
13
+ return {
14
+ content: [{
15
+ type: 'text',
16
+ text: `No bugs found for user story id: ${id}`,
17
+ }],
18
+ };
19
+ }
20
+ return {
21
+ content: [{ type: 'text', text: JSON.stringify(items) }],
22
+ };
23
+ }