|
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'; |
13 | 12 | import type { AngularWorkspace } from '../../utilities/config'; |
14 | 13 | import { VERSION } from '../../utilities/version'; |
15 | 14 | import { registerBestPracticesTool } from './tools/best-practices'; |
16 | 15 | import { registerDocSearchTool } from './tools/doc-search'; |
| 16 | +import { registerListProjectsTool } from './tools/projects'; |
17 | 17 |
|
18 | 18 | export async function createMcpServer(context: { |
19 | 19 | workspace?: AngularWorkspace; |
@@ -50,88 +50,7 @@ export async function createMcpServer(context: { |
50 | 50 | ); |
51 | 51 |
|
52 | 52 | registerBestPracticesTool(server); |
53 | | - |
54 | | - server.registerTool( |
55 | | - 'list_projects', |
56 | | - { |
57 | | - title: 'List Angular Projects', |
58 | | - description: |
59 | | - 'Lists the names of all applications and libraries defined within an Angular workspace. ' + |
60 | | - 'It reads the `angular.json` configuration file to identify the projects. ', |
61 | | - annotations: { |
62 | | - readOnlyHint: true, |
63 | | - }, |
64 | | - outputSchema: { |
65 | | - projects: z.array( |
66 | | - z.object({ |
67 | | - name: z |
68 | | - .string() |
69 | | - .describe('The name of the project, as defined in the `angular.json` file.'), |
70 | | - type: z |
71 | | - .enum(['application', 'library']) |
72 | | - .optional() |
73 | | - .describe(`The type of the project, either 'application' or 'library'.`), |
74 | | - root: z |
75 | | - .string() |
76 | | - .describe('The root directory of the project, relative to the workspace root.'), |
77 | | - sourceRoot: z |
78 | | - .string() |
79 | | - .describe( |
80 | | - `The root directory of the project's source files, relative to the workspace root.`, |
81 | | - ), |
82 | | - selectorPrefix: z |
83 | | - .string() |
84 | | - .optional() |
85 | | - .describe( |
86 | | - 'The prefix to use for component selectors.' + |
87 | | - ` For example, a prefix of 'app' would result in selectors like '<app-my-component>'.`, |
88 | | - ), |
89 | | - }), |
90 | | - ), |
91 | | - }, |
92 | | - }, |
93 | | - async () => { |
94 | | - const { workspace } = context; |
95 | | - |
96 | | - if (!workspace) { |
97 | | - return { |
98 | | - content: [ |
99 | | - { |
100 | | - type: 'text' as const, |
101 | | - text: |
102 | | - 'No Angular workspace found.' + |
103 | | - ' An `angular.json` file, which marks the root of a workspace,' + |
104 | | - ' could not be located in the current directory or any of its parent directories.', |
105 | | - }, |
106 | | - ], |
107 | | - }; |
108 | | - } |
109 | | - |
110 | | - const projects = []; |
111 | | - // Convert to output format |
112 | | - for (const [name, project] of workspace.projects.entries()) { |
113 | | - projects.push({ |
114 | | - name, |
115 | | - type: project.extensions['projectType'] as 'application' | 'library' | undefined, |
116 | | - root: project.root, |
117 | | - sourceRoot: project.sourceRoot ?? path.posix.join(project.root, 'src'), |
118 | | - selectorPrefix: project.extensions['prefix'] as string, |
119 | | - }); |
120 | | - } |
121 | | - |
122 | | - // The structuredContent field is newer and may not be supported by all hosts. |
123 | | - // A text representation of the content is also provided for compatibility. |
124 | | - return { |
125 | | - content: [ |
126 | | - { |
127 | | - type: 'text' as const, |
128 | | - text: `Projects in the Angular workspace:\n${JSON.stringify(projects)}`, |
129 | | - }, |
130 | | - ], |
131 | | - structuredContent: { projects }, |
132 | | - }; |
133 | | - }, |
134 | | - ); |
| 53 | + registerListProjectsTool(server, context); |
135 | 54 |
|
136 | 55 | await registerDocSearchTool(server); |
137 | 56 |
|
|
0 commit comments