Skip to content

Commit 647c059

Browse files
committed
feat(@angular/cli): add --experimental-tool option to mcp command
This change introduces an `--experimental-tool` flag (with a `-E` alias) to the `ng mcp` command. This flag allows users to enable specific experimental tools by providing their names. Experimental tools are kept separate from the main toolset and are only registered if explicitly enabled via this option. This provides a mechanism for safely developing and testing new tools without exposing them to all users by default.
1 parent d4967d7 commit 647c059

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,20 @@ export default class McpCommandModule extends CommandModule implements CommandMo
4343
type: 'boolean',
4444
default: false,
4545
describe: 'Only register tools that do not require internet access.',
46+
})
47+
.option('experimental-tool', {
48+
type: 'string',
49+
alias: 'E',
50+
array: true,
51+
describe: 'Enable an experimental tool.',
4652
});
4753
}
4854

49-
async run(options: { readOnly: boolean; localOnly: boolean }): Promise<void> {
55+
async run(options: {
56+
readOnly: boolean;
57+
localOnly: boolean;
58+
experimentalTool: string[] | undefined;
59+
}): Promise<void> {
5060
if (isTTY()) {
5161
this.context.logger.info(INTERACTIVE_MESSAGE);
5262

@@ -58,6 +68,7 @@ export default class McpCommandModule extends CommandModule implements CommandMo
5868
workspace: this.context.workspace,
5969
readOnly: options.readOnly,
6070
localOnly: options.localOnly,
71+
experimentalTools: options.experimentalTool,
6172
},
6273
this.context.logger,
6374
);

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ import { BEST_PRACTICES_TOOL } from './tools/best-practices';
1515
import { DOC_SEARCH_TOOL } from './tools/doc-search';
1616
import { FIND_EXAMPLE_TOOL } from './tools/examples';
1717
import { LIST_PROJECTS_TOOL } from './tools/projects';
18-
import { registerTools } from './tools/tool-registry';
18+
import { McpToolDeclaration, registerTools } from './tools/tool-registry';
1919

2020
export async function createMcpServer(
2121
context: {
2222
workspace?: AngularWorkspace;
2323
readOnly?: boolean;
2424
localOnly?: boolean;
25+
experimentalTools?: string[];
2526
},
2627
logger: { warn(text: string): void },
2728
): Promise<McpServer> {
@@ -71,6 +72,9 @@ export async function createMcpServer(
7172
FIND_EXAMPLE_TOOL,
7273
];
7374

75+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
76+
const experimentalToolDeclarations: McpToolDeclaration<any, any>[] = [];
77+
7478
if (context.readOnly) {
7579
toolDeclarations = toolDeclarations.filter((tool) => tool.isReadOnly);
7680
}
@@ -79,6 +83,21 @@ export async function createMcpServer(
7983
toolDeclarations = toolDeclarations.filter((tool) => tool.isLocalOnly);
8084
}
8185

86+
if (context.experimentalTools?.length) {
87+
const experimentalToolsMap = new Map(
88+
experimentalToolDeclarations.map((tool) => [tool.name, tool]),
89+
);
90+
91+
for (const toolName of context.experimentalTools) {
92+
const tool = experimentalToolsMap.get(toolName);
93+
if (tool) {
94+
toolDeclarations.push(tool);
95+
} else {
96+
logger.warn(`Unknown experimental tool: ${toolName}`);
97+
}
98+
}
99+
}
100+
82101
await registerTools(
83102
server,
84103
{

0 commit comments

Comments
 (0)