Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 31d4dfc

Browse files
clydinalan-agius4
authored andcommitted
refactor(@angular/cli): add experimental flag for MCP examples
This commit introduces a feature to mark and filter code examples that use experimental APIs, ensuring that the `find_examples` tool provides production-safe results by default. Key changes: - The example format now supports an optional `experimental: true` flag in the front matter. - The database schema is updated with an `experimental` column. Both the build-time and runtime database generators now parse and store this flag. - The `find_examples` tool's input schema is enhanced with an `includeExperimental` boolean flag, which defaults to `false`. - The query logic is updated to filter out experimental examples unless `includeExperimental` is explicitly set to `true`. - The schema description for the new flag includes a strong prescriptive guardrail, instructing the AI to warn the user when it shows an experimental example.
1 parent def412a commit 31d4dfc

File tree

2 files changed

+43
-9
lines changed

2 files changed

+43
-9
lines changed

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

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ const findExampleInputSchema = z.object({
5555
'A list of high-level concepts to filter by. Use this to find examples related to broader ' +
5656
'architectural ideas or patterns (e.g., `signals`, `dependency injection`, `routing`).',
5757
),
58+
includeExperimental: z
59+
.boolean()
60+
.optional()
61+
.default(false)
62+
.describe(
63+
'By default, this tool returns only production-safe examples. Set this to `true` **only if** ' +
64+
'the user explicitly asks for a bleeding-edge feature or if a stable solution to their ' +
65+
'problem cannot be found. If you set this to `true`, you **MUST** preface your answer by ' +
66+
'warning the user that the example uses experimental APIs that are not suitable for production.',
67+
),
5868
});
5969

6070
type FindExampleInput = z.infer<typeof findExampleInputSchema>;
@@ -181,7 +191,7 @@ async function createFindExampleHandler({ exampleDatabasePath }: McpToolContext)
181191
db = new DatabaseSync(exampleDatabasePath, { readOnly: true });
182192
}
183193

184-
const { query, keywords, required_packages, related_concepts } = input;
194+
const { query, keywords, required_packages, related_concepts, includeExperimental } = input;
185195

186196
// Build the query dynamically
187197
const params: SQLInputValue[] = [];
@@ -209,6 +219,10 @@ async function createFindExampleHandler({ exampleDatabasePath }: McpToolContext)
209219
addJsonFilter('required_packages', required_packages);
210220
addJsonFilter('related_concepts', related_concepts);
211221

222+
if (!includeExperimental) {
223+
whereClauses.push('experimental = 0');
224+
}
225+
212226
if (whereClauses.length > 0) {
213227
sql += ` WHERE ${whereClauses.join(' AND ')}`;
214228
}
@@ -402,6 +416,7 @@ async function setupRuntimeExamples(
402416
required_packages TEXT,
403417
related_concepts TEXT,
404418
related_tools TEXT,
419+
experimental INTEGER NOT NULL DEFAULT 0,
405420
content TEXT NOT NULL
406421
);
407422
`);
@@ -435,8 +450,8 @@ async function setupRuntimeExamples(
435450

436451
const insertStatement = db.prepare(
437452
'INSERT INTO examples(' +
438-
'title, summary, keywords, required_packages, related_concepts, related_tools, content' +
439-
') VALUES(?, ?, ?, ?, ?, ?, ?);',
453+
'title, summary, keywords, required_packages, related_concepts, related_tools, experimental, content' +
454+
') VALUES(?, ?, ?, ?, ?, ?, ?, ?);',
440455
);
441456

442457
const frontmatterSchema = z.object({
@@ -446,6 +461,7 @@ async function setupRuntimeExamples(
446461
required_packages: z.array(z.string()).optional(),
447462
related_concepts: z.array(z.string()).optional(),
448463
related_tools: z.array(z.string()).optional(),
464+
experimental: z.boolean().optional(),
449465
});
450466

451467
db.exec('BEGIN TRANSACTION');
@@ -464,8 +480,15 @@ async function setupRuntimeExamples(
464480
continue;
465481
}
466482

467-
const { title, summary, keywords, required_packages, related_concepts, related_tools } =
468-
validation.data;
483+
const {
484+
title,
485+
summary,
486+
keywords,
487+
required_packages,
488+
related_concepts,
489+
related_tools,
490+
experimental,
491+
} = validation.data;
469492

470493
insertStatement.run(
471494
title,
@@ -474,6 +497,7 @@ async function setupRuntimeExamples(
474497
JSON.stringify(required_packages ?? []),
475498
JSON.stringify(related_concepts ?? []),
476499
JSON.stringify(related_tools ?? []),
500+
experimental ? 1 : 0,
477501
content,
478502
);
479503
}

tools/example_db_generator.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ function generate(inPath, outPath) {
8484
required_packages TEXT,
8585
related_concepts TEXT,
8686
related_tools TEXT,
87+
experimental INTEGER NOT NULL DEFAULT 0,
8788
content TEXT NOT NULL
8889
);
8990
`);
@@ -120,8 +121,8 @@ function generate(inPath, outPath) {
120121

121122
const insertStatement = db.prepare(
122123
'INSERT INTO examples(' +
123-
'title, summary, keywords, required_packages, related_concepts, related_tools, content' +
124-
') VALUES(?, ?, ?, ?, ?, ?, ?);',
124+
'title, summary, keywords, required_packages, related_concepts, related_tools, experimental, content' +
125+
') VALUES(?, ?, ?, ?, ?, ?, ?, ?);',
125126
);
126127

127128
const frontmatterSchema = z.object({
@@ -131,6 +132,7 @@ function generate(inPath, outPath) {
131132
required_packages: z.array(z.string()).optional(),
132133
related_concepts: z.array(z.string()).optional(),
133134
related_tools: z.array(z.string()).optional(),
135+
experimental: z.boolean().optional(),
134136
});
135137

136138
db.exec('BEGIN TRANSACTION');
@@ -152,15 +154,23 @@ function generate(inPath, outPath) {
152154
throw new Error(`Invalid front matter in ${entry.name}`);
153155
}
154156

155-
const { title, summary, keywords, required_packages, related_concepts, related_tools } =
156-
validation.data;
157+
const {
158+
title,
159+
summary,
160+
keywords,
161+
required_packages,
162+
related_concepts,
163+
related_tools,
164+
experimental,
165+
} = validation.data;
157166
insertStatement.run(
158167
title,
159168
summary,
160169
JSON.stringify(keywords ?? []),
161170
JSON.stringify(required_packages ?? []),
162171
JSON.stringify(related_concepts ?? []),
163172
JSON.stringify(related_tools ?? []),
173+
experimental ? 1 : 0,
164174
content,
165175
);
166176
}

0 commit comments

Comments
 (0)