targetprocess-mcp-server 2.2.12 → 2.3.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 +1 -0
- package/build/index.js +179 -0
- package/build/tp.js +65 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,6 +105,7 @@ Teams
|
|
|
105
105
|
User
|
|
106
106
|
- `get_logged_in_user` — Get the currently logged-in user's info (no params needed)
|
|
107
107
|
- `get_users` — Get all Targetprocess users (no params needed)
|
|
108
|
+
- `get_user_by_id` — Get a single Targetprocess user by their ID (id)
|
|
108
109
|
|
|
109
110
|
Developer Tools
|
|
110
111
|
- `get_commit_message` — Returns a formatted commit message string for a task or bug ID (id, type: task | bug)
|
package/build/index.js
CHANGED
|
@@ -435,6 +435,30 @@ server.registerTool('get_bug_content', {
|
|
|
435
435
|
}],
|
|
436
436
|
};
|
|
437
437
|
});
|
|
438
|
+
server.registerTool('get_user_by_id', {
|
|
439
|
+
title: 'Get user by id',
|
|
440
|
+
description: 'Get user by id',
|
|
441
|
+
inputSchema: {
|
|
442
|
+
id: z.string()
|
|
443
|
+
.describe('User email'),
|
|
444
|
+
},
|
|
445
|
+
}, async ({ id }) => {
|
|
446
|
+
const user = await tp.getUser(id);
|
|
447
|
+
if (!user) {
|
|
448
|
+
return {
|
|
449
|
+
content: [{
|
|
450
|
+
type: 'text',
|
|
451
|
+
text: `Failed to get user, id: ${id}\n JSON: ${JSON.stringify(user, null, 2)}`
|
|
452
|
+
}],
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
return {
|
|
456
|
+
content: [{
|
|
457
|
+
type: 'text',
|
|
458
|
+
text: JSON.stringify(user)
|
|
459
|
+
}],
|
|
460
|
+
};
|
|
461
|
+
});
|
|
438
462
|
server.registerTool('get_users', {
|
|
439
463
|
title: 'Get users',
|
|
440
464
|
description: 'Get all users',
|
|
@@ -1773,6 +1797,161 @@ Formats:
|
|
|
1773
1797
|
content: [{ type: 'text', text: `${prefix} ${bug.Name}` }],
|
|
1774
1798
|
};
|
|
1775
1799
|
});
|
|
1800
|
+
server.registerTool('list_my_user_stories', {
|
|
1801
|
+
title: 'List my user stories',
|
|
1802
|
+
description: 'List User Stories assigned to me. Use this to get an overview of current work. Optionally filter by state.',
|
|
1803
|
+
inputSchema: {
|
|
1804
|
+
state: z.string()
|
|
1805
|
+
.optional()
|
|
1806
|
+
.describe('Filter by state name (e.g. "Open", "In Progress", "Done")'),
|
|
1807
|
+
take: z.number()
|
|
1808
|
+
.default(25)
|
|
1809
|
+
.optional()
|
|
1810
|
+
.describe('Number of results to return, default is 25'),
|
|
1811
|
+
skip: z.number()
|
|
1812
|
+
.default(0)
|
|
1813
|
+
.optional()
|
|
1814
|
+
.describe('Pagination offset, default is 0'),
|
|
1815
|
+
},
|
|
1816
|
+
}, async ({ state, take, skip }) => {
|
|
1817
|
+
const response = await tp.getMyUserStories({ state, take, skip });
|
|
1818
|
+
if (!response) {
|
|
1819
|
+
return {
|
|
1820
|
+
content: [{
|
|
1821
|
+
type: 'text',
|
|
1822
|
+
text: `Failed to get user stories, JSON: ${JSON.stringify(response, null, 2)}`
|
|
1823
|
+
}],
|
|
1824
|
+
};
|
|
1825
|
+
}
|
|
1826
|
+
const items = response.Items || [];
|
|
1827
|
+
if (items.length === 0) {
|
|
1828
|
+
return {
|
|
1829
|
+
content: [{
|
|
1830
|
+
type: 'text',
|
|
1831
|
+
text: `No user stories assigned to you${state ? ` with state "${state}"` : ''}`,
|
|
1832
|
+
}],
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
return {
|
|
1836
|
+
content: [{
|
|
1837
|
+
type: 'text',
|
|
1838
|
+
text: JSON.stringify(items)
|
|
1839
|
+
}],
|
|
1840
|
+
};
|
|
1841
|
+
});
|
|
1842
|
+
server.registerTool('list_my_bugs', {
|
|
1843
|
+
title: 'List my bugs',
|
|
1844
|
+
description: 'List Bugs assigned to me. Optionally filter by state.',
|
|
1845
|
+
inputSchema: {
|
|
1846
|
+
state: z.string()
|
|
1847
|
+
.optional()
|
|
1848
|
+
.describe('Filter by state name (e.g. "Open", "In Progress", "Fixed")'),
|
|
1849
|
+
take: z.number()
|
|
1850
|
+
.default(25)
|
|
1851
|
+
.optional()
|
|
1852
|
+
.describe('Number of results to return, default is 25'),
|
|
1853
|
+
skip: z.number()
|
|
1854
|
+
.default(0)
|
|
1855
|
+
.optional()
|
|
1856
|
+
.describe('Pagination offset, default is 0'),
|
|
1857
|
+
},
|
|
1858
|
+
}, async ({ state, take, skip }) => {
|
|
1859
|
+
const response = await tp.getMyBugs({ state, take, skip });
|
|
1860
|
+
if (!response) {
|
|
1861
|
+
return {
|
|
1862
|
+
content: [{
|
|
1863
|
+
type: 'text',
|
|
1864
|
+
text: `Failed to get bugs, JSON: ${JSON.stringify(response, null, 2)}`
|
|
1865
|
+
}],
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
const items = response.Items || [];
|
|
1869
|
+
if (items.length === 0) {
|
|
1870
|
+
return {
|
|
1871
|
+
content: [{
|
|
1872
|
+
type: 'text',
|
|
1873
|
+
text: `No bugs assigned to you${state ? ` with state "${state}"` : ''}`,
|
|
1874
|
+
}],
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
return {
|
|
1878
|
+
content: [{
|
|
1879
|
+
type: 'text',
|
|
1880
|
+
text: JSON.stringify(items)
|
|
1881
|
+
}],
|
|
1882
|
+
};
|
|
1883
|
+
});
|
|
1884
|
+
server.registerTool('log_time', {
|
|
1885
|
+
title: 'Log time on a Task, User Story, or Bug',
|
|
1886
|
+
description: 'Log time spent working on a Task, User Story, or Bug. Call this after completing a task or at the end of a work session.',
|
|
1887
|
+
inputSchema: {
|
|
1888
|
+
entityId: z.string()
|
|
1889
|
+
.min(1)
|
|
1890
|
+
.describe('ID of the Task, User Story, or Bug to log time against (e.g. 145789)'),
|
|
1891
|
+
entityType: z.enum(['Task', 'UserStory', 'Bug'])
|
|
1892
|
+
.describe('Type of the entity'),
|
|
1893
|
+
hours: z.number()
|
|
1894
|
+
.positive()
|
|
1895
|
+
.describe('Hours spent (can be decimal e.g. 1.5)'),
|
|
1896
|
+
description: z.string()
|
|
1897
|
+
.optional()
|
|
1898
|
+
.describe('What was done — brief summary of the work'),
|
|
1899
|
+
date: z.string()
|
|
1900
|
+
.optional()
|
|
1901
|
+
.describe('ISO date string, defaults to today (e.g. "2024-05-21")'),
|
|
1902
|
+
},
|
|
1903
|
+
}, async ({ entityId, entityType, hours, description, date }) => {
|
|
1904
|
+
const response = await tp.logTime({ entityId, entityType, hours, description, date });
|
|
1905
|
+
if (!response) {
|
|
1906
|
+
return {
|
|
1907
|
+
content: [{
|
|
1908
|
+
type: 'text',
|
|
1909
|
+
text: `Failed to log time on ${entityType} id: ${entityId}`
|
|
1910
|
+
}],
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1913
|
+
return {
|
|
1914
|
+
content: [{
|
|
1915
|
+
type: 'text',
|
|
1916
|
+
text: JSON.stringify(response)
|
|
1917
|
+
}],
|
|
1918
|
+
};
|
|
1919
|
+
});
|
|
1920
|
+
server.registerTool('get_my_time_logs', {
|
|
1921
|
+
title: 'Get my recent time log entries',
|
|
1922
|
+
description: 'Get recent time log entries submitted by me.',
|
|
1923
|
+
inputSchema: {
|
|
1924
|
+
take: z.number()
|
|
1925
|
+
.default(25)
|
|
1926
|
+
.optional()
|
|
1927
|
+
.describe('Number of entries to return, default is 25'),
|
|
1928
|
+
},
|
|
1929
|
+
}, async ({ take }) => {
|
|
1930
|
+
const response = await tp.getMyTimeLogs(take);
|
|
1931
|
+
if (!response) {
|
|
1932
|
+
return {
|
|
1933
|
+
content: [{
|
|
1934
|
+
type: 'text',
|
|
1935
|
+
text: `Failed to get time logs, JSON: ${JSON.stringify(response, null, 2)}`
|
|
1936
|
+
}],
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
const items = response.Items || [];
|
|
1940
|
+
if (items.length === 0) {
|
|
1941
|
+
return {
|
|
1942
|
+
content: [{
|
|
1943
|
+
type: 'text',
|
|
1944
|
+
text: `No time logs found`,
|
|
1945
|
+
}],
|
|
1946
|
+
};
|
|
1947
|
+
}
|
|
1948
|
+
return {
|
|
1949
|
+
content: [{
|
|
1950
|
+
type: 'text',
|
|
1951
|
+
text: JSON.stringify(items)
|
|
1952
|
+
}],
|
|
1953
|
+
};
|
|
1954
|
+
});
|
|
1776
1955
|
async function main() {
|
|
1777
1956
|
const transport = new StdioServerTransport();
|
|
1778
1957
|
await server.connect(transport);
|
package/build/tp.js
CHANGED
|
@@ -310,6 +310,12 @@ export class TpClient {
|
|
|
310
310
|
param: { "format": "json" },
|
|
311
311
|
}, testPlan);
|
|
312
312
|
}
|
|
313
|
+
async getUser(userId) {
|
|
314
|
+
return this.get({
|
|
315
|
+
pathParam: ["Users", userId],
|
|
316
|
+
param: { "format": "json" },
|
|
317
|
+
});
|
|
318
|
+
}
|
|
313
319
|
async getUsers() {
|
|
314
320
|
return this.get({
|
|
315
321
|
pathParam: ["Users"],
|
|
@@ -678,6 +684,65 @@ export class TpClient {
|
|
|
678
684
|
param: { "format": "json" },
|
|
679
685
|
}, task);
|
|
680
686
|
}
|
|
687
|
+
async logTime({ entityId, entityType, hours, description, date, }) {
|
|
688
|
+
const timestamp = date ? new Date(date).getTime() : Date.now();
|
|
689
|
+
const body = {
|
|
690
|
+
Spent: hours,
|
|
691
|
+
Date: `/Date(${timestamp})/`,
|
|
692
|
+
User: { Id: config.tp.ownerId },
|
|
693
|
+
Assignable: { Id: entityId, ResourceType: entityType },
|
|
694
|
+
};
|
|
695
|
+
if (description)
|
|
696
|
+
body["Description"] = description;
|
|
697
|
+
return this.post({
|
|
698
|
+
pathParam: ["Times"],
|
|
699
|
+
param: { "format": "json" },
|
|
700
|
+
}, body);
|
|
701
|
+
}
|
|
702
|
+
async getMyTimeLogs(take = 25) {
|
|
703
|
+
return this.get({
|
|
704
|
+
pathParam: ["Times"],
|
|
705
|
+
param: {
|
|
706
|
+
"format": "json",
|
|
707
|
+
"where": `User.Id eq ${config.tp.ownerId}`,
|
|
708
|
+
"include": "[Id,Spent,Date,Description,Assignable[Id,Name,ResourceType]]",
|
|
709
|
+
"orderByDesc": "Date",
|
|
710
|
+
"take": take,
|
|
711
|
+
},
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
async getMyUserStories({ state, take = 25, skip = 0 }) {
|
|
715
|
+
const whereParts = [`AssignedUser.Id eq ${config.tp.ownerId}`];
|
|
716
|
+
if (state)
|
|
717
|
+
whereParts.push(`EntityState.Name contains '${state}'`);
|
|
718
|
+
return this.get({
|
|
719
|
+
pathParam: ["UserStories"],
|
|
720
|
+
param: {
|
|
721
|
+
"format": "json",
|
|
722
|
+
"where": whereParts.join(' and '),
|
|
723
|
+
"include": "[Id,Name,EntityState[Name],Effort,Project[Name],Feature[Id,Name],CreateDate,ModifyDate]",
|
|
724
|
+
"orderByDesc": "ModifyDate",
|
|
725
|
+
"take": take,
|
|
726
|
+
"skip": skip,
|
|
727
|
+
},
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
async getMyBugs({ state, take = 25, skip = 0 }) {
|
|
731
|
+
const whereParts = [`AssignedUser.Id eq ${config.tp.ownerId}`];
|
|
732
|
+
if (state)
|
|
733
|
+
whereParts.push(`EntityState.Name contains '${state}'`);
|
|
734
|
+
return this.get({
|
|
735
|
+
pathParam: ["Bugs"],
|
|
736
|
+
param: {
|
|
737
|
+
"format": "json",
|
|
738
|
+
"where": whereParts.join(' and '),
|
|
739
|
+
"include": "[Id,Name,EntityState[Name],Severity[Name],Priority[Name],Project[Name],UserStory[Id,Name],CreateDate,ModifyDate]",
|
|
740
|
+
"orderByDesc": "ModifyDate",
|
|
741
|
+
"take": take,
|
|
742
|
+
"skip": skip,
|
|
743
|
+
},
|
|
744
|
+
});
|
|
745
|
+
}
|
|
681
746
|
async addAttachedFile(generalId, source) {
|
|
682
747
|
let blob;
|
|
683
748
|
let fileName;
|