@@ -50,6 +50,27 @@ function branchesFilterOutIrrelevantProperties(branches: GitRef[], top: number)
5050 . slice ( 0 , top ) ;
5151}
5252
53+ /**
54+ * Trims comment data to essential properties, filtering out deleted comments
55+ * @param comments Array of comments to trim (can be undefined/null)
56+ * @returns Array of trimmed comment objects with essential properties only
57+ */
58+ function trimComments ( comments : any [ ] | undefined | null ) {
59+ return comments
60+ ?. filter ( ( comment ) => ! comment . isDeleted ) // Exclude deleted comments
61+ ?. map ( ( comment ) => ( {
62+ id : comment . id ,
63+ author : {
64+ displayName : comment . author ?. displayName ,
65+ uniqueName : comment . author ?. uniqueName ,
66+ } ,
67+ content : comment . content ,
68+ publishedDate : comment . publishedDate ,
69+ lastUpdatedDate : comment . lastUpdatedDate ,
70+ lastContentUpdatedDate : comment . lastContentUpdatedDate ,
71+ } ) ) ;
72+ }
73+
5374function pullRequestStatusStringToInt ( status : string ) : number {
5475 switch ( status ) {
5576 case "Abandoned" :
@@ -349,17 +370,33 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<Acce
349370 baseIteration : z . number ( ) . optional ( ) . describe ( "The base iteration ID for which to retrieve threads. Optional, defaults to the latest base iteration." ) ,
350371 top : z . number ( ) . default ( 100 ) . describe ( "The maximum number of threads to return." ) ,
351372 skip : z . number ( ) . default ( 0 ) . describe ( "The number of threads to skip." ) ,
373+ fullResponse : z . boolean ( ) . optional ( ) . default ( false ) . describe ( "Return full thread JSON response instead of trimmed data." ) ,
352374 } ,
353- async ( { repositoryId, pullRequestId, project, iteration, baseIteration, top, skip } ) => {
375+ async ( { repositoryId, pullRequestId, project, iteration, baseIteration, top, skip, fullResponse } ) => {
354376 const connection = await connectionProvider ( ) ;
355377 const gitApi = await connection . getGitApi ( ) ;
356378
357379 const threads = await gitApi . getThreads ( repositoryId , pullRequestId , project , iteration , baseIteration ) ;
358380
359381 const paginatedThreads = threads ?. sort ( ( a , b ) => ( a . id ?? 0 ) - ( b . id ?? 0 ) ) . slice ( skip , skip + top ) ;
360382
383+ if ( fullResponse ) {
384+ return {
385+ content : [ { type : "text" , text : JSON . stringify ( paginatedThreads , null , 2 ) } ] ,
386+ } ;
387+ }
388+
389+ // Return trimmed thread data focusing on essential information
390+ const trimmedThreads = paginatedThreads ?. map ( ( thread ) => ( {
391+ id : thread . id ,
392+ publishedDate : thread . publishedDate ,
393+ lastUpdatedDate : thread . lastUpdatedDate ,
394+ status : thread . status ,
395+ comments : trimComments ( thread . comments ) ,
396+ } ) ) ;
397+
361398 return {
362- content : [ { type : "text" , text : JSON . stringify ( paginatedThreads , null , 2 ) } ] ,
399+ content : [ { type : "text" , text : JSON . stringify ( trimmedThreads , null , 2 ) } ] ,
363400 } ;
364401 }
365402 ) ;
@@ -374,8 +411,9 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<Acce
374411 project : z . string ( ) . optional ( ) . describe ( "Project ID or project name (optional)" ) ,
375412 top : z . number ( ) . default ( 100 ) . describe ( "The maximum number of comments to return." ) ,
376413 skip : z . number ( ) . default ( 0 ) . describe ( "The number of comments to skip." ) ,
414+ fullResponse : z . boolean ( ) . optional ( ) . default ( false ) . describe ( "Return full comment JSON response instead of trimmed data." ) ,
377415 } ,
378- async ( { repositoryId, pullRequestId, threadId, project, top, skip } ) => {
416+ async ( { repositoryId, pullRequestId, threadId, project, top, skip, fullResponse } ) => {
379417 const connection = await connectionProvider ( ) ;
380418 const gitApi = await connection . getGitApi ( ) ;
381419
@@ -384,8 +422,17 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<Acce
384422
385423 const paginatedComments = comments ?. sort ( ( a , b ) => ( a . id ?? 0 ) - ( b . id ?? 0 ) ) . slice ( skip , skip + top ) ;
386424
425+ if ( fullResponse ) {
426+ return {
427+ content : [ { type : "text" , text : JSON . stringify ( paginatedComments , null , 2 ) } ] ,
428+ } ;
429+ }
430+
431+ // Return trimmed comment data focusing on essential information
432+ const trimmedComments = trimComments ( paginatedComments ) ;
433+
387434 return {
388- content : [ { type : "text" , text : JSON . stringify ( paginatedComments , null , 2 ) } ] ,
435+ content : [ { type : "text" , text : JSON . stringify ( trimmedComments , null , 2 ) } ] ,
389436 } ;
390437 }
391438 ) ;
@@ -508,14 +555,29 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<Acce
508555 threadId : z . number ( ) . describe ( "The ID of the thread to which the comment will be added." ) ,
509556 content : z . string ( ) . describe ( "The content of the comment to be added." ) ,
510557 project : z . string ( ) . optional ( ) . describe ( "Project ID or project name (optional)" ) ,
558+ fullResponse : z . boolean ( ) . optional ( ) . default ( false ) . describe ( "Return full comment JSON response instead of a simple confirmation message." ) ,
511559 } ,
512- async ( { repositoryId, pullRequestId, threadId, content, project } ) => {
560+ async ( { repositoryId, pullRequestId, threadId, content, project, fullResponse } ) => {
513561 const connection = await connectionProvider ( ) ;
514562 const gitApi = await connection . getGitApi ( ) ;
515563 const comment = await gitApi . createComment ( { content } , repositoryId , pullRequestId , threadId , project ) ;
516564
565+ // Check if the comment was successfully created
566+ if ( ! comment ) {
567+ return {
568+ content : [ { type : "text" , text : `Error: Failed to add comment to thread ${ threadId } . The comment was not created successfully.` } ] ,
569+ isError : true ,
570+ } ;
571+ }
572+
573+ if ( fullResponse ) {
574+ return {
575+ content : [ { type : "text" , text : JSON . stringify ( comment , null , 2 ) } ] ,
576+ } ;
577+ }
578+
517579 return {
518- content : [ { type : "text" , text : JSON . stringify ( comment , null , 2 ) } ] ,
580+ content : [ { type : "text" , text : `Comment successfully added to thread ${ threadId } .` } ] ,
519581 } ;
520582 }
521583 ) ;
@@ -606,8 +668,9 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<Acce
606668 repositoryId : z . string ( ) . describe ( "The ID of the repository where the pull request is located." ) ,
607669 pullRequestId : z . number ( ) . describe ( "The ID of the pull request where the comment thread exists." ) ,
608670 threadId : z . number ( ) . describe ( "The ID of the thread to be resolved." ) ,
671+ fullResponse : z . boolean ( ) . optional ( ) . default ( false ) . describe ( "Return full thread JSON response instead of a simple confirmation message." ) ,
609672 } ,
610- async ( { repositoryId, pullRequestId, threadId } ) => {
673+ async ( { repositoryId, pullRequestId, threadId, fullResponse } ) => {
611674 const connection = await connectionProvider ( ) ;
612675 const gitApi = await connection . getGitApi ( ) ;
613676 const thread = await gitApi . updateThread (
@@ -617,8 +680,22 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<Acce
617680 threadId
618681 ) ;
619682
683+ // Check if the thread was successfully resolved
684+ if ( ! thread ) {
685+ return {
686+ content : [ { type : "text" , text : `Error: Failed to resolve thread ${ threadId } . The thread status was not updated successfully.` } ] ,
687+ isError : true ,
688+ } ;
689+ }
690+
691+ if ( fullResponse ) {
692+ return {
693+ content : [ { type : "text" , text : JSON . stringify ( thread , null , 2 ) } ] ,
694+ } ;
695+ }
696+
620697 return {
621- content : [ { type : "text" , text : JSON . stringify ( thread , null , 2 ) } ] ,
698+ content : [ { type : "text" , text : `Thread ${ threadId } was successfully resolved.` } ] ,
622699 } ;
623700 }
624701 ) ;
0 commit comments