Skip to content

Commit b0c9105

Browse files
committed
feat(@angular/cli): add a modernize MCP tool.
1 parent b287b6e commit b0c9105

2 files changed

Lines changed: 100 additions & 0 deletions

File tree

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { registerDocSearchTool } from './tools/doc-search';
1616
import { registerFindExampleTool } from './tools/examples';
1717
import { registerListProjectsTool } from './tools/projects';
1818
import { registerInstructionsResource } from './resources/instructions';
19+
import { registerModernizeTool } from './tools/modernize';
1920

2021
export async function createMcpServer(
2122
context: {
@@ -37,6 +38,7 @@ export async function createMcpServer(
3738

3839
registerInstructionsResource(server);
3940
registerBestPracticesTool(server);
41+
registerModernizeTool(server);
4042

4143
// If run outside an Angular workspace (e.g., globally) skip the workspace specific tools.
4244
if (context.workspace) {
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2+
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
3+
import { Tree } from '@angular-devkit/schematics';
4+
import { z } from 'zod';
5+
import path from 'node:path';
6+
7+
export function registerModernizeTool(server: McpServer): void {
8+
server.registerTool(
9+
'modernize',
10+
{
11+
title: 'Modernize Angular Code',
12+
description:
13+
'Runs migrations on Angular code to make it more modern and idiomatic. ' +
14+
'This tool should be run when creating new Angular code, or when existing Angular code needs to be updated. ' +
15+
'It can apply transformations for things like control flow, self-closing tags, and dependency injection.',
16+
inputSchema: {
17+
files: z.array(
18+
z.object({
19+
name: z.string().describe('The name of the file.'),
20+
content: z.string().describe('The content of the file.'),
21+
}),
22+
),
23+
},
24+
outputSchema: {
25+
files: z.array(
26+
z.object({
27+
name: z.string().describe('The name of the file.'),
28+
content: z.string().describe('The updated content of the file.'),
29+
}),
30+
),
31+
},
32+
},
33+
async (input) => {
34+
try {
35+
const migrationRunner = new SchematicTestRunner(
36+
'@angular/core',
37+
path.join(
38+
__dirname,
39+
'../../../../../../node_modules/@angular/core/schematics/migrations.json',
40+
),
41+
);
42+
43+
const collectionRunner = new SchematicTestRunner(
44+
'@angular/core',
45+
path.join(
46+
__dirname,
47+
'../../../../../../node_modules/@angular/core/schematics/collection.json',
48+
),
49+
);
50+
51+
let tree: Tree = new UnitTestTree(Tree.empty());
52+
for (const file of input.files) {
53+
tree.create(file.name, file.content);
54+
}
55+
56+
for (const file of input.files) {
57+
if (file.name.endsWith('.ts')) {
58+
tree = await migrationRunner.runSchematic('test-bed-get', {}, tree);
59+
tree = await migrationRunner.runSchematic('inject-flags', {}, tree);
60+
} else if (file.name.endsWith('.html') || file.name.endsWith('.ng.html')) {
61+
tree = await migrationRunner.runSchematic('control-flow-migration', {}, tree);
62+
tree = await collectionRunner.runSchematic('self-closing-tags-migration', {}, tree);
63+
}
64+
}
65+
66+
const updatedFiles = input.files.map((file) => {
67+
const updatedContent = tree.read(file.name)?.toString() ?? file.content;
68+
return {
69+
name: file.name,
70+
content: updatedContent,
71+
};
72+
});
73+
74+
return {
75+
content: [
76+
{
77+
type: 'text' as const,
78+
text: 'Modernization migrations applied successfully.',
79+
},
80+
],
81+
structuredContent: {
82+
files: updatedFiles,
83+
},
84+
};
85+
} catch (e) {
86+
const message = e instanceof Error ? e.message : 'An unknown error occurred.';
87+
return {
88+
content: [
89+
{
90+
type: 'text' as const,
91+
text: `Failed to run modernization migrations: ${message}`,
92+
},
93+
],
94+
};
95+
}
96+
},
97+
);
98+
}

0 commit comments

Comments
 (0)