11import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js" ;
22import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js" ;
3- import { z } from "zod" ;
4- import { renderStorylineUI } from "./tool/storylineRenderer.js" ;
5- import type { FeatureImpactAnalyzerInputs , ContributorRecommenderInputs , ReactComponentTestInputs , DataDrivenComponentInputs } from "./common/types.js" ;
6- import { I18n } from "./common/i18n.js" ;
73import { registerTestTools } from "./tools/test/testTools.js" ;
84import { registerVisualizationTools } from "./tools/visualization/register.js" ;
95import { registerReactTools } from "./tools/react/register.js" ;
6+ import { registerContributorRecommenderTool } from "./tools/analysis/contributorRecommenderTool.js" ;
7+ import { registerFeatureImpactTool } from "./tools/analysis/featureImpactTool.js" ;
8+ import { registerStorylineUITool } from "./tools/storyLineUI/storyLineUITool.js" ;
109
1110const server = new McpServer ( {
1211 name : "githru-mcp" ,
@@ -16,191 +15,10 @@ const server = new McpServer({
1615registerTestTools ( server ) ;
1716registerVisualizationTools ( server ) ;
1817registerReactTools ( server ) ;
18+ registerContributorRecommenderTool ( server ) ;
19+ registerFeatureImpactTool ( server ) ;
20+ registerStorylineUITool ( server ) ;
1921
20- // ✨ Feature Impact Analyzer
21- server . registerTool (
22- "feature_impact_analyzer" ,
23- {
24- title : "Feature Integration Impact Analyzer" ,
25- description : `
26- Takes a GitHub repository URL, Pull Request number, and authentication token as input.
27- Analyzes the PR’s commits and changed files to compute impact metrics — scale, dispersion,
28- chaos, isolation, lag, and coupling — and outputs a detailed HTML report highlighting
29- long-tail file path outliers.
30- ` . trim ( ) ,
31- inputSchema : {
32- repoUrl : z . string ( ) . url ( ) . describe ( "Full URL of GitHub repository to analyze (e.g. https://github.com/owner/repo)" ) ,
33- prNumber : z . number ( ) . int ( ) . positive ( ) . describe ( "Pull Request number to analyze" ) ,
34- githubToken : z . string ( ) . describe ( "GitHub authentication token" ) ,
35- locale : z . enum ( [ "en" , "ko" ] ) . default ( "en" ) . describe ( "Response language (en: English, ko: Korean)" ) ,
36- isChart : z . boolean ( ) . default ( false ) . describe ( "Return HTML chart (true) or JSON (false, default)" ) ,
37- } ,
38- } ,
39-
40- async ( { repoUrl, prNumber, githubToken, locale, isChart } : FeatureImpactAnalyzerInputs & { locale ?: string ; isChart ?: boolean } ) => {
41- try {
42- I18n . setLocale ( locale || 'en' ) ;
43-
44- const { McpReportGenerator } = await import ( "./tool/featureImpactAnalyzer.js" ) ;
45- const analyzeFeatureImpact = new McpReportGenerator ( { repoUrl, prNumber, githubToken, locale } ) ;
46-
47- const payload = await analyzeFeatureImpact . generateWithOutlierRatings ( ) ;
48-
49- if ( isChart ) {
50- const chartHtml = analyzeFeatureImpact . generateReport ( payload ) ;
51- return {
52- content : [
53- {
54- type : "text" ,
55- text : JSON . stringify ( payload , null , 2 ) + "\n created chart:" + chartHtml
56- } ,
57- ] ,
58- } ;
59- } else {
60- return {
61- content : [
62- {
63- type : "text" ,
64- text : JSON . stringify ( payload , null , 2 ) ,
65- } ,
66- ] ,
67- } ;
68- }
69- } catch ( err : any ) {
70- return {
71- content : [
72- { type : "text" , text : `Analysis error occurred: ${ err ?. message ?? String ( err ) } ` } ,
73- ] ,
74- } ;
75- }
76- }
77- ) ;
78-
79- // 🏆 Contributor Recommender
80- server . registerTool (
81- "contributor_recommender" ,
82- {
83- title : "Code Contributor Recommender" ,
84- description : "Recommends contributors who have contributed most to specific files/branches/PR areas by aggregating recent contribution data." ,
85- inputSchema : {
86- repoPath : z . string ( ) . describe ( "GitHub repository path (e.g: owner/repo or https://github.com/owner/repo)" ) ,
87- pr : z . union ( [ z . string ( ) , z . number ( ) ] ) . optional ( ) . describe ( "PR-based recommendation (PR number)" ) ,
88- paths : z . array ( z . string ( ) ) . optional ( ) . describe ( "File/directory path array (supports glob patterns)" ) ,
89- branch : z . string ( ) . optional ( ) . describe ( "Branch-based recommendation (default: main)" ) ,
90- since : z . string ( ) . optional ( ) . describe ( "Analysis period start (default 90 days, 30d/ISO date etc.)" ) ,
91- until : z . string ( ) . optional ( ) . describe ( "Analysis period end (current if unspecified)" ) ,
92- githubToken : z . string ( ) . describe ( "GitHub authentication token" ) ,
93- locale : z . enum ( [ "en" , "ko" ] ) . default ( "en" ) . describe ( "Response language (en: English, ko: Korean)" ) ,
94- chart : z . boolean ( ) . default ( false ) . describe ( "Generate interactive chart visualization (true: HTML chart display, false: JSON data)" ) ,
95- } ,
96- } ,
97-
98- async ( { repoPath, pr, paths, branch, since, until, githubToken, locale, chart } : ContributorRecommenderInputs & { locale ?: string ; chart ?: boolean } ) => {
99- try {
100- I18n . setLocale ( locale || 'en' ) ;
101-
102- const { ContributorRecommender } = await import ( './tool/contributorRecommender.js' ) ;
103- const recommender = new ContributorRecommender ( {
104- repoPath,
105- pr,
106- paths,
107- branch,
108- since,
109- until,
110- githubToken,
111- locale,
112- } ) ;
113-
114- const recommendation = await recommender . analyze ( ) ;
115-
116- if ( chart ) {
117- const chartHtml = recommender . generateChart ( recommendation ) ;
118- return {
119- content : [
120- {
121- type : "text" ,
122- text : chartHtml ,
123- } ,
124- ] ,
125- } ;
126- } else {
127- return {
128- content : [
129- {
130- type : "text" ,
131- text : JSON . stringify ( recommendation , null , 2 ) ,
132- } ,
133- ] ,
134- } ;
135- }
136- } catch ( err : any ) {
137- return {
138- content : [
139- { type : "text" , text : `Contributor recommendation error occurred: ${ err ?. message ?? String ( err ) } ` } ,
140- ] ,
141- } ;
142- }
143- }
144- ) ;
145-
146- server . registerTool (
147- "render_storyline_ui" ,
148- {
149- title : "Render Storyline UI" ,
150- description : "Generate storyline visualization using FolderActivityFlow component with CSMDict data" ,
151- inputSchema : {
152- repo : z . string ( ) . describe ( "GitHub repository in format 'owner/repo'" ) ,
153- githubToken : z . string ( ) . describe ( "GitHub personal access token" ) ,
154- baseBranchName : z . string ( ) . optional ( ) . describe ( "Base branch name (default: main)" ) ,
155- locale : z . enum ( [ "en" , "ko" ] ) . default ( "en" ) . describe ( "Response language" ) ,
156- debug : z . boolean ( ) . default ( false ) . describe ( "Enable debug logging" )
157- }
158- } ,
159-
160- async ( { repo, githubToken, baseBranchName, locale, debug } ) => {
161- try {
162- const result = await renderStorylineUI ( {
163- repo,
164- githubToken,
165- baseBranchName,
166- locale,
167- debug
168- } ) ;
169-
170- if ( result . type === 'image' ) {
171- return {
172- content : [
173- {
174- type : "text" ,
175- text : "# 📊 Storyline Visualization\n\nGenerated storyline chart showing contributor activity flow across releases:" ,
176- } ,
177- {
178- type : "image" ,
179- data : result . data ,
180- mimeType : result . mimeType ,
181- annotations : result . annotations
182- }
183- ] ,
184- } ;
185- } else {
186- return {
187- content : [
188- {
189- type : "text" ,
190- text : `# 📊 Storyline Visualization\n\n${ result . data } ` ,
191- } ,
192- ] ,
193- } ;
194- }
195- } catch ( err : any ) {
196- return {
197- content : [
198- { type : "text" , text : `Storyline UI rendering error: ${ err ?. message ?? String ( err ) } ` } ,
199- ] ,
200- } ;
201- }
202- }
203- ) ;
20422
20523async function main ( ) {
20624 const transport = new StdioServerTransport ( ) ;
0 commit comments