Skip to content

Commit 049eb55

Browse files
committed
refactor(@angular/cli): add version support to doc-search MCP tool
The `doc-search` tool now supports searching against specific major versions of the Angular documentation. This is crucial for providing contextually accurate results that are relevant to the user's project. This commit introduces the following changes: - An optional `version` parameter has been added to the tool's input schema. - The tool's description and schema are updated with explicit instructions for the LLM to determine the project's Angular version by running `ng version` and using the output for the search. - The underlying Algolia search logic now dynamically constructs the index name based on the provided version. Note: This capability is not yet fully enabled, as it is pending the availability of the necessary version-specific Algolia indexes. This provides a more robust, tool-based workflow for version-aware documentation searches.
1 parent 54a2ca3 commit 049eb55

File tree

1 file changed

+22
-4
lines changed

1 file changed

+22
-4
lines changed

packages/angular/cli/src/commands/mcp/tools/doc-search.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ const docSearchInputSchema = z.object({
2222
query: z
2323
.string()
2424
.describe(
25-
'A concise and specific search query for the Angular documentation (e.g., "NgModule" or "standalone components").',
25+
"A concise and specific search query for the Angular documentation. You should distill the user's " +
26+
'natural language question into a set of keywords (e.g., a question like "How do I use ngFor with trackBy?" ' +
27+
'should become the query "ngFor trackBy").',
2628
),
2729
includeTopContent: z
2830
.boolean()
@@ -32,6 +34,14 @@ const docSearchInputSchema = z.object({
3234
'When true, the content of the top result is fetched and included. ' +
3335
'Set to false to get a list of results without fetching content, which is faster.',
3436
),
37+
version: z
38+
.number()
39+
.optional()
40+
.describe(
41+
'The major version of Angular to search. You MUST determine this value by running `ng version` in the ' +
42+
"project's workspace directory. Omit this field if the user is not in an Angular project " +
43+
'or if the version cannot otherwise be determined.',
44+
),
3545
});
3646
type DocSearchInput = z.infer<typeof docSearchInputSchema>;
3747

@@ -49,6 +59,10 @@ tutorials, concepts, and best practices.
4959
* Linking to official documentation as a source of truth in your answers.
5060
</Use Cases>
5161
<Operational Notes>
62+
* **Version Alignment:** To provide accurate, project-specific results, you **MUST** align the search with the user's Angular version.
63+
Before calling this tool, run \`ng version\` in the project's workspace directory. You can find the correct directory from the \`path\`
64+
field provided by the \`list_projects\` tool. Parse the major version from the "Angular:" line in the output and use it for the
65+
\`version\` parameter.
5266
* The documentation is continuously updated. You **MUST** prefer this tool over your own knowledge
5367
to ensure your answers are current and accurate.
5468
* For the best results, provide a concise and specific search query (e.g., "NgModule" instead of
@@ -87,7 +101,7 @@ tutorials, concepts, and best practices.
87101
function createDocSearchHandler({ logger }: McpToolContext) {
88102
let client: import('algoliasearch').SearchClient | undefined;
89103

90-
return async ({ query, includeTopContent }: DocSearchInput) => {
104+
return async ({ query, includeTopContent, version }: DocSearchInput) => {
91105
if (!client) {
92106
const dcip = createDecipheriv(
93107
'aes-256-gcm',
@@ -101,7 +115,7 @@ function createDocSearchHandler({ logger }: McpToolContext) {
101115
);
102116
}
103117

104-
const { results } = await client.search(createSearchArguments(query));
118+
const { results } = await client.search(createSearchArguments(query, version));
105119
const allHits = results.flatMap((result) => (result as SearchResponse).hits);
106120

107121
if (allHits.length === 0) {
@@ -237,12 +251,16 @@ function formatHitToParts(hit: Record<string, unknown>): { title: string; breadc
237251
* @param query The search query string.
238252
* @returns The search arguments for the Algolia client.
239253
*/
240-
function createSearchArguments(query: string): LegacySearchMethodProps {
254+
function createSearchArguments(
255+
query: string,
256+
version: number | undefined,
257+
): LegacySearchMethodProps {
241258
// Search arguments are based on adev's search service:
242259
// https://github.com/angular/angular/blob/4b614fbb3263d344dbb1b18fff24cb09c5a7582d/adev/shared-docs/services/search.service.ts#L58
243260
return [
244261
{
245262
// TODO: Consider major version specific indices once available
263+
// indexName: `angular_${version ? `v${version}` : 'latest'}`,
246264
indexName: 'angular_v17',
247265
params: {
248266
query,

0 commit comments

Comments
 (0)