Skip to content

Commit 9d5c807

Browse files
committed
refactor(@angular/cli): provide additional project details for MCP list projects tool
The Angular CLI's MCP server will now provide additional information regarding each project when the list projects tool is used. This includes: * name * type (application/library) * root (project root path relative to the Angular workspace root) * sourceRoot (source code root path relative to the Angular workspace root) * selectorPrefix (default selector prefix used for component generation)
1 parent e23730a commit 9d5c807

File tree

4 files changed

+65
-16
lines changed

4 files changed

+65
-16
lines changed

packages/angular/cli/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ ts_project(
5858
":node_modules/pacote",
5959
":node_modules/resolve",
6060
":node_modules/yargs",
61+
":node_modules/zod",
6162
"//:node_modules/@angular/core",
6263
"//:node_modules/@types/ini",
6364
"//:node_modules/@types/node",

packages/angular/cli/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
"pacote": "21.0.0",
3939
"resolve": "1.22.10",
4040
"semver": "7.7.2",
41-
"yargs": "18.0.0"
41+
"yargs": "18.0.0",
42+
"zod": "3.25.75"
4243
},
4344
"ng-update": {
4445
"migrations": "@schematics/angular/migrations/migration-collection.json",

packages/angular/cli/src/commands/mcp/mcp-server.ts

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1010
import { readFile } from 'node:fs/promises';
1111
import path from 'node:path';
12+
import { z } from 'zod';
1213
import type { AngularWorkspace } from '../../utilities/config';
1314
import { VERSION } from '../../utilities/version';
1415

@@ -30,10 +31,10 @@ export async function createMcpServer(context: {
3031
{
3132
title: 'Angular Best Practices and Code Generation Guide',
3233
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.',
3738
mimeType: 'text/markdown',
3839
},
3940
async () => {
@@ -56,6 +57,34 @@ export async function createMcpServer(context: {
5657
annotations: {
5758
readOnlyHint: true,
5859
},
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+
},
5988
},
6089
async () => {
6190
const { workspace } = context;
@@ -74,13 +103,28 @@ export async function createMcpServer(context: {
74103
};
75104
}
76105

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.
77120
return {
78121
content: [
79122
{
80123
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)}`,
82125
},
83126
],
127+
structuredContent: { projects },
84128
};
85129
},
86130
);

pnpm-lock.yaml

Lines changed: 13 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)