@equinor/fusion-framework-cli-plugin-ai-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/LICENSE +21 -0
  3. package/README.md +131 -0
  4. package/dist/esm/index.js +11 -0
  5. package/dist/esm/index.js.map +1 -0
  6. package/dist/esm/mcp.js +66 -0
  7. package/dist/esm/mcp.js.map +1 -0
  8. package/dist/esm/tools/fusion-search-api.js +65 -0
  9. package/dist/esm/tools/fusion-search-api.js.map +1 -0
  10. package/dist/esm/tools/fusion-search-cookbook.js +65 -0
  11. package/dist/esm/tools/fusion-search-cookbook.js.map +1 -0
  12. package/dist/esm/tools/fusion-search-eds.js +65 -0
  13. package/dist/esm/tools/fusion-search-eds.js.map +1 -0
  14. package/dist/esm/tools/fusion-search-markdown.js +65 -0
  15. package/dist/esm/tools/fusion-search-markdown.js.map +1 -0
  16. package/dist/esm/tools/fusion-search.tool.js +152 -0
  17. package/dist/esm/tools/fusion-search.tool.js.map +1 -0
  18. package/dist/esm/version.js +3 -0
  19. package/dist/esm/version.js.map +1 -0
  20. package/dist/tsconfig.tsbuildinfo +1 -0
  21. package/dist/types/index.d.ts +7 -0
  22. package/dist/types/mcp.d.ts +2 -0
  23. package/dist/types/tools/fusion-search-api.d.ts +37 -0
  24. package/dist/types/tools/fusion-search-cookbook.d.ts +37 -0
  25. package/dist/types/tools/fusion-search-eds.d.ts +37 -0
  26. package/dist/types/tools/fusion-search-markdown.d.ts +37 -0
  27. package/dist/types/tools/fusion-search.tool.d.ts +52 -0
  28. package/dist/types/version.d.ts +1 -0
  29. package/package.json +61 -0
  30. package/src/index.ts +13 -0
  31. package/src/mcp.ts +130 -0
  32. package/src/tools/fusion-search-api.ts +90 -0
  33. package/src/tools/fusion-search-cookbook.ts +90 -0
  34. package/src/tools/fusion-search-eds.ts +91 -0
  35. package/src/tools/fusion-search-markdown.ts +90 -0
  36. package/src/tools/fusion-search.tool.ts +187 -0
  37. package/src/version.ts +2 -0
  38. package/tsconfig.json +24 -0
