9
9
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' ;
10
10
import { readFile } from 'node:fs/promises' ;
11
11
import path from 'node:path' ;
12
+ import { z } from 'zod' ;
12
13
import type { AngularWorkspace } from '../../utilities/config' ;
13
14
import { VERSION } from '../../utilities/version' ;
14
15
@@ -30,10 +31,10 @@ export async function createMcpServer(context: {
30
31
{
31
32
title : 'Angular Best Practices and Code Generation Guide' ,
32
33
description :
33
- "A comprehensive guide detailing Angular's best practices for code generation and development. " +
34
- 'This guide should be used as a reference by an LLM to ensure any generated code ' +
35
- 'adheres to modern Angular standards, including the use of standalone components, ' +
36
- 'typed forms, modern control flow syntax, and other current conventions.' ,
34
+ "A comprehensive guide detailing Angular's best practices for code generation and development." +
35
+ ' This guide should be used as a reference by an LLM to ensure any generated code' +
36
+ ' adheres to modern Angular standards, including the use of standalone components,' +
37
+ ' typed forms, modern control flow syntax, and other current conventions.' ,
37
38
mimeType : 'text/markdown' ,
38
39
} ,
39
40
async ( ) => {
@@ -56,6 +57,34 @@ export async function createMcpServer(context: {
56
57
annotations : {
57
58
readOnlyHint : true ,
58
59
} ,
60
+ outputSchema : {
61
+ projects : z . array (
62
+ z . object ( {
63
+ name : z
64
+ . string ( )
65
+ . describe ( 'The name of the project, as defined in the `angular.json` file.' ) ,
66
+ type : z
67
+ . enum ( [ 'application' , 'library' ] )
68
+ . optional ( )
69
+ . describe ( `The type of the project, either 'application' or 'library'.` ) ,
70
+ root : z
71
+ . string ( )
72
+ . describe ( 'The root directory of the project, relative to the workspace root.' ) ,
73
+ sourceRoot : z
74
+ . string ( )
75
+ . describe (
76
+ `The root directory of the project's source files, relative to the workspace root.` ,
77
+ ) ,
78
+ selectorPrefix : z
79
+ . string ( )
80
+ . optional ( )
81
+ . describe (
82
+ 'The prefix to use for component selectors.' +
83
+ ` For example, a prefix of 'app' would result in selectors like '<app-my-component>'.` ,
84
+ ) ,
85
+ } ) ,
86
+ ) ,
87
+ } ,
59
88
} ,
60
89
async ( ) => {
61
90
const { workspace } = context ;
@@ -74,13 +103,28 @@ export async function createMcpServer(context: {
74
103
} ;
75
104
}
76
105
106
+ const projects = [ ] ;
107
+ // Convert to output format
108
+ for ( const [ name , project ] of workspace . projects . entries ( ) ) {
109
+ projects . push ( {
110
+ name,
111
+ type : project . extensions [ 'projectType' ] as 'application' | 'library' | undefined ,
112
+ root : project . root ,
113
+ sourceRoot : project . sourceRoot ?? path . posix . join ( project . root , 'src' ) ,
114
+ selectorPrefix : project . extensions [ 'prefix' ] as string ,
115
+ } ) ;
116
+ }
117
+
118
+ // The structuredContent field is newer and may not be supported by all hosts.
119
+ // A text representation of the content is also provided for compatibility.
77
120
return {
78
121
content : [
79
122
{
80
123
type : 'text' as const ,
81
- text : ' Projects in the Angular workspace: ' + [ ... workspace . projects . keys ( ) ] . join ( ',' ) ,
124
+ text : ` Projects in the Angular workspace:\n ${ JSON . stringify ( projects ) } ` ,
82
125
} ,
83
126
] ,
127
+ structuredContent : { projects } ,
84
128
} ;
85
129
} ,
86
130
) ;
0 commit comments