Skip to content

Commit 78937bc

Browse files
committed
feat(@angular/cli): add schematics mcp tools
1 parent 0aab115 commit 78937bc

File tree

8 files changed

+1581
-1
lines changed

8 files changed

+1581
-1
lines changed

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { FIND_EXAMPLE_TOOL } from './tools/examples';
2323
import { MODERNIZE_TOOL } from './tools/modernize';
2424
import { ZONELESS_MIGRATION_TOOL } from './tools/onpush-zoneless-migration/zoneless-migration';
2525
import { LIST_PROJECTS_TOOL } from './tools/projects';
26+
import { SCHEMATICS_TOOLS } from './tools/schematics';
2627
import { type AnyMcpToolDeclaration, registerTools } from './tools/tool-registry';
2728

2829
/**
@@ -47,7 +48,12 @@ const STABLE_TOOLS = [
4748
* The set of tools that are available but not enabled by default.
4849
* These tools are considered experimental and may have limitations.
4950
*/
50-
export const EXPERIMENTAL_TOOLS = [BUILD_TOOL, MODERNIZE_TOOL, ...SERVE_TOOLS] as const;
51+
export const EXPERIMENTAL_TOOLS = [
52+
BUILD_TOOL,
53+
MODERNIZE_TOOL,
54+
...SCHEMATICS_TOOLS,
55+
...SERVE_TOOLS,
56+
] as const;
5157

5258
export async function createMcpServer(
5359
options: {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import { LIST_SCHEMATICS_TOOL } from './list-schematics';
10+
import { RUN_SCHEMATIC_TOOL } from './run-schematic';
11+
12+
export { LIST_SCHEMATICS_TOOL, RUN_SCHEMATIC_TOOL };
13+
export const SCHEMATICS_TOOLS = [LIST_SCHEMATICS_TOOL, RUN_SCHEMATIC_TOOL] as const;
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import { z } from 'zod';
10+
import { createStructuredContentOutput } from '../../utils';
11+
import { type McpToolContext, type McpToolDeclaration, declareTool } from '../tool-registry';
12+
import { loadSchematicsMetadata } from './utils';
13+
14+
const listInputSchema = z.object({
15+
workspacePath: z
16+
.string()
17+
.describe('Path to the workspace angular.json (or any file within the workspace).'),
18+
});
19+
20+
const listOutputSchema = z.object({
21+
schematics: z.array(
22+
z.object({
23+
name: z.string(),
24+
aliases: z.array(z.string()).optional(),
25+
description: z.string().optional(),
26+
hidden: z.boolean().optional(),
27+
private: z.boolean().optional(),
28+
required: z.array(z.string()).optional(),
29+
options: z
30+
.array(
31+
z.object({
32+
name: z.string(),
33+
description: z.string().optional(),
34+
type: z.union([z.string(), z.array(z.string())]).optional(),
35+
enum: z.array(z.any()).optional(),
36+
default: z.any().optional(),
37+
required: z.boolean().optional(),
38+
alias: z.string().optional(),
39+
prompt: z.string().optional(),
40+
}),
41+
)
42+
.optional(),
43+
}),
44+
),
45+
});
46+
47+
export type ListSchematicsInput = z.infer<typeof listInputSchema>;
48+
export type ListSchematicsOutput = z.infer<typeof listOutputSchema>;
49+
50+
async function handleListSchematics(input: ListSchematicsInput, context: McpToolContext) {
51+
// Always use injected loader if present (for tests)
52+
const { meta } = await loadSchematicsMetadata(
53+
input.workspacePath,
54+
context.logger,
55+
typeof context.schematicMetaLoader === 'function' ? context.schematicMetaLoader : undefined,
56+
);
57+
const serialized = meta.map((m) => ({
58+
name: m.name,
59+
aliases: m.aliases,
60+
description: m.description,
61+
hidden: m.hidden,
62+
private: m.private,
63+
required: m.required,
64+
options: m.options?.map((o) => ({
65+
name: o.name,
66+
description: o.description,
67+
type: o.type,
68+
enum: o.enum,
69+
default: o.default,
70+
required: o.required,
71+
alias: o.alias,
72+
prompt: o.prompt,
73+
})),
74+
}));
75+
76+
return createStructuredContentOutput<ListSchematicsOutput>({
77+
schematics: serialized,
78+
});
79+
}
80+
81+
export const LIST_SCHEMATICS_TOOL: McpToolDeclaration<
82+
typeof listInputSchema.shape,
83+
typeof listOutputSchema.shape
84+
> = declareTool({
85+
name: 'list_schematics',
86+
title: 'List Angular Schematics',
87+
description: `
88+
<Purpose>
89+
Enumerates all schematics provided by @schematics/angular with full option metadata (types, defaults, enums, prompts, required flags).
90+
</Purpose>
91+
<Use Cases>
92+
* Discover generators available before planning code changes.
93+
* Inspect required options for a schematic prior to execution.
94+
* Provide intelligent suggestions to users based on option types and prompts.
95+
</Use Cases>
96+
<Operational Notes>
97+
* Resolution uses Node's module loader. If a schematic collection cannot be resolved, this tool returns an empty list.
98+
* Hidden/private schematics are included for transparency.
99+
* Use 'run_schematic' to actually execute a schematic after reviewing options here.
100+
* Official docs: https://angular.dev/tools/cli/schematics and https://angular.dev/cli/generate
101+
</Operational Notes>
102+
`,
103+
inputSchema: listInputSchema.shape,
104+
outputSchema: listOutputSchema.shape,
105+
isLocalOnly: true,
106+
isReadOnly: true,
107+
factory: (context) => (input) => handleListSchematics(input, context),
108+
});

0 commit comments

Comments
 (0)