88
99import { ChildProcess , spawn } from 'child_process' ;
1010import { z } from 'zod' ;
11- import { McpToolContext , declareTool } from './tool-registry' ;
12-
13- let devServerProcess : ChildProcess | null = null ;
14- const serverLogs : string [ ] = [ ] ;
11+ import { Host , LocalWorkspaceHost } from '../host' ;
12+ import { McpToolDeclaration , declareTool } from './tool-registry' ;
1513
1614const serveToolInputSchema = z . object ( {
1715 command : z . enum ( [ 'start_devserver' , 'stop_devserver' ] ) . describe ( 'The subcommand to execute.' ) ,
@@ -37,77 +35,83 @@ const serveToolOutputSchema = z.object({
3735
3836export type ServeToolOutput = z . infer < typeof serveToolOutputSchema > ;
3937
40- function serveToolFactory ( context : McpToolContext ) {
41- return ( input : ServeToolInput ) => {
42- switch ( input . command ) {
43- case 'start_devserver' :
44- if ( devServerProcess ) {
45- return {
46- structuredContent : {
47- message : 'Development server is already running.' ,
48- } ,
49- } ;
50- }
51-
52- const args = [ 'serve' ] ;
53- if ( input . project ) {
54- args . push ( input . project ) ;
55- }
56- if ( input . configuration ) {
57- args . push ( `--configuration=${ input . configuration } ` ) ;
58- }
59-
60- serverLogs . length = 0 ; // Clear previous logs
61- devServerProcess = spawn ( 'ng' , args , { stdio : 'pipe' } ) ;
62-
63- devServerProcess . stdout ?. on ( 'data' , ( data ) => {
64- serverLogs . push ( data . toString ( ) ) ;
65- } ) ;
66- devServerProcess . stderr ?. on ( 'data' , ( data ) => {
67- serverLogs . push ( data . toString ( ) ) ;
68- } ) ;
69-
70- devServerProcess . on ( 'close' , ( ) => {
71- devServerProcess = null ;
72- } ) ;
73-
74- return {
75- structuredContent : {
76- message : 'Development server started.' ,
77- } ,
78- } ;
79-
80- case 'stop_devserver' :
81- if ( ! devServerProcess ) {
82- return {
83- structuredContent : {
84- message : 'Development server is not running.' ,
85- } ,
86- } ;
87- }
88-
89- devServerProcess . kill ( 'SIGTERM' ) ;
90- devServerProcess = null ;
91-
92- return {
93- structuredContent : {
94- message : 'Development server stopped.' ,
95- logs : serverLogs ,
96- } ,
97- } ;
98- }
99- } ;
38+ interface ServeContext {
39+ devServerProcess : ChildProcess | null ;
40+ serverLogs : string [ ] ;
41+ }
42+
43+ function startDevserver ( input : ServeToolInput , host : Host , context : ServeContext ) {
44+ if ( context . devServerProcess ) {
45+ return createStructureContentOutput ( {
46+ message : 'Development server is already running.' ,
47+ } ) ;
48+ }
49+
50+ const args = [ 'serve' ] ;
51+ if ( input . project ) {
52+ args . push ( input . project ) ;
53+ }
54+ if ( input . configuration ) {
55+ args . push ( `--configuration=${ input . configuration } ` ) ;
56+ }
57+
58+ context . serverLogs . length = 0 ; // Clear previous logs
59+ context . devServerProcess = host . spawn ( 'ng' , args , { stdio : 'pipe' } ) ;
60+
61+ context . devServerProcess . stdout ?. on ( 'data' , ( data ) => {
62+ context . serverLogs . push ( data . toString ( ) ) ;
63+ } ) ;
64+ context . devServerProcess . stderr ?. on ( 'data' , ( data ) => {
65+ context . serverLogs . push ( data . toString ( ) ) ;
66+ } ) ;
67+
68+ context . devServerProcess . on ( 'close' , ( ) => {
69+ context . devServerProcess = null ;
70+ } ) ;
71+
72+ return createStructureContentOutput ( {
73+ message : 'Development server started.' ,
74+ } ) ;
75+ }
76+
77+ function stopDevserver ( context : ServeContext ) {
78+ if ( ! context . devServerProcess ) {
79+ return createStructureContentOutput ( {
80+ message : 'Development server is already not running.' ,
81+ } ) ;
82+ }
83+
84+ context . devServerProcess . kill ( 'SIGTERM' ) ;
85+ context . devServerProcess = null ;
86+
87+ return createStructureContentOutput ( {
88+ message : 'Development server stopped.' ,
89+ logs : context . serverLogs ,
90+ } ) ;
91+ }
92+
93+ function runServeTool ( input : ServeToolInput , host : Host , context : ServeContext ) {
94+ switch ( input . command ) {
95+ case 'start_devserver' :
96+ return startDevserver ( input , host , context ) ;
97+ case 'stop_devserver' :
98+ return stopDevserver ( context ) ;
99+ }
100100}
101101
102- export const SERVE_TOOL = declareTool ( {
102+ export const SERVE_TOOL : McpToolDeclaration <
103+ typeof serveToolInputSchema . shape ,
104+ typeof serveToolOutputSchema . shape
105+ > = declareTool ( {
103106 name : 'serve' ,
104107 title : 'Serve Tool' ,
105108 description : `
106109<Purpose>
107110Manages the Angular development server ("ng serve"). It allows you to start and stop the server as a background process.
108111</Purpose>
109112<Use Cases>
110- * **Starting the Server:** Use the 'start_devserver' command to begin serving the application. The tool will return immediately while the server runs in the background.
113+ * **Starting the Server:** Use the 'start_devserver' command to begin serving the application. The tool will return immediately
114+ while the server runs in the background.
111115* **Stopping the Server:** Use the 'stop_devserver' command to terminate the running development server and retrieve the logs.
112116</Use Cases>
113117<Operational Notes>
@@ -120,5 +124,7 @@ Manages the Angular development server ("ng serve"). It allows you to start and
120124 isLocalOnly : true ,
121125 inputSchema : serveToolInputSchema . shape ,
122126 outputSchema : serveToolOutputSchema . shape ,
123- factory : serveToolFactory ,
127+ factory : ( ) => ( input ) => {
128+ return runServeTool ( input , LocalWorkspaceHost , { devServerProcess : null , serverLogs : [ ] } ) ;
129+ } ,
124130} ) ;
0 commit comments