@@ -0,0 +1,152 @@
1
+ import { z } from 'zod';
2
+ export const inputSchema = z.object({
3
+ query: z
4
+ .string()
5
+ .describe('Ask anything about Fusion Framework in plain English — the more specific, the better the results.'),
6
+ limit: z
7
+ .number()
8
+ .optional()
9
+ .default(5)
10
+ .describe('Maximum number of results to return. Recommended range: 3–8 (default: 5). Lower values help prevent context window overflow.'),
11
+ category: z
12
+ // .enum(['api', 'cookbook', 'markdown', 'eds', 'all'])
13
+ .enum(['all'])
14
+ .optional()
15
+ .default('all'),
16
+ // .describe(
17
+ // [
18
+ // 'Optional filter to narrow search scope:',
19
+ // '• api → TypeScript API reference (classes, methods, interfaces)',
20
+ // '• cookbook → Code examples, tutorials, and practical recipes',
21
+ // '• markdown → Guides, architecture docs, migration guides',
22
+ // '• eds → EDS components (Storybook stories, props, tokens, accessibility)',
23
+ // '• all → Search all sources (default)',
24
+ // ].join('\n'),
25
+ // ),
26
+ });
27
+ /**
28
+ * Tool configuration for McpServer.registerTool().
29
+ */
30
+ export const toolConfig = {
31
+ description: [
32
+ 'THE BEST AND FASTEST WAY to get accurate answers about Fusion Framework, modules, configurators, EDS components, and best practices.',
33
+ 'Understands natural questions and returns the exact code examples, API docs, cookbooks, or EDS stories you need — always with direct GitHub links.',
34
+ 'Covers everything: TypeScript APIs, practical cookbooks, architecture guides, and full EDS component documentation.',
35
+ ].join('\n'),
36
+ inputSchema,
37
+ };
38
+ /**
39
+ * Azure Cognitive Search OData filter expressions per category
40
+ */
41
+ const FILTER_EXPRESSIONS = {
42
+ api: "metadata/attributes/any(x: x/key eq 'type' and x/value eq 'tsdoc')",
43
+ cookbook: "metadata/attributes/any(x: x/key eq 'type' and x/value eq 'cookbook')",
44
+ markdown: "metadata/attributes/any(x: x/key eq 'type' and x/value eq 'markdown')",
45
+ eds: "metadata/attributes/any(x: x/key eq 'type' and x/value eq 'storybook')",
46
+ all: undefined,
47
+ };
48
+ /**
49
+ * Performs a semantic search with Maximal Marginal Relevance (MMR) in a specific category.
50
+ *
51
+ * MMR balances relevance and diversity — perfect for avoiding near-duplicate results
52
+ * when multiple docs describe the same concept.
53
+ *
54
+ * @param category - Documentation category to search within
55
+ * @param query - Natural language search query
56
+ * @param limit - Maximum number of results (final count after MMR)
57
+ * @param framework - Fusion Framework instance with AI module loaded
58
+ * @param options - AI plugin options (must include Azure Search index name)
59
+ * @returns Array of relevant documents with metadata
60
+ */
61
+ async function searchWithMMR(category, query, limit, framework, options) {
62
+ const filterExpression = FILTER_EXPRESSIONS[category];
63
+ if (!framework.ai || !options.azureSearchIndexName) {
64
+ throw new Error('Fusion AI module or Azure Search index not configured. ' +
65
+ 'Ensure `@equinor/fusion-framework-cli-plugin-ai` is installed and configured.');
66
+ }
67
+ const vectorStoreService = framework.ai.getService('search', options.azureSearchIndexName);
68
+ const retriever = vectorStoreService.asRetriever({
69
+ k: limit,
70
+ searchType: 'mmr',
71
+ searchKwargs: {
72
+ fetchK: Math.max(60, limit * 6), // Fetch more candidates for better diversity
73
+ lambda: 0.5, // Balance between relevance (1.0) and diversity (0.0)
74
+ },
75
+ filter: filterExpression ? { filterExpression } : undefined,
76
+ });
77
+ const docs = await retriever.invoke(query);
78
+ return Array.isArray(docs) ? docs : [];
79
+ }
80
+ /**
81
+ * Main handler for the `fusion_search` tool.
82
+ *
83
+ * Returns a curried function that takes tool input arguments and returns search results.
84
+ *
85
+ * @param framework - Active Fusion Framework instance
86
+ * @param options - AI plugin options, optionally with `{ verbose: true }`
87
+ * @returns A function that takes validated tool arguments and returns search results
88
+ *
89
+ * @throws {Error} If AI module or Azure Search index is not configured
90
+ */
91
+ export function handleTool(framework, options) {
92
+ return async (args) => {
93
+ // ── Preconditions ─────────────────────────────────────────────────────
94
+ if (!framework.ai || !options.azureSearchIndexName) {
95
+ return {
96
+ content: [
97
+ {
98
+ type: 'text',
99
+ text: JSON.stringify({
100
+ error: 'Fusion AI module or Azure Search index not configured',
101
+ message: 'Ensure `@equinor/fusion-framework-cli-plugin-ai` is installed and configured with Azure Search credentials.',
102
+ required: {
103
+ azureSearchIndexName: 'Azure Search index name',
104
+ azureSearchEndpoint: 'Azure Search endpoint URL',
105
+ azureSearchApiKey: 'Azure Search API key',
106
+ openaiEmbeddingDeployment: 'Azure OpenAI embedding deployment name',
107
+ },
108
+ }),
109
+ },
110
+ ],
111
+ isError: true,
112
+ };
113
+ }
114
+ const query = args.query.trim();
115
+ const limit = args.limit && args.limit > 0 ? Math.floor(args.limit) : 10;
116
+ const category = args.category && args.category in FILTER_EXPRESSIONS ? args.category : 'all';
117
+ if (!query || query === '') {
118
+ throw new Error('Parameter "query" is required and must be a non-empty string.');
119
+ }
120
+ // ── Verbose logging (useful when running in Cursor, VS Code, etc.) ───
121
+ if (options.verbose) {
122
+ console.error(`Fusion Search → "${query}" | Category: ${category} | Limit: ${limit}`);
123
+ }
124
+ // ── Execute search ───────────────────────────────────────────────────
125
+ try {
126
+ const results = await searchWithMMR(category, query, limit, framework, options);
127
+ return {
128
+ content: results.map((doc) => ({
129
+ type: 'text',
130
+ text: doc.pageContent,
131
+ _meta: doc.metadata,
132
+ })),
133
+ isError: false,
134
+ };
135
+ }
136
+ catch (error) {
137
+ return {
138
+ content: [
139
+ {
140
+ type: 'text',
141
+ text: JSON.stringify({
142
+ error: error instanceof Error ? error.message : String(error),
143
+ results: [],
144
+ }),
145
+ },
146
+ ],
147
+ isError: true,
148
+ };
149
+ }
150
+ };
151
+ }
152
+ //# sourceMappingURL=fusion-search.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fusion-search.tool.js","sourceRoot":"","sources":["../../../src/tools/fusion-search.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ // Generated by genversion.
2
+ export const version = '1.0.0';
3
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}