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 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;
package/package.json CHANGED
@@ -25,7 +25,7 @@
25
25
  "engines": {
26
26
  "node": ">=20.x"
27
27
  },
28
- "version": "2.2.12",
28
+ "version": "2.3.0",
29
29
  "description": "MCP server for Tartget Process",
30
30
  "main": "build/index.js",
31
31
  "keywords": [