docusaurus-plugin-mcp-server 0.9.0 → 0.10.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.
- package/README.md +2 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/theme/index.d.mts +4 -2
- package/dist/theme/index.d.ts +4 -2
- package/dist/theme/index.js +23 -23
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +23 -23
- package/dist/theme/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -178,7 +178,8 @@ The button shows a dropdown with copy-to-clipboard configurations for all suppor
|
|
|
178
178
|
|------|------|---------|-------------|
|
|
179
179
|
| `serverUrl` | `string` | required | Your MCP server endpoint URL |
|
|
180
180
|
| `serverName` | `string` | required | Name for the MCP server |
|
|
181
|
-
| `label` | `string` |
|
|
181
|
+
| `label` | `string` | (none) | Button label. If omitted, shows only the MCP icon |
|
|
182
|
+
| `headerText` | `string` | `"Choose your AI tool:"` | Text shown at the top of the dropdown |
|
|
182
183
|
| `className` | `string` | `""` | Optional CSS class |
|
|
183
184
|
| `clients` | `ClientId[]` | All HTTP-capable | Which clients to show |
|
|
184
185
|
|
package/dist/index.d.mts
CHANGED
|
@@ -476,4 +476,4 @@ declare function discoverHtmlFiles(outDir: string): Promise<FlattenedRoute[]>;
|
|
|
476
476
|
*/
|
|
477
477
|
declare function collectRoutes(outDir: string, excludePatterns: string[]): Promise<FlattenedRoute[]>;
|
|
478
478
|
|
|
479
|
-
export { type ContentIndexer, type ContentIndexerModule, DocHeading, ExtractedContent, FlattenedRoute, type FlexSearchDocument, FlexSearchIndexer, FlexSearchProvider, McpDocsServer, McpServerConfig, McpServerPluginOptions, ProcessedDoc, type ProviderContext, type SearchOptions, type SearchProvider, type SearchProviderInitData, type SearchProviderModule, SearchResult, buildSearchIndex, collectRoutes, discoverHtmlFiles, docsFetchTool, docsSearchTool, exportSearchIndex, extractContent, extractHeadingsFromMarkdown, extractSection, htmlToMarkdown, importSearchIndex, loadIndexer, loadSearchProvider, mcpServerPlugin, parseHtml, parseHtmlFile, searchIndex };
|
|
479
|
+
export { type ContentIndexer, type ContentIndexerModule, DocHeading, ExtractedContent, FlattenedRoute, type FlexSearchDocument, FlexSearchIndexer, FlexSearchProvider, McpDocsServer, McpServerConfig, McpServerPluginOptions, ProcessedDoc, type ProviderContext, type SearchOptions, type SearchProvider, type SearchProviderInitData, type SearchProviderModule, SearchResult, buildSearchIndex, collectRoutes, mcpServerPlugin as default, discoverHtmlFiles, docsFetchTool, docsSearchTool, exportSearchIndex, extractContent, extractHeadingsFromMarkdown, extractSection, htmlToMarkdown, importSearchIndex, loadIndexer, loadSearchProvider, mcpServerPlugin, parseHtml, parseHtmlFile, searchIndex };
|
package/dist/index.d.ts
CHANGED
|
@@ -476,4 +476,4 @@ declare function discoverHtmlFiles(outDir: string): Promise<FlattenedRoute[]>;
|
|
|
476
476
|
*/
|
|
477
477
|
declare function collectRoutes(outDir: string, excludePatterns: string[]): Promise<FlattenedRoute[]>;
|
|
478
478
|
|
|
479
|
-
export { type ContentIndexer, type ContentIndexerModule, DocHeading, ExtractedContent, FlattenedRoute, type FlexSearchDocument, FlexSearchIndexer, FlexSearchProvider, McpDocsServer, McpServerConfig, McpServerPluginOptions, ProcessedDoc, type ProviderContext, type SearchOptions, type SearchProvider, type SearchProviderInitData, type SearchProviderModule, SearchResult, buildSearchIndex, collectRoutes, discoverHtmlFiles, docsFetchTool, docsSearchTool, exportSearchIndex, extractContent, extractHeadingsFromMarkdown, extractSection, htmlToMarkdown, importSearchIndex, loadIndexer, loadSearchProvider, mcpServerPlugin, parseHtml, parseHtmlFile, searchIndex };
|
|
479
|
+
export { type ContentIndexer, type ContentIndexerModule, DocHeading, ExtractedContent, FlattenedRoute, type FlexSearchDocument, FlexSearchIndexer, FlexSearchProvider, McpDocsServer, McpServerConfig, McpServerPluginOptions, ProcessedDoc, type ProviderContext, type SearchOptions, type SearchProvider, type SearchProviderInitData, type SearchProviderModule, SearchResult, buildSearchIndex, collectRoutes, mcpServerPlugin as default, discoverHtmlFiles, docsFetchTool, docsSearchTool, exportSearchIndex, extractContent, extractHeadingsFromMarkdown, extractSection, htmlToMarkdown, importSearchIndex, loadIndexer, loadSearchProvider, mcpServerPlugin, parseHtml, parseHtmlFile, searchIndex };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
3
5
|
var path = require('path');
|
|
4
6
|
var fs3 = require('fs-extra');
|
|
5
7
|
var pMap = require('p-map');
|
|
@@ -1070,6 +1072,7 @@ exports.FlexSearchProvider = FlexSearchProvider;
|
|
|
1070
1072
|
exports.McpDocsServer = McpDocsServer;
|
|
1071
1073
|
exports.buildSearchIndex = buildSearchIndex;
|
|
1072
1074
|
exports.collectRoutes = collectRoutes;
|
|
1075
|
+
exports.default = mcpServerPlugin;
|
|
1073
1076
|
exports.discoverHtmlFiles = discoverHtmlFiles;
|
|
1074
1077
|
exports.docsFetchTool = docsFetchTool;
|
|
1075
1078
|
exports.docsSearchTool = docsSearchTool;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types/index.ts","../src/plugin/route-collector.ts","../src/processing/html-parser.ts","../src/processing/html-to-markdown.ts","../src/processing/heading-extractor.ts","../src/search/flexsearch-core.ts","../src/providers/indexers/flexsearch-indexer.ts","../src/providers/search/flexsearch-provider.ts","../src/providers/loader.ts","../src/plugin/docusaurus-plugin.ts","../src/mcp/tools/docs-search.ts","../src/mcp/tools/docs-fetch.ts","../src/mcp/server.ts"],"names":["fs","path","unified","rehypeParse","select","toString","toHtml","rehypeRemark","remarkGfm","remarkStringify","FlexSearch","results","searchIndex","pMap","z","McpServer","StreamableHTTPServerTransport","WebStandardStreamableHTTPServerTransport"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Configuration options for the MCP server plugin\n */\nexport interface McpServerPluginOptions {\n /** Output directory for MCP artifacts (relative to build dir). Default: 'mcp' */\n outputDir?: string;\n /** CSS selectors for content extraction, in order of priority */\n contentSelectors?: string[];\n /** CSS selectors for elements to remove from content before processing */\n excludeSelectors?: string[];\n /** Minimum content length (in characters) to consider a page valid. Default: 50 */\n minContentLength?: number;\n /** Server configuration */\n server?: {\n /** Name of the MCP server */\n name?: string;\n /** Version of the MCP server */\n version?: string;\n };\n /** Routes to exclude from processing (glob patterns) */\n excludeRoutes?: string[];\n\n /**\n * Indexers to run during build.\n *\n * - undefined (default): runs 'flexsearch' for backward compatibility\n * - ['flexsearch']: same as default, produces docs.json + search-index.json\n * - ['./my-indexer.js']: runs only custom indexer(s)\n * - false: disables all indexing, no artifacts produced\n *\n * Each string can be:\n * - 'flexsearch' (built-in)\n * - './path/to/indexer.js' (relative path)\n * - '@myorg/custom-indexer' (npm package)\n */\n indexers?: string[] | false;\n\n /**\n * Search provider module. Default: 'flexsearch'\n *\n * Can be:\n * - 'flexsearch' (built-in, requires FlexSearch indexer to have run)\n * - './path/to/search.js' (relative path)\n * - '@myorg/glean-search' (npm package)\n */\n search?: string;\n}\n\n/**\n * Resolved plugin options with defaults applied\n */\nexport interface ResolvedPluginOptions {\n outputDir: string;\n contentSelectors: string[];\n excludeSelectors: string[];\n minContentLength: number;\n server: {\n name: string;\n version: string;\n };\n excludeRoutes: string[];\n /** Indexers to run. undefined means ['flexsearch'], false disables indexing */\n indexers: string[] | false | undefined;\n /** Search provider module */\n search: string;\n}\n\n/**\n * A processed documentation page\n */\nexport interface ProcessedDoc {\n /** URL route path (e.g., /docs/getting-started) */\n route: string;\n /** Page title extracted from HTML */\n title: string;\n /** Meta description if available */\n description: string;\n /** Full page content as markdown */\n markdown: string;\n /** Headings with IDs for section navigation */\n headings: DocHeading[];\n}\n\n/**\n * A heading within a document\n */\nexport interface DocHeading {\n /** Heading level (1-6) */\n level: number;\n /** Heading text content */\n text: string;\n /** Anchor ID for linking */\n id: string;\n /** Character offset where this section starts in the markdown */\n startOffset: number;\n /** Character offset where this section ends in the markdown */\n endOffset: number;\n}\n\n/**\n * A flattened route from Docusaurus\n */\nexport interface FlattenedRoute {\n /** The URL path */\n path: string;\n /** Path to the corresponding HTML file */\n htmlPath: string;\n}\n\n/**\n * Search result from FlexSearch\n */\nexport interface SearchResult {\n /** Full URL of the matching document (use this with docs_fetch) */\n url: string;\n /** Route path of the matching document */\n route: string;\n /** Title of the document */\n title: string;\n /** Relevance score */\n score: number;\n /** Snippet of matching content */\n snippet: string;\n /** Matching headings if any */\n matchingHeadings?: string[];\n}\n\n/**\n * Manifest metadata for the MCP artifacts\n */\nexport interface McpManifest {\n /** Plugin version */\n version: string;\n /** Build timestamp */\n buildTime: string;\n /** Number of documents indexed */\n docCount: number;\n /** Server name */\n serverName: string;\n /** Base URL of the documentation site */\n baseUrl?: string;\n /** Names of indexers that ran during build */\n indexers?: string[];\n}\n\n/**\n * MCP Server configuration for file-based loading\n */\nexport interface McpServerFileConfig {\n /** Path to docs.json file */\n docsPath: string;\n /** Path to search-index.json file */\n indexPath: string;\n /** Server name */\n name: string;\n /** Server version */\n version?: string;\n /** Base URL for constructing full page URLs (e.g., https://docs.example.com) */\n baseUrl?: string;\n /** Search provider module. Default: 'flexsearch' */\n search?: string;\n}\n\n/**\n * MCP Server configuration for pre-loaded data (e.g., Cloudflare Workers)\n */\nexport interface McpServerDataConfig {\n /** Pre-loaded docs data */\n docs: Record<string, ProcessedDoc>;\n /** Pre-loaded search index data (exported from FlexSearch via exportSearchIndex) */\n searchIndexData: Record<string, unknown>;\n /** Server name */\n name: string;\n /** Server version */\n version?: string;\n /** Base URL for constructing full page URLs (e.g., https://docs.example.com) */\n baseUrl?: string;\n /** Search provider module. Default: 'flexsearch' */\n search?: string;\n}\n\n/**\n * MCP Server configuration - supports both file-based and pre-loaded data modes\n */\nexport type McpServerConfig = McpServerFileConfig | McpServerDataConfig;\n\n/**\n * Internal representation of the docs index\n */\nexport interface DocsIndex {\n /** All processed documents keyed by route */\n docs: Record<string, ProcessedDoc>;\n /** Manifest metadata */\n manifest: McpManifest;\n}\n\n/**\n * Input parameters for docs_search tool\n */\nexport interface DocsSearchParams {\n /** Search query string */\n query: string;\n /** Maximum number of results (default: 5, max: 20) */\n limit?: number;\n}\n\n/**\n * Input parameters for docs_fetch tool\n */\nexport interface DocsFetchParams {\n /** Full URL of the page to fetch */\n url: string;\n}\n\n/**\n * Content extraction result from HTML\n */\nexport interface ExtractedContent {\n /** Page title */\n title: string;\n /** Meta description */\n description: string;\n /** Main content as HTML */\n contentHtml: string;\n}\n\n/**\n * Default plugin options\n */\nexport const DEFAULT_OPTIONS: ResolvedPluginOptions = {\n outputDir: 'mcp',\n contentSelectors: ['article', 'main', '.main-wrapper', '[role=\"main\"]'],\n excludeSelectors: [\n 'nav',\n 'header',\n 'footer',\n 'aside',\n '[role=\"navigation\"]',\n '[role=\"banner\"]',\n '[role=\"contentinfo\"]',\n ],\n minContentLength: 50,\n server: {\n name: 'docs-mcp-server',\n version: '1.0.0',\n },\n excludeRoutes: ['/404*', '/search*'],\n indexers: undefined, // Default: ['flexsearch'] applied at runtime\n search: 'flexsearch',\n};\n","import path from 'path';\nimport fs from 'fs-extra';\nimport type { RouteConfig } from '@docusaurus/types';\nimport type { FlattenedRoute } from '../types/index.js';\n\n/**\n * Flatten nested Docusaurus routes into a simple array\n */\nexport function flattenRoutes(routes: RouteConfig[]): FlattenedRoute[] {\n const flattened: FlattenedRoute[] = [];\n\n function traverse(route: RouteConfig): void {\n // Add the route if it has a path\n if (route.path) {\n flattened.push({\n path: route.path,\n htmlPath: '', // Will be resolved later\n });\n }\n\n // Recursively process child routes\n if (route.routes && Array.isArray(route.routes)) {\n for (const childRoute of route.routes) {\n traverse(childRoute);\n }\n }\n }\n\n for (const route of routes) {\n traverse(route);\n }\n\n return flattened;\n}\n\n/**\n * Convert a URL path to the corresponding HTML file path in the build directory\n *\n * Examples:\n * - /guides/chat/overview -> build/guides/chat/overview/index.html\n * - / -> build/index.html\n * - /api -> build/api/index.html\n */\nexport function routeToHtmlPath(routePath: string, outDir: string): string {\n // Normalize the route path\n let normalizedPath = routePath;\n\n // Remove trailing slash if present (except for root)\n if (normalizedPath.length > 1 && normalizedPath.endsWith('/')) {\n normalizedPath = normalizedPath.slice(0, -1);\n }\n\n // Handle root path\n if (normalizedPath === '/') {\n return path.join(outDir, 'index.html');\n }\n\n // For all other paths, append /index.html\n return path.join(outDir, normalizedPath, 'index.html');\n}\n\n/**\n * Filter out routes that should not be processed\n */\nexport function filterRoutes(\n routes: FlattenedRoute[],\n excludePatterns: string[]\n): FlattenedRoute[] {\n return routes.filter((route) => {\n return !excludePatterns.some((pattern) => {\n // Convert glob pattern to regex\n const regexPattern = pattern.replace(/\\*/g, '.*').replace(/\\?/g, '.');\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(route.path);\n });\n });\n}\n\n/**\n * Discover all HTML files in the build directory and create routes for them.\n * This is more reliable than using Docusaurus routes as it captures all built pages.\n */\nexport async function discoverHtmlFiles(outDir: string): Promise<FlattenedRoute[]> {\n const routes: FlattenedRoute[] = [];\n\n async function scanDirectory(dir: string): Promise<void> {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip common non-content directories\n if (['assets', 'img', 'static'].includes(entry.name)) {\n continue;\n }\n await scanDirectory(fullPath);\n } else if (entry.name === 'index.html') {\n // Convert file path back to route\n const relativePath = path.relative(outDir, fullPath);\n let routePath = '/' + path.dirname(relativePath).replace(/\\\\/g, '/');\n\n // Handle root index.html\n if (routePath === '/.') {\n routePath = '/';\n }\n\n routes.push({\n path: routePath,\n htmlPath: fullPath,\n });\n }\n }\n }\n\n await scanDirectory(outDir);\n return routes;\n}\n\n/**\n * Resolve HTML paths for flattened routes, filtering out those that don't exist\n */\nexport async function resolveHtmlPaths(\n routes: FlattenedRoute[],\n outDir: string\n): Promise<FlattenedRoute[]> {\n const resolved: FlattenedRoute[] = [];\n\n for (const route of routes) {\n const htmlPath = routeToHtmlPath(route.path, outDir);\n\n if (await fs.pathExists(htmlPath)) {\n resolved.push({\n ...route,\n htmlPath,\n });\n }\n }\n\n return resolved;\n}\n\n/**\n * Get all processable routes from the build directory\n */\nexport async function collectRoutes(\n outDir: string,\n excludePatterns: string[]\n): Promise<FlattenedRoute[]> {\n // Discover all HTML files in the build directory\n const allRoutes = await discoverHtmlFiles(outDir);\n\n // Filter out excluded routes\n const filteredRoutes = filterRoutes(allRoutes, excludePatterns);\n\n // Deduplicate routes by path\n const uniqueRoutes = new Map<string, FlattenedRoute>();\n for (const route of filteredRoutes) {\n if (!uniqueRoutes.has(route.path)) {\n uniqueRoutes.set(route.path, route);\n }\n }\n\n return Array.from(uniqueRoutes.values());\n}\n","import fs from 'fs-extra';\nimport { unified } from 'unified';\nimport rehypeParse from 'rehype-parse';\nimport { select } from 'hast-util-select';\nimport { toString } from 'hast-util-to-string';\nimport { toHtml } from 'hast-util-to-html';\nimport type { Root, Element } from 'hast';\nimport type { ExtractedContent } from '../types/index.js';\n\n/**\n * Parse HTML string into HAST (HTML AST)\n */\nexport function parseHtml(html: string): Root {\n const processor = unified().use(rehypeParse);\n return processor.parse(html);\n}\n\n/**\n * Parse HTML file into HAST\n */\nexport async function parseHtmlFile(filePath: string): Promise<Root> {\n const html = await fs.readFile(filePath, 'utf-8');\n return parseHtml(html);\n}\n\n/**\n * Extract page title from the HTML document\n *\n * Uses h1 as primary source (most reliable for page title),\n * falls back to <title> tag if no h1 is found.\n */\nexport function extractTitle(tree: Root): string {\n // Prefer h1 as it's the actual page heading\n const h1Element = select('h1', tree);\n if (h1Element) {\n return toString(h1Element).trim();\n }\n\n // Fall back to title tag\n const titleElement = select('title', tree);\n if (titleElement) {\n return toString(titleElement).trim();\n }\n\n return 'Untitled';\n}\n\n/**\n * Extract meta description from the HTML document\n */\nexport function extractDescription(tree: Root): string {\n const metaDescription = select('meta[name=\"description\"]', tree) as Element | null;\n if (metaDescription && metaDescription.properties?.content) {\n return String(metaDescription.properties.content);\n }\n\n // Try og:description as fallback\n const ogDescription = select('meta[property=\"og:description\"]', tree) as Element | null;\n if (ogDescription && ogDescription.properties?.content) {\n return String(ogDescription.properties.content);\n }\n\n return '';\n}\n\n/**\n * Find the main content element using CSS selectors in priority order\n */\nexport function findContentElement(tree: Root, selectors: string[]): Element | null {\n for (const selector of selectors) {\n const element = select(selector, tree) as Element | null;\n if (element) {\n // Verify the element has meaningful content\n const text = toString(element).trim();\n if (text.length > 50) {\n return element;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Always-excluded elements that should never appear in content\n */\nconst ALWAYS_EXCLUDED = ['script', 'style', 'noscript'];\n\n/**\n * Remove unwanted elements from content\n *\n * @param element - The HAST element to clean\n * @param excludeSelectors - CSS selectors for elements to remove (tag names or .class-names)\n */\nexport function cleanContentElement(element: Element, excludeSelectors: string[]): Element {\n const allSelectors = [...ALWAYS_EXCLUDED, ...excludeSelectors];\n\n // Deep clone the element to avoid mutating the original\n const cloned = JSON.parse(JSON.stringify(element)) as Element;\n\n function removeUnwanted(node: Element): void {\n if (!node.children) return;\n\n node.children = node.children.filter((child) => {\n if (child.type !== 'element') return true;\n\n const childElement = child as Element;\n\n // Check if this element matches any unwanted selectors\n for (const selector of allSelectors) {\n if (selector.startsWith('.')) {\n // Class selector\n const className = selector.slice(1);\n const classes = childElement.properties?.className;\n if (Array.isArray(classes) && classes.includes(className)) {\n return false;\n }\n if (typeof classes === 'string' && classes.includes(className)) {\n return false;\n }\n } else if (selector.startsWith('[')) {\n // Attribute selector like [role=\"navigation\"]\n const match = selector.match(/\\[([^=]+)=\"([^\"]+)\"\\]/);\n if (match) {\n const [, attr, value] = match;\n if (attr && childElement.properties?.[attr] === value) {\n return false;\n }\n }\n } else {\n // Tag selector\n if (childElement.tagName === selector) {\n return false;\n }\n }\n }\n\n // Recursively clean children\n removeUnwanted(childElement);\n return true;\n });\n }\n\n removeUnwanted(cloned);\n return cloned;\n}\n\n/**\n * Options for content extraction\n */\nexport interface ExtractContentOptions {\n /** CSS selectors for content containers, in priority order */\n contentSelectors: string[];\n /** CSS selectors for elements to exclude from content */\n excludeSelectors: string[];\n}\n\n/**\n * Extract content from HTML file\n */\nexport async function extractContent(\n filePath: string,\n options: ExtractContentOptions\n): Promise<ExtractedContent> {\n const tree = await parseHtmlFile(filePath);\n\n const title = extractTitle(tree);\n const description = extractDescription(tree);\n\n // Find main content element\n let contentElement = findContentElement(tree, options.contentSelectors);\n\n if (!contentElement) {\n // Last resort: try to find any element with substantial text\n const body = select('body', tree) as Element | null;\n if (body) {\n contentElement = body;\n }\n }\n\n let contentHtml = '';\n if (contentElement) {\n const cleanedElement = cleanContentElement(contentElement, options.excludeSelectors);\n // Serialize back to HTML string using hast-util-to-html\n contentHtml = toHtml(cleanedElement);\n }\n\n return {\n title,\n description,\n contentHtml,\n };\n}\n","import { unified } from 'unified';\nimport rehypeParse from 'rehype-parse';\nimport rehypeRemark from 'rehype-remark';\nimport remarkStringify from 'remark-stringify';\nimport remarkGfm from 'remark-gfm';\n\n/**\n * Convert HTML string to Markdown\n */\nexport async function htmlToMarkdown(html: string): Promise<string> {\n if (!html || html.trim().length === 0) {\n return '';\n }\n\n try {\n const processor = unified()\n .use(rehypeParse, { fragment: true })\n .use(rehypeRemark)\n .use(remarkGfm)\n .use(remarkStringify, {\n bullet: '-',\n fences: true,\n });\n\n const result = await processor.process(html);\n let markdown = String(result);\n\n // Post-process: clean up excessive whitespace\n markdown = cleanMarkdown(markdown);\n\n return markdown;\n } catch (error) {\n console.error('Error converting HTML to Markdown:', error);\n // Return a basic text extraction as fallback\n return extractTextFallback(html);\n }\n}\n\n/**\n * Clean up markdown output\n */\nfunction cleanMarkdown(markdown: string): string {\n return (\n markdown\n // Remove excessive blank lines (more than 2 in a row)\n .replace(/\\n{3,}/g, '\\n\\n')\n // Remove trailing whitespace from lines\n .split('\\n')\n .map((line) => line.trimEnd())\n .join('\\n')\n // Ensure single newline at end\n .trim() + '\\n'\n );\n}\n\n/**\n * Fallback text extraction when markdown conversion fails\n */\nfunction extractTextFallback(html: string): string {\n // Remove script and style tags\n let text = html.replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '');\n text = text.replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, '');\n\n // Convert common HTML elements to text\n text = text.replace(/<br\\s*\\/?>/gi, '\\n');\n text = text.replace(/<\\/p>/gi, '\\n\\n');\n text = text.replace(/<\\/h[1-6]>/gi, '\\n\\n');\n text = text.replace(/<\\/li>/gi, '\\n');\n text = text.replace(/<\\/div>/gi, '\\n');\n\n // Remove remaining HTML tags\n text = text.replace(/<[^>]+>/g, '');\n\n // Decode common HTML entities\n text = text.replace(/ /g, ' ');\n text = text.replace(/&/g, '&');\n text = text.replace(/</g, '<');\n text = text.replace(/>/g, '>');\n text = text.replace(/"/g, '\"');\n text = text.replace(/'/g, \"'\");\n\n // Clean up whitespace\n text = text.replace(/[ \\t]+/g, ' ');\n text = text.replace(/\\n{3,}/g, '\\n\\n');\n\n return text.trim();\n}\n","import type { DocHeading } from '../types/index.js';\n\n/**\n * Extract headings from markdown content with their positions\n */\nexport function extractHeadingsFromMarkdown(markdown: string): DocHeading[] {\n const headings: DocHeading[] = [];\n const lines = markdown.split('\\n');\n let currentOffset = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? '';\n const headingMatch = line.match(/^(#{1,6})\\s+(.+?)(?:\\s+\\{#([^}]+)\\})?$/);\n\n if (headingMatch) {\n const hashes = headingMatch[1] ?? '';\n const level = hashes.length;\n let text = headingMatch[2] ?? '';\n let id = headingMatch[3] ?? '';\n\n // If no explicit ID, generate one from text (Docusaurus style)\n if (!id) {\n id = generateHeadingId(text);\n }\n\n // Clean up text (remove any remaining markdown formatting)\n text = text.replace(/\\*\\*([^*]+)\\*\\*/g, '$1'); // Remove bold\n text = text.replace(/_([^_]+)_/g, '$1'); // Remove italic\n text = text.replace(/`([^`]+)`/g, '$1'); // Remove code\n\n headings.push({\n level,\n text: text.trim(),\n id,\n startOffset: currentOffset,\n endOffset: -1, // Will be calculated below\n });\n }\n\n currentOffset += line.length + 1; // +1 for newline\n }\n\n // Calculate end offsets (each heading ends where the next same-or-higher level heading starts)\n for (let i = 0; i < headings.length; i++) {\n const current = headings[i];\n if (!current) continue;\n\n let endOffset = markdown.length;\n\n // Find the next heading at the same or higher level\n for (let j = i + 1; j < headings.length; j++) {\n const next = headings[j];\n if (next && next.level <= current.level) {\n endOffset = next.startOffset;\n break;\n }\n }\n\n current.endOffset = endOffset;\n }\n\n return headings;\n}\n\n/**\n * Generate a URL-safe heading ID (Docusaurus style)\n */\nexport function generateHeadingId(text: string): string {\n return (\n text\n .toLowerCase()\n // Remove any non-alphanumeric characters except spaces and hyphens\n .replace(/[^\\w\\s-]/g, '')\n // Replace spaces with hyphens\n .replace(/\\s+/g, '-')\n // Remove consecutive hyphens\n .replace(/-+/g, '-')\n // Remove leading/trailing hyphens\n .replace(/^-|-$/g, '')\n );\n}\n\n/**\n * Extract a specific section from markdown by heading ID\n */\nexport function extractSection(\n markdown: string,\n headingId: string,\n headings: DocHeading[]\n): string | null {\n const heading = headings.find((h) => h.id === headingId);\n\n if (!heading) {\n return null;\n }\n\n return markdown.slice(heading.startOffset, heading.endOffset).trim();\n}\n","import FlexSearch from 'flexsearch';\nimport type { ProcessedDoc, SearchResult } from '../types/index.js';\nimport type { IndexableDocument } from './types.js';\n\nexport type FlexSearchDocument = FlexSearch.Document<IndexableDocument, string[]>;\n\n/**\n * Field weights for search ranking\n * Higher values = more importance\n */\nconst FIELD_WEIGHTS = {\n title: 3.0,\n headings: 2.0,\n description: 1.5,\n content: 1.0,\n} as const;\n\n/**\n * Simple English stemmer\n * Handles common suffixes for better matching\n */\nfunction englishStemmer(word: string): string {\n // Only process words longer than 3 characters\n if (word.length <= 3) return word;\n\n return (\n word\n // -ing endings\n .replace(/ing$/, '')\n // -tion, -sion endings -> t, s\n .replace(/tion$/, 't')\n .replace(/sion$/, 's')\n // -ed endings (careful with short words)\n .replace(/([^aeiou])ed$/, '$1')\n // -es endings\n .replace(/([^aeiou])es$/, '$1')\n // -ly endings\n .replace(/ly$/, '')\n // -ment endings\n .replace(/ment$/, '')\n // -ness endings\n .replace(/ness$/, '')\n // -ies -> y\n .replace(/ies$/, 'y')\n // -s endings (simple plural)\n .replace(/([^s])s$/, '$1')\n );\n}\n\n/**\n * Create a FlexSearch document index with enhanced configuration\n *\n * Features:\n * - Full substring matching (finds \"auth\" in \"authentication\")\n * - English stemming (finds \"authenticate\" when searching \"authentication\")\n * - Context-aware scoring for phrase matching\n * - Optimized resolution for relevance ranking\n */\nexport function createSearchIndex(): FlexSearchDocument {\n return new FlexSearch.Document<IndexableDocument, string[]>({\n // Use 'full' tokenization for substring matching\n // This allows \"auth\" to match \"authentication\"\n tokenize: 'full',\n\n // Enable caching for faster repeated queries\n cache: 100,\n\n // Higher resolution = more granular ranking (1-9)\n resolution: 9,\n\n // Enable context for phrase/proximity matching\n context: {\n resolution: 2,\n depth: 2,\n bidirectional: true,\n },\n\n // Apply stemming to normalize word forms\n encode: (str: string) => {\n // Normalize to lowercase and split into words\n const words = str.toLowerCase().split(/[\\s\\-_.,;:!?'\"()[\\]{}]+/);\n // Apply stemmer to each word\n return words.filter(Boolean).map(englishStemmer);\n },\n\n // Document schema\n document: {\n id: 'id',\n // Index these fields for searching\n index: ['title', 'content', 'headings', 'description'],\n // Store these fields in results (for enriched queries)\n store: ['title', 'description'],\n },\n });\n}\n\n/**\n * Add a document to the search index\n *\n * @param index - The FlexSearch index\n * @param doc - The document to add\n * @param baseUrl - Optional base URL to construct full URL as document ID\n */\nexport function addDocumentToIndex(\n index: FlexSearchDocument,\n doc: ProcessedDoc,\n baseUrl?: string\n): void {\n // Use full URL as ID if baseUrl is provided, otherwise use route\n const id = baseUrl ? `${baseUrl.replace(/\\/$/, '')}${doc.route}` : doc.route;\n\n const indexable: IndexableDocument = {\n id,\n title: doc.title,\n content: doc.markdown,\n headings: doc.headings.map((h) => h.text).join(' '),\n description: doc.description,\n };\n\n index.add(indexable);\n}\n\n/**\n * Build the search index from processed documents\n *\n * @param docs - Documents to index\n * @param baseUrl - Optional base URL to construct full URLs as document IDs\n */\nexport function buildSearchIndex(docs: ProcessedDoc[], baseUrl?: string): FlexSearchDocument {\n const index = createSearchIndex();\n\n for (const doc of docs) {\n addDocumentToIndex(index, doc, baseUrl);\n }\n\n return index;\n}\n\n/**\n * Search the index and return results with weighted ranking\n *\n * Ranking combines:\n * - Field importance (title > headings > description > content)\n * - Position in results (earlier = more relevant)\n */\nexport function searchIndex(\n index: FlexSearchDocument,\n docs: Record<string, ProcessedDoc>,\n query: string,\n options: { limit?: number } = {}\n): SearchResult[] {\n const { limit = 5 } = options;\n\n // Search across all fields\n const rawResults = index.search(query, {\n limit: limit * 3, // Get extra results for better ranking after weighting\n enrich: true,\n });\n\n // Aggregate scores across fields with weighting\n const docScores = new Map<string, number>();\n\n for (const fieldResult of rawResults) {\n // Determine which field this result is from\n const field = fieldResult.field as keyof typeof FIELD_WEIGHTS;\n const fieldWeight = FIELD_WEIGHTS[field] ?? 1.0;\n\n // With enrich: true, results are objects with id property\n const results = fieldResult.result as unknown as Array<{ id: string } | string>;\n\n for (let i = 0; i < results.length; i++) {\n const item = results[i];\n if (!item) continue;\n\n const docId = typeof item === 'string' ? item : item.id;\n\n // Position-based score (earlier = higher)\n const positionScore = (results.length - i) / results.length;\n\n // Apply field weight to position score\n const weightedScore = positionScore * fieldWeight;\n\n // Combine with existing score (additive for multi-field matches)\n const existingScore = docScores.get(docId) ?? 0;\n docScores.set(docId, existingScore + weightedScore);\n }\n }\n\n // Build results array\n const results: SearchResult[] = [];\n\n for (const [docId, score] of docScores) {\n const doc = docs[docId];\n if (!doc) continue;\n\n results.push({\n url: docId, // docId is the full URL when indexed with baseUrl\n route: doc.route,\n title: doc.title,\n score,\n snippet: generateSnippet(doc.markdown, query),\n matchingHeadings: findMatchingHeadings(doc, query),\n });\n }\n\n // Sort by score (highest first) and limit\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, limit);\n}\n\n/**\n * Generate a snippet from the markdown content around the query terms\n */\nexport function generateSnippet(markdown: string, query: string): string {\n const maxLength = 200;\n const queryTerms = query.toLowerCase().split(/\\s+/).filter(Boolean);\n\n if (queryTerms.length === 0) {\n return markdown.slice(0, maxLength) + (markdown.length > maxLength ? '...' : '');\n }\n\n const lowerMarkdown = markdown.toLowerCase();\n let bestIndex = -1;\n let bestTerm = '';\n\n // Also try stemmed versions of query terms\n const allTerms = [...queryTerms, ...queryTerms.map(englishStemmer)];\n\n for (const term of allTerms) {\n const index = lowerMarkdown.indexOf(term);\n if (index !== -1 && (bestIndex === -1 || index < bestIndex)) {\n bestIndex = index;\n bestTerm = term;\n }\n }\n\n if (bestIndex === -1) {\n // No term found, return beginning of document\n return markdown.slice(0, maxLength) + (markdown.length > maxLength ? '...' : '');\n }\n\n const snippetStart = Math.max(0, bestIndex - 50);\n const snippetEnd = Math.min(markdown.length, bestIndex + bestTerm.length + 150);\n\n let snippet = markdown.slice(snippetStart, snippetEnd);\n\n snippet = snippet\n // Remove markdown headings\n .replace(/^#{1,6}\\s+/gm, '')\n // Remove markdown links but keep text\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1')\n // Remove markdown images\n .replace(/!\\[([^\\]]*)\\]\\([^)]+\\)/g, '')\n // Remove code block markers\n .replace(/```[a-z]*\\n?/g, '')\n // Remove inline code backticks\n .replace(/`([^`]+)`/g, '$1')\n // Clean up whitespace\n .replace(/\\s+/g, ' ')\n .trim();\n\n const prefix = snippetStart > 0 ? '...' : '';\n const suffix = snippetEnd < markdown.length ? '...' : '';\n\n return prefix + snippet + suffix;\n}\n\n/**\n * Find headings that match the query (including stemmed forms)\n */\nfunction findMatchingHeadings(doc: ProcessedDoc, query: string): string[] {\n const queryTerms = query.toLowerCase().split(/\\s+/).filter(Boolean);\n // Include stemmed versions for better matching\n const allTerms = [...queryTerms, ...queryTerms.map(englishStemmer)];\n const matching: string[] = [];\n\n for (const heading of doc.headings) {\n const headingLower = heading.text.toLowerCase();\n const headingStemmed = headingLower.split(/\\s+/).map(englishStemmer).join(' ');\n\n // Check if any query term matches the heading or its stemmed form\n if (\n allTerms.some(\n (term) => headingLower.includes(term) || headingStemmed.includes(englishStemmer(term))\n )\n ) {\n matching.push(heading.text);\n }\n }\n\n return matching.slice(0, 3); // Limit to 3 matching headings\n}\n\n/**\n * Export the search index to a serializable format\n */\nexport async function exportSearchIndex(index: FlexSearchDocument): Promise<unknown> {\n const exportData: Record<string, unknown> = {};\n\n await index.export((key, data) => {\n exportData[key as string] = data;\n });\n\n return exportData;\n}\n\n/**\n * Import a search index from serialized data\n */\nexport async function importSearchIndex(\n data: Record<string, unknown>\n): Promise<FlexSearchDocument> {\n const index = createSearchIndex();\n\n for (const [key, value] of Object.entries(data)) {\n // FlexSearch's import expects the data in a specific format\n await (index as unknown as { import: (key: string, data: unknown) => Promise<void> }).import(\n key,\n value\n );\n }\n\n return index;\n}\n","import type { ProcessedDoc } from '../../types/index.js';\nimport type { ContentIndexer, ProviderContext } from '../types.js';\nimport { buildSearchIndex, exportSearchIndex } from '../../search/flexsearch-core.js';\n\n/**\n * Built-in FlexSearch content indexer.\n *\n * This indexer builds a local FlexSearch index and produces:\n * - docs.json: All processed documents keyed by full URL\n * - search-index.json: Exported FlexSearch index for runtime search\n */\nexport class FlexSearchIndexer implements ContentIndexer {\n readonly name = 'flexsearch';\n\n private baseUrl = '';\n private docsIndex: Record<string, ProcessedDoc> = {};\n private exportedIndex: unknown = null;\n private docCount = 0;\n\n /**\n * FlexSearch indexer always runs by default.\n * It respects the indexers configuration - if not included, it won't run.\n */\n shouldRun(): boolean {\n return true;\n }\n\n async initialize(context: ProviderContext): Promise<void> {\n // Reset state for fresh indexing\n this.baseUrl = context.baseUrl.replace(/\\/$/, '');\n this.docsIndex = {};\n this.exportedIndex = null;\n this.docCount = 0;\n }\n\n async indexDocuments(docs: ProcessedDoc[]): Promise<void> {\n this.docCount = docs.length;\n\n // Build docs index (keyed by full URL)\n for (const doc of docs) {\n const fullUrl = `${this.baseUrl}${doc.route}`;\n this.docsIndex[fullUrl] = doc;\n }\n\n // Build and export FlexSearch index (use full URLs as document IDs)\n console.log('[FlexSearch] Building search index...');\n const searchIndex = buildSearchIndex(docs, this.baseUrl);\n this.exportedIndex = await exportSearchIndex(searchIndex);\n console.log(`[FlexSearch] Indexed ${this.docCount} documents`);\n }\n\n async finalize(): Promise<Map<string, unknown>> {\n const artifacts = new Map<string, unknown>();\n\n // docs.json - all documents keyed by full URL\n artifacts.set('docs.json', this.docsIndex);\n\n // search-index.json - exported FlexSearch index\n artifacts.set('search-index.json', this.exportedIndex);\n\n return artifacts;\n }\n\n async getManifestData(): Promise<Record<string, unknown>> {\n return {\n searchEngine: 'flexsearch',\n };\n }\n}\n","import fs from 'fs-extra';\nimport type { ProcessedDoc, SearchResult } from '../../types/index.js';\nimport type {\n SearchProvider,\n ProviderContext,\n SearchProviderInitData,\n SearchOptions,\n} from '../types.js';\nimport {\n importSearchIndex,\n searchIndex,\n type FlexSearchDocument,\n} from '../../search/flexsearch-core.js';\n\n/**\n * Built-in FlexSearch search provider.\n *\n * This provider uses the local FlexSearch index for search queries.\n * Supports both file-based loading (Node.js) and pre-loaded data (Workers).\n */\nexport class FlexSearchProvider implements SearchProvider {\n readonly name = 'flexsearch';\n\n private docs: Record<string, ProcessedDoc> | null = null;\n private searchIndex: FlexSearchDocument | null = null;\n private ready = false;\n\n async initialize(_context: ProviderContext, initData?: SearchProviderInitData): Promise<void> {\n if (!initData) {\n throw new Error('[FlexSearch] SearchProviderInitData required for FlexSearch provider');\n }\n\n // Pre-loaded data mode (Cloudflare Workers, etc.)\n if (initData.docs && initData.indexData) {\n this.docs = initData.docs;\n this.searchIndex = await importSearchIndex(initData.indexData as Record<string, unknown>);\n this.ready = true;\n return;\n }\n\n // File-based mode (Node.js)\n if (initData.docsPath && initData.indexPath) {\n if (await fs.pathExists(initData.docsPath)) {\n this.docs = await fs.readJson(initData.docsPath);\n } else {\n throw new Error(`[FlexSearch] Docs file not found: ${initData.docsPath}`);\n }\n\n if (await fs.pathExists(initData.indexPath)) {\n const indexData = await fs.readJson(initData.indexPath);\n this.searchIndex = await importSearchIndex(indexData);\n } else {\n throw new Error(`[FlexSearch] Search index not found: ${initData.indexPath}`);\n }\n\n this.ready = true;\n return;\n }\n\n throw new Error(\n '[FlexSearch] Invalid init data: must provide either file paths (docsPath, indexPath) or pre-loaded data (docs, indexData)'\n );\n }\n\n isReady(): boolean {\n return this.ready && this.docs !== null && this.searchIndex !== null;\n }\n\n async search(query: string, options?: SearchOptions): Promise<SearchResult[]> {\n if (!this.isReady() || !this.docs || !this.searchIndex) {\n throw new Error('[FlexSearch] Provider not initialized');\n }\n\n const limit = options?.limit ?? 5;\n return searchIndex(this.searchIndex, this.docs, query, { limit });\n }\n\n async getDocument(url: string): Promise<ProcessedDoc | null> {\n if (!this.docs) {\n throw new Error('[FlexSearch] Provider not initialized');\n }\n\n // Direct lookup by URL\n return this.docs[url] ?? null;\n }\n\n async healthCheck(): Promise<{ healthy: boolean; message?: string }> {\n if (!this.isReady()) {\n return { healthy: false, message: 'FlexSearch provider not initialized' };\n }\n\n const docCount = this.docs ? Object.keys(this.docs).length : 0;\n return {\n healthy: true,\n message: `FlexSearch provider ready with ${docCount} documents`,\n };\n }\n\n /**\n * Get all loaded documents (for compatibility with existing server code)\n */\n getDocs(): Record<string, ProcessedDoc> | null {\n return this.docs;\n }\n\n /**\n * Get the FlexSearch index (for compatibility with existing server code)\n */\n getSearchIndex(): FlexSearchDocument | null {\n return this.searchIndex;\n }\n}\n","import type { ContentIndexer, SearchProvider } from './types.js';\nimport { FlexSearchIndexer } from './indexers/flexsearch-indexer.js';\nimport { FlexSearchProvider } from './search/flexsearch-provider.js';\n\n/**\n * Load an indexer by name or module path.\n *\n * @param specifier - Either 'flexsearch' for the built-in indexer, or a module path\n * (relative path like './my-indexer.js' or npm package like '@myorg/indexer')\n * @returns Instantiated ContentIndexer\n *\n * @example\n * ```typescript\n * // Built-in\n * const indexer = await loadIndexer('flexsearch');\n *\n * // Custom relative path\n * const indexer = await loadIndexer('./src/providers/algolia-indexer.js');\n *\n * // Custom npm package\n * const indexer = await loadIndexer('@myorg/custom-indexer');\n * ```\n */\nexport async function loadIndexer(specifier: string): Promise<ContentIndexer> {\n // Built-in FlexSearch indexer\n if (specifier === 'flexsearch') {\n return new FlexSearchIndexer();\n }\n\n try {\n const module = await import(specifier);\n const IndexerClass = module.default;\n\n if (typeof IndexerClass === 'function') {\n // It's a class constructor\n const instance = new IndexerClass();\n\n if (!isContentIndexer(instance)) {\n throw new Error(\n `Invalid indexer module \"${specifier}\": does not implement ContentIndexer interface`\n );\n }\n\n return instance;\n }\n\n if (isContentIndexer(IndexerClass)) {\n return IndexerClass;\n }\n\n throw new Error(\n `Invalid indexer module \"${specifier}\": must export a default class or ContentIndexer instance`\n );\n } catch (error) {\n if (error instanceof Error && error.message.includes('Cannot find module')) {\n throw new Error(`Indexer module not found: \"${specifier}\". Check the path or package name.`);\n }\n throw error;\n }\n}\n\n/**\n * Load a search provider by name or module path.\n *\n * @param specifier - Either 'flexsearch' for the built-in provider, or a module path\n * (relative path like './my-search.js' or npm package like '@myorg/search')\n * @returns Instantiated SearchProvider\n *\n * @example\n * ```typescript\n * // Built-in\n * const provider = await loadSearchProvider('flexsearch');\n *\n * // Custom relative path\n * const provider = await loadSearchProvider('./src/providers/glean-search.js');\n *\n * // Custom npm package\n * const provider = await loadSearchProvider('@myorg/glean-search');\n * ```\n */\nexport async function loadSearchProvider(specifier: string): Promise<SearchProvider> {\n if (specifier === 'flexsearch') {\n return new FlexSearchProvider();\n }\n\n try {\n const module = await import(specifier);\n const ProviderClass = module.default;\n\n if (typeof ProviderClass === 'function') {\n const instance = new ProviderClass();\n\n if (!isSearchProvider(instance)) {\n throw new Error(\n `Invalid search provider module \"${specifier}\": does not implement SearchProvider interface`\n );\n }\n\n return instance;\n }\n\n if (isSearchProvider(ProviderClass)) {\n return ProviderClass;\n }\n\n throw new Error(\n `Invalid search provider module \"${specifier}\": must export a default class or SearchProvider instance`\n );\n } catch (error) {\n if (error instanceof Error && error.message.includes('Cannot find module')) {\n throw new Error(\n `Search provider module not found: \"${specifier}\". Check the path or package name.`\n );\n }\n throw error;\n }\n}\n\n/**\n * Type guard to check if an object implements ContentIndexer\n */\nfunction isContentIndexer(obj: unknown): obj is ContentIndexer {\n if (!obj || typeof obj !== 'object') {\n return false;\n }\n\n const indexer = obj as ContentIndexer;\n return (\n typeof indexer.name === 'string' &&\n typeof indexer.initialize === 'function' &&\n typeof indexer.indexDocuments === 'function' &&\n typeof indexer.finalize === 'function'\n );\n}\n\n/**\n * Type guard to check if an object implements SearchProvider\n */\nfunction isSearchProvider(obj: unknown): obj is SearchProvider {\n if (!obj || typeof obj !== 'object') {\n return false;\n }\n\n const provider = obj as SearchProvider;\n return (\n typeof provider.name === 'string' &&\n typeof provider.initialize === 'function' &&\n typeof provider.isReady === 'function' &&\n typeof provider.search === 'function'\n );\n}\n","import path from 'path';\nimport fs from 'fs-extra';\nimport pMap from 'p-map';\nimport type { LoadContext, Plugin } from '@docusaurus/types';\nimport type {\n McpServerPluginOptions,\n ResolvedPluginOptions,\n ProcessedDoc,\n McpManifest,\n} from '../types/index.js';\nimport { DEFAULT_OPTIONS } from '../types/index.js';\nimport { collectRoutes } from './route-collector.js';\nimport { extractContent, type ExtractContentOptions } from '../processing/html-parser.js';\nimport { htmlToMarkdown } from '../processing/html-to-markdown.js';\nimport { extractHeadingsFromMarkdown } from '../processing/heading-extractor.js';\nimport { loadIndexer } from '../providers/loader.js';\nimport type { ProviderContext } from '../providers/types.js';\n\n/**\n * Resolve plugin options with defaults.\n */\nfunction resolveOptions(options: McpServerPluginOptions): ResolvedPluginOptions {\n return {\n ...DEFAULT_OPTIONS,\n ...options,\n server: {\n ...DEFAULT_OPTIONS.server,\n ...options.server,\n },\n };\n}\n\n/**\n * Options for processing an HTML file\n */\ninterface ProcessHtmlOptions {\n contentSelectors: string[];\n excludeSelectors: string[];\n minContentLength: number;\n}\n\n/**\n * Process a single HTML file into a ProcessedDoc\n */\nasync function processHtmlFile(\n htmlPath: string,\n route: string,\n options: ProcessHtmlOptions\n): Promise<ProcessedDoc | null> {\n try {\n // Extract content from HTML\n const extractOptions: ExtractContentOptions = {\n contentSelectors: options.contentSelectors,\n excludeSelectors: options.excludeSelectors,\n };\n const extracted = await extractContent(htmlPath, extractOptions);\n\n if (!extracted.contentHtml) {\n console.warn(`[MCP] No content found in ${htmlPath}`);\n return null;\n }\n\n // Convert to markdown\n const markdown = await htmlToMarkdown(extracted.contentHtml);\n\n if (!markdown || markdown.trim().length < options.minContentLength) {\n console.warn(`[MCP] Insufficient content in ${htmlPath}`);\n return null;\n }\n\n // Extract headings\n const headings = extractHeadingsFromMarkdown(markdown);\n\n return {\n route,\n title: extracted.title,\n description: extracted.description,\n markdown,\n headings,\n };\n } catch (error) {\n console.error(`[MCP] Error processing ${htmlPath}:`, error);\n return null;\n }\n}\n\n/**\n * Docusaurus plugin that generates MCP server artifacts during build\n */\nexport default function mcpServerPlugin(\n context: LoadContext,\n options: McpServerPluginOptions\n): Plugin {\n const resolvedOptions = resolveOptions(options);\n\n return {\n name: 'docusaurus-plugin-mcp-server',\n\n // Expose configuration to theme components via globalData\n async contentLoaded({ actions }) {\n const { setGlobalData } = actions;\n\n // Construct server URL from site URL + output directory\n const serverUrl = `${context.siteConfig.url}/${resolvedOptions.outputDir}`;\n\n setGlobalData({\n serverUrl,\n serverName: resolvedOptions.server.name,\n });\n },\n\n async postBuild({ outDir }) {\n console.log('[MCP] Starting MCP artifact generation...');\n const startTime = Date.now();\n\n // Check if indexing is disabled\n if (resolvedOptions.indexers === false) {\n console.log('[MCP] Indexing disabled, skipping artifact generation');\n return;\n }\n\n // Collect routes from the build output\n const routes = await collectRoutes(outDir, resolvedOptions.excludeRoutes);\n console.log(`[MCP] Found ${routes.length} routes to process`);\n\n if (routes.length === 0) {\n console.warn('[MCP] No routes found to process');\n return;\n }\n\n // Process all HTML files in parallel (with concurrency limit)\n const processOptions: ProcessHtmlOptions = {\n contentSelectors: resolvedOptions.contentSelectors,\n excludeSelectors: resolvedOptions.excludeSelectors,\n minContentLength: resolvedOptions.minContentLength,\n };\n\n const processedDocs = await pMap(\n routes,\n async (route) => {\n return processHtmlFile(route.htmlPath, route.path, processOptions);\n },\n { concurrency: 10 }\n );\n\n // Filter out null results\n const validDocs = processedDocs.filter((doc): doc is ProcessedDoc => doc !== null);\n console.log(`[MCP] Successfully processed ${validDocs.length} documents`);\n\n if (validDocs.length === 0) {\n console.warn('[MCP] No valid documents to index');\n return;\n }\n\n // Create provider context\n const mcpOutputDir = path.join(outDir, resolvedOptions.outputDir);\n const providerContext: ProviderContext = {\n baseUrl: context.siteConfig.url,\n serverName: resolvedOptions.server.name,\n serverVersion: resolvedOptions.server.version,\n outputDir: mcpOutputDir,\n };\n\n // Determine which indexers to run\n // undefined = ['flexsearch'] for backward compatibility\n const indexerSpecs = resolvedOptions.indexers ?? ['flexsearch'];\n\n await fs.ensureDir(mcpOutputDir);\n\n const indexerNames: string[] = [];\n\n for (const indexerSpec of indexerSpecs) {\n try {\n const indexer = await loadIndexer(indexerSpec);\n\n // Check if indexer wants to run (env var gating)\n if (indexer.shouldRun && !indexer.shouldRun()) {\n console.log(`[MCP] Skipping indexer: ${indexer.name}`);\n continue;\n }\n\n console.log(`[MCP] Running indexer: ${indexer.name}`);\n await indexer.initialize(providerContext);\n await indexer.indexDocuments(validDocs);\n\n // Write artifacts from this indexer\n const artifacts = await indexer.finalize();\n for (const [filename, content] of artifacts) {\n await fs.writeJson(path.join(mcpOutputDir, filename), content, { spaces: 0 });\n }\n\n indexerNames.push(indexer.name);\n } catch (error) {\n console.error(`[MCP] Error running indexer \"${indexerSpec}\":`, error);\n throw error;\n }\n }\n\n // Write manifest (only if at least one indexer ran)\n if (indexerNames.length > 0) {\n const manifest: McpManifest = {\n version: resolvedOptions.server.version,\n buildTime: new Date().toISOString(),\n docCount: validDocs.length,\n serverName: resolvedOptions.server.name,\n baseUrl: context.siteConfig.url,\n indexers: indexerNames,\n };\n\n await fs.writeJson(path.join(mcpOutputDir, 'manifest.json'), manifest, { spaces: 2 });\n }\n\n const elapsed = Date.now() - startTime;\n console.log(`[MCP] Artifacts written to ${mcpOutputDir}`);\n console.log(`[MCP] Generation complete in ${elapsed}ms`);\n },\n };\n}\n\n// Named export for ESM compatibility\nexport { mcpServerPlugin };\n","import { z } from 'zod';\nimport type { ProcessedDoc, SearchResult, DocsSearchParams } from '../../types/index.js';\nimport { searchIndex, type FlexSearchDocument } from '../../search/flexsearch-core.js';\n\n/**\n * Zod schema for docs_search input parameters\n */\nexport const docsSearchInputSchema = {\n query: z.string().min(1).describe('The search query string'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(20)\n .optional()\n .default(5)\n .describe('Maximum number of results to return (1-20, default: 5)'),\n};\n\n/**\n * Tool definition for docs_search\n */\nexport const docsSearchTool = {\n name: 'docs_search',\n description:\n 'Search the documentation for relevant pages. Returns matching documents with URLs, snippets, and relevance scores. Use this to find information across all documentation.',\n inputSchema: docsSearchInputSchema,\n};\n\n/**\n * Execute the docs_search tool\n */\nexport function executeDocsSearch(\n params: DocsSearchParams,\n index: FlexSearchDocument,\n docs: Record<string, ProcessedDoc>\n): SearchResult[] {\n const { query, limit = 5 } = params;\n\n // Validate parameters\n if (!query || typeof query !== 'string' || query.trim().length === 0) {\n throw new Error('Query parameter is required and must be a non-empty string');\n }\n\n const effectiveLimit = Math.min(Math.max(1, limit), 20);\n\n // Search the index\n const results = searchIndex(index, docs, query.trim(), {\n limit: effectiveLimit,\n });\n\n return results;\n}\n\n/**\n * Format search results for MCP response\n */\nexport function formatSearchResults(results: SearchResult[]): string {\n if (results.length === 0) {\n return 'No matching documents found.';\n }\n\n const lines: string[] = [`Found ${results.length} result(s):\\n`];\n\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n if (!result) continue;\n\n lines.push(`${i + 1}. **${result.title}**`);\n lines.push(` URL: ${result.url}`);\n\n if (result.matchingHeadings && result.matchingHeadings.length > 0) {\n lines.push(` Matching sections: ${result.matchingHeadings.join(', ')}`);\n }\n\n lines.push(` ${result.snippet}`);\n lines.push('');\n }\n\n lines.push('Use docs_fetch with the URL to retrieve the full page content.');\n\n return lines.join('\\n');\n}\n","import { z } from 'zod';\nimport type { ProcessedDoc } from '../../types/index.js';\n\n/**\n * Zod schema for docs_fetch input parameters\n */\nexport const docsFetchInputSchema = {\n url: z\n .string()\n .url()\n .describe(\n 'The full URL of the page to fetch (e.g., \"https://docs.example.com/docs/getting-started\")'\n ),\n};\n\n/**\n * Tool definition for docs_fetch\n */\nexport const docsFetchTool = {\n name: 'docs_fetch',\n description:\n 'Fetch the complete content of a documentation page. Use this after searching to get the full markdown content of a specific page.',\n inputSchema: docsFetchInputSchema,\n};\n\n/**\n * Format page content for MCP response\n */\nexport function formatPageContent(doc: ProcessedDoc | null): string {\n if (!doc) {\n return 'Page not found. Please check the URL and try again.';\n }\n\n const lines: string[] = [];\n\n // Header\n lines.push(`# ${doc.title}`);\n lines.push('');\n\n // Metadata\n if (doc.description) {\n lines.push(`> ${doc.description}`);\n lines.push('');\n }\n\n // Table of contents (if there are headings)\n if (doc.headings.length > 0) {\n lines.push('## Contents');\n lines.push('');\n for (const heading of doc.headings) {\n if (heading.level <= 3) {\n const indent = ' '.repeat(heading.level - 1);\n lines.push(`${indent}- [${heading.text}](#${heading.id})`);\n }\n }\n lines.push('');\n lines.push('---');\n lines.push('');\n }\n\n // Main content\n lines.push(doc.markdown);\n\n return lines.join('\\n');\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type {\n ProcessedDoc,\n McpServerConfig,\n McpServerFileConfig,\n McpServerDataConfig,\n} from '../types/index.js';\nimport { loadSearchProvider } from '../providers/loader.js';\nimport { FlexSearchProvider } from '../providers/search/flexsearch-provider.js';\nimport type {\n SearchProvider,\n ProviderContext,\n SearchProviderInitData,\n} from '../providers/types.js';\nimport { docsSearchTool, formatSearchResults } from './tools/docs-search.js';\nimport { docsFetchTool, formatPageContent } from './tools/docs-fetch.js';\n\n/**\n * Type guard to check if config uses file-based loading\n */\nfunction isFileConfig(config: McpServerConfig): config is McpServerFileConfig {\n return 'docsPath' in config && 'indexPath' in config;\n}\n\n/**\n * Type guard to check if config uses pre-loaded data\n */\nfunction isDataConfig(config: McpServerConfig): config is McpServerDataConfig {\n return 'docs' in config && 'searchIndexData' in config;\n}\n\n/**\n * MCP Server for documentation\n *\n * This class provides the MCP server implementation that can be used\n * with any HTTP framework (Express, Vercel, Cloudflare Workers, etc.)\n *\n * Supports two modes:\n * - File-based: Load docs and search index from filesystem (Node.js)\n * - Pre-loaded: Accept docs and search index data directly (Workers)\n *\n * Uses the official MCP SDK for proper protocol handling.\n */\nexport class McpDocsServer {\n private config: McpServerConfig;\n private searchProvider: SearchProvider | null = null;\n private mcpServer: McpServer;\n private initialized = false;\n\n constructor(config: McpServerConfig) {\n this.config = config;\n\n this.mcpServer = new McpServer(\n {\n name: config.name,\n version: config.version ?? '1.0.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n this.registerTools();\n }\n\n /**\n * Register all MCP tools using definitions from tool files\n */\n private registerTools(): void {\n // Register docs_search tool\n this.mcpServer.registerTool(\n docsSearchTool.name,\n {\n description: docsSearchTool.description,\n inputSchema: docsSearchTool.inputSchema,\n },\n async ({ query, limit }) => {\n await this.initialize();\n\n if (!this.searchProvider || !this.searchProvider.isReady()) {\n return {\n content: [{ type: 'text' as const, text: 'Server not initialized. Please try again.' }],\n isError: true,\n };\n }\n\n try {\n const results = await this.searchProvider.search(query, { limit });\n return {\n content: [{ type: 'text' as const, text: formatSearchResults(results) }],\n };\n } catch (error) {\n console.error('[MCP] Search error:', error);\n return {\n content: [{ type: 'text' as const, text: `Search error: ${String(error)}` }],\n isError: true,\n };\n }\n }\n );\n\n // Register docs_fetch tool\n this.mcpServer.registerTool(\n docsFetchTool.name,\n {\n description: docsFetchTool.description,\n inputSchema: docsFetchTool.inputSchema,\n },\n async ({ url }) => {\n await this.initialize();\n\n if (!this.searchProvider || !this.searchProvider.isReady()) {\n return {\n content: [{ type: 'text' as const, text: 'Server not initialized. Please try again.' }],\n isError: true,\n };\n }\n\n try {\n const doc = await this.getDocument(url);\n return {\n content: [{ type: 'text' as const, text: formatPageContent(doc) }],\n };\n } catch (error) {\n console.error('[MCP] Fetch error:', error);\n return {\n content: [{ type: 'text' as const, text: `Error fetching page: ${String(error)}` }],\n isError: true,\n };\n }\n }\n );\n }\n\n /**\n * Get a document by URL using the search provider\n */\n private async getDocument(url: string): Promise<ProcessedDoc | null> {\n if (!this.searchProvider) {\n return null;\n }\n\n if (this.searchProvider.getDocument) {\n return this.searchProvider.getDocument(url);\n }\n\n return null;\n }\n\n /**\n * Load docs and search index using the configured search provider\n *\n * For file-based config: reads from disk\n * For data config: uses pre-loaded data directly\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n try {\n // Load the search provider\n const searchSpecifier = this.config.search ?? 'flexsearch';\n this.searchProvider = await loadSearchProvider(searchSpecifier);\n\n // Build provider context\n const providerContext: ProviderContext = {\n baseUrl: this.config.baseUrl ?? '',\n serverName: this.config.name,\n serverVersion: this.config.version ?? '1.0.0',\n outputDir: '', // Not relevant for runtime\n };\n\n // Build init data based on config type\n const initData: SearchProviderInitData = {};\n\n if (isDataConfig(this.config)) {\n // Pre-loaded data mode (Cloudflare Workers, etc.)\n initData.docs = this.config.docs;\n initData.indexData = this.config.searchIndexData;\n } else if (isFileConfig(this.config)) {\n // File-based mode (Node.js)\n initData.docsPath = this.config.docsPath;\n initData.indexPath = this.config.indexPath;\n } else {\n throw new Error('Invalid server config: must provide either file paths or pre-loaded data');\n }\n\n // Initialize the search provider\n await this.searchProvider.initialize(providerContext, initData);\n\n this.initialized = true;\n } catch (error) {\n console.error('[MCP] Failed to initialize:', error);\n throw error;\n }\n }\n\n /**\n * Handle an HTTP request using the MCP SDK's transport\n *\n * This method is designed for serverless environments (Vercel, Netlify).\n * It creates a stateless transport instance and processes the request.\n *\n * @param req - Node.js IncomingMessage or compatible request object\n * @param res - Node.js ServerResponse or compatible response object\n * @param parsedBody - Optional pre-parsed request body\n */\n async handleHttpRequest(\n req: IncomingMessage,\n res: ServerResponse,\n parsedBody?: unknown\n ): Promise<void> {\n await this.initialize();\n\n // Create a stateless transport for this request\n // enableJsonResponse: true means we get simple JSON responses instead of SSE\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined, // Stateless mode - no session tracking\n enableJsonResponse: true, // Return JSON instead of SSE streams\n });\n\n // Connect the server to this transport\n await this.mcpServer.connect(transport);\n\n try {\n // Let the transport handle the request\n await transport.handleRequest(req, res, parsedBody);\n } finally {\n // Clean up the transport after request\n await transport.close();\n }\n }\n\n /**\n * Handle a Web Standard Request (Cloudflare Workers, Deno, Bun)\n *\n * This method is designed for Web Standard environments that use\n * the Fetch API Request/Response pattern.\n *\n * @param request - Web Standard Request object\n * @returns Web Standard Response object\n */\n async handleWebRequest(request: Request): Promise<Response> {\n await this.initialize();\n\n // Create a stateless transport for Web Standards\n const transport = new WebStandardStreamableHTTPServerTransport({\n sessionIdGenerator: undefined, // Stateless mode\n enableJsonResponse: true,\n });\n\n // Connect the server to this transport\n await this.mcpServer.connect(transport);\n\n try {\n // Let the transport handle the request and return the response\n return await transport.handleRequest(request);\n } finally {\n // Clean up the transport after request\n await transport.close();\n }\n }\n\n /**\n * Get server status information\n *\n * Useful for health checks and debugging\n */\n async getStatus(): Promise<{\n name: string;\n version: string;\n initialized: boolean;\n docCount: number;\n baseUrl?: string;\n searchProvider?: string;\n }> {\n let docCount = 0;\n\n // Get doc count from FlexSearchProvider if available\n if (this.searchProvider instanceof FlexSearchProvider) {\n const docs = this.searchProvider.getDocs();\n docCount = docs ? Object.keys(docs).length : 0;\n }\n\n return {\n name: this.config.name,\n version: this.config.version ?? '1.0.0',\n initialized: this.initialized,\n docCount,\n baseUrl: this.config.baseUrl,\n searchProvider: this.searchProvider?.name,\n };\n }\n\n /**\n * Get the underlying McpServer instance\n *\n * Useful for advanced use cases like custom transports\n */\n getMcpServer(): McpServer {\n return this.mcpServer;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types/index.ts","../src/plugin/route-collector.ts","../src/processing/html-parser.ts","../src/processing/html-to-markdown.ts","../src/processing/heading-extractor.ts","../src/search/flexsearch-core.ts","../src/providers/indexers/flexsearch-indexer.ts","../src/providers/search/flexsearch-provider.ts","../src/providers/loader.ts","../src/plugin/docusaurus-plugin.ts","../src/mcp/tools/docs-search.ts","../src/mcp/tools/docs-fetch.ts","../src/mcp/server.ts"],"names":["fs","path","unified","rehypeParse","select","toString","toHtml","rehypeRemark","remarkGfm","remarkStringify","FlexSearch","results","searchIndex","pMap","z","McpServer","StreamableHTTPServerTransport","WebStandardStreamableHTTPServerTransport"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqOO,IAAM,eAAA,GAAyC;AAAA,EACpD,SAAA,EAAW,KAAA;AAAA,EACX,gBAAA,EAAkB,CAAC,SAAA,EAAW,MAAA,EAAQ,iBAAiB,eAAe,CAAA;AAAA,EACtE,gBAAA,EAAkB;AAAA,IAChB,KAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA,OAAA;AAAA,IACA,qBAAA;AAAA,IACA,iBAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,gBAAA,EAAkB,EAAA;AAAA,EAClB,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,iBAAA;AAAA,IACN,OAAA,EAAS;AAAA,GACX;AAAA,EACA,aAAA,EAAe,CAAC,OAAA,EAAS,UAAU,CAAA;AAAA,EACnC,QAAA,EAAU,MAAA;AAAA;AAAA,EACV,MAAA,EAAQ;AACV;ACzLO,SAAS,YAAA,CACd,QACA,eAAA,EACkB;AAClB,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,CAAC,KAAA,KAAU;AAC9B,IAAA,OAAO,CAAC,eAAA,CAAgB,IAAA,CAAK,CAAC,OAAA,KAAY;AAExC,MAAA,MAAM,YAAA,GAAe,QAAQ,OAAA,CAAQ,KAAA,EAAO,IAAI,CAAA,CAAE,OAAA,CAAQ,OAAO,GAAG,CAAA;AACpE,MAAA,MAAM,KAAA,GAAQ,IAAI,MAAA,CAAO,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA,CAAG,CAAA;AAC5C,MAAA,OAAO,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAAA,IAC9B,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACH;AAMA,eAAsB,kBAAkB,MAAA,EAA2C;AACjF,EAAA,MAAM,SAA2B,EAAC;AAElC,EAAA,eAAe,cAAc,GAAA,EAA4B;AACvD,IAAA,MAAM,OAAA,GAAU,MAAMA,oBAAA,CAAG,OAAA,CAAQ,KAAK,EAAE,aAAA,EAAe,MAAM,CAAA;AAE7D,IAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,MAAA,MAAM,QAAA,GAAWC,qBAAA,CAAK,IAAA,CAAK,GAAA,EAAK,MAAM,IAAI,CAAA;AAE1C,MAAA,IAAI,KAAA,CAAM,aAAY,EAAG;AAEvB,QAAA,IAAI,CAAC,UAAU,KAAA,EAAO,QAAQ,EAAE,QAAA,CAAS,KAAA,CAAM,IAAI,CAAA,EAAG;AACpD,UAAA;AAAA,QACF;AACA,QAAA,MAAM,cAAc,QAAQ,CAAA;AAAA,MAC9B,CAAA,MAAA,IAAW,KAAA,CAAM,IAAA,KAAS,YAAA,EAAc;AAEtC,QAAA,MAAM,YAAA,GAAeA,qBAAA,CAAK,QAAA,CAAS,MAAA,EAAQ,QAAQ,CAAA;AACnD,QAAA,IAAI,SAAA,GAAY,MAAMA,qBAAA,CAAK,OAAA,CAAQ,YAAY,CAAA,CAAE,OAAA,CAAQ,OAAO,GAAG,CAAA;AAGnE,QAAA,IAAI,cAAc,IAAA,EAAM;AACtB,UAAA,SAAA,GAAY,GAAA;AAAA,QACd;AAEA,QAAA,MAAA,CAAO,IAAA,CAAK;AAAA,UACV,IAAA,EAAM,SAAA;AAAA,UACN,QAAA,EAAU;AAAA,SACX,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,EAAA,MAAM,cAAc,MAAM,CAAA;AAC1B,EAAA,OAAO,MAAA;AACT;AA4BA,eAAsB,aAAA,CACpB,QACA,eAAA,EAC2B;AAE3B,EAAA,MAAM,SAAA,GAAY,MAAM,iBAAA,CAAkB,MAAM,CAAA;AAGhD,EAAA,MAAM,cAAA,GAAiB,YAAA,CAAa,SAAA,EAAW,eAAe,CAAA;AAG9D,EAAA,MAAM,YAAA,uBAAmB,GAAA,EAA4B;AACrD,EAAA,KAAA,MAAW,SAAS,cAAA,EAAgB;AAClC,IAAA,IAAI,CAAC,YAAA,CAAa,GAAA,CAAI,KAAA,CAAM,IAAI,CAAA,EAAG;AACjC,MAAA,YAAA,CAAa,GAAA,CAAI,KAAA,CAAM,IAAA,EAAM,KAAK,CAAA;AAAA,IACpC;AAAA,EACF;AAEA,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,YAAA,CAAa,MAAA,EAAQ,CAAA;AACzC;ACxJO,SAAS,UAAU,IAAA,EAAoB;AAC5C,EAAA,MAAM,SAAA,GAAYC,eAAA,EAAQ,CAAE,GAAA,CAAIC,4BAAW,CAAA;AAC3C,EAAA,OAAO,SAAA,CAAU,MAAM,IAAI,CAAA;AAC7B;AAKA,eAAsB,cAAc,QAAA,EAAiC;AACnE,EAAA,MAAM,IAAA,GAAO,MAAMH,oBAAAA,CAAG,QAAA,CAAS,UAAU,OAAO,CAAA;AAChD,EAAA,OAAO,UAAU,IAAI,CAAA;AACvB;AAQO,SAAS,aAAa,IAAA,EAAoB;AAE/C,EAAA,MAAM,SAAA,GAAYI,qBAAA,CAAO,IAAA,EAAM,IAAI,CAAA;AACnC,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,OAAOC,yBAAA,CAAS,SAAS,CAAA,CAAE,IAAA,EAAK;AAAA,EAClC;AAGA,EAAA,MAAM,YAAA,GAAeD,qBAAA,CAAO,OAAA,EAAS,IAAI,CAAA;AACzC,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,OAAOC,yBAAA,CAAS,YAAY,CAAA,CAAE,IAAA,EAAK;AAAA,EACrC;AAEA,EAAA,OAAO,UAAA;AACT;AAKO,SAAS,mBAAmB,IAAA,EAAoB;AACrD,EAAA,MAAM,eAAA,GAAkBD,qBAAA,CAAO,0BAAA,EAA4B,IAAI,CAAA;AAC/D,EAAA,IAAI,eAAA,IAAmB,eAAA,CAAgB,UAAA,EAAY,OAAA,EAAS;AAC1D,IAAA,OAAO,MAAA,CAAO,eAAA,CAAgB,UAAA,CAAW,OAAO,CAAA;AAAA,EAClD;AAGA,EAAA,MAAM,aAAA,GAAgBA,qBAAA,CAAO,iCAAA,EAAmC,IAAI,CAAA;AACpE,EAAA,IAAI,aAAA,IAAiB,aAAA,CAAc,UAAA,EAAY,OAAA,EAAS;AACtD,IAAA,OAAO,MAAA,CAAO,aAAA,CAAc,UAAA,CAAW,OAAO,CAAA;AAAA,EAChD;AAEA,EAAA,OAAO,EAAA;AACT;AAKO,SAAS,kBAAA,CAAmB,MAAY,SAAA,EAAqC;AAClF,EAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAChC,IAAA,MAAM,OAAA,GAAUA,qBAAA,CAAO,QAAA,EAAU,IAAI,CAAA;AACrC,IAAA,IAAI,OAAA,EAAS;AAEX,MAAA,MAAM,IAAA,GAAOC,yBAAA,CAAS,OAAO,CAAA,CAAE,IAAA,EAAK;AACpC,MAAA,IAAI,IAAA,CAAK,SAAS,EAAA,EAAI;AACpB,QAAA,OAAO,OAAA;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAKA,IAAM,eAAA,GAAkB,CAAC,QAAA,EAAU,OAAA,EAAS,UAAU,CAAA;AAQ/C,SAAS,mBAAA,CAAoB,SAAkB,gBAAA,EAAqC;AACzF,EAAA,MAAM,YAAA,GAAe,CAAC,GAAG,eAAA,EAAiB,GAAG,gBAAgB,CAAA;AAG7D,EAAA,MAAM,SAAS,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAEjD,EAAA,SAAS,eAAe,IAAA,EAAqB;AAC3C,IAAA,IAAI,CAAC,KAAK,QAAA,EAAU;AAEpB,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,CAAC,KAAA,KAAU;AAC9C,MAAA,IAAI,KAAA,CAAM,IAAA,KAAS,SAAA,EAAW,OAAO,IAAA;AAErC,MAAA,MAAM,YAAA,GAAe,KAAA;AAGrB,MAAA,KAAA,MAAW,YAAY,YAAA,EAAc;AACnC,QAAA,IAAI,QAAA,CAAS,UAAA,CAAW,GAAG,CAAA,EAAG;AAE5B,UAAA,MAAM,SAAA,GAAY,QAAA,CAAS,KAAA,CAAM,CAAC,CAAA;AAClC,UAAA,MAAM,OAAA,GAAU,aAAa,UAAA,EAAY,SAAA;AACzC,UAAA,IAAI,MAAM,OAAA,CAAQ,OAAO,KAAK,OAAA,CAAQ,QAAA,CAAS,SAAS,CAAA,EAAG;AACzD,YAAA,OAAO,KAAA;AAAA,UACT;AACA,UAAA,IAAI,OAAO,OAAA,KAAY,QAAA,IAAY,OAAA,CAAQ,QAAA,CAAS,SAAS,CAAA,EAAG;AAC9D,YAAA,OAAO,KAAA;AAAA,UACT;AAAA,QACF,CAAA,MAAA,IAAW,QAAA,CAAS,UAAA,CAAW,GAAG,CAAA,EAAG;AAEnC,UAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,uBAAuB,CAAA;AACpD,UAAA,IAAI,KAAA,EAAO;AACT,YAAA,MAAM,GAAG,IAAA,EAAM,KAAK,CAAA,GAAI,KAAA;AACxB,YAAA,IAAI,IAAA,IAAQ,YAAA,CAAa,UAAA,GAAa,IAAI,MAAM,KAAA,EAAO;AACrD,cAAA,OAAO,KAAA;AAAA,YACT;AAAA,UACF;AAAA,QACF,CAAA,MAAO;AAEL,UAAA,IAAI,YAAA,CAAa,YAAY,QAAA,EAAU;AACrC,YAAA,OAAO,KAAA;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAGA,MAAA,cAAA,CAAe,YAAY,CAAA;AAC3B,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,cAAA,CAAe,MAAM,CAAA;AACrB,EAAA,OAAO,MAAA;AACT;AAeA,eAAsB,cAAA,CACpB,UACA,OAAA,EAC2B;AAC3B,EAAA,MAAM,IAAA,GAAO,MAAM,aAAA,CAAc,QAAQ,CAAA;AAEzC,EAAA,MAAM,KAAA,GAAQ,aAAa,IAAI,CAAA;AAC/B,EAAA,MAAM,WAAA,GAAc,mBAAmB,IAAI,CAAA;AAG3C,EAAA,IAAI,cAAA,GAAiB,kBAAA,CAAmB,IAAA,EAAM,OAAA,CAAQ,gBAAgB,CAAA;AAEtE,EAAA,IAAI,CAAC,cAAA,EAAgB;AAEnB,IAAA,MAAM,IAAA,GAAOD,qBAAA,CAAO,MAAA,EAAQ,IAAI,CAAA;AAChC,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,cAAA,GAAiB,IAAA;AAAA,IACnB;AAAA,EACF;AAEA,EAAA,IAAI,WAAA,GAAc,EAAA;AAClB,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,MAAM,cAAA,GAAiB,mBAAA,CAAoB,cAAA,EAAgB,OAAA,CAAQ,gBAAgB,CAAA;AAEnF,IAAA,WAAA,GAAcE,sBAAO,cAAc,CAAA;AAAA,EACrC;AAEA,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AACF;ACvLA,eAAsB,eAAe,IAAA,EAA+B;AAClE,EAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,IAAA,EAAK,CAAE,WAAW,CAAA,EAAG;AACrC,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,YAAYJ,eAAAA,EAAQ,CACvB,GAAA,CAAIC,4BAAAA,EAAa,EAAE,QAAA,EAAU,IAAA,EAAM,CAAA,CACnC,IAAII,6BAAY,CAAA,CAChB,IAAIC,0BAAS,CAAA,CACb,IAAIC,gCAAA,EAAiB;AAAA,MACpB,MAAA,EAAQ,GAAA;AAAA,MACR,MAAA,EAAQ;AAAA,KACT,CAAA;AAEH,IAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,OAAA,CAAQ,IAAI,CAAA;AAC3C,IAAA,IAAI,QAAA,GAAW,OAAO,MAAM,CAAA;AAG5B,IAAA,QAAA,GAAW,cAAc,QAAQ,CAAA;AAEjC,IAAA,OAAO,QAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,sCAAsC,KAAK,CAAA;AAEzD,IAAA,OAAO,oBAAoB,IAAI,CAAA;AAAA,EACjC;AACF;AAKA,SAAS,cAAc,QAAA,EAA0B;AAC/C,EAAA,OACE,SAEG,OAAA,CAAQ,SAAA,EAAW,MAAM,CAAA,CAEzB,KAAA,CAAM,IAAI,CAAA,CACV,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,SAAS,CAAA,CAC5B,KAAK,IAAI,CAAA,CAET,MAAK,GAAI,IAAA;AAEhB;AAKA,SAAS,oBAAoB,IAAA,EAAsB;AAEjD,EAAA,IAAI,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,mCAAA,EAAqC,EAAE,CAAA;AAC/D,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,iCAAA,EAAmC,EAAE,CAAA;AAGzD,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,cAAA,EAAgB,IAAI,CAAA;AACxC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,SAAA,EAAW,MAAM,CAAA;AACrC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,cAAA,EAAgB,MAAM,CAAA;AAC1C,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,UAAA,EAAY,IAAI,CAAA;AACpC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,WAAA,EAAa,IAAI,CAAA;AAGrC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA;AAGlC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,SAAA,EAAW,GAAG,CAAA;AAClC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,QAAA,EAAU,GAAG,CAAA;AACjC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS,GAAG,CAAA;AAChC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS,GAAG,CAAA;AAChC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,SAAA,EAAW,GAAG,CAAA;AAClC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,QAAA,EAAU,GAAG,CAAA;AAGjC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,SAAA,EAAW,GAAG,CAAA;AAClC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,SAAA,EAAW,MAAM,CAAA;AAErC,EAAA,OAAO,KAAK,IAAA,EAAK;AACnB;;;ACjFO,SAAS,4BAA4B,QAAA,EAAgC;AAC1E,EAAA,MAAM,WAAyB,EAAC;AAChC,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,IAAI,CAAA;AACjC,EAAA,IAAI,aAAA,GAAgB,CAAA;AAEpB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,CAAC,CAAA,IAAK,EAAA;AACzB,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,KAAA,CAAM,wCAAwC,CAAA;AAExE,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,MAAM,MAAA,GAAS,YAAA,CAAa,CAAC,CAAA,IAAK,EAAA;AAClC,MAAA,MAAM,QAAQ,MAAA,CAAO,MAAA;AACrB,MAAA,IAAI,IAAA,GAAO,YAAA,CAAa,CAAC,CAAA,IAAK,EAAA;AAC9B,MAAA,IAAI,EAAA,GAAK,YAAA,CAAa,CAAC,CAAA,IAAK,EAAA;AAG5B,MAAA,IAAI,CAAC,EAAA,EAAI;AACP,QAAA,EAAA,GAAK,kBAAkB,IAAI,CAAA;AAAA,MAC7B;AAGA,MAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,kBAAA,EAAoB,IAAI,CAAA;AAC5C,MAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,YAAA,EAAc,IAAI,CAAA;AACtC,MAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,YAAA,EAAc,IAAI,CAAA;AAEtC,MAAA,QAAA,CAAS,IAAA,CAAK;AAAA,QACZ,KAAA;AAAA,QACA,IAAA,EAAM,KAAK,IAAA,EAAK;AAAA,QAChB,EAAA;AAAA,QACA,WAAA,EAAa,aAAA;AAAA,QACb,SAAA,EAAW;AAAA;AAAA,OACZ,CAAA;AAAA,IACH;AAEA,IAAA,aAAA,IAAiB,KAAK,MAAA,GAAS,CAAA;AAAA,EACjC;AAGA,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AACxC,IAAA,MAAM,OAAA,GAAU,SAAS,CAAC,CAAA;AAC1B,IAAA,IAAI,CAAC,OAAA,EAAS;AAEd,IAAA,IAAI,YAAY,QAAA,CAAS,MAAA;AAGzB,IAAA,KAAA,IAAS,IAAI,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AAC5C,MAAA,MAAM,IAAA,GAAO,SAAS,CAAC,CAAA;AACvB,MAAA,IAAI,IAAA,IAAQ,IAAA,CAAK,KAAA,IAAS,OAAA,CAAQ,KAAA,EAAO;AACvC,QAAA,SAAA,GAAY,IAAA,CAAK,WAAA;AACjB,QAAA;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAA,CAAQ,SAAA,GAAY,SAAA;AAAA,EACtB;AAEA,EAAA,OAAO,QAAA;AACT;AAKO,SAAS,kBAAkB,IAAA,EAAsB;AACtD,EAAA,OACE,KACG,WAAA,EAAY,CAEZ,OAAA,CAAQ,WAAA,EAAa,EAAE,CAAA,CAEvB,OAAA,CAAQ,MAAA,EAAQ,GAAG,EAEnB,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAElB,OAAA,CAAQ,UAAU,EAAE,CAAA;AAE3B;AAKO,SAAS,cAAA,CACd,QAAA,EACA,SAAA,EACA,QAAA,EACe;AACf,EAAA,MAAM,UAAU,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,SAAS,CAAA;AAEvD,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,SAAS,KAAA,CAAM,OAAA,CAAQ,aAAa,OAAA,CAAQ,SAAS,EAAE,IAAA,EAAK;AACrE;ACvFA,IAAM,aAAA,GAAgB;AAAA,EACpB,KAAA,EAAO,CAAA;AAAA,EACP,QAAA,EAAU,CAAA;AAAA,EACV,WAAA,EAAa,GAAA;AAAA,EACb,OAAA,EAAS;AACX,CAAA;AAMA,SAAS,eAAe,IAAA,EAAsB;AAE5C,EAAA,IAAI,IAAA,CAAK,MAAA,IAAU,CAAA,EAAG,OAAO,IAAA;AAE7B,EAAA,OACE,KAEG,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA,CAElB,QAAQ,OAAA,EAAS,GAAG,CAAA,CACpB,OAAA,CAAQ,SAAS,GAAG,CAAA,CAEpB,QAAQ,eAAA,EAAiB,IAAI,EAE7B,OAAA,CAAQ,eAAA,EAAiB,IAAI,CAAA,CAE7B,QAAQ,KAAA,EAAO,EAAE,EAEjB,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAA,CAEnB,OAAA,CAAQ,OAAA,EAAS,EAAE,EAEnB,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,CAEnB,OAAA,CAAQ,YAAY,IAAI,CAAA;AAE/B;AAWO,SAAS,iBAAA,GAAwC;AACtD,EAAA,OAAO,IAAIC,4BAAW,QAAA,CAAsC;AAAA;AAAA;AAAA,IAG1D,QAAA,EAAU,MAAA;AAAA;AAAA,IAGV,KAAA,EAAO,GAAA;AAAA;AAAA,IAGP,UAAA,EAAY,CAAA;AAAA;AAAA,IAGZ,OAAA,EAAS;AAAA,MACP,UAAA,EAAY,CAAA;AAAA,MACZ,KAAA,EAAO,CAAA;AAAA,MACP,aAAA,EAAe;AAAA,KACjB;AAAA;AAAA,IAGA,MAAA,EAAQ,CAAC,GAAA,KAAgB;AAEvB,MAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,WAAA,EAAY,CAAE,MAAM,yBAAyB,CAAA;AAE/D,MAAA,OAAO,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,CAAE,IAAI,cAAc,CAAA;AAAA,IACjD,CAAA;AAAA;AAAA,IAGA,QAAA,EAAU;AAAA,MACR,EAAA,EAAI,IAAA;AAAA;AAAA,MAEJ,KAAA,EAAO,CAAC,OAAA,EAAS,SAAA,EAAW,YAAY,aAAa,CAAA;AAAA;AAAA,MAErD,KAAA,EAAO,CAAC,OAAA,EAAS,aAAa;AAAA;AAChC,GACD,CAAA;AACH;AASO,SAAS,kBAAA,CACd,KAAA,EACA,GAAA,EACA,OAAA,EACM;AAEN,EAAA,MAAM,EAAA,GAAK,OAAA,GAAU,CAAA,EAAG,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,EAAG,GAAA,CAAI,KAAK,CAAA,CAAA,GAAK,GAAA,CAAI,KAAA;AAEvE,EAAA,MAAM,SAAA,GAA+B;AAAA,IACnC,EAAA;AAAA,IACA,OAAO,GAAA,CAAI,KAAA;AAAA,IACX,SAAS,GAAA,CAAI,QAAA;AAAA,IACb,QAAA,EAAU,GAAA,CAAI,QAAA,CAAS,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,IAAI,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAAA,IAClD,aAAa,GAAA,CAAI;AAAA,GACnB;AAEA,EAAA,KAAA,CAAM,IAAI,SAAS,CAAA;AACrB;AAQO,SAAS,gBAAA,CAAiB,MAAsB,OAAA,EAAsC;AAC3F,EAAA,MAAM,QAAQ,iBAAA,EAAkB;AAEhC,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,kBAAA,CAAmB,KAAA,EAAO,KAAK,OAAO,CAAA;AAAA,EACxC;AAEA,EAAA,OAAO,KAAA;AACT;AASO,SAAS,YACd,KAAA,EACA,IAAA,EACA,KAAA,EACA,OAAA,GAA8B,EAAC,EACf;AAChB,EAAA,MAAM,EAAE,KAAA,GAAQ,CAAA,EAAE,GAAI,OAAA;AAGtB,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,MAAA,CAAO,KAAA,EAAO;AAAA,IACrC,OAAO,KAAA,GAAQ,CAAA;AAAA;AAAA,IACf,MAAA,EAAQ;AAAA,GACT,CAAA;AAGD,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAoB;AAE1C,EAAA,KAAA,MAAW,eAAe,UAAA,EAAY;AAEpC,IAAA,MAAM,QAAQ,WAAA,CAAY,KAAA;AAC1B,IAAA,MAAM,WAAA,GAAc,aAAA,CAAc,KAAK,CAAA,IAAK,CAAA;AAG5C,IAAA,MAAMC,WAAU,WAAA,CAAY,MAAA;AAE5B,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAIA,QAAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK;AACvC,MAAA,MAAM,IAAA,GAAOA,SAAQ,CAAC,CAAA;AACtB,MAAA,IAAI,CAAC,IAAA,EAAM;AAEX,MAAA,MAAM,KAAA,GAAQ,OAAO,IAAA,KAAS,QAAA,GAAW,OAAO,IAAA,CAAK,EAAA;AAGrD,MAAA,MAAM,aAAA,GAAA,CAAiBA,QAAAA,CAAQ,MAAA,GAAS,CAAA,IAAKA,QAAAA,CAAQ,MAAA;AAGrD,MAAA,MAAM,gBAAgB,aAAA,GAAgB,WAAA;AAGtC,MAAA,MAAM,aAAA,GAAgB,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA,IAAK,CAAA;AAC9C,MAAA,SAAA,CAAU,GAAA,CAAI,KAAA,EAAO,aAAA,GAAgB,aAAa,CAAA;AAAA,IACpD;AAAA,EACF;AAGA,EAAA,MAAM,UAA0B,EAAC;AAEjC,EAAA,KAAA,MAAW,CAAC,KAAA,EAAO,KAAK,CAAA,IAAK,SAAA,EAAW;AACtC,IAAA,MAAM,GAAA,GAAM,KAAK,KAAK,CAAA;AACtB,IAAA,IAAI,CAAC,GAAA,EAAK;AAEV,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,GAAA,EAAK,KAAA;AAAA;AAAA,MACL,OAAO,GAAA,CAAI,KAAA;AAAA,MACX,OAAO,GAAA,CAAI,KAAA;AAAA,MACX,KAAA;AAAA,MACA,OAAA,EAAS,eAAA,CAAgB,GAAA,CAAI,QAAA,EAAU,KAAK,CAAA;AAAA,MAC5C,gBAAA,EAAkB,oBAAA,CAAqB,GAAA,EAAK,KAAK;AAAA,KAClD,CAAA;AAAA,EACH;AAGA,EAAA,OAAA,CAAQ,KAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAK,CAAA;AACxC,EAAA,OAAO,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA;AAC/B;AAKO,SAAS,eAAA,CAAgB,UAAkB,KAAA,EAAuB;AACvE,EAAA,MAAM,SAAA,GAAY,GAAA;AAClB,EAAA,MAAM,UAAA,GAAa,MAAM,WAAA,EAAY,CAAE,MAAM,KAAK,CAAA,CAAE,OAAO,OAAO,CAAA;AAElE,EAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAC3B,IAAA,OAAO,QAAA,CAAS,MAAM,CAAA,EAAG,SAAS,KAAK,QAAA,CAAS,MAAA,GAAS,YAAY,KAAA,GAAQ,EAAA,CAAA;AAAA,EAC/E;AAEA,EAAA,MAAM,aAAA,GAAgB,SAAS,WAAA,EAAY;AAC3C,EAAA,IAAI,SAAA,GAAY,EAAA;AAChB,EAAA,IAAI,QAAA,GAAW,EAAA;AAGf,EAAA,MAAM,QAAA,GAAW,CAAC,GAAG,UAAA,EAAY,GAAG,UAAA,CAAW,GAAA,CAAI,cAAc,CAAC,CAAA;AAElE,EAAA,KAAA,MAAW,QAAQ,QAAA,EAAU;AAC3B,IAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,OAAA,CAAQ,IAAI,CAAA;AACxC,IAAA,IAAI,KAAA,KAAU,EAAA,KAAO,SAAA,KAAc,EAAA,IAAM,QAAQ,SAAA,CAAA,EAAY;AAC3D,MAAA,SAAA,GAAY,KAAA;AACZ,MAAA,QAAA,GAAW,IAAA;AAAA,IACb;AAAA,EACF;AAEA,EAAA,IAAI,cAAc,EAAA,EAAI;AAEpB,IAAA,OAAO,QAAA,CAAS,MAAM,CAAA,EAAG,SAAS,KAAK,QAAA,CAAS,MAAA,GAAS,YAAY,KAAA,GAAQ,EAAA,CAAA;AAAA,EAC/E;AAEA,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,YAAY,EAAE,CAAA;AAC/C,EAAA,MAAM,UAAA,GAAa,KAAK,GAAA,CAAI,QAAA,CAAS,QAAQ,SAAA,GAAY,QAAA,CAAS,SAAS,GAAG,CAAA;AAE9E,EAAA,IAAI,OAAA,GAAU,QAAA,CAAS,KAAA,CAAM,YAAA,EAAc,UAAU,CAAA;AAErD,EAAA,OAAA,GAAU,OAAA,CAEP,OAAA,CAAQ,cAAA,EAAgB,EAAE,CAAA,CAE1B,QAAQ,wBAAA,EAA0B,IAAI,CAAA,CAEtC,OAAA,CAAQ,yBAAA,EAA2B,EAAE,EAErC,OAAA,CAAQ,eAAA,EAAiB,EAAE,CAAA,CAE3B,OAAA,CAAQ,YAAA,EAAc,IAAI,CAAA,CAE1B,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,CACnB,IAAA,EAAK;AAER,EAAA,MAAM,MAAA,GAAS,YAAA,GAAe,CAAA,GAAI,KAAA,GAAQ,EAAA;AAC1C,EAAA,MAAM,MAAA,GAAS,UAAA,GAAa,QAAA,CAAS,MAAA,GAAS,KAAA,GAAQ,EAAA;AAEtD,EAAA,OAAO,SAAS,OAAA,GAAU,MAAA;AAC5B;AAKA,SAAS,oBAAA,CAAqB,KAAmB,KAAA,EAAyB;AACxE,EAAA,MAAM,UAAA,GAAa,MAAM,WAAA,EAAY,CAAE,MAAM,KAAK,CAAA,CAAE,OAAO,OAAO,CAAA;AAElE,EAAA,MAAM,QAAA,GAAW,CAAC,GAAG,UAAA,EAAY,GAAG,UAAA,CAAW,GAAA,CAAI,cAAc,CAAC,CAAA;AAClE,EAAA,MAAM,WAAqB,EAAC;AAE5B,EAAA,KAAA,MAAW,OAAA,IAAW,IAAI,QAAA,EAAU;AAClC,IAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,IAAA,CAAK,WAAA,EAAY;AAC9C,IAAA,MAAM,cAAA,GAAiB,aAAa,KAAA,CAAM,KAAK,EAAE,GAAA,CAAI,cAAc,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAG7E,IAAA,IACE,QAAA,CAAS,IAAA;AAAA,MACP,CAAC,IAAA,KAAS,YAAA,CAAa,QAAA,CAAS,IAAI,KAAK,cAAA,CAAe,QAAA,CAAS,cAAA,CAAe,IAAI,CAAC;AAAA,KACvF,EACA;AACA,MAAA,QAAA,CAAS,IAAA,CAAK,QAAQ,IAAI,CAAA;AAAA,IAC5B;AAAA,EACF;AAEA,EAAA,OAAO,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA;AAC5B;AAKA,eAAsB,kBAAkB,KAAA,EAA6C;AACnF,EAAA,MAAM,aAAsC,EAAC;AAE7C,EAAA,MAAM,KAAA,CAAM,MAAA,CAAO,CAAC,GAAA,EAAK,IAAA,KAAS;AAChC,IAAA,UAAA,CAAW,GAAa,CAAA,GAAI,IAAA;AAAA,EAC9B,CAAC,CAAA;AAED,EAAA,OAAO,UAAA;AACT;AAKA,eAAsB,kBACpB,IAAA,EAC6B;AAC7B,EAAA,MAAM,QAAQ,iBAAA,EAAkB;AAEhC,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA,EAAG;AAE/C,IAAA,MAAO,KAAA,CAA+E,MAAA;AAAA,MACpF,GAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;;;ACxTO,IAAM,oBAAN,MAAkD;AAAA,EAC9C,IAAA,GAAO,YAAA;AAAA,EAER,OAAA,GAAU,EAAA;AAAA,EACV,YAA0C,EAAC;AAAA,EAC3C,aAAA,GAAyB,IAAA;AAAA,EACzB,QAAA,GAAW,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMnB,SAAA,GAAqB;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,OAAA,EAAyC;AAExD,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,OAAO,EAAE,CAAA;AAChD,IAAA,IAAA,CAAK,YAAY,EAAC;AAClB,IAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AACrB,IAAA,IAAA,CAAK,QAAA,GAAW,CAAA;AAAA,EAClB;AAAA,EAEA,MAAM,eAAe,IAAA,EAAqC;AACxD,IAAA,IAAA,CAAK,WAAW,IAAA,CAAK,MAAA;AAGrB,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,MAAM,UAAU,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,EAAG,IAAI,KAAK,CAAA,CAAA;AAC3C,MAAA,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA,GAAI,GAAA;AAAA,IAC5B;AAGA,IAAA,OAAA,CAAQ,IAAI,uCAAuC,CAAA;AACnD,IAAA,MAAMC,YAAAA,GAAc,gBAAA,CAAiB,IAAA,EAAM,IAAA,CAAK,OAAO,CAAA;AACvD,IAAA,IAAA,CAAK,aAAA,GAAgB,MAAM,iBAAA,CAAkBA,YAAW,CAAA;AACxD,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,qBAAA,EAAwB,IAAA,CAAK,QAAQ,CAAA,UAAA,CAAY,CAAA;AAAA,EAC/D;AAAA,EAEA,MAAM,QAAA,GAA0C;AAC9C,IAAA,MAAM,SAAA,uBAAgB,GAAA,EAAqB;AAG3C,IAAA,SAAA,CAAU,GAAA,CAAI,WAAA,EAAa,IAAA,CAAK,SAAS,CAAA;AAGzC,IAAA,SAAA,CAAU,GAAA,CAAI,mBAAA,EAAqB,IAAA,CAAK,aAAa,CAAA;AAErD,IAAA,OAAO,SAAA;AAAA,EACT;AAAA,EAEA,MAAM,eAAA,GAAoD;AACxD,IAAA,OAAO;AAAA,MACL,YAAA,EAAc;AAAA,KAChB;AAAA,EACF;AACF;AChDO,IAAM,qBAAN,MAAmD;AAAA,EAC/C,IAAA,GAAO,YAAA;AAAA,EAER,IAAA,GAA4C,IAAA;AAAA,EAC5C,WAAA,GAAyC,IAAA;AAAA,EACzC,KAAA,GAAQ,KAAA;AAAA,EAEhB,MAAM,UAAA,CAAW,QAAA,EAA2B,QAAA,EAAkD;AAC5F,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,MAAM,IAAI,MAAM,sEAAsE,CAAA;AAAA,IACxF;AAGA,IAAA,IAAI,QAAA,CAAS,IAAA,IAAQ,QAAA,CAAS,SAAA,EAAW;AACvC,MAAA,IAAA,CAAK,OAAO,QAAA,CAAS,IAAA;AACrB,MAAA,IAAA,CAAK,WAAA,GAAc,MAAM,iBAAA,CAAkB,QAAA,CAAS,SAAoC,CAAA;AACxF,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,MAAA;AAAA,IACF;AAGA,IAAA,IAAI,QAAA,CAAS,QAAA,IAAY,QAAA,CAAS,SAAA,EAAW;AAC3C,MAAA,IAAI,MAAMZ,oBAAAA,CAAG,UAAA,CAAW,QAAA,CAAS,QAAQ,CAAA,EAAG;AAC1C,QAAA,IAAA,CAAK,IAAA,GAAO,MAAMA,oBAAAA,CAAG,QAAA,CAAS,SAAS,QAAQ,CAAA;AAAA,MACjD,CAAA,MAAO;AACL,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,QAAA,CAAS,QAAQ,CAAA,CAAE,CAAA;AAAA,MAC1E;AAEA,MAAA,IAAI,MAAMA,oBAAAA,CAAG,UAAA,CAAW,QAAA,CAAS,SAAS,CAAA,EAAG;AAC3C,QAAA,MAAM,SAAA,GAAY,MAAMA,oBAAAA,CAAG,QAAA,CAAS,SAAS,SAAS,CAAA;AACtD,QAAA,IAAA,CAAK,WAAA,GAAc,MAAM,iBAAA,CAAkB,SAAS,CAAA;AAAA,MACtD,CAAA,MAAO;AACL,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qCAAA,EAAwC,QAAA,CAAS,SAAS,CAAA,CAAE,CAAA;AAAA,MAC9E;AAEA,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAAA,EAEA,OAAA,GAAmB;AACjB,IAAA,OAAO,KAAK,KAAA,IAAS,IAAA,CAAK,IAAA,KAAS,IAAA,IAAQ,KAAK,WAAA,KAAgB,IAAA;AAAA,EAClE;AAAA,EAEA,MAAM,MAAA,CAAO,KAAA,EAAe,OAAA,EAAkD;AAC5E,IAAA,IAAI,CAAC,KAAK,OAAA,EAAQ,IAAK,CAAC,IAAA,CAAK,IAAA,IAAQ,CAAC,IAAA,CAAK,WAAA,EAAa;AACtD,MAAA,MAAM,IAAI,MAAM,uCAAuC,CAAA;AAAA,IACzD;AAEA,IAAA,MAAM,KAAA,GAAQ,SAAS,KAAA,IAAS,CAAA;AAChC,IAAA,OAAO,WAAA,CAAY,KAAK,WAAA,EAAa,IAAA,CAAK,MAAM,KAAA,EAAO,EAAE,OAAO,CAAA;AAAA,EAClE;AAAA,EAEA,MAAM,YAAY,GAAA,EAA2C;AAC3D,IAAA,IAAI,CAAC,KAAK,IAAA,EAAM;AACd,MAAA,MAAM,IAAI,MAAM,uCAAuC,CAAA;AAAA,IACzD;AAGA,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA,IAAK,IAAA;AAAA,EAC3B;AAAA,EAEA,MAAM,WAAA,GAA+D;AACnE,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,EAAQ,EAAG;AACnB,MAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,OAAA,EAAS,qCAAA,EAAsC;AAAA,IAC1E;AAEA,IAAA,MAAM,QAAA,GAAW,KAAK,IAAA,GAAO,MAAA,CAAO,KAAK,IAAA,CAAK,IAAI,EAAE,MAAA,GAAS,CAAA;AAC7D,IAAA,OAAO;AAAA,MACL,OAAA,EAAS,IAAA;AAAA,MACT,OAAA,EAAS,kCAAkC,QAAQ,CAAA,UAAA;AAAA,KACrD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,GAA+C;AAC7C,IAAA,OAAO,IAAA,CAAK,IAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,cAAA,GAA4C;AAC1C,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EACd;AACF;;;ACxFA,eAAsB,YAAY,SAAA,EAA4C;AAE5E,EAAA,IAAI,cAAc,YAAA,EAAc;AAC9B,IAAA,OAAO,IAAI,iBAAA,EAAkB;AAAA,EAC/B;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,OAAO,SAAA,CAAA;AAC5B,IAAA,MAAM,eAAe,MAAA,CAAO,OAAA;AAE5B,IAAA,IAAI,OAAO,iBAAiB,UAAA,EAAY;AAEtC,MAAA,MAAM,QAAA,GAAW,IAAI,YAAA,EAAa;AAElC,MAAA,IAAI,CAAC,gBAAA,CAAiB,QAAQ,CAAA,EAAG;AAC/B,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,2BAA2B,SAAS,CAAA,8CAAA;AAAA,SACtC;AAAA,MACF;AAEA,MAAA,OAAO,QAAA;AAAA,IACT;AAEA,IAAA,IAAI,gBAAA,CAAiB,YAAY,CAAA,EAAG;AAClC,MAAA,OAAO,YAAA;AAAA,IACT;AAEA,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,2BAA2B,SAAS,CAAA,yDAAA;AAAA,KACtC;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,iBAAiB,KAAA,IAAS,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,oBAAoB,CAAA,EAAG;AAC1E,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,SAAS,CAAA,kCAAA,CAAoC,CAAA;AAAA,IAC7F;AACA,IAAA,MAAM,KAAA;AAAA,EACR;AACF;AAqBA,eAAsB,mBAAmB,SAAA,EAA4C;AACnF,EAAA,IAAI,cAAc,YAAA,EAAc;AAC9B,IAAA,OAAO,IAAI,kBAAA,EAAmB;AAAA,EAChC;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,OAAO,SAAA,CAAA;AAC5B,IAAA,MAAM,gBAAgB,MAAA,CAAO,OAAA;AAE7B,IAAA,IAAI,OAAO,kBAAkB,UAAA,EAAY;AACvC,MAAA,MAAM,QAAA,GAAW,IAAI,aAAA,EAAc;AAEnC,MAAA,IAAI,CAAC,gBAAA,CAAiB,QAAQ,CAAA,EAAG;AAC/B,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,mCAAmC,SAAS,CAAA,8CAAA;AAAA,SAC9C;AAAA,MACF;AAEA,MAAA,OAAO,QAAA;AAAA,IACT;AAEA,IAAA,IAAI,gBAAA,CAAiB,aAAa,CAAA,EAAG;AACnC,MAAA,OAAO,aAAA;AAAA,IACT;AAEA,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,mCAAmC,SAAS,CAAA,yDAAA;AAAA,KAC9C;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,iBAAiB,KAAA,IAAS,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,oBAAoB,CAAA,EAAG;AAC1E,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,sCAAsC,SAAS,CAAA,kCAAA;AAAA,OACjD;AAAA,IACF;AACA,IAAA,MAAM,KAAA;AAAA,EACR;AACF;AAKA,SAAS,iBAAiB,GAAA,EAAqC;AAC7D,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,EAAU;AACnC,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,GAAA;AAChB,EAAA,OACE,OAAO,OAAA,CAAQ,IAAA,KAAS,QAAA,IACxB,OAAO,OAAA,CAAQ,UAAA,KAAe,UAAA,IAC9B,OAAO,OAAA,CAAQ,cAAA,KAAmB,UAAA,IAClC,OAAO,QAAQ,QAAA,KAAa,UAAA;AAEhC;AAKA,SAAS,iBAAiB,GAAA,EAAqC;AAC7D,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,EAAU;AACnC,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAA,GAAW,GAAA;AACjB,EAAA,OACE,OAAO,QAAA,CAAS,IAAA,KAAS,QAAA,IACzB,OAAO,QAAA,CAAS,UAAA,KAAe,UAAA,IAC/B,OAAO,QAAA,CAAS,OAAA,KAAY,UAAA,IAC5B,OAAO,SAAS,MAAA,KAAW,UAAA;AAE/B;;;ACjIA,SAAS,eAAe,OAAA,EAAwD;AAC9E,EAAA,OAAO;AAAA,IACL,GAAG,eAAA;AAAA,IACH,GAAG,OAAA;AAAA,IACH,MAAA,EAAQ;AAAA,MACN,GAAG,eAAA,CAAgB,MAAA;AAAA,MACnB,GAAG,OAAA,CAAQ;AAAA;AACb,GACF;AACF;AAcA,eAAe,eAAA,CACb,QAAA,EACA,KAAA,EACA,OAAA,EAC8B;AAC9B,EAAA,IAAI;AAEF,IAAA,MAAM,cAAA,GAAwC;AAAA,MAC5C,kBAAkB,OAAA,CAAQ,gBAAA;AAAA,MAC1B,kBAAkB,OAAA,CAAQ;AAAA,KAC5B;AACA,IAAA,MAAM,SAAA,GAAY,MAAM,cAAA,CAAe,QAAA,EAAU,cAAc,CAAA;AAE/D,IAAA,IAAI,CAAC,UAAU,WAAA,EAAa;AAC1B,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,0BAAA,EAA6B,QAAQ,CAAA,CAAE,CAAA;AACpD,MAAA,OAAO,IAAA;AAAA,IACT;AAGA,IAAA,MAAM,QAAA,GAAW,MAAM,cAAA,CAAe,SAAA,CAAU,WAAW,CAAA;AAE3D,IAAA,IAAI,CAAC,QAAA,IAAY,QAAA,CAAS,MAAK,CAAE,MAAA,GAAS,QAAQ,gBAAA,EAAkB;AAClE,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,8BAAA,EAAiC,QAAQ,CAAA,CAAE,CAAA;AACxD,MAAA,OAAO,IAAA;AAAA,IACT;AAGA,IAAA,MAAM,QAAA,GAAW,4BAA4B,QAAQ,CAAA;AAErD,IAAA,OAAO;AAAA,MACL,KAAA;AAAA,MACA,OAAO,SAAA,CAAU,KAAA;AAAA,MACjB,aAAa,SAAA,CAAU,WAAA;AAAA,MACvB,QAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,uBAAA,EAA0B,QAAQ,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AAC1D,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAKe,SAAR,eAAA,CACL,SACA,OAAA,EACQ;AACR,EAAA,MAAM,eAAA,GAAkB,eAAe,OAAO,CAAA;AAE9C,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,8BAAA;AAAA;AAAA,IAGN,MAAM,aAAA,CAAc,EAAE,OAAA,EAAQ,EAAG;AAC/B,MAAA,MAAM,EAAE,eAAc,GAAI,OAAA;AAG1B,MAAA,MAAM,YAAY,CAAA,EAAG,OAAA,CAAQ,WAAW,GAAG,CAAA,CAAA,EAAI,gBAAgB,SAAS,CAAA,CAAA;AAExE,MAAA,aAAA,CAAc;AAAA,QACZ,SAAA;AAAA,QACA,UAAA,EAAY,gBAAgB,MAAA,CAAO;AAAA,OACpC,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,MAAM,SAAA,CAAU,EAAE,MAAA,EAAO,EAAG;AAC1B,MAAA,OAAA,CAAQ,IAAI,2CAA2C,CAAA;AACvD,MAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAG3B,MAAA,IAAI,eAAA,CAAgB,aAAa,KAAA,EAAO;AACtC,QAAA,OAAA,CAAQ,IAAI,uDAAuD,CAAA;AACnE,QAAA;AAAA,MACF;AAGA,MAAA,MAAM,MAAA,GAAS,MAAM,aAAA,CAAc,MAAA,EAAQ,gBAAgB,aAAa,CAAA;AACxE,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,YAAA,EAAe,MAAA,CAAO,MAAM,CAAA,kBAAA,CAAoB,CAAA;AAE5D,MAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,QAAA,OAAA,CAAQ,KAAK,kCAAkC,CAAA;AAC/C,QAAA;AAAA,MACF;AAGA,MAAA,MAAM,cAAA,GAAqC;AAAA,QACzC,kBAAkB,eAAA,CAAgB,gBAAA;AAAA,QAClC,kBAAkB,eAAA,CAAgB,gBAAA;AAAA,QAClC,kBAAkB,eAAA,CAAgB;AAAA,OACpC;AAEA,MAAA,MAAM,gBAAgB,MAAMa,qBAAA;AAAA,QAC1B,MAAA;AAAA,QACA,OAAO,KAAA,KAAU;AACf,UAAA,OAAO,eAAA,CAAgB,KAAA,CAAM,QAAA,EAAU,KAAA,CAAM,MAAM,cAAc,CAAA;AAAA,QACnE,CAAA;AAAA,QACA,EAAE,aAAa,EAAA;AAAG,OACpB;AAGA,MAAA,MAAM,YAAY,aAAA,CAAc,MAAA,CAAO,CAAC,GAAA,KAA6B,QAAQ,IAAI,CAAA;AACjF,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,6BAAA,EAAgC,SAAA,CAAU,MAAM,CAAA,UAAA,CAAY,CAAA;AAExE,MAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,QAAA,OAAA,CAAQ,KAAK,mCAAmC,CAAA;AAChD,QAAA;AAAA,MACF;AAGA,MAAA,MAAM,YAAA,GAAeZ,qBAAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,gBAAgB,SAAS,CAAA;AAChE,MAAA,MAAM,eAAA,GAAmC;AAAA,QACvC,OAAA,EAAS,QAAQ,UAAA,CAAW,GAAA;AAAA,QAC5B,UAAA,EAAY,gBAAgB,MAAA,CAAO,IAAA;AAAA,QACnC,aAAA,EAAe,gBAAgB,MAAA,CAAO,OAAA;AAAA,QACtC,SAAA,EAAW;AAAA,OACb;AAIA,MAAA,MAAM,YAAA,GAAe,eAAA,CAAgB,QAAA,IAAY,CAAC,YAAY,CAAA;AAE9D,MAAA,MAAMD,oBAAAA,CAAG,UAAU,YAAY,CAAA;AAE/B,MAAA,MAAM,eAAyB,EAAC;AAEhC,MAAA,KAAA,MAAW,eAAe,YAAA,EAAc;AACtC,QAAA,IAAI;AACF,UAAA,MAAM,OAAA,GAAU,MAAM,WAAA,CAAY,WAAW,CAAA;AAG7C,UAAA,IAAI,OAAA,CAAQ,SAAA,IAAa,CAAC,OAAA,CAAQ,WAAU,EAAG;AAC7C,YAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,wBAAA,EAA2B,OAAA,CAAQ,IAAI,CAAA,CAAE,CAAA;AACrD,YAAA;AAAA,UACF;AAEA,UAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,uBAAA,EAA0B,OAAA,CAAQ,IAAI,CAAA,CAAE,CAAA;AACpD,UAAA,MAAM,OAAA,CAAQ,WAAW,eAAe,CAAA;AACxC,UAAA,MAAM,OAAA,CAAQ,eAAe,SAAS,CAAA;AAGtC,UAAA,MAAM,SAAA,GAAY,MAAM,OAAA,CAAQ,QAAA,EAAS;AACzC,UAAA,KAAA,MAAW,CAAC,QAAA,EAAU,OAAO,CAAA,IAAK,SAAA,EAAW;AAC3C,YAAA,MAAMA,oBAAAA,CAAG,SAAA,CAAUC,qBAAAA,CAAK,IAAA,CAAK,YAAA,EAAc,QAAQ,CAAA,EAAG,OAAA,EAAS,EAAE,MAAA,EAAQ,CAAA,EAAG,CAAA;AAAA,UAC9E;AAEA,UAAA,YAAA,CAAa,IAAA,CAAK,QAAQ,IAAI,CAAA;AAAA,QAChC,SAAS,KAAA,EAAO;AACd,UAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,6BAAA,EAAgC,WAAW,CAAA,EAAA,CAAA,EAAM,KAAK,CAAA;AACpE,UAAA,MAAM,KAAA;AAAA,QACR;AAAA,MACF;AAGA,MAAA,IAAI,YAAA,CAAa,SAAS,CAAA,EAAG;AAC3B,QAAA,MAAM,QAAA,GAAwB;AAAA,UAC5B,OAAA,EAAS,gBAAgB,MAAA,CAAO,OAAA;AAAA,UAChC,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,UAClC,UAAU,SAAA,CAAU,MAAA;AAAA,UACpB,UAAA,EAAY,gBAAgB,MAAA,CAAO,IAAA;AAAA,UACnC,OAAA,EAAS,QAAQ,UAAA,CAAW,GAAA;AAAA,UAC5B,QAAA,EAAU;AAAA,SACZ;AAEA,QAAA,MAAMD,oBAAAA,CAAG,SAAA,CAAUC,qBAAAA,CAAK,IAAA,CAAK,YAAA,EAAc,eAAe,CAAA,EAAG,QAAA,EAAU,EAAE,MAAA,EAAQ,CAAA,EAAG,CAAA;AAAA,MACtF;AAEA,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAC7B,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,2BAAA,EAA8B,YAAY,CAAA,CAAE,CAAA;AACxD,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,6BAAA,EAAgC,OAAO,CAAA,EAAA,CAAI,CAAA;AAAA,IACzD;AAAA,GACF;AACF;AClNO,IAAM,qBAAA,GAAwB;AAAA,EACnC,KAAA,EAAOa,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,SAAS,yBAAyB,CAAA;AAAA,EAC3D,OAAOA,KAAA,CACJ,MAAA,GACA,GAAA,EAAI,CACJ,IAAI,CAAC,CAAA,CACL,GAAA,CAAI,EAAE,EACN,QAAA,EAAS,CACT,QAAQ,CAAC,CAAA,CACT,SAAS,wDAAwD;AACtE,CAAA;AAKO,IAAM,cAAA,GAAiB;AAAA,EAC5B,IAAA,EAAM,aAAA;AAAA,EACN,WAAA,EACE,2KAAA;AAAA,EACF,WAAA,EAAa;AACf;AA8BO,SAAS,oBAAoB,OAAA,EAAiC;AACnE,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,IAAA,OAAO,8BAAA;AAAA,EACT;AAEA,EAAA,MAAM,KAAA,GAAkB,CAAC,CAAA,MAAA,EAAS,OAAA,CAAQ,MAAM,CAAA;AAAA,CAAe,CAAA;AAE/D,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK;AACvC,IAAA,MAAM,MAAA,GAAS,QAAQ,CAAC,CAAA;AACxB,IAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,IAAA,KAAA,CAAM,KAAK,CAAA,EAAG,CAAA,GAAI,CAAC,CAAA,IAAA,EAAO,MAAA,CAAO,KAAK,CAAA,EAAA,CAAI,CAAA;AAC1C,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,QAAA,EAAW,MAAA,CAAO,GAAG,CAAA,CAAE,CAAA;AAElC,IAAA,IAAI,MAAA,CAAO,gBAAA,IAAoB,MAAA,CAAO,gBAAA,CAAiB,SAAS,CAAA,EAAG;AACjE,MAAA,KAAA,CAAM,KAAK,CAAA,sBAAA,EAAyB,MAAA,CAAO,iBAAiB,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,IAC1E;AAEA,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,GAAA,EAAM,MAAA,CAAO,OAAO,CAAA,CAAE,CAAA;AACjC,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AAEA,EAAA,KAAA,CAAM,KAAK,gEAAgE,CAAA;AAE3E,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AC5EO,IAAM,oBAAA,GAAuB;AAAA,EAClC,GAAA,EAAKA,KAAAA,CACF,MAAA,EAAO,CACP,KAAI,CACJ,QAAA;AAAA,IACC;AAAA;AAEN,CAAA;AAKO,IAAM,aAAA,GAAgB;AAAA,EAC3B,IAAA,EAAM,YAAA;AAAA,EACN,WAAA,EACE,mIAAA;AAAA,EACF,WAAA,EAAa;AACf;AAKO,SAAS,kBAAkB,GAAA,EAAkC;AAClE,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,OAAO,qDAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAkB,EAAC;AAGzB,EAAA,KAAA,CAAM,IAAA,CAAK,CAAA,EAAA,EAAK,GAAA,CAAI,KAAK,CAAA,CAAE,CAAA;AAC3B,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAGb,EAAA,IAAI,IAAI,WAAA,EAAa;AACnB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,EAAA,EAAK,GAAA,CAAI,WAAW,CAAA,CAAE,CAAA;AACjC,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AAGA,EAAA,IAAI,GAAA,CAAI,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG;AAC3B,IAAA,KAAA,CAAM,KAAK,aAAa,CAAA;AACxB,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,IAAA,KAAA,MAAW,OAAA,IAAW,IAAI,QAAA,EAAU;AAClC,MAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,QAAQ,CAAC,CAAA;AAC5C,QAAA,KAAA,CAAM,IAAA,CAAK,GAAG,MAAM,CAAA,GAAA,EAAM,QAAQ,IAAI,CAAA,GAAA,EAAM,OAAA,CAAQ,EAAE,CAAA,CAAA,CAAG,CAAA;AAAA,MAC3D;AAAA,IACF;AACA,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,IAAA,KAAA,CAAM,KAAK,KAAK,CAAA;AAChB,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AAGA,EAAA,KAAA,CAAM,IAAA,CAAK,IAAI,QAAQ,CAAA;AAEvB,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;;;ACzCA,SAAS,aAAa,MAAA,EAAwD;AAC5E,EAAA,OAAO,UAAA,IAAc,UAAU,WAAA,IAAe,MAAA;AAChD;AAKA,SAAS,aAAa,MAAA,EAAwD;AAC5E,EAAA,OAAO,MAAA,IAAU,UAAU,iBAAA,IAAqB,MAAA;AAClD;AAcO,IAAM,gBAAN,MAAoB;AAAA,EACjB,MAAA;AAAA,EACA,cAAA,GAAwC,IAAA;AAAA,EACxC,SAAA;AAAA,EACA,WAAA,GAAc,KAAA;AAAA,EAEtB,YAAY,MAAA,EAAyB;AACnC,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAEd,IAAA,IAAA,CAAK,YAAY,IAAIC,gBAAA;AAAA,MACnB;AAAA,QACE,MAAM,MAAA,CAAO,IAAA;AAAA,QACb,OAAA,EAAS,OAAO,OAAA,IAAW;AAAA,OAC7B;AAAA,MACA;AAAA,QACE,YAAA,EAAc;AAAA,UACZ,OAAO;AAAC;AACV;AACF,KACF;AAEA,IAAA,IAAA,CAAK,aAAA,EAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAA,GAAsB;AAE5B,IAAA,IAAA,CAAK,SAAA,CAAU,YAAA;AAAA,MACb,cAAA,CAAe,IAAA;AAAA,MACf;AAAA,QACE,aAAa,cAAA,CAAe,WAAA;AAAA,QAC5B,aAAa,cAAA,CAAe;AAAA,OAC9B;AAAA,MACA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAM,KAAM;AAC1B,QAAA,MAAM,KAAK,UAAA,EAAW;AAEtB,QAAA,IAAI,CAAC,IAAA,CAAK,cAAA,IAAkB,CAAC,IAAA,CAAK,cAAA,CAAe,SAAQ,EAAG;AAC1D,UAAA,OAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,MAAA,EAAiB,IAAA,EAAM,6CAA6C,CAAA;AAAA,YACtF,OAAA,EAAS;AAAA,WACX;AAAA,QACF;AAEA,QAAA,IAAI;AACF,UAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,cAAA,CAAe,OAAO,KAAA,EAAO,EAAE,OAAO,CAAA;AACjE,UAAA,OAAO;AAAA,YACL,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,QAAiB,IAAA,EAAM,mBAAA,CAAoB,OAAO,CAAA,EAAG;AAAA,WACzE;AAAA,QACF,SAAS,KAAA,EAAO;AACd,UAAA,OAAA,CAAQ,KAAA,CAAM,uBAAuB,KAAK,CAAA;AAC1C,UAAA,OAAO;AAAA,YACL,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAiB,IAAA,EAAM,CAAA,cAAA,EAAiB,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA,EAAI,CAAA;AAAA,YAC3E,OAAA,EAAS;AAAA,WACX;AAAA,QACF;AAAA,MACF;AAAA,KACF;AAGA,IAAA,IAAA,CAAK,SAAA,CAAU,YAAA;AAAA,MACb,aAAA,CAAc,IAAA;AAAA,MACd;AAAA,QACE,aAAa,aAAA,CAAc,WAAA;AAAA,QAC3B,aAAa,aAAA,CAAc;AAAA,OAC7B;AAAA,MACA,OAAO,EAAE,GAAA,EAAI,KAAM;AACjB,QAAA,MAAM,KAAK,UAAA,EAAW;AAEtB,QAAA,IAAI,CAAC,IAAA,CAAK,cAAA,IAAkB,CAAC,IAAA,CAAK,cAAA,CAAe,SAAQ,EAAG;AAC1D,UAAA,OAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,MAAA,EAAiB,IAAA,EAAM,6CAA6C,CAAA;AAAA,YACtF,OAAA,EAAS;AAAA,WACX;AAAA,QACF;AAEA,QAAA,IAAI;AACF,UAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA;AACtC,UAAA,OAAO;AAAA,YACL,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,QAAiB,IAAA,EAAM,iBAAA,CAAkB,GAAG,CAAA,EAAG;AAAA,WACnE;AAAA,QACF,SAAS,KAAA,EAAO;AACd,UAAA,OAAA,CAAQ,KAAA,CAAM,sBAAsB,KAAK,CAAA;AACzC,UAAA,OAAO;AAAA,YACL,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAiB,IAAA,EAAM,CAAA,qBAAA,EAAwB,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA,EAAI,CAAA;AAAA,YAClF,OAAA,EAAS;AAAA,WACX;AAAA,QACF;AAAA,MACF;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,YAAY,GAAA,EAA2C;AACnE,IAAA,IAAI,CAAC,KAAK,cAAA,EAAgB;AACxB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,IAAI,IAAA,CAAK,eAAe,WAAA,EAAa;AACnC,MAAA,OAAO,IAAA,CAAK,cAAA,CAAe,WAAA,CAAY,GAAG,CAAA;AAAA,IAC5C;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,UAAA,GAA4B;AAChC,IAAA,IAAI,KAAK,WAAA,EAAa;AACpB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI;AAEF,MAAA,MAAM,eAAA,GAAkB,IAAA,CAAK,MAAA,CAAO,MAAA,IAAU,YAAA;AAC9C,MAAA,IAAA,CAAK,cAAA,GAAiB,MAAM,kBAAA,CAAmB,eAAe,CAAA;AAG9D,MAAA,MAAM,eAAA,GAAmC;AAAA,QACvC,OAAA,EAAS,IAAA,CAAK,MAAA,CAAO,OAAA,IAAW,EAAA;AAAA,QAChC,UAAA,EAAY,KAAK,MAAA,CAAO,IAAA;AAAA,QACxB,aAAA,EAAe,IAAA,CAAK,MAAA,CAAO,OAAA,IAAW,OAAA;AAAA,QACtC,SAAA,EAAW;AAAA;AAAA,OACb;AAGA,MAAA,MAAM,WAAmC,EAAC;AAE1C,MAAA,IAAI,YAAA,CAAa,IAAA,CAAK,MAAM,CAAA,EAAG;AAE7B,QAAA,QAAA,CAAS,IAAA,GAAO,KAAK,MAAA,CAAO,IAAA;AAC5B,QAAA,QAAA,CAAS,SAAA,GAAY,KAAK,MAAA,CAAO,eAAA;AAAA,MACnC,CAAA,MAAA,IAAW,YAAA,CAAa,IAAA,CAAK,MAAM,CAAA,EAAG;AAEpC,QAAA,QAAA,CAAS,QAAA,GAAW,KAAK,MAAA,CAAO,QAAA;AAChC,QAAA,QAAA,CAAS,SAAA,GAAY,KAAK,MAAA,CAAO,SAAA;AAAA,MACnC,CAAA,MAAO;AACL,QAAA,MAAM,IAAI,MAAM,0EAA0E,CAAA;AAAA,MAC5F;AAGA,MAAA,MAAM,IAAA,CAAK,cAAA,CAAe,UAAA,CAAW,eAAA,EAAiB,QAAQ,CAAA;AAE9D,MAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAAA,IACrB,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,+BAA+B,KAAK,CAAA;AAClD,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,iBAAA,CACJ,GAAA,EACA,GAAA,EACA,UAAA,EACe;AACf,IAAA,MAAM,KAAK,UAAA,EAAW;AAItB,IAAA,MAAM,SAAA,GAAY,IAAIC,+CAAA,CAA8B;AAAA,MAClD,kBAAA,EAAoB,MAAA;AAAA;AAAA,MACpB,kBAAA,EAAoB;AAAA;AAAA,KACrB,CAAA;AAGD,IAAA,MAAM,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,SAAS,CAAA;AAEtC,IAAA,IAAI;AAEF,MAAA,MAAM,SAAA,CAAU,aAAA,CAAc,GAAA,EAAK,GAAA,EAAK,UAAU,CAAA;AAAA,IACpD,CAAA,SAAE;AAEA,MAAA,MAAM,UAAU,KAAA,EAAM;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,iBAAiB,OAAA,EAAqC;AAC1D,IAAA,MAAM,KAAK,UAAA,EAAW;AAGtB,IAAA,MAAM,SAAA,GAAY,IAAIC,qEAAA,CAAyC;AAAA,MAC7D,kBAAA,EAAoB,MAAA;AAAA;AAAA,MACpB,kBAAA,EAAoB;AAAA,KACrB,CAAA;AAGD,IAAA,MAAM,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,SAAS,CAAA;AAEtC,IAAA,IAAI;AAEF,MAAA,OAAO,MAAM,SAAA,CAAU,aAAA,CAAc,OAAO,CAAA;AAAA,IAC9C,CAAA,SAAE;AAEA,MAAA,MAAM,UAAU,KAAA,EAAM;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SAAA,GAOH;AACD,IAAA,IAAI,QAAA,GAAW,CAAA;AAGf,IAAA,IAAI,IAAA,CAAK,0BAA0B,kBAAA,EAAoB;AACrD,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,cAAA,CAAe,OAAA,EAAQ;AACzC,MAAA,QAAA,GAAW,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,IAAI,EAAE,MAAA,GAAS,CAAA;AAAA,IAC/C;AAEA,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,KAAK,MAAA,CAAO,IAAA;AAAA,MAClB,OAAA,EAAS,IAAA,CAAK,MAAA,CAAO,OAAA,IAAW,OAAA;AAAA,MAChC,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,QAAA;AAAA,MACA,OAAA,EAAS,KAAK,MAAA,CAAO,OAAA;AAAA,MACrB,cAAA,EAAgB,KAAK,cAAA,EAAgB;AAAA,KACvC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAA,GAA0B;AACxB,IAAA,OAAO,IAAA,CAAK,SAAA;AAAA,EACd;AACF","file":"index.js","sourcesContent":["/**\n * Configuration options for the MCP server plugin\n */\nexport interface McpServerPluginOptions {\n /** Output directory for MCP artifacts (relative to build dir). Default: 'mcp' */\n outputDir?: string;\n /** CSS selectors for content extraction, in order of priority */\n contentSelectors?: string[];\n /** CSS selectors for elements to remove from content before processing */\n excludeSelectors?: string[];\n /** Minimum content length (in characters) to consider a page valid. Default: 50 */\n minContentLength?: number;\n /** Server configuration */\n server?: {\n /** Name of the MCP server */\n name?: string;\n /** Version of the MCP server */\n version?: string;\n };\n /** Routes to exclude from processing (glob patterns) */\n excludeRoutes?: string[];\n\n /**\n * Indexers to run during build.\n *\n * - undefined (default): runs 'flexsearch' for backward compatibility\n * - ['flexsearch']: same as default, produces docs.json + search-index.json\n * - ['./my-indexer.js']: runs only custom indexer(s)\n * - false: disables all indexing, no artifacts produced\n *\n * Each string can be:\n * - 'flexsearch' (built-in)\n * - './path/to/indexer.js' (relative path)\n * - '@myorg/custom-indexer' (npm package)\n */\n indexers?: string[] | false;\n\n /**\n * Search provider module. Default: 'flexsearch'\n *\n * Can be:\n * - 'flexsearch' (built-in, requires FlexSearch indexer to have run)\n * - './path/to/search.js' (relative path)\n * - '@myorg/glean-search' (npm package)\n */\n search?: string;\n}\n\n/**\n * Resolved plugin options with defaults applied\n */\nexport interface ResolvedPluginOptions {\n outputDir: string;\n contentSelectors: string[];\n excludeSelectors: string[];\n minContentLength: number;\n server: {\n name: string;\n version: string;\n };\n excludeRoutes: string[];\n /** Indexers to run. undefined means ['flexsearch'], false disables indexing */\n indexers: string[] | false | undefined;\n /** Search provider module */\n search: string;\n}\n\n/**\n * A processed documentation page\n */\nexport interface ProcessedDoc {\n /** URL route path (e.g., /docs/getting-started) */\n route: string;\n /** Page title extracted from HTML */\n title: string;\n /** Meta description if available */\n description: string;\n /** Full page content as markdown */\n markdown: string;\n /** Headings with IDs for section navigation */\n headings: DocHeading[];\n}\n\n/**\n * A heading within a document\n */\nexport interface DocHeading {\n /** Heading level (1-6) */\n level: number;\n /** Heading text content */\n text: string;\n /** Anchor ID for linking */\n id: string;\n /** Character offset where this section starts in the markdown */\n startOffset: number;\n /** Character offset where this section ends in the markdown */\n endOffset: number;\n}\n\n/**\n * A flattened route from Docusaurus\n */\nexport interface FlattenedRoute {\n /** The URL path */\n path: string;\n /** Path to the corresponding HTML file */\n htmlPath: string;\n}\n\n/**\n * Search result from FlexSearch\n */\nexport interface SearchResult {\n /** Full URL of the matching document (use this with docs_fetch) */\n url: string;\n /** Route path of the matching document */\n route: string;\n /** Title of the document */\n title: string;\n /** Relevance score */\n score: number;\n /** Snippet of matching content */\n snippet: string;\n /** Matching headings if any */\n matchingHeadings?: string[];\n}\n\n/**\n * Manifest metadata for the MCP artifacts\n */\nexport interface McpManifest {\n /** Plugin version */\n version: string;\n /** Build timestamp */\n buildTime: string;\n /** Number of documents indexed */\n docCount: number;\n /** Server name */\n serverName: string;\n /** Base URL of the documentation site */\n baseUrl?: string;\n /** Names of indexers that ran during build */\n indexers?: string[];\n}\n\n/**\n * MCP Server configuration for file-based loading\n */\nexport interface McpServerFileConfig {\n /** Path to docs.json file */\n docsPath: string;\n /** Path to search-index.json file */\n indexPath: string;\n /** Server name */\n name: string;\n /** Server version */\n version?: string;\n /** Base URL for constructing full page URLs (e.g., https://docs.example.com) */\n baseUrl?: string;\n /** Search provider module. Default: 'flexsearch' */\n search?: string;\n}\n\n/**\n * MCP Server configuration for pre-loaded data (e.g., Cloudflare Workers)\n */\nexport interface McpServerDataConfig {\n /** Pre-loaded docs data */\n docs: Record<string, ProcessedDoc>;\n /** Pre-loaded search index data (exported from FlexSearch via exportSearchIndex) */\n searchIndexData: Record<string, unknown>;\n /** Server name */\n name: string;\n /** Server version */\n version?: string;\n /** Base URL for constructing full page URLs (e.g., https://docs.example.com) */\n baseUrl?: string;\n /** Search provider module. Default: 'flexsearch' */\n search?: string;\n}\n\n/**\n * MCP Server configuration - supports both file-based and pre-loaded data modes\n */\nexport type McpServerConfig = McpServerFileConfig | McpServerDataConfig;\n\n/**\n * Internal representation of the docs index\n */\nexport interface DocsIndex {\n /** All processed documents keyed by route */\n docs: Record<string, ProcessedDoc>;\n /** Manifest metadata */\n manifest: McpManifest;\n}\n\n/**\n * Input parameters for docs_search tool\n */\nexport interface DocsSearchParams {\n /** Search query string */\n query: string;\n /** Maximum number of results (default: 5, max: 20) */\n limit?: number;\n}\n\n/**\n * Input parameters for docs_fetch tool\n */\nexport interface DocsFetchParams {\n /** Full URL of the page to fetch */\n url: string;\n}\n\n/**\n * Content extraction result from HTML\n */\nexport interface ExtractedContent {\n /** Page title */\n title: string;\n /** Meta description */\n description: string;\n /** Main content as HTML */\n contentHtml: string;\n}\n\n/**\n * Default plugin options\n */\nexport const DEFAULT_OPTIONS: ResolvedPluginOptions = {\n outputDir: 'mcp',\n contentSelectors: ['article', 'main', '.main-wrapper', '[role=\"main\"]'],\n excludeSelectors: [\n 'nav',\n 'header',\n 'footer',\n 'aside',\n '[role=\"navigation\"]',\n '[role=\"banner\"]',\n '[role=\"contentinfo\"]',\n ],\n minContentLength: 50,\n server: {\n name: 'docs-mcp-server',\n version: '1.0.0',\n },\n excludeRoutes: ['/404*', '/search*'],\n indexers: undefined, // Default: ['flexsearch'] applied at runtime\n search: 'flexsearch',\n};\n","import path from 'path';\nimport fs from 'fs-extra';\nimport type { RouteConfig } from '@docusaurus/types';\nimport type { FlattenedRoute } from '../types/index.js';\n\n/**\n * Flatten nested Docusaurus routes into a simple array\n */\nexport function flattenRoutes(routes: RouteConfig[]): FlattenedRoute[] {\n const flattened: FlattenedRoute[] = [];\n\n function traverse(route: RouteConfig): void {\n // Add the route if it has a path\n if (route.path) {\n flattened.push({\n path: route.path,\n htmlPath: '', // Will be resolved later\n });\n }\n\n // Recursively process child routes\n if (route.routes && Array.isArray(route.routes)) {\n for (const childRoute of route.routes) {\n traverse(childRoute);\n }\n }\n }\n\n for (const route of routes) {\n traverse(route);\n }\n\n return flattened;\n}\n\n/**\n * Convert a URL path to the corresponding HTML file path in the build directory\n *\n * Examples:\n * - /guides/chat/overview -> build/guides/chat/overview/index.html\n * - / -> build/index.html\n * - /api -> build/api/index.html\n */\nexport function routeToHtmlPath(routePath: string, outDir: string): string {\n // Normalize the route path\n let normalizedPath = routePath;\n\n // Remove trailing slash if present (except for root)\n if (normalizedPath.length > 1 && normalizedPath.endsWith('/')) {\n normalizedPath = normalizedPath.slice(0, -1);\n }\n\n // Handle root path\n if (normalizedPath === '/') {\n return path.join(outDir, 'index.html');\n }\n\n // For all other paths, append /index.html\n return path.join(outDir, normalizedPath, 'index.html');\n}\n\n/**\n * Filter out routes that should not be processed\n */\nexport function filterRoutes(\n routes: FlattenedRoute[],\n excludePatterns: string[]\n): FlattenedRoute[] {\n return routes.filter((route) => {\n return !excludePatterns.some((pattern) => {\n // Convert glob pattern to regex\n const regexPattern = pattern.replace(/\\*/g, '.*').replace(/\\?/g, '.');\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(route.path);\n });\n });\n}\n\n/**\n * Discover all HTML files in the build directory and create routes for them.\n * This is more reliable than using Docusaurus routes as it captures all built pages.\n */\nexport async function discoverHtmlFiles(outDir: string): Promise<FlattenedRoute[]> {\n const routes: FlattenedRoute[] = [];\n\n async function scanDirectory(dir: string): Promise<void> {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip common non-content directories\n if (['assets', 'img', 'static'].includes(entry.name)) {\n continue;\n }\n await scanDirectory(fullPath);\n } else if (entry.name === 'index.html') {\n // Convert file path back to route\n const relativePath = path.relative(outDir, fullPath);\n let routePath = '/' + path.dirname(relativePath).replace(/\\\\/g, '/');\n\n // Handle root index.html\n if (routePath === '/.') {\n routePath = '/';\n }\n\n routes.push({\n path: routePath,\n htmlPath: fullPath,\n });\n }\n }\n }\n\n await scanDirectory(outDir);\n return routes;\n}\n\n/**\n * Resolve HTML paths for flattened routes, filtering out those that don't exist\n */\nexport async function resolveHtmlPaths(\n routes: FlattenedRoute[],\n outDir: string\n): Promise<FlattenedRoute[]> {\n const resolved: FlattenedRoute[] = [];\n\n for (const route of routes) {\n const htmlPath = routeToHtmlPath(route.path, outDir);\n\n if (await fs.pathExists(htmlPath)) {\n resolved.push({\n ...route,\n htmlPath,\n });\n }\n }\n\n return resolved;\n}\n\n/**\n * Get all processable routes from the build directory\n */\nexport async function collectRoutes(\n outDir: string,\n excludePatterns: string[]\n): Promise<FlattenedRoute[]> {\n // Discover all HTML files in the build directory\n const allRoutes = await discoverHtmlFiles(outDir);\n\n // Filter out excluded routes\n const filteredRoutes = filterRoutes(allRoutes, excludePatterns);\n\n // Deduplicate routes by path\n const uniqueRoutes = new Map<string, FlattenedRoute>();\n for (const route of filteredRoutes) {\n if (!uniqueRoutes.has(route.path)) {\n uniqueRoutes.set(route.path, route);\n }\n }\n\n return Array.from(uniqueRoutes.values());\n}\n","import fs from 'fs-extra';\nimport { unified } from 'unified';\nimport rehypeParse from 'rehype-parse';\nimport { select } from 'hast-util-select';\nimport { toString } from 'hast-util-to-string';\nimport { toHtml } from 'hast-util-to-html';\nimport type { Root, Element } from 'hast';\nimport type { ExtractedContent } from '../types/index.js';\n\n/**\n * Parse HTML string into HAST (HTML AST)\n */\nexport function parseHtml(html: string): Root {\n const processor = unified().use(rehypeParse);\n return processor.parse(html);\n}\n\n/**\n * Parse HTML file into HAST\n */\nexport async function parseHtmlFile(filePath: string): Promise<Root> {\n const html = await fs.readFile(filePath, 'utf-8');\n return parseHtml(html);\n}\n\n/**\n * Extract page title from the HTML document\n *\n * Uses h1 as primary source (most reliable for page title),\n * falls back to <title> tag if no h1 is found.\n */\nexport function extractTitle(tree: Root): string {\n // Prefer h1 as it's the actual page heading\n const h1Element = select('h1', tree);\n if (h1Element) {\n return toString(h1Element).trim();\n }\n\n // Fall back to title tag\n const titleElement = select('title', tree);\n if (titleElement) {\n return toString(titleElement).trim();\n }\n\n return 'Untitled';\n}\n\n/**\n * Extract meta description from the HTML document\n */\nexport function extractDescription(tree: Root): string {\n const metaDescription = select('meta[name=\"description\"]', tree) as Element | null;\n if (metaDescription && metaDescription.properties?.content) {\n return String(metaDescription.properties.content);\n }\n\n // Try og:description as fallback\n const ogDescription = select('meta[property=\"og:description\"]', tree) as Element | null;\n if (ogDescription && ogDescription.properties?.content) {\n return String(ogDescription.properties.content);\n }\n\n return '';\n}\n\n/**\n * Find the main content element using CSS selectors in priority order\n */\nexport function findContentElement(tree: Root, selectors: string[]): Element | null {\n for (const selector of selectors) {\n const element = select(selector, tree) as Element | null;\n if (element) {\n // Verify the element has meaningful content\n const text = toString(element).trim();\n if (text.length > 50) {\n return element;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Always-excluded elements that should never appear in content\n */\nconst ALWAYS_EXCLUDED = ['script', 'style', 'noscript'];\n\n/**\n * Remove unwanted elements from content\n *\n * @param element - The HAST element to clean\n * @param excludeSelectors - CSS selectors for elements to remove (tag names or .class-names)\n */\nexport function cleanContentElement(element: Element, excludeSelectors: string[]): Element {\n const allSelectors = [...ALWAYS_EXCLUDED, ...excludeSelectors];\n\n // Deep clone the element to avoid mutating the original\n const cloned = JSON.parse(JSON.stringify(element)) as Element;\n\n function removeUnwanted(node: Element): void {\n if (!node.children) return;\n\n node.children = node.children.filter((child) => {\n if (child.type !== 'element') return true;\n\n const childElement = child as Element;\n\n // Check if this element matches any unwanted selectors\n for (const selector of allSelectors) {\n if (selector.startsWith('.')) {\n // Class selector\n const className = selector.slice(1);\n const classes = childElement.properties?.className;\n if (Array.isArray(classes) && classes.includes(className)) {\n return false;\n }\n if (typeof classes === 'string' && classes.includes(className)) {\n return false;\n }\n } else if (selector.startsWith('[')) {\n // Attribute selector like [role=\"navigation\"]\n const match = selector.match(/\\[([^=]+)=\"([^\"]+)\"\\]/);\n if (match) {\n const [, attr, value] = match;\n if (attr && childElement.properties?.[attr] === value) {\n return false;\n }\n }\n } else {\n // Tag selector\n if (childElement.tagName === selector) {\n return false;\n }\n }\n }\n\n // Recursively clean children\n removeUnwanted(childElement);\n return true;\n });\n }\n\n removeUnwanted(cloned);\n return cloned;\n}\n\n/**\n * Options for content extraction\n */\nexport interface ExtractContentOptions {\n /** CSS selectors for content containers, in priority order */\n contentSelectors: string[];\n /** CSS selectors for elements to exclude from content */\n excludeSelectors: string[];\n}\n\n/**\n * Extract content from HTML file\n */\nexport async function extractContent(\n filePath: string,\n options: ExtractContentOptions\n): Promise<ExtractedContent> {\n const tree = await parseHtmlFile(filePath);\n\n const title = extractTitle(tree);\n const description = extractDescription(tree);\n\n // Find main content element\n let contentElement = findContentElement(tree, options.contentSelectors);\n\n if (!contentElement) {\n // Last resort: try to find any element with substantial text\n const body = select('body', tree) as Element | null;\n if (body) {\n contentElement = body;\n }\n }\n\n let contentHtml = '';\n if (contentElement) {\n const cleanedElement = cleanContentElement(contentElement, options.excludeSelectors);\n // Serialize back to HTML string using hast-util-to-html\n contentHtml = toHtml(cleanedElement);\n }\n\n return {\n title,\n description,\n contentHtml,\n };\n}\n","import { unified } from 'unified';\nimport rehypeParse from 'rehype-parse';\nimport rehypeRemark from 'rehype-remark';\nimport remarkStringify from 'remark-stringify';\nimport remarkGfm from 'remark-gfm';\n\n/**\n * Convert HTML string to Markdown\n */\nexport async function htmlToMarkdown(html: string): Promise<string> {\n if (!html || html.trim().length === 0) {\n return '';\n }\n\n try {\n const processor = unified()\n .use(rehypeParse, { fragment: true })\n .use(rehypeRemark)\n .use(remarkGfm)\n .use(remarkStringify, {\n bullet: '-',\n fences: true,\n });\n\n const result = await processor.process(html);\n let markdown = String(result);\n\n // Post-process: clean up excessive whitespace\n markdown = cleanMarkdown(markdown);\n\n return markdown;\n } catch (error) {\n console.error('Error converting HTML to Markdown:', error);\n // Return a basic text extraction as fallback\n return extractTextFallback(html);\n }\n}\n\n/**\n * Clean up markdown output\n */\nfunction cleanMarkdown(markdown: string): string {\n return (\n markdown\n // Remove excessive blank lines (more than 2 in a row)\n .replace(/\\n{3,}/g, '\\n\\n')\n // Remove trailing whitespace from lines\n .split('\\n')\n .map((line) => line.trimEnd())\n .join('\\n')\n // Ensure single newline at end\n .trim() + '\\n'\n );\n}\n\n/**\n * Fallback text extraction when markdown conversion fails\n */\nfunction extractTextFallback(html: string): string {\n // Remove script and style tags\n let text = html.replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '');\n text = text.replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, '');\n\n // Convert common HTML elements to text\n text = text.replace(/<br\\s*\\/?>/gi, '\\n');\n text = text.replace(/<\\/p>/gi, '\\n\\n');\n text = text.replace(/<\\/h[1-6]>/gi, '\\n\\n');\n text = text.replace(/<\\/li>/gi, '\\n');\n text = text.replace(/<\\/div>/gi, '\\n');\n\n // Remove remaining HTML tags\n text = text.replace(/<[^>]+>/g, '');\n\n // Decode common HTML entities\n text = text.replace(/ /g, ' ');\n text = text.replace(/&/g, '&');\n text = text.replace(/</g, '<');\n text = text.replace(/>/g, '>');\n text = text.replace(/"/g, '\"');\n text = text.replace(/'/g, \"'\");\n\n // Clean up whitespace\n text = text.replace(/[ \\t]+/g, ' ');\n text = text.replace(/\\n{3,}/g, '\\n\\n');\n\n return text.trim();\n}\n","import type { DocHeading } from '../types/index.js';\n\n/**\n * Extract headings from markdown content with their positions\n */\nexport function extractHeadingsFromMarkdown(markdown: string): DocHeading[] {\n const headings: DocHeading[] = [];\n const lines = markdown.split('\\n');\n let currentOffset = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? '';\n const headingMatch = line.match(/^(#{1,6})\\s+(.+?)(?:\\s+\\{#([^}]+)\\})?$/);\n\n if (headingMatch) {\n const hashes = headingMatch[1] ?? '';\n const level = hashes.length;\n let text = headingMatch[2] ?? '';\n let id = headingMatch[3] ?? '';\n\n // If no explicit ID, generate one from text (Docusaurus style)\n if (!id) {\n id = generateHeadingId(text);\n }\n\n // Clean up text (remove any remaining markdown formatting)\n text = text.replace(/\\*\\*([^*]+)\\*\\*/g, '$1'); // Remove bold\n text = text.replace(/_([^_]+)_/g, '$1'); // Remove italic\n text = text.replace(/`([^`]+)`/g, '$1'); // Remove code\n\n headings.push({\n level,\n text: text.trim(),\n id,\n startOffset: currentOffset,\n endOffset: -1, // Will be calculated below\n });\n }\n\n currentOffset += line.length + 1; // +1 for newline\n }\n\n // Calculate end offsets (each heading ends where the next same-or-higher level heading starts)\n for (let i = 0; i < headings.length; i++) {\n const current = headings[i];\n if (!current) continue;\n\n let endOffset = markdown.length;\n\n // Find the next heading at the same or higher level\n for (let j = i + 1; j < headings.length; j++) {\n const next = headings[j];\n if (next && next.level <= current.level) {\n endOffset = next.startOffset;\n break;\n }\n }\n\n current.endOffset = endOffset;\n }\n\n return headings;\n}\n\n/**\n * Generate a URL-safe heading ID (Docusaurus style)\n */\nexport function generateHeadingId(text: string): string {\n return (\n text\n .toLowerCase()\n // Remove any non-alphanumeric characters except spaces and hyphens\n .replace(/[^\\w\\s-]/g, '')\n // Replace spaces with hyphens\n .replace(/\\s+/g, '-')\n // Remove consecutive hyphens\n .replace(/-+/g, '-')\n // Remove leading/trailing hyphens\n .replace(/^-|-$/g, '')\n );\n}\n\n/**\n * Extract a specific section from markdown by heading ID\n */\nexport function extractSection(\n markdown: string,\n headingId: string,\n headings: DocHeading[]\n): string | null {\n const heading = headings.find((h) => h.id === headingId);\n\n if (!heading) {\n return null;\n }\n\n return markdown.slice(heading.startOffset, heading.endOffset).trim();\n}\n","import FlexSearch from 'flexsearch';\nimport type { ProcessedDoc, SearchResult } from '../types/index.js';\nimport type { IndexableDocument } from './types.js';\n\nexport type FlexSearchDocument = FlexSearch.Document<IndexableDocument, string[]>;\n\n/**\n * Field weights for search ranking\n * Higher values = more importance\n */\nconst FIELD_WEIGHTS = {\n title: 3.0,\n headings: 2.0,\n description: 1.5,\n content: 1.0,\n} as const;\n\n/**\n * Simple English stemmer\n * Handles common suffixes for better matching\n */\nfunction englishStemmer(word: string): string {\n // Only process words longer than 3 characters\n if (word.length <= 3) return word;\n\n return (\n word\n // -ing endings\n .replace(/ing$/, '')\n // -tion, -sion endings -> t, s\n .replace(/tion$/, 't')\n .replace(/sion$/, 's')\n // -ed endings (careful with short words)\n .replace(/([^aeiou])ed$/, '$1')\n // -es endings\n .replace(/([^aeiou])es$/, '$1')\n // -ly endings\n .replace(/ly$/, '')\n // -ment endings\n .replace(/ment$/, '')\n // -ness endings\n .replace(/ness$/, '')\n // -ies -> y\n .replace(/ies$/, 'y')\n // -s endings (simple plural)\n .replace(/([^s])s$/, '$1')\n );\n}\n\n/**\n * Create a FlexSearch document index with enhanced configuration\n *\n * Features:\n * - Full substring matching (finds \"auth\" in \"authentication\")\n * - English stemming (finds \"authenticate\" when searching \"authentication\")\n * - Context-aware scoring for phrase matching\n * - Optimized resolution for relevance ranking\n */\nexport function createSearchIndex(): FlexSearchDocument {\n return new FlexSearch.Document<IndexableDocument, string[]>({\n // Use 'full' tokenization for substring matching\n // This allows \"auth\" to match \"authentication\"\n tokenize: 'full',\n\n // Enable caching for faster repeated queries\n cache: 100,\n\n // Higher resolution = more granular ranking (1-9)\n resolution: 9,\n\n // Enable context for phrase/proximity matching\n context: {\n resolution: 2,\n depth: 2,\n bidirectional: true,\n },\n\n // Apply stemming to normalize word forms\n encode: (str: string) => {\n // Normalize to lowercase and split into words\n const words = str.toLowerCase().split(/[\\s\\-_.,;:!?'\"()[\\]{}]+/);\n // Apply stemmer to each word\n return words.filter(Boolean).map(englishStemmer);\n },\n\n // Document schema\n document: {\n id: 'id',\n // Index these fields for searching\n index: ['title', 'content', 'headings', 'description'],\n // Store these fields in results (for enriched queries)\n store: ['title', 'description'],\n },\n });\n}\n\n/**\n * Add a document to the search index\n *\n * @param index - The FlexSearch index\n * @param doc - The document to add\n * @param baseUrl - Optional base URL to construct full URL as document ID\n */\nexport function addDocumentToIndex(\n index: FlexSearchDocument,\n doc: ProcessedDoc,\n baseUrl?: string\n): void {\n // Use full URL as ID if baseUrl is provided, otherwise use route\n const id = baseUrl ? `${baseUrl.replace(/\\/$/, '')}${doc.route}` : doc.route;\n\n const indexable: IndexableDocument = {\n id,\n title: doc.title,\n content: doc.markdown,\n headings: doc.headings.map((h) => h.text).join(' '),\n description: doc.description,\n };\n\n index.add(indexable);\n}\n\n/**\n * Build the search index from processed documents\n *\n * @param docs - Documents to index\n * @param baseUrl - Optional base URL to construct full URLs as document IDs\n */\nexport function buildSearchIndex(docs: ProcessedDoc[], baseUrl?: string): FlexSearchDocument {\n const index = createSearchIndex();\n\n for (const doc of docs) {\n addDocumentToIndex(index, doc, baseUrl);\n }\n\n return index;\n}\n\n/**\n * Search the index and return results with weighted ranking\n *\n * Ranking combines:\n * - Field importance (title > headings > description > content)\n * - Position in results (earlier = more relevant)\n */\nexport function searchIndex(\n index: FlexSearchDocument,\n docs: Record<string, ProcessedDoc>,\n query: string,\n options: { limit?: number } = {}\n): SearchResult[] {\n const { limit = 5 } = options;\n\n // Search across all fields\n const rawResults = index.search(query, {\n limit: limit * 3, // Get extra results for better ranking after weighting\n enrich: true,\n });\n\n // Aggregate scores across fields with weighting\n const docScores = new Map<string, number>();\n\n for (const fieldResult of rawResults) {\n // Determine which field this result is from\n const field = fieldResult.field as keyof typeof FIELD_WEIGHTS;\n const fieldWeight = FIELD_WEIGHTS[field] ?? 1.0;\n\n // With enrich: true, results are objects with id property\n const results = fieldResult.result as unknown as Array<{ id: string } | string>;\n\n for (let i = 0; i < results.length; i++) {\n const item = results[i];\n if (!item) continue;\n\n const docId = typeof item === 'string' ? item : item.id;\n\n // Position-based score (earlier = higher)\n const positionScore = (results.length - i) / results.length;\n\n // Apply field weight to position score\n const weightedScore = positionScore * fieldWeight;\n\n // Combine with existing score (additive for multi-field matches)\n const existingScore = docScores.get(docId) ?? 0;\n docScores.set(docId, existingScore + weightedScore);\n }\n }\n\n // Build results array\n const results: SearchResult[] = [];\n\n for (const [docId, score] of docScores) {\n const doc = docs[docId];\n if (!doc) continue;\n\n results.push({\n url: docId, // docId is the full URL when indexed with baseUrl\n route: doc.route,\n title: doc.title,\n score,\n snippet: generateSnippet(doc.markdown, query),\n matchingHeadings: findMatchingHeadings(doc, query),\n });\n }\n\n // Sort by score (highest first) and limit\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, limit);\n}\n\n/**\n * Generate a snippet from the markdown content around the query terms\n */\nexport function generateSnippet(markdown: string, query: string): string {\n const maxLength = 200;\n const queryTerms = query.toLowerCase().split(/\\s+/).filter(Boolean);\n\n if (queryTerms.length === 0) {\n return markdown.slice(0, maxLength) + (markdown.length > maxLength ? '...' : '');\n }\n\n const lowerMarkdown = markdown.toLowerCase();\n let bestIndex = -1;\n let bestTerm = '';\n\n // Also try stemmed versions of query terms\n const allTerms = [...queryTerms, ...queryTerms.map(englishStemmer)];\n\n for (const term of allTerms) {\n const index = lowerMarkdown.indexOf(term);\n if (index !== -1 && (bestIndex === -1 || index < bestIndex)) {\n bestIndex = index;\n bestTerm = term;\n }\n }\n\n if (bestIndex === -1) {\n // No term found, return beginning of document\n return markdown.slice(0, maxLength) + (markdown.length > maxLength ? '...' : '');\n }\n\n const snippetStart = Math.max(0, bestIndex - 50);\n const snippetEnd = Math.min(markdown.length, bestIndex + bestTerm.length + 150);\n\n let snippet = markdown.slice(snippetStart, snippetEnd);\n\n snippet = snippet\n // Remove markdown headings\n .replace(/^#{1,6}\\s+/gm, '')\n // Remove markdown links but keep text\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1')\n // Remove markdown images\n .replace(/!\\[([^\\]]*)\\]\\([^)]+\\)/g, '')\n // Remove code block markers\n .replace(/```[a-z]*\\n?/g, '')\n // Remove inline code backticks\n .replace(/`([^`]+)`/g, '$1')\n // Clean up whitespace\n .replace(/\\s+/g, ' ')\n .trim();\n\n const prefix = snippetStart > 0 ? '...' : '';\n const suffix = snippetEnd < markdown.length ? '...' : '';\n\n return prefix + snippet + suffix;\n}\n\n/**\n * Find headings that match the query (including stemmed forms)\n */\nfunction findMatchingHeadings(doc: ProcessedDoc, query: string): string[] {\n const queryTerms = query.toLowerCase().split(/\\s+/).filter(Boolean);\n // Include stemmed versions for better matching\n const allTerms = [...queryTerms, ...queryTerms.map(englishStemmer)];\n const matching: string[] = [];\n\n for (const heading of doc.headings) {\n const headingLower = heading.text.toLowerCase();\n const headingStemmed = headingLower.split(/\\s+/).map(englishStemmer).join(' ');\n\n // Check if any query term matches the heading or its stemmed form\n if (\n allTerms.some(\n (term) => headingLower.includes(term) || headingStemmed.includes(englishStemmer(term))\n )\n ) {\n matching.push(heading.text);\n }\n }\n\n return matching.slice(0, 3); // Limit to 3 matching headings\n}\n\n/**\n * Export the search index to a serializable format\n */\nexport async function exportSearchIndex(index: FlexSearchDocument): Promise<unknown> {\n const exportData: Record<string, unknown> = {};\n\n await index.export((key, data) => {\n exportData[key as string] = data;\n });\n\n return exportData;\n}\n\n/**\n * Import a search index from serialized data\n */\nexport async function importSearchIndex(\n data: Record<string, unknown>\n): Promise<FlexSearchDocument> {\n const index = createSearchIndex();\n\n for (const [key, value] of Object.entries(data)) {\n // FlexSearch's import expects the data in a specific format\n await (index as unknown as { import: (key: string, data: unknown) => Promise<void> }).import(\n key,\n value\n );\n }\n\n return index;\n}\n","import type { ProcessedDoc } from '../../types/index.js';\nimport type { ContentIndexer, ProviderContext } from '../types.js';\nimport { buildSearchIndex, exportSearchIndex } from '../../search/flexsearch-core.js';\n\n/**\n * Built-in FlexSearch content indexer.\n *\n * This indexer builds a local FlexSearch index and produces:\n * - docs.json: All processed documents keyed by full URL\n * - search-index.json: Exported FlexSearch index for runtime search\n */\nexport class FlexSearchIndexer implements ContentIndexer {\n readonly name = 'flexsearch';\n\n private baseUrl = '';\n private docsIndex: Record<string, ProcessedDoc> = {};\n private exportedIndex: unknown = null;\n private docCount = 0;\n\n /**\n * FlexSearch indexer always runs by default.\n * It respects the indexers configuration - if not included, it won't run.\n */\n shouldRun(): boolean {\n return true;\n }\n\n async initialize(context: ProviderContext): Promise<void> {\n // Reset state for fresh indexing\n this.baseUrl = context.baseUrl.replace(/\\/$/, '');\n this.docsIndex = {};\n this.exportedIndex = null;\n this.docCount = 0;\n }\n\n async indexDocuments(docs: ProcessedDoc[]): Promise<void> {\n this.docCount = docs.length;\n\n // Build docs index (keyed by full URL)\n for (const doc of docs) {\n const fullUrl = `${this.baseUrl}${doc.route}`;\n this.docsIndex[fullUrl] = doc;\n }\n\n // Build and export FlexSearch index (use full URLs as document IDs)\n console.log('[FlexSearch] Building search index...');\n const searchIndex = buildSearchIndex(docs, this.baseUrl);\n this.exportedIndex = await exportSearchIndex(searchIndex);\n console.log(`[FlexSearch] Indexed ${this.docCount} documents`);\n }\n\n async finalize(): Promise<Map<string, unknown>> {\n const artifacts = new Map<string, unknown>();\n\n // docs.json - all documents keyed by full URL\n artifacts.set('docs.json', this.docsIndex);\n\n // search-index.json - exported FlexSearch index\n artifacts.set('search-index.json', this.exportedIndex);\n\n return artifacts;\n }\n\n async getManifestData(): Promise<Record<string, unknown>> {\n return {\n searchEngine: 'flexsearch',\n };\n }\n}\n","import fs from 'fs-extra';\nimport type { ProcessedDoc, SearchResult } from '../../types/index.js';\nimport type {\n SearchProvider,\n ProviderContext,\n SearchProviderInitData,\n SearchOptions,\n} from '../types.js';\nimport {\n importSearchIndex,\n searchIndex,\n type FlexSearchDocument,\n} from '../../search/flexsearch-core.js';\n\n/**\n * Built-in FlexSearch search provider.\n *\n * This provider uses the local FlexSearch index for search queries.\n * Supports both file-based loading (Node.js) and pre-loaded data (Workers).\n */\nexport class FlexSearchProvider implements SearchProvider {\n readonly name = 'flexsearch';\n\n private docs: Record<string, ProcessedDoc> | null = null;\n private searchIndex: FlexSearchDocument | null = null;\n private ready = false;\n\n async initialize(_context: ProviderContext, initData?: SearchProviderInitData): Promise<void> {\n if (!initData) {\n throw new Error('[FlexSearch] SearchProviderInitData required for FlexSearch provider');\n }\n\n // Pre-loaded data mode (Cloudflare Workers, etc.)\n if (initData.docs && initData.indexData) {\n this.docs = initData.docs;\n this.searchIndex = await importSearchIndex(initData.indexData as Record<string, unknown>);\n this.ready = true;\n return;\n }\n\n // File-based mode (Node.js)\n if (initData.docsPath && initData.indexPath) {\n if (await fs.pathExists(initData.docsPath)) {\n this.docs = await fs.readJson(initData.docsPath);\n } else {\n throw new Error(`[FlexSearch] Docs file not found: ${initData.docsPath}`);\n }\n\n if (await fs.pathExists(initData.indexPath)) {\n const indexData = await fs.readJson(initData.indexPath);\n this.searchIndex = await importSearchIndex(indexData);\n } else {\n throw new Error(`[FlexSearch] Search index not found: ${initData.indexPath}`);\n }\n\n this.ready = true;\n return;\n }\n\n throw new Error(\n '[FlexSearch] Invalid init data: must provide either file paths (docsPath, indexPath) or pre-loaded data (docs, indexData)'\n );\n }\n\n isReady(): boolean {\n return this.ready && this.docs !== null && this.searchIndex !== null;\n }\n\n async search(query: string, options?: SearchOptions): Promise<SearchResult[]> {\n if (!this.isReady() || !this.docs || !this.searchIndex) {\n throw new Error('[FlexSearch] Provider not initialized');\n }\n\n const limit = options?.limit ?? 5;\n return searchIndex(this.searchIndex, this.docs, query, { limit });\n }\n\n async getDocument(url: string): Promise<ProcessedDoc | null> {\n if (!this.docs) {\n throw new Error('[FlexSearch] Provider not initialized');\n }\n\n // Direct lookup by URL\n return this.docs[url] ?? null;\n }\n\n async healthCheck(): Promise<{ healthy: boolean; message?: string }> {\n if (!this.isReady()) {\n return { healthy: false, message: 'FlexSearch provider not initialized' };\n }\n\n const docCount = this.docs ? Object.keys(this.docs).length : 0;\n return {\n healthy: true,\n message: `FlexSearch provider ready with ${docCount} documents`,\n };\n }\n\n /**\n * Get all loaded documents (for compatibility with existing server code)\n */\n getDocs(): Record<string, ProcessedDoc> | null {\n return this.docs;\n }\n\n /**\n * Get the FlexSearch index (for compatibility with existing server code)\n */\n getSearchIndex(): FlexSearchDocument | null {\n return this.searchIndex;\n }\n}\n","import type { ContentIndexer, SearchProvider } from './types.js';\nimport { FlexSearchIndexer } from './indexers/flexsearch-indexer.js';\nimport { FlexSearchProvider } from './search/flexsearch-provider.js';\n\n/**\n * Load an indexer by name or module path.\n *\n * @param specifier - Either 'flexsearch' for the built-in indexer, or a module path\n * (relative path like './my-indexer.js' or npm package like '@myorg/indexer')\n * @returns Instantiated ContentIndexer\n *\n * @example\n * ```typescript\n * // Built-in\n * const indexer = await loadIndexer('flexsearch');\n *\n * // Custom relative path\n * const indexer = await loadIndexer('./src/providers/algolia-indexer.js');\n *\n * // Custom npm package\n * const indexer = await loadIndexer('@myorg/custom-indexer');\n * ```\n */\nexport async function loadIndexer(specifier: string): Promise<ContentIndexer> {\n // Built-in FlexSearch indexer\n if (specifier === 'flexsearch') {\n return new FlexSearchIndexer();\n }\n\n try {\n const module = await import(specifier);\n const IndexerClass = module.default;\n\n if (typeof IndexerClass === 'function') {\n // It's a class constructor\n const instance = new IndexerClass();\n\n if (!isContentIndexer(instance)) {\n throw new Error(\n `Invalid indexer module \"${specifier}\": does not implement ContentIndexer interface`\n );\n }\n\n return instance;\n }\n\n if (isContentIndexer(IndexerClass)) {\n return IndexerClass;\n }\n\n throw new Error(\n `Invalid indexer module \"${specifier}\": must export a default class or ContentIndexer instance`\n );\n } catch (error) {\n if (error instanceof Error && error.message.includes('Cannot find module')) {\n throw new Error(`Indexer module not found: \"${specifier}\". Check the path or package name.`);\n }\n throw error;\n }\n}\n\n/**\n * Load a search provider by name or module path.\n *\n * @param specifier - Either 'flexsearch' for the built-in provider, or a module path\n * (relative path like './my-search.js' or npm package like '@myorg/search')\n * @returns Instantiated SearchProvider\n *\n * @example\n * ```typescript\n * // Built-in\n * const provider = await loadSearchProvider('flexsearch');\n *\n * // Custom relative path\n * const provider = await loadSearchProvider('./src/providers/glean-search.js');\n *\n * // Custom npm package\n * const provider = await loadSearchProvider('@myorg/glean-search');\n * ```\n */\nexport async function loadSearchProvider(specifier: string): Promise<SearchProvider> {\n if (specifier === 'flexsearch') {\n return new FlexSearchProvider();\n }\n\n try {\n const module = await import(specifier);\n const ProviderClass = module.default;\n\n if (typeof ProviderClass === 'function') {\n const instance = new ProviderClass();\n\n if (!isSearchProvider(instance)) {\n throw new Error(\n `Invalid search provider module \"${specifier}\": does not implement SearchProvider interface`\n );\n }\n\n return instance;\n }\n\n if (isSearchProvider(ProviderClass)) {\n return ProviderClass;\n }\n\n throw new Error(\n `Invalid search provider module \"${specifier}\": must export a default class or SearchProvider instance`\n );\n } catch (error) {\n if (error instanceof Error && error.message.includes('Cannot find module')) {\n throw new Error(\n `Search provider module not found: \"${specifier}\". Check the path or package name.`\n );\n }\n throw error;\n }\n}\n\n/**\n * Type guard to check if an object implements ContentIndexer\n */\nfunction isContentIndexer(obj: unknown): obj is ContentIndexer {\n if (!obj || typeof obj !== 'object') {\n return false;\n }\n\n const indexer = obj as ContentIndexer;\n return (\n typeof indexer.name === 'string' &&\n typeof indexer.initialize === 'function' &&\n typeof indexer.indexDocuments === 'function' &&\n typeof indexer.finalize === 'function'\n );\n}\n\n/**\n * Type guard to check if an object implements SearchProvider\n */\nfunction isSearchProvider(obj: unknown): obj is SearchProvider {\n if (!obj || typeof obj !== 'object') {\n return false;\n }\n\n const provider = obj as SearchProvider;\n return (\n typeof provider.name === 'string' &&\n typeof provider.initialize === 'function' &&\n typeof provider.isReady === 'function' &&\n typeof provider.search === 'function'\n );\n}\n","import path from 'path';\nimport fs from 'fs-extra';\nimport pMap from 'p-map';\nimport type { LoadContext, Plugin } from '@docusaurus/types';\nimport type {\n McpServerPluginOptions,\n ResolvedPluginOptions,\n ProcessedDoc,\n McpManifest,\n} from '../types/index.js';\nimport { DEFAULT_OPTIONS } from '../types/index.js';\nimport { collectRoutes } from './route-collector.js';\nimport { extractContent, type ExtractContentOptions } from '../processing/html-parser.js';\nimport { htmlToMarkdown } from '../processing/html-to-markdown.js';\nimport { extractHeadingsFromMarkdown } from '../processing/heading-extractor.js';\nimport { loadIndexer } from '../providers/loader.js';\nimport type { ProviderContext } from '../providers/types.js';\n\n/**\n * Resolve plugin options with defaults.\n */\nfunction resolveOptions(options: McpServerPluginOptions): ResolvedPluginOptions {\n return {\n ...DEFAULT_OPTIONS,\n ...options,\n server: {\n ...DEFAULT_OPTIONS.server,\n ...options.server,\n },\n };\n}\n\n/**\n * Options for processing an HTML file\n */\ninterface ProcessHtmlOptions {\n contentSelectors: string[];\n excludeSelectors: string[];\n minContentLength: number;\n}\n\n/**\n * Process a single HTML file into a ProcessedDoc\n */\nasync function processHtmlFile(\n htmlPath: string,\n route: string,\n options: ProcessHtmlOptions\n): Promise<ProcessedDoc | null> {\n try {\n // Extract content from HTML\n const extractOptions: ExtractContentOptions = {\n contentSelectors: options.contentSelectors,\n excludeSelectors: options.excludeSelectors,\n };\n const extracted = await extractContent(htmlPath, extractOptions);\n\n if (!extracted.contentHtml) {\n console.warn(`[MCP] No content found in ${htmlPath}`);\n return null;\n }\n\n // Convert to markdown\n const markdown = await htmlToMarkdown(extracted.contentHtml);\n\n if (!markdown || markdown.trim().length < options.minContentLength) {\n console.warn(`[MCP] Insufficient content in ${htmlPath}`);\n return null;\n }\n\n // Extract headings\n const headings = extractHeadingsFromMarkdown(markdown);\n\n return {\n route,\n title: extracted.title,\n description: extracted.description,\n markdown,\n headings,\n };\n } catch (error) {\n console.error(`[MCP] Error processing ${htmlPath}:`, error);\n return null;\n }\n}\n\n/**\n * Docusaurus plugin that generates MCP server artifacts during build\n */\nexport default function mcpServerPlugin(\n context: LoadContext,\n options: McpServerPluginOptions\n): Plugin {\n const resolvedOptions = resolveOptions(options);\n\n return {\n name: 'docusaurus-plugin-mcp-server',\n\n // Expose configuration to theme components via globalData\n async contentLoaded({ actions }) {\n const { setGlobalData } = actions;\n\n // Construct server URL from site URL + output directory\n const serverUrl = `${context.siteConfig.url}/${resolvedOptions.outputDir}`;\n\n setGlobalData({\n serverUrl,\n serverName: resolvedOptions.server.name,\n });\n },\n\n async postBuild({ outDir }) {\n console.log('[MCP] Starting MCP artifact generation...');\n const startTime = Date.now();\n\n // Check if indexing is disabled\n if (resolvedOptions.indexers === false) {\n console.log('[MCP] Indexing disabled, skipping artifact generation');\n return;\n }\n\n // Collect routes from the build output\n const routes = await collectRoutes(outDir, resolvedOptions.excludeRoutes);\n console.log(`[MCP] Found ${routes.length} routes to process`);\n\n if (routes.length === 0) {\n console.warn('[MCP] No routes found to process');\n return;\n }\n\n // Process all HTML files in parallel (with concurrency limit)\n const processOptions: ProcessHtmlOptions = {\n contentSelectors: resolvedOptions.contentSelectors,\n excludeSelectors: resolvedOptions.excludeSelectors,\n minContentLength: resolvedOptions.minContentLength,\n };\n\n const processedDocs = await pMap(\n routes,\n async (route) => {\n return processHtmlFile(route.htmlPath, route.path, processOptions);\n },\n { concurrency: 10 }\n );\n\n // Filter out null results\n const validDocs = processedDocs.filter((doc): doc is ProcessedDoc => doc !== null);\n console.log(`[MCP] Successfully processed ${validDocs.length} documents`);\n\n if (validDocs.length === 0) {\n console.warn('[MCP] No valid documents to index');\n return;\n }\n\n // Create provider context\n const mcpOutputDir = path.join(outDir, resolvedOptions.outputDir);\n const providerContext: ProviderContext = {\n baseUrl: context.siteConfig.url,\n serverName: resolvedOptions.server.name,\n serverVersion: resolvedOptions.server.version,\n outputDir: mcpOutputDir,\n };\n\n // Determine which indexers to run\n // undefined = ['flexsearch'] for backward compatibility\n const indexerSpecs = resolvedOptions.indexers ?? ['flexsearch'];\n\n await fs.ensureDir(mcpOutputDir);\n\n const indexerNames: string[] = [];\n\n for (const indexerSpec of indexerSpecs) {\n try {\n const indexer = await loadIndexer(indexerSpec);\n\n // Check if indexer wants to run (env var gating)\n if (indexer.shouldRun && !indexer.shouldRun()) {\n console.log(`[MCP] Skipping indexer: ${indexer.name}`);\n continue;\n }\n\n console.log(`[MCP] Running indexer: ${indexer.name}`);\n await indexer.initialize(providerContext);\n await indexer.indexDocuments(validDocs);\n\n // Write artifacts from this indexer\n const artifacts = await indexer.finalize();\n for (const [filename, content] of artifacts) {\n await fs.writeJson(path.join(mcpOutputDir, filename), content, { spaces: 0 });\n }\n\n indexerNames.push(indexer.name);\n } catch (error) {\n console.error(`[MCP] Error running indexer \"${indexerSpec}\":`, error);\n throw error;\n }\n }\n\n // Write manifest (only if at least one indexer ran)\n if (indexerNames.length > 0) {\n const manifest: McpManifest = {\n version: resolvedOptions.server.version,\n buildTime: new Date().toISOString(),\n docCount: validDocs.length,\n serverName: resolvedOptions.server.name,\n baseUrl: context.siteConfig.url,\n indexers: indexerNames,\n };\n\n await fs.writeJson(path.join(mcpOutputDir, 'manifest.json'), manifest, { spaces: 2 });\n }\n\n const elapsed = Date.now() - startTime;\n console.log(`[MCP] Artifacts written to ${mcpOutputDir}`);\n console.log(`[MCP] Generation complete in ${elapsed}ms`);\n },\n };\n}\n\n// Named export for ESM compatibility\nexport { mcpServerPlugin };\n","import { z } from 'zod';\nimport type { ProcessedDoc, SearchResult, DocsSearchParams } from '../../types/index.js';\nimport { searchIndex, type FlexSearchDocument } from '../../search/flexsearch-core.js';\n\n/**\n * Zod schema for docs_search input parameters\n */\nexport const docsSearchInputSchema = {\n query: z.string().min(1).describe('The search query string'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(20)\n .optional()\n .default(5)\n .describe('Maximum number of results to return (1-20, default: 5)'),\n};\n\n/**\n * Tool definition for docs_search\n */\nexport const docsSearchTool = {\n name: 'docs_search',\n description:\n 'Search the documentation for relevant pages. Returns matching documents with URLs, snippets, and relevance scores. Use this to find information across all documentation.',\n inputSchema: docsSearchInputSchema,\n};\n\n/**\n * Execute the docs_search tool\n */\nexport function executeDocsSearch(\n params: DocsSearchParams,\n index: FlexSearchDocument,\n docs: Record<string, ProcessedDoc>\n): SearchResult[] {\n const { query, limit = 5 } = params;\n\n // Validate parameters\n if (!query || typeof query !== 'string' || query.trim().length === 0) {\n throw new Error('Query parameter is required and must be a non-empty string');\n }\n\n const effectiveLimit = Math.min(Math.max(1, limit), 20);\n\n // Search the index\n const results = searchIndex(index, docs, query.trim(), {\n limit: effectiveLimit,\n });\n\n return results;\n}\n\n/**\n * Format search results for MCP response\n */\nexport function formatSearchResults(results: SearchResult[]): string {\n if (results.length === 0) {\n return 'No matching documents found.';\n }\n\n const lines: string[] = [`Found ${results.length} result(s):\\n`];\n\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n if (!result) continue;\n\n lines.push(`${i + 1}. **${result.title}**`);\n lines.push(` URL: ${result.url}`);\n\n if (result.matchingHeadings && result.matchingHeadings.length > 0) {\n lines.push(` Matching sections: ${result.matchingHeadings.join(', ')}`);\n }\n\n lines.push(` ${result.snippet}`);\n lines.push('');\n }\n\n lines.push('Use docs_fetch with the URL to retrieve the full page content.');\n\n return lines.join('\\n');\n}\n","import { z } from 'zod';\nimport type { ProcessedDoc } from '../../types/index.js';\n\n/**\n * Zod schema for docs_fetch input parameters\n */\nexport const docsFetchInputSchema = {\n url: z\n .string()\n .url()\n .describe(\n 'The full URL of the page to fetch (e.g., \"https://docs.example.com/docs/getting-started\")'\n ),\n};\n\n/**\n * Tool definition for docs_fetch\n */\nexport const docsFetchTool = {\n name: 'docs_fetch',\n description:\n 'Fetch the complete content of a documentation page. Use this after searching to get the full markdown content of a specific page.',\n inputSchema: docsFetchInputSchema,\n};\n\n/**\n * Format page content for MCP response\n */\nexport function formatPageContent(doc: ProcessedDoc | null): string {\n if (!doc) {\n return 'Page not found. Please check the URL and try again.';\n }\n\n const lines: string[] = [];\n\n // Header\n lines.push(`# ${doc.title}`);\n lines.push('');\n\n // Metadata\n if (doc.description) {\n lines.push(`> ${doc.description}`);\n lines.push('');\n }\n\n // Table of contents (if there are headings)\n if (doc.headings.length > 0) {\n lines.push('## Contents');\n lines.push('');\n for (const heading of doc.headings) {\n if (heading.level <= 3) {\n const indent = ' '.repeat(heading.level - 1);\n lines.push(`${indent}- [${heading.text}](#${heading.id})`);\n }\n }\n lines.push('');\n lines.push('---');\n lines.push('');\n }\n\n // Main content\n lines.push(doc.markdown);\n\n return lines.join('\\n');\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type {\n ProcessedDoc,\n McpServerConfig,\n McpServerFileConfig,\n McpServerDataConfig,\n} from '../types/index.js';\nimport { loadSearchProvider } from '../providers/loader.js';\nimport { FlexSearchProvider } from '../providers/search/flexsearch-provider.js';\nimport type {\n SearchProvider,\n ProviderContext,\n SearchProviderInitData,\n} from '../providers/types.js';\nimport { docsSearchTool, formatSearchResults } from './tools/docs-search.js';\nimport { docsFetchTool, formatPageContent } from './tools/docs-fetch.js';\n\n/**\n * Type guard to check if config uses file-based loading\n */\nfunction isFileConfig(config: McpServerConfig): config is McpServerFileConfig {\n return 'docsPath' in config && 'indexPath' in config;\n}\n\n/**\n * Type guard to check if config uses pre-loaded data\n */\nfunction isDataConfig(config: McpServerConfig): config is McpServerDataConfig {\n return 'docs' in config && 'searchIndexData' in config;\n}\n\n/**\n * MCP Server for documentation\n *\n * This class provides the MCP server implementation that can be used\n * with any HTTP framework (Express, Vercel, Cloudflare Workers, etc.)\n *\n * Supports two modes:\n * - File-based: Load docs and search index from filesystem (Node.js)\n * - Pre-loaded: Accept docs and search index data directly (Workers)\n *\n * Uses the official MCP SDK for proper protocol handling.\n */\nexport class McpDocsServer {\n private config: McpServerConfig;\n private searchProvider: SearchProvider | null = null;\n private mcpServer: McpServer;\n private initialized = false;\n\n constructor(config: McpServerConfig) {\n this.config = config;\n\n this.mcpServer = new McpServer(\n {\n name: config.name,\n version: config.version ?? '1.0.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n this.registerTools();\n }\n\n /**\n * Register all MCP tools using definitions from tool files\n */\n private registerTools(): void {\n // Register docs_search tool\n this.mcpServer.registerTool(\n docsSearchTool.name,\n {\n description: docsSearchTool.description,\n inputSchema: docsSearchTool.inputSchema,\n },\n async ({ query, limit }) => {\n await this.initialize();\n\n if (!this.searchProvider || !this.searchProvider.isReady()) {\n return {\n content: [{ type: 'text' as const, text: 'Server not initialized. Please try again.' }],\n isError: true,\n };\n }\n\n try {\n const results = await this.searchProvider.search(query, { limit });\n return {\n content: [{ type: 'text' as const, text: formatSearchResults(results) }],\n };\n } catch (error) {\n console.error('[MCP] Search error:', error);\n return {\n content: [{ type: 'text' as const, text: `Search error: ${String(error)}` }],\n isError: true,\n };\n }\n }\n );\n\n // Register docs_fetch tool\n this.mcpServer.registerTool(\n docsFetchTool.name,\n {\n description: docsFetchTool.description,\n inputSchema: docsFetchTool.inputSchema,\n },\n async ({ url }) => {\n await this.initialize();\n\n if (!this.searchProvider || !this.searchProvider.isReady()) {\n return {\n content: [{ type: 'text' as const, text: 'Server not initialized. Please try again.' }],\n isError: true,\n };\n }\n\n try {\n const doc = await this.getDocument(url);\n return {\n content: [{ type: 'text' as const, text: formatPageContent(doc) }],\n };\n } catch (error) {\n console.error('[MCP] Fetch error:', error);\n return {\n content: [{ type: 'text' as const, text: `Error fetching page: ${String(error)}` }],\n isError: true,\n };\n }\n }\n );\n }\n\n /**\n * Get a document by URL using the search provider\n */\n private async getDocument(url: string): Promise<ProcessedDoc | null> {\n if (!this.searchProvider) {\n return null;\n }\n\n if (this.searchProvider.getDocument) {\n return this.searchProvider.getDocument(url);\n }\n\n return null;\n }\n\n /**\n * Load docs and search index using the configured search provider\n *\n * For file-based config: reads from disk\n * For data config: uses pre-loaded data directly\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n try {\n // Load the search provider\n const searchSpecifier = this.config.search ?? 'flexsearch';\n this.searchProvider = await loadSearchProvider(searchSpecifier);\n\n // Build provider context\n const providerContext: ProviderContext = {\n baseUrl: this.config.baseUrl ?? '',\n serverName: this.config.name,\n serverVersion: this.config.version ?? '1.0.0',\n outputDir: '', // Not relevant for runtime\n };\n\n // Build init data based on config type\n const initData: SearchProviderInitData = {};\n\n if (isDataConfig(this.config)) {\n // Pre-loaded data mode (Cloudflare Workers, etc.)\n initData.docs = this.config.docs;\n initData.indexData = this.config.searchIndexData;\n } else if (isFileConfig(this.config)) {\n // File-based mode (Node.js)\n initData.docsPath = this.config.docsPath;\n initData.indexPath = this.config.indexPath;\n } else {\n throw new Error('Invalid server config: must provide either file paths or pre-loaded data');\n }\n\n // Initialize the search provider\n await this.searchProvider.initialize(providerContext, initData);\n\n this.initialized = true;\n } catch (error) {\n console.error('[MCP] Failed to initialize:', error);\n throw error;\n }\n }\n\n /**\n * Handle an HTTP request using the MCP SDK's transport\n *\n * This method is designed for serverless environments (Vercel, Netlify).\n * It creates a stateless transport instance and processes the request.\n *\n * @param req - Node.js IncomingMessage or compatible request object\n * @param res - Node.js ServerResponse or compatible response object\n * @param parsedBody - Optional pre-parsed request body\n */\n async handleHttpRequest(\n req: IncomingMessage,\n res: ServerResponse,\n parsedBody?: unknown\n ): Promise<void> {\n await this.initialize();\n\n // Create a stateless transport for this request\n // enableJsonResponse: true means we get simple JSON responses instead of SSE\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined, // Stateless mode - no session tracking\n enableJsonResponse: true, // Return JSON instead of SSE streams\n });\n\n // Connect the server to this transport\n await this.mcpServer.connect(transport);\n\n try {\n // Let the transport handle the request\n await transport.handleRequest(req, res, parsedBody);\n } finally {\n // Clean up the transport after request\n await transport.close();\n }\n }\n\n /**\n * Handle a Web Standard Request (Cloudflare Workers, Deno, Bun)\n *\n * This method is designed for Web Standard environments that use\n * the Fetch API Request/Response pattern.\n *\n * @param request - Web Standard Request object\n * @returns Web Standard Response object\n */\n async handleWebRequest(request: Request): Promise<Response> {\n await this.initialize();\n\n // Create a stateless transport for Web Standards\n const transport = new WebStandardStreamableHTTPServerTransport({\n sessionIdGenerator: undefined, // Stateless mode\n enableJsonResponse: true,\n });\n\n // Connect the server to this transport\n await this.mcpServer.connect(transport);\n\n try {\n // Let the transport handle the request and return the response\n return await transport.handleRequest(request);\n } finally {\n // Clean up the transport after request\n await transport.close();\n }\n }\n\n /**\n * Get server status information\n *\n * Useful for health checks and debugging\n */\n async getStatus(): Promise<{\n name: string;\n version: string;\n initialized: boolean;\n docCount: number;\n baseUrl?: string;\n searchProvider?: string;\n }> {\n let docCount = 0;\n\n // Get doc count from FlexSearchProvider if available\n if (this.searchProvider instanceof FlexSearchProvider) {\n const docs = this.searchProvider.getDocs();\n docCount = docs ? Object.keys(docs).length : 0;\n }\n\n return {\n name: this.config.name,\n version: this.config.version ?? '1.0.0',\n initialized: this.initialized,\n docCount,\n baseUrl: this.config.baseUrl,\n searchProvider: this.searchProvider?.name,\n };\n }\n\n /**\n * Get the underlying McpServer instance\n *\n * Useful for advanced use cases like custom transports\n */\n getMcpServer(): McpServer {\n return this.mcpServer;\n }\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1051,6 +1051,6 @@ var McpDocsServer = class {
|
|
|
1051
1051
|
}
|
|
1052
1052
|
};
|
|
1053
1053
|
|
|
1054
|
-
export { DEFAULT_OPTIONS, FlexSearchIndexer, FlexSearchProvider, McpDocsServer, buildSearchIndex, collectRoutes, discoverHtmlFiles, docsFetchTool, docsSearchTool, exportSearchIndex, extractContent, extractHeadingsFromMarkdown, extractSection, htmlToMarkdown, importSearchIndex, loadIndexer, loadSearchProvider, mcpServerPlugin, parseHtml, parseHtmlFile, searchIndex };
|
|
1054
|
+
export { DEFAULT_OPTIONS, FlexSearchIndexer, FlexSearchProvider, McpDocsServer, buildSearchIndex, collectRoutes, mcpServerPlugin as default, discoverHtmlFiles, docsFetchTool, docsSearchTool, exportSearchIndex, extractContent, extractHeadingsFromMarkdown, extractSection, htmlToMarkdown, importSearchIndex, loadIndexer, loadSearchProvider, mcpServerPlugin, parseHtml, parseHtmlFile, searchIndex };
|
|
1055
1055
|
//# sourceMappingURL=index.mjs.map
|
|
1056
1056
|
//# sourceMappingURL=index.mjs.map
|
package/dist/theme/index.d.mts
CHANGED
|
@@ -9,12 +9,14 @@ interface McpInstallButtonProps {
|
|
|
9
9
|
serverUrl?: string;
|
|
10
10
|
/** Server name. If not provided, uses plugin configuration. */
|
|
11
11
|
serverName?: string;
|
|
12
|
-
/** Button label
|
|
12
|
+
/** Button label. If not provided, shows only the MCP icon. */
|
|
13
13
|
label?: string;
|
|
14
14
|
/** Optional className for styling */
|
|
15
15
|
className?: string;
|
|
16
16
|
/** Clients to show. Defaults to all HTTP-capable clients from registry. */
|
|
17
17
|
clients?: ClientId[];
|
|
18
|
+
/** Header text shown at top of dropdown (default: "Choose your AI tool:") */
|
|
19
|
+
headerText?: string;
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
20
22
|
* A dropdown button component for installing MCP servers in various AI tools.
|
|
@@ -28,7 +30,7 @@ interface McpInstallButtonProps {
|
|
|
28
30
|
* />
|
|
29
31
|
* ```
|
|
30
32
|
*/
|
|
31
|
-
declare function McpInstallButton({ serverUrl: serverUrlProp, serverName: serverNameProp, label, className, clients: clientsProp, }: McpInstallButtonProps): react_jsx_runtime.JSX.Element | null;
|
|
33
|
+
declare function McpInstallButton({ serverUrl: serverUrlProp, serverName: serverNameProp, label, className, clients: clientsProp, headerText, }: McpInstallButtonProps): react_jsx_runtime.JSX.Element | null;
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Configuration from the plugin
|
package/dist/theme/index.d.ts
CHANGED
|
@@ -9,12 +9,14 @@ interface McpInstallButtonProps {
|
|
|
9
9
|
serverUrl?: string;
|
|
10
10
|
/** Server name. If not provided, uses plugin configuration. */
|
|
11
11
|
serverName?: string;
|
|
12
|
-
/** Button label
|
|
12
|
+
/** Button label. If not provided, shows only the MCP icon. */
|
|
13
13
|
label?: string;
|
|
14
14
|
/** Optional className for styling */
|
|
15
15
|
className?: string;
|
|
16
16
|
/** Clients to show. Defaults to all HTTP-capable clients from registry. */
|
|
17
17
|
clients?: ClientId[];
|
|
18
|
+
/** Header text shown at top of dropdown (default: "Choose your AI tool:") */
|
|
19
|
+
headerText?: string;
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
20
22
|
* A dropdown button component for installing MCP servers in various AI tools.
|
|
@@ -28,7 +30,7 @@ interface McpInstallButtonProps {
|
|
|
28
30
|
* />
|
|
29
31
|
* ```
|
|
30
32
|
*/
|
|
31
|
-
declare function McpInstallButton({ serverUrl: serverUrlProp, serverName: serverNameProp, label, className, clients: clientsProp, }: McpInstallButtonProps): react_jsx_runtime.JSX.Element | null;
|
|
33
|
+
declare function McpInstallButton({ serverUrl: serverUrlProp, serverName: serverNameProp, label, className, clients: clientsProp, headerText, }: McpInstallButtonProps): react_jsx_runtime.JSX.Element | null;
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Configuration from the plugin
|
package/dist/theme/index.js
CHANGED
|
@@ -145,9 +145,10 @@ function CodeBlock({
|
|
|
145
145
|
function McpInstallButton({
|
|
146
146
|
serverUrl: serverUrlProp,
|
|
147
147
|
serverName: serverNameProp,
|
|
148
|
-
label
|
|
148
|
+
label,
|
|
149
149
|
className = "",
|
|
150
|
-
clients: clientsProp
|
|
150
|
+
clients: clientsProp,
|
|
151
|
+
headerText = "Choose your AI tool:"
|
|
151
152
|
}) {
|
|
152
153
|
const [isOpen, setIsOpen] = react.useState(false);
|
|
153
154
|
const [copiedClient, setCopiedClient] = react.useState(null);
|
|
@@ -247,19 +248,20 @@ function McpInstallButton({
|
|
|
247
248
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
248
249
|
"button",
|
|
249
250
|
{
|
|
250
|
-
className:
|
|
251
|
+
className: `button button--primary mcp-install-dropdown__button${label ? "" : " mcp-install-dropdown__button--icon-only"}`,
|
|
251
252
|
onClick: () => setIsOpen(!isOpen),
|
|
252
253
|
"aria-expanded": isOpen,
|
|
253
254
|
"aria-haspopup": "true",
|
|
255
|
+
"aria-label": label || "Install MCP",
|
|
254
256
|
children: [
|
|
255
257
|
/* @__PURE__ */ jsxRuntime.jsx(IconMcp, { size: 16 }),
|
|
256
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: label }),
|
|
258
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("span", { children: label }),
|
|
257
259
|
/* @__PURE__ */ jsxRuntime.jsx(IconChevron, { isOpen })
|
|
258
260
|
]
|
|
259
261
|
}
|
|
260
262
|
),
|
|
261
263
|
/* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "dropdown__menu mcp-install-dropdown__menu", children: [
|
|
262
|
-
/* @__PURE__ */ jsxRuntime.jsx("li", { className: "mcp-install-dropdown__header", children:
|
|
264
|
+
/* @__PURE__ */ jsxRuntime.jsx("li", { className: "mcp-install-dropdown__header", children: headerText }),
|
|
263
265
|
clientConfigs.map((client) => {
|
|
264
266
|
const command = getCommandForClient(client.id);
|
|
265
267
|
const clientConfig = getConfigForClient(client.id);
|
|
@@ -306,21 +308,19 @@ function McpInstallButton({
|
|
|
306
308
|
) })
|
|
307
309
|
] }),
|
|
308
310
|
/* @__PURE__ */ jsxRuntime.jsx("style", { children: `
|
|
309
|
-
.mcp-install-dropdown {
|
|
310
|
-
--mcp-dropdown-width: 520px;
|
|
311
|
-
/* Always use dark code blocks for consistency across themes */
|
|
312
|
-
--mcp-code-bg: #1e1e1e;
|
|
313
|
-
--mcp-code-color: #e5e7eb;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
311
|
.mcp-install-dropdown__button {
|
|
317
312
|
display: inline-flex;
|
|
318
313
|
align-items: center;
|
|
319
314
|
gap: 0.5rem;
|
|
320
315
|
}
|
|
321
316
|
|
|
317
|
+
.mcp-install-dropdown__button--icon-only {
|
|
318
|
+
padding: 0.5rem 0.75rem;
|
|
319
|
+
gap: 0.25rem;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
322
|
.mcp-install-dropdown__menu {
|
|
323
|
-
width:
|
|
323
|
+
width: 520px;
|
|
324
324
|
padding: 0;
|
|
325
325
|
top: calc(100% + 0.25rem);
|
|
326
326
|
}
|
|
@@ -329,7 +329,7 @@ function McpInstallButton({
|
|
|
329
329
|
padding: 0.75rem 1rem;
|
|
330
330
|
font-size: var(--ifm-font-size-small);
|
|
331
331
|
font-weight: var(--ifm-font-weight-semibold);
|
|
332
|
-
color: var(--ifm-color-
|
|
332
|
+
color: var(--ifm-color-emphasis-700);
|
|
333
333
|
background-color: var(--ifm-background-color);
|
|
334
334
|
border-bottom: 1px solid var(--ifm-toc-border-color);
|
|
335
335
|
}
|
|
@@ -354,7 +354,7 @@ function McpInstallButton({
|
|
|
354
354
|
.mcp-install-dropdown__notes {
|
|
355
355
|
margin: 0.5rem 0 0;
|
|
356
356
|
font-size: var(--ifm-font-size-small);
|
|
357
|
-
color: var(--ifm-color-
|
|
357
|
+
color: var(--ifm-color-emphasis-700);
|
|
358
358
|
line-height: 1.4;
|
|
359
359
|
}
|
|
360
360
|
|
|
@@ -378,16 +378,16 @@ function McpInstallButton({
|
|
|
378
378
|
text-decoration: none;
|
|
379
379
|
}
|
|
380
380
|
|
|
381
|
-
/* Code block styles */
|
|
381
|
+
/* Code block styles - uses Docusaurus pre/code variables */
|
|
382
382
|
.mcp-code-block {
|
|
383
383
|
display: flex;
|
|
384
|
-
border-radius: var(--ifm-code-border-radius
|
|
384
|
+
border-radius: var(--ifm-code-border-radius);
|
|
385
385
|
overflow: hidden;
|
|
386
386
|
}
|
|
387
387
|
|
|
388
388
|
.mcp-code-block__content {
|
|
389
389
|
flex: 1;
|
|
390
|
-
background-color: var(--
|
|
390
|
+
background-color: var(--ifm-pre-background);
|
|
391
391
|
padding: 0.75rem 1rem;
|
|
392
392
|
overflow-x: auto;
|
|
393
393
|
}
|
|
@@ -395,7 +395,7 @@ function McpInstallButton({
|
|
|
395
395
|
.mcp-code-block__content code {
|
|
396
396
|
font-family: var(--ifm-font-family-monospace);
|
|
397
397
|
font-size: var(--ifm-code-font-size);
|
|
398
|
-
color: var(--
|
|
398
|
+
color: var(--ifm-pre-color);
|
|
399
399
|
background: none;
|
|
400
400
|
padding: 0;
|
|
401
401
|
border: none;
|
|
@@ -418,15 +418,15 @@ function McpInstallButton({
|
|
|
418
418
|
align-items: center;
|
|
419
419
|
justify-content: center;
|
|
420
420
|
width: 2.75rem;
|
|
421
|
-
background-color: var(--ifm-color-
|
|
421
|
+
background-color: var(--ifm-color-emphasis-200);
|
|
422
422
|
border: none;
|
|
423
423
|
cursor: pointer;
|
|
424
|
-
color: var(--ifm-color-
|
|
424
|
+
color: var(--ifm-color-emphasis-700);
|
|
425
425
|
transition: background-color var(--ifm-transition-fast);
|
|
426
426
|
}
|
|
427
427
|
|
|
428
428
|
.mcp-code-block__copy:hover {
|
|
429
|
-
background-color: var(--ifm-color-
|
|
429
|
+
background-color: var(--ifm-color-emphasis-300);
|
|
430
430
|
}
|
|
431
431
|
|
|
432
432
|
.mcp-code-block__icon {
|
|
@@ -436,7 +436,7 @@ function McpInstallButton({
|
|
|
436
436
|
}
|
|
437
437
|
|
|
438
438
|
.mcp-code-block__icon--success {
|
|
439
|
-
color: var(--ifm-color-success
|
|
439
|
+
color: var(--ifm-color-success);
|
|
440
440
|
}
|
|
441
441
|
` })
|
|
442
442
|
] });
|
package/dist/theme/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/theme/McpRegistryContext.tsx","../../src/theme/McpInstallButton.tsx"],"names":["MCPConfigRegistry","usePluginData","useMemo","jsxs","jsx","IconSuccess","IconCopy","useState","useRef","useEffect","useCallback"],"mappings":";;;;;;;;;;;;;;;AA0BO,SAAS,0BAA0B,MAAA,EAAoC;AAC5E,EAAA,OAAO;AAAA;AAAA,IAEL,iBAAA,EAAmB,MAAM,MAAA,CAAO;AAAA,GAClC;AACF;AAUO,SAAS,mBAAmB,MAAA,EAGjC;AACA,EAAA,MAAM,OAAA,GAAU,0BAA0B,MAAM,CAAA;AAChD,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,IAAIA,yBAAA,CAAkB,OAAO,CAAA;AAAA,IACvC;AAAA,GACF;AACF;AA0BO,SAAS,cAAA,GAAiF;AAE/F,EAAA,IAAI,UAAA;AACJ,EAAA,IAAI;AACF,IAAA,UAAA,GAAaC,4BAAc,8BAA8B,CAAA;AAAA,EAC3D,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,MAAA;AAAA,EACT;AAGA,EAAA,MAAM,MAAA,GAASC,cAAQ,MAAM;AAC3B,IAAA,IAAI,CAAC,UAAA,EAAY,SAAA,IAAa,CAAC,YAAY,UAAA,EAAY;AACrD,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,MAAM,MAAA,GAAoB;AAAA,MACxB,WAAW,UAAA,CAAW,SAAA;AAAA,MACtB,YAAY,UAAA,CAAW;AAAA,KACzB;AACA,IAAA,OAAO,mBAAmB,MAAM,CAAA;AAAA,EAClC,GAAG,CAAC,UAAA,EAAY,SAAA,EAAW,UAAA,EAAY,UAAU,CAAC,CAAA;AAElD,EAAA,OAAO,MAAA;AACT;ACtFA,SAAS,OAAA,CAAQ,EAAE,IAAA,GAAO,EAAA,EAAG,EAAsB;AACjD,EAAA,uBACEC,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAQ,aAAA;AAAA,MACR,KAAA,EAAO,IAAA;AAAA,MACP,MAAA,EAAQ,IAAA;AAAA,MACR,IAAA,EAAK,MAAA;AAAA,MACL,KAAA,EAAM,4BAAA;AAAA,MACN,KAAA,EAAO,EAAE,OAAA,EAAS,OAAA,EAAQ;AAAA,MAE1B,QAAA,EAAA;AAAA,wBAAAC,cAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,CAAA,EAAE,2IAAA;AAAA,YACF,MAAA,EAAO,cAAA;AAAA,YACP,WAAA,EAAY,IAAA;AAAA,YACZ,aAAA,EAAc;AAAA;AAAA,SAChB;AAAA,wBACAA,cAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,CAAA,EAAE,8NAAA;AAAA,YACF,MAAA,EAAO,cAAA;AAAA,YACP,WAAA,EAAY,IAAA;AAAA,YACZ,aAAA,EAAc;AAAA;AAAA,SAChB;AAAA,wBACAA,cAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,CAAA,EAAE,kJAAA;AAAA,YACF,MAAA,EAAO,cAAA;AAAA,YACP,WAAA,EAAY,IAAA;AAAA,YACZ,aAAA,EAAc;AAAA;AAAA;AAChB;AAAA;AAAA,GACF;AAEJ;AAKA,SAAS,WAAA,CAAY,EAAE,MAAA,EAAO,EAAwB;AACpD,EAAA,uBACEA,cAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAM,IAAA;AAAA,MACN,MAAA,EAAO,IAAA;AAAA,MACP,OAAA,EAAQ,WAAA;AAAA,MACR,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,OAAA;AAAA,QACT,SAAA,EAAW,SAAS,gBAAA,GAAmB,cAAA;AAAA,QACvC,UAAA,EAAY;AAAA,OACd;AAAA,MAEA,QAAA,kBAAAA,cAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UACC,CAAA,EAAE,sBAAA;AAAA,UACF,MAAA,EAAO,cAAA;AAAA,UACP,WAAA,EAAY,KAAA;AAAA,UACZ,aAAA,EAAc,OAAA;AAAA,UACd,cAAA,EAAe,OAAA;AAAA,UACf,IAAA,EAAK;AAAA;AAAA;AACP;AAAA,GACF;AAEJ;AAKA,SAAS,gBAAA,GAAmB;AAC1B,EAAA,uBACEA,cAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,QAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,KAAA,EAAO,EAAE,OAAA,EAAS,OAAA,EAAS,UAAA,EAAY,OAAM,EAC3F,QAAA,kBAAAA,cAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,cAAA;AAAA,MACL,CAAA,EAAE;AAAA;AAAA,GACJ,EACF,CAAA;AAEJ;AAKA,SAAS,SAAA,CAAU;AAAA,EACjB,IAAA;AAAA,EACA,WAAA,GAAc,KAAA;AAAA,EACd,QAAA;AAAA,EACA;AACF,CAAA,EAKG;AACD,EAAA,uBACED,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EACb,QAAA,EAAA;AAAA,oBAAAC,cAAA,CAAC,SAAI,SAAA,EAAU,yBAAA,EACZ,QAAA,EAAA,WAAA,mBACCA,cAAA,CAAC,SAAI,SAAA,EAAU,qBAAA,EACb,QAAA,kBAAAA,cAAA,CAAC,MAAA,EAAA,EAAM,gBAAK,CAAA,EACd,CAAA,mBAEAA,cAAA,CAAC,MAAA,EAAA,EAAM,gBAAK,CAAA,EAEhB,CAAA;AAAA,oBACAA,cAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,sBAAA;AAAA,QACV,OAAA,EAAS,MAAA;AAAA,QACT,KAAA,EAAO,WAAW,SAAA,GAAY,mBAAA;AAAA,QAC9B,YAAA,EAAY,WAAW,QAAA,GAAW,mBAAA;AAAA,QAEjC,QAAA,EAAA,QAAA,kCACEC,4BAAA,EAAA,EAAY,SAAA,EAAU,sDAAqD,CAAA,mBAE5ED,cAAA,CAACE,yBAAA,EAAA,EAAS,SAAA,EAAU,sBAAA,EAAuB;AAAA;AAAA;AAE/C,GAAA,EACF,CAAA;AAEJ;AA8BO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,SAAA,EAAW,aAAA;AAAA,EACX,UAAA,EAAY,cAAA;AAAA,EACZ,KAAA,GAAQ,kBAAA;AAAA,EACR,SAAA,GAAY,EAAA;AAAA,EACZ,OAAA,EAAS;AACX,CAAA,EAA0B;AACxB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIC,eAAS,KAAK,CAAA;AAC1C,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIA,eAAwB,IAAI,CAAA;AACpE,EAAA,MAAM,WAAA,GAAcC,aAAuB,IAAI,CAAA;AAG/C,EAAA,MAAM,YAAY,cAAA,EAAe;AAGjC,EAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAO,GAAIN,cAAQ,MAAM;AACzC,IAAA,IAAI,iBAAiB,cAAA,EAAgB;AACnC,MAAA,OAAO,kBAAA,CAAmB;AAAA,QACxB,SAAA,EAAW,aAAA;AAAA,QACX,UAAA,EAAY;AAAA,OACb,CAAA;AAAA,IACH;AACA,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,OAAO,SAAA;AAAA,IACT;AACA,IAAA,OAAO;AAAA,MACL,QAAA,EAAU,IAAIF,yBAAAA,EAAkB;AAAA,MAChC,MAAA,EAAQ,EAAE,SAAA,EAAW,EAAA,EAAI,YAAY,EAAA;AAAG,KAC1C;AAAA,EACF,CAAA,EAAG,CAAC,aAAA,EAAe,cAAA,EAAgB,SAAS,CAAC,CAAA;AAG7C,EAAAS,eAAA,CAAU,MAAM;AACd,IAAA,SAAS,mBAAmB,KAAA,EAAmB;AAC7C,MAAA,IAAI,WAAA,CAAY,WAAW,CAAC,WAAA,CAAY,QAAQ,QAAA,CAAS,KAAA,CAAM,MAAc,CAAA,EAAG;AAC9E,QAAA,SAAA,CAAU,KAAK,CAAA;AAAA,MACjB;AAAA,IACF;AACA,IAAA,QAAA,CAAS,gBAAA,CAAiB,aAAa,kBAAkB,CAAA;AACzD,IAAA,OAAO,MAAM,QAAA,CAAS,mBAAA,CAAoB,WAAA,EAAa,kBAAkB,CAAA;AAAA,EAC3E,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,IAAI,CAAC,MAAA,CAAO,SAAA,IAAa,CAAC,OAAO,UAAA,EAAY;AAC3C,IAAA,OAAA,CAAQ,KAAA;AAAA,MACN;AAAA,KAEF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,MAAM,aAAA,GAAgBP,cAAQ,MAAM;AAClC,IAAA,IAAI,OAAA;AACJ,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,OAAA,GAAU,WAAA,CACP,GAAA,CAAI,CAAC,EAAA,KAAO,QAAA,CAAS,SAAA,CAAU,EAAE,CAAC,CAAA,CAClC,MAAA,CAAO,CAAC,CAAA,KAA4B,MAAM,MAAS,CAAA;AAAA,IACxD,CAAA,MAAO;AACL,MAAA,OAAA,GAAU,SAAS,oBAAA,EAAqB;AAAA,IAC1C;AAEA,IAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,WAAA,CAAY,aAAA,CAAc,CAAA,CAAE,WAAW,CAAC,CAAA;AAAA,EAC1E,CAAA,EAAG,CAAC,QAAA,EAAU,WAAW,CAAC,CAAA;AAE1B,EAAA,MAAM,eAAA,GAAkBQ,iBAAA,CAAY,OAAO,IAAA,EAAc,QAAA,KAAqB;AAC5E,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,CAAU,SAAA,CAAU,SAAA,CAAU,IAAI,CAAA;AACxC,MAAA,eAAA,CAAgB,QAAQ,CAAA;AACxB,MAAA,UAAA,CAAW,MAAM,eAAA,CAAgB,IAAI,CAAA,EAAG,GAAI,CAAA;AAAA,IAC9C,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,CAAQ,KAAA,CAAM,mBAAmB,GAAG,CAAA;AAAA,IACtC;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,kBAAA,GAAqBA,iBAAA;AAAA,IACzB,CAAC,QAAA,KAAsC;AACrC,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC/C,QAAA,MAAM,YAAA,GAAe,QAAQ,kBAAA,CAAmB;AAAA,UAC9C,SAAA,EAAW,MAAA;AAAA,UACX,WAAW,MAAA,CAAO,SAAA;AAAA,UAClB,YAAY,MAAA,CAAO;AAAA,SACpB,CAAA;AACD,QAAA,OAAO,IAAA,CAAK,SAAA,CAAU,YAAA,EAAc,IAAA,EAAM,CAAC,CAAA;AAAA,MAC7C,CAAA,CAAA,MAAQ;AAEN,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF,CAAA;AAAA,IACA,CAAC,QAAA,EAAU,MAAA,CAAO,SAAA,EAAW,OAAO,UAAU;AAAA,GAChD;AAEA,EAAA,MAAM,mBAAA,GAAsBA,iBAAA;AAAA,IAC1B,CAAC,QAAA,KAAsC;AACrC,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC/C,QAAA,MAAM,SAAA,GAAY,QAAQ,uBAAA,EAAwB;AAClD,QAAA,IAAI,CAAC,UAAU,SAAA,EAAW;AACxB,UAAA,OAAO,IAAA;AAAA,QACT;AACA,QAAA,OAAO,QAAQ,YAAA,CAAa;AAAA,UAC1B,SAAA,EAAW,MAAA;AAAA,UACX,WAAW,MAAA,CAAO,SAAA;AAAA,UAClB,YAAY,MAAA,CAAO;AAAA,SACpB,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF,CAAA;AAAA,IACA,CAAC,QAAA,EAAU,MAAA,CAAO,SAAA,EAAW,OAAO,UAAU;AAAA,GAChD;AAGA,EAAA,MAAM,eAAA,GAAkB;AAAA,IACtB,UAAA;AAAA,IACA,iBAAA;AAAA,IACA,SAAS,gBAAA,GAAmB,EAAA;AAAA,IAC5B,sBAAA;AAAA,IACA;AAAA,GACF,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAEX,EAAA,uBACEP,eAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,WAAA,EAAa,WAAW,eAAA,EAEhC,QAAA,EAAA;AAAA,oBAAAA,eAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,qDAAA;AAAA,QACV,OAAA,EAAS,MAAM,SAAA,CAAU,CAAC,MAAM,CAAA;AAAA,QAChC,eAAA,EAAe,MAAA;AAAA,QACf,eAAA,EAAc,MAAA;AAAA,QAEd,QAAA,EAAA;AAAA,0BAAAC,cAAA,CAAC,OAAA,EAAA,EAAQ,MAAM,EAAA,EAAI,CAAA;AAAA,0BACnBA,cAAA,CAAC,UAAM,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,0BACbA,cAAA,CAAC,eAAY,MAAA,EAAgB;AAAA;AAAA;AAAA,KAC/B;AAAA,oBAGAD,eAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,2CAAA,EACZ,QAAA,EAAA;AAAA,sBAAAC,cAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,8BAAA,EAA+B,QAAA,EAAA,sBAAA,EAAoB,CAAA;AAAA,MAEhE,aAAA,CAAc,GAAA,CAAI,CAAC,MAAA,KAAW;AAC7B,QAAA,MAAM,OAAA,GAAU,mBAAA,CAAoB,MAAA,CAAO,EAAE,CAAA;AAC7C,QAAA,MAAM,YAAA,GAAe,kBAAA,CAAmB,MAAA,CAAO,EAAE,CAAA;AACjD,QAAA,MAAM,QAAA,GAAW,iBAAiB,MAAA,CAAO,EAAA;AAEzC,QAAA,IAAI,CAAC,OAAA,IAAW,CAAC,YAAA,EAAc;AAC7B,UAAA,OAAO,IAAA;AAAA,QACT;AAEA,QAAA,uBACED,eAAA,CAAC,IAAA,EAAA,EAAmB,SAAA,EAAU,4BAAA,EAC5B,QAAA,EAAA;AAAA,0BAAAA,eAAA,CAAC,KAAA,EAAA,EAAI,WAAU,qCAAA,EACb,QAAA,EAAA;AAAA,4BAAAC,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAA,EAAqC,QAAA,EAAA,MAAA,CAAO,WAAA,EAAY,CAAA;AAAA,YACvE,OAAA,oBAAWA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,wBAAuB,QAAA,EAAA,KAAA,EAAG;AAAA,WAAA,EACxD,CAAA;AAAA,UAEC,OAAA,mBACCA,cAAA;AAAA,YAAC,SAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAM,OAAA;AAAA,cACN,QAAA;AAAA,cACA,MAAA,EAAQ,MAAM,eAAA,CAAgB,OAAA,EAAS,OAAO,EAAE;AAAA;AAAA,cAEhD,YAAA,mBACFA,cAAA;AAAA,YAAC,SAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAM,YAAA;AAAA,cACN,WAAA,EAAW,IAAA;AAAA,cACX,QAAA;AAAA,cACA,MAAA,EAAQ,MAAM,eAAA,CAAgB,YAAA,EAAc,OAAO,EAAE;AAAA;AAAA,WACvD,GACE,IAAA;AAAA,UAEH,OAAO,gBAAA,oBACNA,cAAA,CAAC,OAAE,SAAA,EAAU,6BAAA,EAA+B,iBAAO,gBAAA,EAAiB;AAAA,SAAA,EAAA,EAtB/D,OAAO,EAwBhB,CAAA;AAAA,MAEJ,CAAC,CAAA;AAAA,sBAEDA,cAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,8BAAA,EACZ,QAAA,kBAAAD,eAAA;AAAA,QAAC,GAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,kCAAA;AAAA,UACL,MAAA,EAAO,QAAA;AAAA,UACP,GAAA,EAAI,qBAAA;AAAA,UACJ,SAAA,EAAU,kCAAA;AAAA,UACX,QAAA,EAAA;AAAA,YAAA,sBAAA;AAAA,2CAEE,gBAAA,EAAA,EAAiB;AAAA;AAAA;AAAA,OACpB,EACF;AAAA,KAAA,EACF,CAAA;AAAA,mCAGC,OAAA,EAAA,EAAO,QAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,MAAA,CAAA,EAqIN;AAAA,GAAA,EACJ,CAAA;AAEJ","file":"index.js","sourcesContent":["import { useMemo } from 'react';\nimport { usePluginData } from '@docusaurus/useGlobalData';\nimport { MCPConfigRegistry, type RegistryOptions } from '@gleanwork/mcp-config-schema/browser';\n\n/**\n * Configuration from the plugin\n */\nexport interface McpConfig {\n /** Full URL to the MCP server endpoint */\n serverUrl: string;\n /** Name of the MCP server for configuration */\n serverName: string;\n}\n\n/**\n * Plugin global data shape\n */\ninterface McpPluginGlobalData {\n serverUrl: string;\n serverName: string;\n}\n\n/**\n * Registry options for the docs MCP server.\n * Similar to GLEAN_REGISTRY_OPTIONS in @gleanwork/mcp-config-glean\n */\nexport function createDocsRegistryOptions(config: McpConfig): RegistryOptions {\n return {\n // Use the serverName from config for naming\n serverNameBuilder: () => config.serverName,\n };\n}\n\n/**\n * Creates an MCPConfigRegistry pre-configured with the docs server settings.\n *\n * Similar to createGleanRegistry() from @gleanwork/mcp-config-glean\n *\n * @param config - The server configuration from plugin\n * @returns Object with registry instance and bound config\n */\nexport function createDocsRegistry(config: McpConfig): {\n registry: MCPConfigRegistry;\n config: McpConfig;\n} {\n const options = createDocsRegistryOptions(config);\n return {\n registry: new MCPConfigRegistry(options),\n config,\n };\n}\n\n/**\n * Hook to access the pre-configured MCP registry and config.\n *\n * Reads configuration from plugin globalData and creates a registry\n * with the serverUrl and serverName pre-bound in the config object.\n *\n * @returns { registry, config } or undefined if plugin not configured\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const mcp = useMcpRegistry();\n * if (!mcp) return null;\n *\n * const { registry, config } = mcp;\n * const builder = registry.createBuilder('claude-code');\n * const json = builder.buildConfiguration({\n * transport: 'http',\n * serverUrl: config.serverUrl,\n * serverName: config.serverName,\n * });\n * }\n * ```\n */\nexport function useMcpRegistry(): { registry: MCPConfigRegistry; config: McpConfig } | undefined {\n // Read plugin globalData\n let pluginData: McpPluginGlobalData | undefined;\n try {\n pluginData = usePluginData('docusaurus-plugin-mcp-server') as McpPluginGlobalData | undefined;\n } catch {\n // Plugin not installed\n return undefined;\n }\n\n // Memoize registry creation\n const result = useMemo(() => {\n if (!pluginData?.serverUrl || !pluginData?.serverName) {\n return undefined;\n }\n const config: McpConfig = {\n serverUrl: pluginData.serverUrl,\n serverName: pluginData.serverName,\n };\n return createDocsRegistry(config);\n }, [pluginData?.serverUrl, pluginData?.serverName]);\n\n return result;\n}\n\nexport default useMcpRegistry;\n","import { useState, useRef, useEffect, useCallback, useMemo } from 'react';\nimport {\n MCPConfigRegistry,\n type ClientId,\n type MCPClientConfig,\n} from '@gleanwork/mcp-config-schema/browser';\nimport IconCopy from '@theme/Icon/Copy';\nimport IconSuccess from '@theme/Icon/Success';\nimport { useMcpRegistry, createDocsRegistry, type McpConfig } from './McpRegistryContext.js';\n\n/**\n * MCP Logo icon - extracted from official MCP branding\n */\nfunction IconMcp({ size = 16 }: { size?: number }) {\n return (\n <svg\n viewBox=\"0 0 170 195\"\n width={size}\n height={size}\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ display: 'block' }}\n >\n <path\n d=\"M25 97.8528L92.8823 29.9706C102.255 20.598 117.451 20.598 126.823 29.9706C136.196 39.3431 136.196 54.5391 126.823 63.9117L75.5581 115.177\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M76.2653 114.47L126.823 63.9117C136.196 54.5391 151.392 54.5391 160.765 63.9117L161.118 64.2652C170.491 73.6378 170.491 88.8338 161.118 98.2063L99.7248 159.6C96.6006 162.724 96.6006 167.789 99.7248 170.913L112.331 183.52\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M109.853 46.9411L59.6482 97.1457C50.2757 106.518 50.2757 121.714 59.6482 131.087C69.0208 140.459 84.2168 140.459 93.5894 131.087L143.794 80.8822\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n\n/**\n * Chevron icon for dropdown\n */\nfunction IconChevron({ isOpen }: { isOpen: boolean }) {\n return (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n style={{\n display: 'block',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform var(--ifm-transition-fast)',\n }}\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n );\n}\n\n/**\n * External link icon\n */\nfunction IconExternalLink() {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" style={{ display: 'block', marginLeft: '4px' }}>\n <path\n fill=\"currentColor\"\n d=\"M3.5 3C3.22386 3 3 3.22386 3 3.5C3 3.77614 3.22386 4 3.5 4H7.29289L3.14645 8.14645C2.95118 8.34171 2.95118 8.65829 3.14645 8.85355C3.34171 9.04882 3.65829 9.04882 3.85355 8.85355L8 4.70711V8.5C8 8.77614 8.22386 9 8.5 9C8.77614 9 9 8.77614 9 8.5V3.5C9 3.22386 8.77614 3 8.5 3H3.5Z\"\n />\n </svg>\n );\n}\n\n/**\n * Code block with integrated copy button\n */\nfunction CodeBlock({\n code,\n isMultiline = false,\n isCopied,\n onCopy,\n}: {\n code: string;\n isMultiline?: boolean;\n isCopied: boolean;\n onCopy: () => void;\n}) {\n return (\n <div className=\"mcp-code-block\">\n <div className=\"mcp-code-block__content\">\n {isMultiline ? (\n <pre className=\"mcp-code-block__pre\">\n <code>{code}</code>\n </pre>\n ) : (\n <code>{code}</code>\n )}\n </div>\n <button\n className=\"mcp-code-block__copy\"\n onClick={onCopy}\n title={isCopied ? 'Copied!' : 'Copy to clipboard'}\n aria-label={isCopied ? 'Copied' : 'Copy to clipboard'}\n >\n {isCopied ? (\n <IconSuccess className=\"mcp-code-block__icon mcp-code-block__icon--success\" />\n ) : (\n <IconCopy className=\"mcp-code-block__icon\" />\n )}\n </button>\n </div>\n );\n}\n\n/**\n * Props for the McpInstallButton component\n */\nexport interface McpInstallButtonProps {\n /** Server URL. If not provided, uses plugin configuration. */\n serverUrl?: string;\n /** Server name. If not provided, uses plugin configuration. */\n serverName?: string;\n /** Button label (default: \"Install docs MCP\") */\n label?: string;\n /** Optional className for styling */\n className?: string;\n /** Clients to show. Defaults to all HTTP-capable clients from registry. */\n clients?: ClientId[];\n}\n\n/**\n * A dropdown button component for installing MCP servers in various AI tools.\n * Uses Docusaurus/Infima CSS classes for consistent theming.\n *\n * @example\n * ```tsx\n * <McpInstallButton\n * serverUrl=\"https://docs.example.com/mcp\"\n * serverName=\"my-docs\"\n * />\n * ```\n */\nexport function McpInstallButton({\n serverUrl: serverUrlProp,\n serverName: serverNameProp,\n label = 'Install docs MCP',\n className = '',\n clients: clientsProp,\n}: McpInstallButtonProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [copiedClient, setCopiedClient] = useState<string | null>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Get pre-configured registry from plugin\n const pluginMcp = useMcpRegistry();\n\n // Use props if provided, otherwise fall back to plugin config\n const { registry, config } = useMemo(() => {\n if (serverUrlProp && serverNameProp) {\n return createDocsRegistry({\n serverUrl: serverUrlProp,\n serverName: serverNameProp,\n });\n }\n if (pluginMcp) {\n return pluginMcp;\n }\n return {\n registry: new MCPConfigRegistry(),\n config: { serverUrl: '', serverName: '' } as McpConfig,\n };\n }, [serverUrlProp, serverNameProp, pluginMcp]);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n }\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // Validate configuration\n if (!config.serverUrl || !config.serverName) {\n console.error(\n '[McpInstallButton] Missing serverUrl or serverName. ' +\n 'Either pass them as props or configure the docusaurus-plugin-mcp-server plugin.'\n );\n return null;\n }\n\n // Get clients to display - dynamic from registry, sorted alphabetically\n const clientConfigs = useMemo(() => {\n let clients: MCPClientConfig[];\n if (clientsProp) {\n clients = clientsProp\n .map((id) => registry.getConfig(id))\n .filter((c): c is MCPClientConfig => c !== undefined);\n } else {\n clients = registry.getNativeHttpClients();\n }\n // Sort alphabetically by display name\n return clients.sort((a, b) => a.displayName.localeCompare(b.displayName));\n }, [registry, clientsProp]);\n\n const copyToClipboard = useCallback(async (text: string, clientId: string) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopiedClient(clientId);\n setTimeout(() => setCopiedClient(null), 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n }, []);\n\n const getConfigForClient = useCallback(\n (clientId: ClientId): string | null => {\n try {\n const builder = registry.createBuilder(clientId);\n const clientConfig = builder.buildConfiguration({\n transport: 'http',\n serverUrl: config.serverUrl,\n serverName: config.serverName,\n });\n return JSON.stringify(clientConfig, null, 2);\n } catch {\n // Client doesn't support local configuration\n return null;\n }\n },\n [registry, config.serverUrl, config.serverName]\n );\n\n const getCommandForClient = useCallback(\n (clientId: ClientId): string | null => {\n try {\n const builder = registry.createBuilder(clientId);\n const cliStatus = builder.supportsCliInstallation();\n if (!cliStatus.supported) {\n return null;\n }\n return builder.buildCommand({\n transport: 'http',\n serverUrl: config.serverUrl,\n serverName: config.serverName,\n });\n } catch {\n return null;\n }\n },\n [registry, config.serverUrl, config.serverName]\n );\n\n // Using Infima dropdown classes\n const dropdownClasses = [\n 'dropdown',\n 'dropdown--right',\n isOpen ? 'dropdown--show' : '',\n 'mcp-install-dropdown',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div ref={dropdownRef} className={dropdownClasses}>\n {/* Infima button classes */}\n <button\n className=\"button button--primary mcp-install-dropdown__button\"\n onClick={() => setIsOpen(!isOpen)}\n aria-expanded={isOpen}\n aria-haspopup=\"true\"\n >\n <IconMcp size={16} />\n <span>{label}</span>\n <IconChevron isOpen={isOpen} />\n </button>\n\n {/* Dropdown menu using Infima classes */}\n <ul className=\"dropdown__menu mcp-install-dropdown__menu\">\n <li className=\"mcp-install-dropdown__header\">Choose your AI tool:</li>\n\n {clientConfigs.map((client) => {\n const command = getCommandForClient(client.id);\n const clientConfig = getConfigForClient(client.id);\n const isCopied = copiedClient === client.id;\n\n if (!command && !clientConfig) {\n return null;\n }\n\n return (\n <li key={client.id} className=\"mcp-install-dropdown__item\">\n <div className=\"mcp-install-dropdown__client-header\">\n <span className=\"mcp-install-dropdown__client-name\">{client.displayName}</span>\n {command && <span className=\"badge badge--success\">CLI</span>}\n </div>\n\n {command ? (\n <CodeBlock\n code={command}\n isCopied={isCopied}\n onCopy={() => copyToClipboard(command, client.id)}\n />\n ) : clientConfig ? (\n <CodeBlock\n code={clientConfig}\n isMultiline\n isCopied={isCopied}\n onCopy={() => copyToClipboard(clientConfig, client.id)}\n />\n ) : null}\n\n {client.localConfigNotes && (\n <p className=\"mcp-install-dropdown__notes\">{client.localConfigNotes}</p>\n )}\n </li>\n );\n })}\n\n <li className=\"mcp-install-dropdown__footer\">\n <a\n href=\"https://modelcontextprotocol.io/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mcp-install-dropdown__learn-more\"\n >\n Learn more about MCP\n <IconExternalLink />\n </a>\n </li>\n </ul>\n\n {/* Scoped styles using CSS variables for customization */}\n <style>{`\n .mcp-install-dropdown {\n --mcp-dropdown-width: 520px;\n /* Always use dark code blocks for consistency across themes */\n --mcp-code-bg: #1e1e1e;\n --mcp-code-color: #e5e7eb;\n }\n\n .mcp-install-dropdown__button {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n }\n\n .mcp-install-dropdown__menu {\n width: var(--mcp-dropdown-width);\n padding: 0;\n top: calc(100% + 0.25rem);\n }\n\n .mcp-install-dropdown__header {\n padding: 0.75rem 1rem;\n font-size: var(--ifm-font-size-small);\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-color-secondary-darkest);\n background-color: var(--ifm-background-color);\n border-bottom: 1px solid var(--ifm-toc-border-color);\n }\n\n .mcp-install-dropdown__item {\n padding: 0.875rem 1rem;\n border-bottom: 1px solid var(--ifm-toc-border-color);\n }\n\n .mcp-install-dropdown__client-header {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-bottom: 0.625rem;\n }\n\n .mcp-install-dropdown__client-name {\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-font-color-base);\n }\n\n .mcp-install-dropdown__notes {\n margin: 0.5rem 0 0;\n font-size: var(--ifm-font-size-small);\n color: var(--ifm-color-secondary-darkest);\n line-height: 1.4;\n }\n\n .mcp-install-dropdown__footer {\n padding: 0.75rem 1rem;\n text-align: center;\n background-color: var(--ifm-background-color);\n }\n\n .mcp-install-dropdown__learn-more {\n display: inline-flex;\n align-items: center;\n font-size: var(--ifm-font-size-small);\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-color-primary);\n text-decoration: none;\n }\n\n .mcp-install-dropdown__learn-more:hover {\n color: var(--ifm-color-primary-dark);\n text-decoration: none;\n }\n\n /* Code block styles */\n .mcp-code-block {\n display: flex;\n border-radius: var(--ifm-code-border-radius, 0.25rem);\n overflow: hidden;\n }\n\n .mcp-code-block__content {\n flex: 1;\n background-color: var(--mcp-code-bg);\n padding: 0.75rem 1rem;\n overflow-x: auto;\n }\n\n .mcp-code-block__content code {\n font-family: var(--ifm-font-family-monospace);\n font-size: var(--ifm-code-font-size);\n color: var(--mcp-code-color);\n background: none;\n padding: 0;\n border: none;\n white-space: nowrap;\n }\n\n .mcp-code-block__pre {\n margin: 0;\n background: none;\n max-height: 120px;\n overflow-y: auto;\n }\n\n .mcp-code-block__pre code {\n white-space: pre;\n }\n\n .mcp-code-block__copy {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n background-color: var(--ifm-color-gray-800, #374151);\n border: none;\n cursor: pointer;\n color: var(--ifm-color-gray-400, #9ca3af);\n transition: background-color var(--ifm-transition-fast);\n }\n\n .mcp-code-block__copy:hover {\n background-color: var(--ifm-color-gray-700, #4b5563);\n }\n\n .mcp-code-block__icon {\n width: 16px;\n height: 16px;\n display: block;\n }\n\n .mcp-code-block__icon--success {\n color: var(--ifm-color-success, #22c55e);\n }\n `}</style>\n </div>\n );\n}\n\nexport default McpInstallButton;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/theme/McpRegistryContext.tsx","../../src/theme/McpInstallButton.tsx"],"names":["MCPConfigRegistry","usePluginData","useMemo","jsxs","jsx","IconSuccess","IconCopy","useState","useRef","useEffect","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["import { useMemo } from 'react';\nimport { usePluginData } from '@docusaurus/useGlobalData';\nimport { MCPConfigRegistry, type RegistryOptions } from '@gleanwork/mcp-config-schema/browser';\n\n/**\n * Configuration from the plugin\n */\nexport interface McpConfig {\n /** Full URL to the MCP server endpoint */\n serverUrl: string;\n /** Name of the MCP server for configuration */\n serverName: string;\n}\n\n/**\n * Plugin global data shape\n */\ninterface McpPluginGlobalData {\n serverUrl: string;\n serverName: string;\n}\n\n/**\n * Registry options for the docs MCP server.\n * Similar to GLEAN_REGISTRY_OPTIONS in @gleanwork/mcp-config-glean\n */\nexport function createDocsRegistryOptions(config: McpConfig): RegistryOptions {\n return {\n // Use the serverName from config for naming\n serverNameBuilder: () => config.serverName,\n };\n}\n\n/**\n * Creates an MCPConfigRegistry pre-configured with the docs server settings.\n *\n * Similar to createGleanRegistry() from @gleanwork/mcp-config-glean\n *\n * @param config - The server configuration from plugin\n * @returns Object with registry instance and bound config\n */\nexport function createDocsRegistry(config: McpConfig): {\n registry: MCPConfigRegistry;\n config: McpConfig;\n} {\n const options = createDocsRegistryOptions(config);\n return {\n registry: new MCPConfigRegistry(options),\n config,\n };\n}\n\n/**\n * Hook to access the pre-configured MCP registry and config.\n *\n * Reads configuration from plugin globalData and creates a registry\n * with the serverUrl and serverName pre-bound in the config object.\n *\n * @returns { registry, config } or undefined if plugin not configured\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const mcp = useMcpRegistry();\n * if (!mcp) return null;\n *\n * const { registry, config } = mcp;\n * const builder = registry.createBuilder('claude-code');\n * const json = builder.buildConfiguration({\n * transport: 'http',\n * serverUrl: config.serverUrl,\n * serverName: config.serverName,\n * });\n * }\n * ```\n */\nexport function useMcpRegistry(): { registry: MCPConfigRegistry; config: McpConfig } | undefined {\n // Read plugin globalData\n let pluginData: McpPluginGlobalData | undefined;\n try {\n pluginData = usePluginData('docusaurus-plugin-mcp-server') as McpPluginGlobalData | undefined;\n } catch {\n // Plugin not installed\n return undefined;\n }\n\n // Memoize registry creation\n const result = useMemo(() => {\n if (!pluginData?.serverUrl || !pluginData?.serverName) {\n return undefined;\n }\n const config: McpConfig = {\n serverUrl: pluginData.serverUrl,\n serverName: pluginData.serverName,\n };\n return createDocsRegistry(config);\n }, [pluginData?.serverUrl, pluginData?.serverName]);\n\n return result;\n}\n\nexport default useMcpRegistry;\n","import { useState, useRef, useEffect, useCallback, useMemo } from 'react';\nimport {\n MCPConfigRegistry,\n type ClientId,\n type MCPClientConfig,\n} from '@gleanwork/mcp-config-schema/browser';\nimport IconCopy from '@theme/Icon/Copy';\nimport IconSuccess from '@theme/Icon/Success';\nimport { useMcpRegistry, createDocsRegistry, type McpConfig } from './McpRegistryContext.js';\n\n/**\n * MCP Logo icon - extracted from official MCP branding\n */\nfunction IconMcp({ size = 16 }: { size?: number }) {\n return (\n <svg\n viewBox=\"0 0 170 195\"\n width={size}\n height={size}\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ display: 'block' }}\n >\n <path\n d=\"M25 97.8528L92.8823 29.9706C102.255 20.598 117.451 20.598 126.823 29.9706C136.196 39.3431 136.196 54.5391 126.823 63.9117L75.5581 115.177\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M76.2653 114.47L126.823 63.9117C136.196 54.5391 151.392 54.5391 160.765 63.9117L161.118 64.2652C170.491 73.6378 170.491 88.8338 161.118 98.2063L99.7248 159.6C96.6006 162.724 96.6006 167.789 99.7248 170.913L112.331 183.52\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M109.853 46.9411L59.6482 97.1457C50.2757 106.518 50.2757 121.714 59.6482 131.087C69.0208 140.459 84.2168 140.459 93.5894 131.087L143.794 80.8822\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n\n/**\n * Chevron icon for dropdown\n */\nfunction IconChevron({ isOpen }: { isOpen: boolean }) {\n return (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n style={{\n display: 'block',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform var(--ifm-transition-fast)',\n }}\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n );\n}\n\n/**\n * External link icon\n */\nfunction IconExternalLink() {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" style={{ display: 'block', marginLeft: '4px' }}>\n <path\n fill=\"currentColor\"\n d=\"M3.5 3C3.22386 3 3 3.22386 3 3.5C3 3.77614 3.22386 4 3.5 4H7.29289L3.14645 8.14645C2.95118 8.34171 2.95118 8.65829 3.14645 8.85355C3.34171 9.04882 3.65829 9.04882 3.85355 8.85355L8 4.70711V8.5C8 8.77614 8.22386 9 8.5 9C8.77614 9 9 8.77614 9 8.5V3.5C9 3.22386 8.77614 3 8.5 3H3.5Z\"\n />\n </svg>\n );\n}\n\n/**\n * Code block with integrated copy button\n */\nfunction CodeBlock({\n code,\n isMultiline = false,\n isCopied,\n onCopy,\n}: {\n code: string;\n isMultiline?: boolean;\n isCopied: boolean;\n onCopy: () => void;\n}) {\n return (\n <div className=\"mcp-code-block\">\n <div className=\"mcp-code-block__content\">\n {isMultiline ? (\n <pre className=\"mcp-code-block__pre\">\n <code>{code}</code>\n </pre>\n ) : (\n <code>{code}</code>\n )}\n </div>\n <button\n className=\"mcp-code-block__copy\"\n onClick={onCopy}\n title={isCopied ? 'Copied!' : 'Copy to clipboard'}\n aria-label={isCopied ? 'Copied' : 'Copy to clipboard'}\n >\n {isCopied ? (\n <IconSuccess className=\"mcp-code-block__icon mcp-code-block__icon--success\" />\n ) : (\n <IconCopy className=\"mcp-code-block__icon\" />\n )}\n </button>\n </div>\n );\n}\n\n/**\n * Props for the McpInstallButton component\n */\nexport interface McpInstallButtonProps {\n /** Server URL. If not provided, uses plugin configuration. */\n serverUrl?: string;\n /** Server name. If not provided, uses plugin configuration. */\n serverName?: string;\n /** Button label. If not provided, shows only the MCP icon. */\n label?: string;\n /** Optional className for styling */\n className?: string;\n /** Clients to show. Defaults to all HTTP-capable clients from registry. */\n clients?: ClientId[];\n /** Header text shown at top of dropdown (default: \"Choose your AI tool:\") */\n headerText?: string;\n}\n\n/**\n * A dropdown button component for installing MCP servers in various AI tools.\n * Uses Docusaurus/Infima CSS classes for consistent theming.\n *\n * @example\n * ```tsx\n * <McpInstallButton\n * serverUrl=\"https://docs.example.com/mcp\"\n * serverName=\"my-docs\"\n * />\n * ```\n */\nexport function McpInstallButton({\n serverUrl: serverUrlProp,\n serverName: serverNameProp,\n label,\n className = '',\n clients: clientsProp,\n headerText = 'Choose your AI tool:',\n}: McpInstallButtonProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [copiedClient, setCopiedClient] = useState<string | null>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Get pre-configured registry from plugin\n const pluginMcp = useMcpRegistry();\n\n // Use props if provided, otherwise fall back to plugin config\n const { registry, config } = useMemo(() => {\n if (serverUrlProp && serverNameProp) {\n return createDocsRegistry({\n serverUrl: serverUrlProp,\n serverName: serverNameProp,\n });\n }\n if (pluginMcp) {\n return pluginMcp;\n }\n return {\n registry: new MCPConfigRegistry(),\n config: { serverUrl: '', serverName: '' } as McpConfig,\n };\n }, [serverUrlProp, serverNameProp, pluginMcp]);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n }\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // Validate configuration\n if (!config.serverUrl || !config.serverName) {\n console.error(\n '[McpInstallButton] Missing serverUrl or serverName. ' +\n 'Either pass them as props or configure the docusaurus-plugin-mcp-server plugin.'\n );\n return null;\n }\n\n // Get clients to display - dynamic from registry, sorted alphabetically\n const clientConfigs = useMemo(() => {\n let clients: MCPClientConfig[];\n if (clientsProp) {\n clients = clientsProp\n .map((id) => registry.getConfig(id))\n .filter((c): c is MCPClientConfig => c !== undefined);\n } else {\n clients = registry.getNativeHttpClients();\n }\n // Sort alphabetically by display name\n return clients.sort((a, b) => a.displayName.localeCompare(b.displayName));\n }, [registry, clientsProp]);\n\n const copyToClipboard = useCallback(async (text: string, clientId: string) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopiedClient(clientId);\n setTimeout(() => setCopiedClient(null), 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n }, []);\n\n const getConfigForClient = useCallback(\n (clientId: ClientId): string | null => {\n try {\n const builder = registry.createBuilder(clientId);\n const clientConfig = builder.buildConfiguration({\n transport: 'http',\n serverUrl: config.serverUrl,\n serverName: config.serverName,\n });\n return JSON.stringify(clientConfig, null, 2);\n } catch {\n // Client doesn't support local configuration\n return null;\n }\n },\n [registry, config.serverUrl, config.serverName]\n );\n\n const getCommandForClient = useCallback(\n (clientId: ClientId): string | null => {\n try {\n const builder = registry.createBuilder(clientId);\n const cliStatus = builder.supportsCliInstallation();\n if (!cliStatus.supported) {\n return null;\n }\n return builder.buildCommand({\n transport: 'http',\n serverUrl: config.serverUrl,\n serverName: config.serverName,\n });\n } catch {\n return null;\n }\n },\n [registry, config.serverUrl, config.serverName]\n );\n\n // Using Infima dropdown classes\n const dropdownClasses = [\n 'dropdown',\n 'dropdown--right',\n isOpen ? 'dropdown--show' : '',\n 'mcp-install-dropdown',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div ref={dropdownRef} className={dropdownClasses}>\n {/* Infima button classes */}\n <button\n className={`button button--primary mcp-install-dropdown__button${label ? '' : ' mcp-install-dropdown__button--icon-only'}`}\n onClick={() => setIsOpen(!isOpen)}\n aria-expanded={isOpen}\n aria-haspopup=\"true\"\n aria-label={label || 'Install MCP'}\n >\n <IconMcp size={16} />\n {label && <span>{label}</span>}\n <IconChevron isOpen={isOpen} />\n </button>\n\n {/* Dropdown menu using Infima classes */}\n <ul className=\"dropdown__menu mcp-install-dropdown__menu\">\n <li className=\"mcp-install-dropdown__header\">{headerText}</li>\n\n {clientConfigs.map((client) => {\n const command = getCommandForClient(client.id);\n const clientConfig = getConfigForClient(client.id);\n const isCopied = copiedClient === client.id;\n\n if (!command && !clientConfig) {\n return null;\n }\n\n return (\n <li key={client.id} className=\"mcp-install-dropdown__item\">\n <div className=\"mcp-install-dropdown__client-header\">\n <span className=\"mcp-install-dropdown__client-name\">{client.displayName}</span>\n {command && <span className=\"badge badge--success\">CLI</span>}\n </div>\n\n {command ? (\n <CodeBlock\n code={command}\n isCopied={isCopied}\n onCopy={() => copyToClipboard(command, client.id)}\n />\n ) : clientConfig ? (\n <CodeBlock\n code={clientConfig}\n isMultiline\n isCopied={isCopied}\n onCopy={() => copyToClipboard(clientConfig, client.id)}\n />\n ) : null}\n\n {client.localConfigNotes && (\n <p className=\"mcp-install-dropdown__notes\">{client.localConfigNotes}</p>\n )}\n </li>\n );\n })}\n\n <li className=\"mcp-install-dropdown__footer\">\n <a\n href=\"https://modelcontextprotocol.io/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mcp-install-dropdown__learn-more\"\n >\n Learn more about MCP\n <IconExternalLink />\n </a>\n </li>\n </ul>\n\n {/* Scoped styles using Docusaurus/Infima CSS variables */}\n <style>{`\n .mcp-install-dropdown__button {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n }\n\n .mcp-install-dropdown__button--icon-only {\n padding: 0.5rem 0.75rem;\n gap: 0.25rem;\n }\n\n .mcp-install-dropdown__menu {\n width: 520px;\n padding: 0;\n top: calc(100% + 0.25rem);\n }\n\n .mcp-install-dropdown__header {\n padding: 0.75rem 1rem;\n font-size: var(--ifm-font-size-small);\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-color-emphasis-700);\n background-color: var(--ifm-background-color);\n border-bottom: 1px solid var(--ifm-toc-border-color);\n }\n\n .mcp-install-dropdown__item {\n padding: 0.875rem 1rem;\n border-bottom: 1px solid var(--ifm-toc-border-color);\n }\n\n .mcp-install-dropdown__client-header {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-bottom: 0.625rem;\n }\n\n .mcp-install-dropdown__client-name {\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-font-color-base);\n }\n\n .mcp-install-dropdown__notes {\n margin: 0.5rem 0 0;\n font-size: var(--ifm-font-size-small);\n color: var(--ifm-color-emphasis-700);\n line-height: 1.4;\n }\n\n .mcp-install-dropdown__footer {\n padding: 0.75rem 1rem;\n text-align: center;\n background-color: var(--ifm-background-color);\n }\n\n .mcp-install-dropdown__learn-more {\n display: inline-flex;\n align-items: center;\n font-size: var(--ifm-font-size-small);\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-color-primary);\n text-decoration: none;\n }\n\n .mcp-install-dropdown__learn-more:hover {\n color: var(--ifm-color-primary-dark);\n text-decoration: none;\n }\n\n /* Code block styles - uses Docusaurus pre/code variables */\n .mcp-code-block {\n display: flex;\n border-radius: var(--ifm-code-border-radius);\n overflow: hidden;\n }\n\n .mcp-code-block__content {\n flex: 1;\n background-color: var(--ifm-pre-background);\n padding: 0.75rem 1rem;\n overflow-x: auto;\n }\n\n .mcp-code-block__content code {\n font-family: var(--ifm-font-family-monospace);\n font-size: var(--ifm-code-font-size);\n color: var(--ifm-pre-color);\n background: none;\n padding: 0;\n border: none;\n white-space: nowrap;\n }\n\n .mcp-code-block__pre {\n margin: 0;\n background: none;\n max-height: 120px;\n overflow-y: auto;\n }\n\n .mcp-code-block__pre code {\n white-space: pre;\n }\n\n .mcp-code-block__copy {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n background-color: var(--ifm-color-emphasis-200);\n border: none;\n cursor: pointer;\n color: var(--ifm-color-emphasis-700);\n transition: background-color var(--ifm-transition-fast);\n }\n\n .mcp-code-block__copy:hover {\n background-color: var(--ifm-color-emphasis-300);\n }\n\n .mcp-code-block__icon {\n width: 16px;\n height: 16px;\n display: block;\n }\n\n .mcp-code-block__icon--success {\n color: var(--ifm-color-success);\n }\n `}</style>\n </div>\n );\n}\n\nexport default McpInstallButton;\n"]}
|
package/dist/theme/index.mjs
CHANGED
|
@@ -138,9 +138,10 @@ function CodeBlock({
|
|
|
138
138
|
function McpInstallButton({
|
|
139
139
|
serverUrl: serverUrlProp,
|
|
140
140
|
serverName: serverNameProp,
|
|
141
|
-
label
|
|
141
|
+
label,
|
|
142
142
|
className = "",
|
|
143
|
-
clients: clientsProp
|
|
143
|
+
clients: clientsProp,
|
|
144
|
+
headerText = "Choose your AI tool:"
|
|
144
145
|
}) {
|
|
145
146
|
const [isOpen, setIsOpen] = useState(false);
|
|
146
147
|
const [copiedClient, setCopiedClient] = useState(null);
|
|
@@ -240,19 +241,20 @@ function McpInstallButton({
|
|
|
240
241
|
/* @__PURE__ */ jsxs(
|
|
241
242
|
"button",
|
|
242
243
|
{
|
|
243
|
-
className:
|
|
244
|
+
className: `button button--primary mcp-install-dropdown__button${label ? "" : " mcp-install-dropdown__button--icon-only"}`,
|
|
244
245
|
onClick: () => setIsOpen(!isOpen),
|
|
245
246
|
"aria-expanded": isOpen,
|
|
246
247
|
"aria-haspopup": "true",
|
|
248
|
+
"aria-label": label || "Install MCP",
|
|
247
249
|
children: [
|
|
248
250
|
/* @__PURE__ */ jsx(IconMcp, { size: 16 }),
|
|
249
|
-
/* @__PURE__ */ jsx("span", { children: label }),
|
|
251
|
+
label && /* @__PURE__ */ jsx("span", { children: label }),
|
|
250
252
|
/* @__PURE__ */ jsx(IconChevron, { isOpen })
|
|
251
253
|
]
|
|
252
254
|
}
|
|
253
255
|
),
|
|
254
256
|
/* @__PURE__ */ jsxs("ul", { className: "dropdown__menu mcp-install-dropdown__menu", children: [
|
|
255
|
-
/* @__PURE__ */ jsx("li", { className: "mcp-install-dropdown__header", children:
|
|
257
|
+
/* @__PURE__ */ jsx("li", { className: "mcp-install-dropdown__header", children: headerText }),
|
|
256
258
|
clientConfigs.map((client) => {
|
|
257
259
|
const command = getCommandForClient(client.id);
|
|
258
260
|
const clientConfig = getConfigForClient(client.id);
|
|
@@ -299,21 +301,19 @@ function McpInstallButton({
|
|
|
299
301
|
) })
|
|
300
302
|
] }),
|
|
301
303
|
/* @__PURE__ */ jsx("style", { children: `
|
|
302
|
-
.mcp-install-dropdown {
|
|
303
|
-
--mcp-dropdown-width: 520px;
|
|
304
|
-
/* Always use dark code blocks for consistency across themes */
|
|
305
|
-
--mcp-code-bg: #1e1e1e;
|
|
306
|
-
--mcp-code-color: #e5e7eb;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
304
|
.mcp-install-dropdown__button {
|
|
310
305
|
display: inline-flex;
|
|
311
306
|
align-items: center;
|
|
312
307
|
gap: 0.5rem;
|
|
313
308
|
}
|
|
314
309
|
|
|
310
|
+
.mcp-install-dropdown__button--icon-only {
|
|
311
|
+
padding: 0.5rem 0.75rem;
|
|
312
|
+
gap: 0.25rem;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
315
|
.mcp-install-dropdown__menu {
|
|
316
|
-
width:
|
|
316
|
+
width: 520px;
|
|
317
317
|
padding: 0;
|
|
318
318
|
top: calc(100% + 0.25rem);
|
|
319
319
|
}
|
|
@@ -322,7 +322,7 @@ function McpInstallButton({
|
|
|
322
322
|
padding: 0.75rem 1rem;
|
|
323
323
|
font-size: var(--ifm-font-size-small);
|
|
324
324
|
font-weight: var(--ifm-font-weight-semibold);
|
|
325
|
-
color: var(--ifm-color-
|
|
325
|
+
color: var(--ifm-color-emphasis-700);
|
|
326
326
|
background-color: var(--ifm-background-color);
|
|
327
327
|
border-bottom: 1px solid var(--ifm-toc-border-color);
|
|
328
328
|
}
|
|
@@ -347,7 +347,7 @@ function McpInstallButton({
|
|
|
347
347
|
.mcp-install-dropdown__notes {
|
|
348
348
|
margin: 0.5rem 0 0;
|
|
349
349
|
font-size: var(--ifm-font-size-small);
|
|
350
|
-
color: var(--ifm-color-
|
|
350
|
+
color: var(--ifm-color-emphasis-700);
|
|
351
351
|
line-height: 1.4;
|
|
352
352
|
}
|
|
353
353
|
|
|
@@ -371,16 +371,16 @@ function McpInstallButton({
|
|
|
371
371
|
text-decoration: none;
|
|
372
372
|
}
|
|
373
373
|
|
|
374
|
-
/* Code block styles */
|
|
374
|
+
/* Code block styles - uses Docusaurus pre/code variables */
|
|
375
375
|
.mcp-code-block {
|
|
376
376
|
display: flex;
|
|
377
|
-
border-radius: var(--ifm-code-border-radius
|
|
377
|
+
border-radius: var(--ifm-code-border-radius);
|
|
378
378
|
overflow: hidden;
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
.mcp-code-block__content {
|
|
382
382
|
flex: 1;
|
|
383
|
-
background-color: var(--
|
|
383
|
+
background-color: var(--ifm-pre-background);
|
|
384
384
|
padding: 0.75rem 1rem;
|
|
385
385
|
overflow-x: auto;
|
|
386
386
|
}
|
|
@@ -388,7 +388,7 @@ function McpInstallButton({
|
|
|
388
388
|
.mcp-code-block__content code {
|
|
389
389
|
font-family: var(--ifm-font-family-monospace);
|
|
390
390
|
font-size: var(--ifm-code-font-size);
|
|
391
|
-
color: var(--
|
|
391
|
+
color: var(--ifm-pre-color);
|
|
392
392
|
background: none;
|
|
393
393
|
padding: 0;
|
|
394
394
|
border: none;
|
|
@@ -411,15 +411,15 @@ function McpInstallButton({
|
|
|
411
411
|
align-items: center;
|
|
412
412
|
justify-content: center;
|
|
413
413
|
width: 2.75rem;
|
|
414
|
-
background-color: var(--ifm-color-
|
|
414
|
+
background-color: var(--ifm-color-emphasis-200);
|
|
415
415
|
border: none;
|
|
416
416
|
cursor: pointer;
|
|
417
|
-
color: var(--ifm-color-
|
|
417
|
+
color: var(--ifm-color-emphasis-700);
|
|
418
418
|
transition: background-color var(--ifm-transition-fast);
|
|
419
419
|
}
|
|
420
420
|
|
|
421
421
|
.mcp-code-block__copy:hover {
|
|
422
|
-
background-color: var(--ifm-color-
|
|
422
|
+
background-color: var(--ifm-color-emphasis-300);
|
|
423
423
|
}
|
|
424
424
|
|
|
425
425
|
.mcp-code-block__icon {
|
|
@@ -429,7 +429,7 @@ function McpInstallButton({
|
|
|
429
429
|
}
|
|
430
430
|
|
|
431
431
|
.mcp-code-block__icon--success {
|
|
432
|
-
color: var(--ifm-color-success
|
|
432
|
+
color: var(--ifm-color-success);
|
|
433
433
|
}
|
|
434
434
|
` })
|
|
435
435
|
] });
|
package/dist/theme/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/theme/McpRegistryContext.tsx","../../src/theme/McpInstallButton.tsx"],"names":["useMemo","MCPConfigRegistry"],"mappings":"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","file":"index.mjs","sourcesContent":["import { useMemo } from 'react';\nimport { usePluginData } from '@docusaurus/useGlobalData';\nimport { MCPConfigRegistry, type RegistryOptions } from '@gleanwork/mcp-config-schema/browser';\n\n/**\n * Configuration from the plugin\n */\nexport interface McpConfig {\n /** Full URL to the MCP server endpoint */\n serverUrl: string;\n /** Name of the MCP server for configuration */\n serverName: string;\n}\n\n/**\n * Plugin global data shape\n */\ninterface McpPluginGlobalData {\n serverUrl: string;\n serverName: string;\n}\n\n/**\n * Registry options for the docs MCP server.\n * Similar to GLEAN_REGISTRY_OPTIONS in @gleanwork/mcp-config-glean\n */\nexport function createDocsRegistryOptions(config: McpConfig): RegistryOptions {\n return {\n // Use the serverName from config for naming\n serverNameBuilder: () => config.serverName,\n };\n}\n\n/**\n * Creates an MCPConfigRegistry pre-configured with the docs server settings.\n *\n * Similar to createGleanRegistry() from @gleanwork/mcp-config-glean\n *\n * @param config - The server configuration from plugin\n * @returns Object with registry instance and bound config\n */\nexport function createDocsRegistry(config: McpConfig): {\n registry: MCPConfigRegistry;\n config: McpConfig;\n} {\n const options = createDocsRegistryOptions(config);\n return {\n registry: new MCPConfigRegistry(options),\n config,\n };\n}\n\n/**\n * Hook to access the pre-configured MCP registry and config.\n *\n * Reads configuration from plugin globalData and creates a registry\n * with the serverUrl and serverName pre-bound in the config object.\n *\n * @returns { registry, config } or undefined if plugin not configured\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const mcp = useMcpRegistry();\n * if (!mcp) return null;\n *\n * const { registry, config } = mcp;\n * const builder = registry.createBuilder('claude-code');\n * const json = builder.buildConfiguration({\n * transport: 'http',\n * serverUrl: config.serverUrl,\n * serverName: config.serverName,\n * });\n * }\n * ```\n */\nexport function useMcpRegistry(): { registry: MCPConfigRegistry; config: McpConfig } | undefined {\n // Read plugin globalData\n let pluginData: McpPluginGlobalData | undefined;\n try {\n pluginData = usePluginData('docusaurus-plugin-mcp-server') as McpPluginGlobalData | undefined;\n } catch {\n // Plugin not installed\n return undefined;\n }\n\n // Memoize registry creation\n const result = useMemo(() => {\n if (!pluginData?.serverUrl || !pluginData?.serverName) {\n return undefined;\n }\n const config: McpConfig = {\n serverUrl: pluginData.serverUrl,\n serverName: pluginData.serverName,\n };\n return createDocsRegistry(config);\n }, [pluginData?.serverUrl, pluginData?.serverName]);\n\n return result;\n}\n\nexport default useMcpRegistry;\n","import { useState, useRef, useEffect, useCallback, useMemo } from 'react';\nimport {\n MCPConfigRegistry,\n type ClientId,\n type MCPClientConfig,\n} from '@gleanwork/mcp-config-schema/browser';\nimport IconCopy from '@theme/Icon/Copy';\nimport IconSuccess from '@theme/Icon/Success';\nimport { useMcpRegistry, createDocsRegistry, type McpConfig } from './McpRegistryContext.js';\n\n/**\n * MCP Logo icon - extracted from official MCP branding\n */\nfunction IconMcp({ size = 16 }: { size?: number }) {\n return (\n <svg\n viewBox=\"0 0 170 195\"\n width={size}\n height={size}\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ display: 'block' }}\n >\n <path\n d=\"M25 97.8528L92.8823 29.9706C102.255 20.598 117.451 20.598 126.823 29.9706C136.196 39.3431 136.196 54.5391 126.823 63.9117L75.5581 115.177\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M76.2653 114.47L126.823 63.9117C136.196 54.5391 151.392 54.5391 160.765 63.9117L161.118 64.2652C170.491 73.6378 170.491 88.8338 161.118 98.2063L99.7248 159.6C96.6006 162.724 96.6006 167.789 99.7248 170.913L112.331 183.52\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M109.853 46.9411L59.6482 97.1457C50.2757 106.518 50.2757 121.714 59.6482 131.087C69.0208 140.459 84.2168 140.459 93.5894 131.087L143.794 80.8822\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n\n/**\n * Chevron icon for dropdown\n */\nfunction IconChevron({ isOpen }: { isOpen: boolean }) {\n return (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n style={{\n display: 'block',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform var(--ifm-transition-fast)',\n }}\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n );\n}\n\n/**\n * External link icon\n */\nfunction IconExternalLink() {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" style={{ display: 'block', marginLeft: '4px' }}>\n <path\n fill=\"currentColor\"\n d=\"M3.5 3C3.22386 3 3 3.22386 3 3.5C3 3.77614 3.22386 4 3.5 4H7.29289L3.14645 8.14645C2.95118 8.34171 2.95118 8.65829 3.14645 8.85355C3.34171 9.04882 3.65829 9.04882 3.85355 8.85355L8 4.70711V8.5C8 8.77614 8.22386 9 8.5 9C8.77614 9 9 8.77614 9 8.5V3.5C9 3.22386 8.77614 3 8.5 3H3.5Z\"\n />\n </svg>\n );\n}\n\n/**\n * Code block with integrated copy button\n */\nfunction CodeBlock({\n code,\n isMultiline = false,\n isCopied,\n onCopy,\n}: {\n code: string;\n isMultiline?: boolean;\n isCopied: boolean;\n onCopy: () => void;\n}) {\n return (\n <div className=\"mcp-code-block\">\n <div className=\"mcp-code-block__content\">\n {isMultiline ? (\n <pre className=\"mcp-code-block__pre\">\n <code>{code}</code>\n </pre>\n ) : (\n <code>{code}</code>\n )}\n </div>\n <button\n className=\"mcp-code-block__copy\"\n onClick={onCopy}\n title={isCopied ? 'Copied!' : 'Copy to clipboard'}\n aria-label={isCopied ? 'Copied' : 'Copy to clipboard'}\n >\n {isCopied ? (\n <IconSuccess className=\"mcp-code-block__icon mcp-code-block__icon--success\" />\n ) : (\n <IconCopy className=\"mcp-code-block__icon\" />\n )}\n </button>\n </div>\n );\n}\n\n/**\n * Props for the McpInstallButton component\n */\nexport interface McpInstallButtonProps {\n /** Server URL. If not provided, uses plugin configuration. */\n serverUrl?: string;\n /** Server name. If not provided, uses plugin configuration. */\n serverName?: string;\n /** Button label (default: \"Install docs MCP\") */\n label?: string;\n /** Optional className for styling */\n className?: string;\n /** Clients to show. Defaults to all HTTP-capable clients from registry. */\n clients?: ClientId[];\n}\n\n/**\n * A dropdown button component for installing MCP servers in various AI tools.\n * Uses Docusaurus/Infima CSS classes for consistent theming.\n *\n * @example\n * ```tsx\n * <McpInstallButton\n * serverUrl=\"https://docs.example.com/mcp\"\n * serverName=\"my-docs\"\n * />\n * ```\n */\nexport function McpInstallButton({\n serverUrl: serverUrlProp,\n serverName: serverNameProp,\n label = 'Install docs MCP',\n className = '',\n clients: clientsProp,\n}: McpInstallButtonProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [copiedClient, setCopiedClient] = useState<string | null>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Get pre-configured registry from plugin\n const pluginMcp = useMcpRegistry();\n\n // Use props if provided, otherwise fall back to plugin config\n const { registry, config } = useMemo(() => {\n if (serverUrlProp && serverNameProp) {\n return createDocsRegistry({\n serverUrl: serverUrlProp,\n serverName: serverNameProp,\n });\n }\n if (pluginMcp) {\n return pluginMcp;\n }\n return {\n registry: new MCPConfigRegistry(),\n config: { serverUrl: '', serverName: '' } as McpConfig,\n };\n }, [serverUrlProp, serverNameProp, pluginMcp]);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n }\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // Validate configuration\n if (!config.serverUrl || !config.serverName) {\n console.error(\n '[McpInstallButton] Missing serverUrl or serverName. ' +\n 'Either pass them as props or configure the docusaurus-plugin-mcp-server plugin.'\n );\n return null;\n }\n\n // Get clients to display - dynamic from registry, sorted alphabetically\n const clientConfigs = useMemo(() => {\n let clients: MCPClientConfig[];\n if (clientsProp) {\n clients = clientsProp\n .map((id) => registry.getConfig(id))\n .filter((c): c is MCPClientConfig => c !== undefined);\n } else {\n clients = registry.getNativeHttpClients();\n }\n // Sort alphabetically by display name\n return clients.sort((a, b) => a.displayName.localeCompare(b.displayName));\n }, [registry, clientsProp]);\n\n const copyToClipboard = useCallback(async (text: string, clientId: string) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopiedClient(clientId);\n setTimeout(() => setCopiedClient(null), 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n }, []);\n\n const getConfigForClient = useCallback(\n (clientId: ClientId): string | null => {\n try {\n const builder = registry.createBuilder(clientId);\n const clientConfig = builder.buildConfiguration({\n transport: 'http',\n serverUrl: config.serverUrl,\n serverName: config.serverName,\n });\n return JSON.stringify(clientConfig, null, 2);\n } catch {\n // Client doesn't support local configuration\n return null;\n }\n },\n [registry, config.serverUrl, config.serverName]\n );\n\n const getCommandForClient = useCallback(\n (clientId: ClientId): string | null => {\n try {\n const builder = registry.createBuilder(clientId);\n const cliStatus = builder.supportsCliInstallation();\n if (!cliStatus.supported) {\n return null;\n }\n return builder.buildCommand({\n transport: 'http',\n serverUrl: config.serverUrl,\n serverName: config.serverName,\n });\n } catch {\n return null;\n }\n },\n [registry, config.serverUrl, config.serverName]\n );\n\n // Using Infima dropdown classes\n const dropdownClasses = [\n 'dropdown',\n 'dropdown--right',\n isOpen ? 'dropdown--show' : '',\n 'mcp-install-dropdown',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div ref={dropdownRef} className={dropdownClasses}>\n {/* Infima button classes */}\n <button\n className=\"button button--primary mcp-install-dropdown__button\"\n onClick={() => setIsOpen(!isOpen)}\n aria-expanded={isOpen}\n aria-haspopup=\"true\"\n >\n <IconMcp size={16} />\n <span>{label}</span>\n <IconChevron isOpen={isOpen} />\n </button>\n\n {/* Dropdown menu using Infima classes */}\n <ul className=\"dropdown__menu mcp-install-dropdown__menu\">\n <li className=\"mcp-install-dropdown__header\">Choose your AI tool:</li>\n\n {clientConfigs.map((client) => {\n const command = getCommandForClient(client.id);\n const clientConfig = getConfigForClient(client.id);\n const isCopied = copiedClient === client.id;\n\n if (!command && !clientConfig) {\n return null;\n }\n\n return (\n <li key={client.id} className=\"mcp-install-dropdown__item\">\n <div className=\"mcp-install-dropdown__client-header\">\n <span className=\"mcp-install-dropdown__client-name\">{client.displayName}</span>\n {command && <span className=\"badge badge--success\">CLI</span>}\n </div>\n\n {command ? (\n <CodeBlock\n code={command}\n isCopied={isCopied}\n onCopy={() => copyToClipboard(command, client.id)}\n />\n ) : clientConfig ? (\n <CodeBlock\n code={clientConfig}\n isMultiline\n isCopied={isCopied}\n onCopy={() => copyToClipboard(clientConfig, client.id)}\n />\n ) : null}\n\n {client.localConfigNotes && (\n <p className=\"mcp-install-dropdown__notes\">{client.localConfigNotes}</p>\n )}\n </li>\n );\n })}\n\n <li className=\"mcp-install-dropdown__footer\">\n <a\n href=\"https://modelcontextprotocol.io/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mcp-install-dropdown__learn-more\"\n >\n Learn more about MCP\n <IconExternalLink />\n </a>\n </li>\n </ul>\n\n {/* Scoped styles using CSS variables for customization */}\n <style>{`\n .mcp-install-dropdown {\n --mcp-dropdown-width: 520px;\n /* Always use dark code blocks for consistency across themes */\n --mcp-code-bg: #1e1e1e;\n --mcp-code-color: #e5e7eb;\n }\n\n .mcp-install-dropdown__button {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n }\n\n .mcp-install-dropdown__menu {\n width: var(--mcp-dropdown-width);\n padding: 0;\n top: calc(100% + 0.25rem);\n }\n\n .mcp-install-dropdown__header {\n padding: 0.75rem 1rem;\n font-size: var(--ifm-font-size-small);\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-color-secondary-darkest);\n background-color: var(--ifm-background-color);\n border-bottom: 1px solid var(--ifm-toc-border-color);\n }\n\n .mcp-install-dropdown__item {\n padding: 0.875rem 1rem;\n border-bottom: 1px solid var(--ifm-toc-border-color);\n }\n\n .mcp-install-dropdown__client-header {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-bottom: 0.625rem;\n }\n\n .mcp-install-dropdown__client-name {\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-font-color-base);\n }\n\n .mcp-install-dropdown__notes {\n margin: 0.5rem 0 0;\n font-size: var(--ifm-font-size-small);\n color: var(--ifm-color-secondary-darkest);\n line-height: 1.4;\n }\n\n .mcp-install-dropdown__footer {\n padding: 0.75rem 1rem;\n text-align: center;\n background-color: var(--ifm-background-color);\n }\n\n .mcp-install-dropdown__learn-more {\n display: inline-flex;\n align-items: center;\n font-size: var(--ifm-font-size-small);\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-color-primary);\n text-decoration: none;\n }\n\n .mcp-install-dropdown__learn-more:hover {\n color: var(--ifm-color-primary-dark);\n text-decoration: none;\n }\n\n /* Code block styles */\n .mcp-code-block {\n display: flex;\n border-radius: var(--ifm-code-border-radius, 0.25rem);\n overflow: hidden;\n }\n\n .mcp-code-block__content {\n flex: 1;\n background-color: var(--mcp-code-bg);\n padding: 0.75rem 1rem;\n overflow-x: auto;\n }\n\n .mcp-code-block__content code {\n font-family: var(--ifm-font-family-monospace);\n font-size: var(--ifm-code-font-size);\n color: var(--mcp-code-color);\n background: none;\n padding: 0;\n border: none;\n white-space: nowrap;\n }\n\n .mcp-code-block__pre {\n margin: 0;\n background: none;\n max-height: 120px;\n overflow-y: auto;\n }\n\n .mcp-code-block__pre code {\n white-space: pre;\n }\n\n .mcp-code-block__copy {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n background-color: var(--ifm-color-gray-800, #374151);\n border: none;\n cursor: pointer;\n color: var(--ifm-color-gray-400, #9ca3af);\n transition: background-color var(--ifm-transition-fast);\n }\n\n .mcp-code-block__copy:hover {\n background-color: var(--ifm-color-gray-700, #4b5563);\n }\n\n .mcp-code-block__icon {\n width: 16px;\n height: 16px;\n display: block;\n }\n\n .mcp-code-block__icon--success {\n color: var(--ifm-color-success, #22c55e);\n }\n `}</style>\n </div>\n );\n}\n\nexport default McpInstallButton;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/theme/McpRegistryContext.tsx","../../src/theme/McpInstallButton.tsx"],"names":["useMemo","MCPConfigRegistry"],"mappings":"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","file":"index.mjs","sourcesContent":["import { useMemo } from 'react';\nimport { usePluginData } from '@docusaurus/useGlobalData';\nimport { MCPConfigRegistry, type RegistryOptions } from '@gleanwork/mcp-config-schema/browser';\n\n/**\n * Configuration from the plugin\n */\nexport interface McpConfig {\n /** Full URL to the MCP server endpoint */\n serverUrl: string;\n /** Name of the MCP server for configuration */\n serverName: string;\n}\n\n/**\n * Plugin global data shape\n */\ninterface McpPluginGlobalData {\n serverUrl: string;\n serverName: string;\n}\n\n/**\n * Registry options for the docs MCP server.\n * Similar to GLEAN_REGISTRY_OPTIONS in @gleanwork/mcp-config-glean\n */\nexport function createDocsRegistryOptions(config: McpConfig): RegistryOptions {\n return {\n // Use the serverName from config for naming\n serverNameBuilder: () => config.serverName,\n };\n}\n\n/**\n * Creates an MCPConfigRegistry pre-configured with the docs server settings.\n *\n * Similar to createGleanRegistry() from @gleanwork/mcp-config-glean\n *\n * @param config - The server configuration from plugin\n * @returns Object with registry instance and bound config\n */\nexport function createDocsRegistry(config: McpConfig): {\n registry: MCPConfigRegistry;\n config: McpConfig;\n} {\n const options = createDocsRegistryOptions(config);\n return {\n registry: new MCPConfigRegistry(options),\n config,\n };\n}\n\n/**\n * Hook to access the pre-configured MCP registry and config.\n *\n * Reads configuration from plugin globalData and creates a registry\n * with the serverUrl and serverName pre-bound in the config object.\n *\n * @returns { registry, config } or undefined if plugin not configured\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const mcp = useMcpRegistry();\n * if (!mcp) return null;\n *\n * const { registry, config } = mcp;\n * const builder = registry.createBuilder('claude-code');\n * const json = builder.buildConfiguration({\n * transport: 'http',\n * serverUrl: config.serverUrl,\n * serverName: config.serverName,\n * });\n * }\n * ```\n */\nexport function useMcpRegistry(): { registry: MCPConfigRegistry; config: McpConfig } | undefined {\n // Read plugin globalData\n let pluginData: McpPluginGlobalData | undefined;\n try {\n pluginData = usePluginData('docusaurus-plugin-mcp-server') as McpPluginGlobalData | undefined;\n } catch {\n // Plugin not installed\n return undefined;\n }\n\n // Memoize registry creation\n const result = useMemo(() => {\n if (!pluginData?.serverUrl || !pluginData?.serverName) {\n return undefined;\n }\n const config: McpConfig = {\n serverUrl: pluginData.serverUrl,\n serverName: pluginData.serverName,\n };\n return createDocsRegistry(config);\n }, [pluginData?.serverUrl, pluginData?.serverName]);\n\n return result;\n}\n\nexport default useMcpRegistry;\n","import { useState, useRef, useEffect, useCallback, useMemo } from 'react';\nimport {\n MCPConfigRegistry,\n type ClientId,\n type MCPClientConfig,\n} from '@gleanwork/mcp-config-schema/browser';\nimport IconCopy from '@theme/Icon/Copy';\nimport IconSuccess from '@theme/Icon/Success';\nimport { useMcpRegistry, createDocsRegistry, type McpConfig } from './McpRegistryContext.js';\n\n/**\n * MCP Logo icon - extracted from official MCP branding\n */\nfunction IconMcp({ size = 16 }: { size?: number }) {\n return (\n <svg\n viewBox=\"0 0 170 195\"\n width={size}\n height={size}\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ display: 'block' }}\n >\n <path\n d=\"M25 97.8528L92.8823 29.9706C102.255 20.598 117.451 20.598 126.823 29.9706C136.196 39.3431 136.196 54.5391 126.823 63.9117L75.5581 115.177\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M76.2653 114.47L126.823 63.9117C136.196 54.5391 151.392 54.5391 160.765 63.9117L161.118 64.2652C170.491 73.6378 170.491 88.8338 161.118 98.2063L99.7248 159.6C96.6006 162.724 96.6006 167.789 99.7248 170.913L112.331 183.52\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M109.853 46.9411L59.6482 97.1457C50.2757 106.518 50.2757 121.714 59.6482 131.087C69.0208 140.459 84.2168 140.459 93.5894 131.087L143.794 80.8822\"\n stroke=\"currentColor\"\n strokeWidth=\"12\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n}\n\n/**\n * Chevron icon for dropdown\n */\nfunction IconChevron({ isOpen }: { isOpen: boolean }) {\n return (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n style={{\n display: 'block',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform var(--ifm-transition-fast)',\n }}\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n );\n}\n\n/**\n * External link icon\n */\nfunction IconExternalLink() {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" style={{ display: 'block', marginLeft: '4px' }}>\n <path\n fill=\"currentColor\"\n d=\"M3.5 3C3.22386 3 3 3.22386 3 3.5C3 3.77614 3.22386 4 3.5 4H7.29289L3.14645 8.14645C2.95118 8.34171 2.95118 8.65829 3.14645 8.85355C3.34171 9.04882 3.65829 9.04882 3.85355 8.85355L8 4.70711V8.5C8 8.77614 8.22386 9 8.5 9C8.77614 9 9 8.77614 9 8.5V3.5C9 3.22386 8.77614 3 8.5 3H3.5Z\"\n />\n </svg>\n );\n}\n\n/**\n * Code block with integrated copy button\n */\nfunction CodeBlock({\n code,\n isMultiline = false,\n isCopied,\n onCopy,\n}: {\n code: string;\n isMultiline?: boolean;\n isCopied: boolean;\n onCopy: () => void;\n}) {\n return (\n <div className=\"mcp-code-block\">\n <div className=\"mcp-code-block__content\">\n {isMultiline ? (\n <pre className=\"mcp-code-block__pre\">\n <code>{code}</code>\n </pre>\n ) : (\n <code>{code}</code>\n )}\n </div>\n <button\n className=\"mcp-code-block__copy\"\n onClick={onCopy}\n title={isCopied ? 'Copied!' : 'Copy to clipboard'}\n aria-label={isCopied ? 'Copied' : 'Copy to clipboard'}\n >\n {isCopied ? (\n <IconSuccess className=\"mcp-code-block__icon mcp-code-block__icon--success\" />\n ) : (\n <IconCopy className=\"mcp-code-block__icon\" />\n )}\n </button>\n </div>\n );\n}\n\n/**\n * Props for the McpInstallButton component\n */\nexport interface McpInstallButtonProps {\n /** Server URL. If not provided, uses plugin configuration. */\n serverUrl?: string;\n /** Server name. If not provided, uses plugin configuration. */\n serverName?: string;\n /** Button label. If not provided, shows only the MCP icon. */\n label?: string;\n /** Optional className for styling */\n className?: string;\n /** Clients to show. Defaults to all HTTP-capable clients from registry. */\n clients?: ClientId[];\n /** Header text shown at top of dropdown (default: \"Choose your AI tool:\") */\n headerText?: string;\n}\n\n/**\n * A dropdown button component for installing MCP servers in various AI tools.\n * Uses Docusaurus/Infima CSS classes for consistent theming.\n *\n * @example\n * ```tsx\n * <McpInstallButton\n * serverUrl=\"https://docs.example.com/mcp\"\n * serverName=\"my-docs\"\n * />\n * ```\n */\nexport function McpInstallButton({\n serverUrl: serverUrlProp,\n serverName: serverNameProp,\n label,\n className = '',\n clients: clientsProp,\n headerText = 'Choose your AI tool:',\n}: McpInstallButtonProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [copiedClient, setCopiedClient] = useState<string | null>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Get pre-configured registry from plugin\n const pluginMcp = useMcpRegistry();\n\n // Use props if provided, otherwise fall back to plugin config\n const { registry, config } = useMemo(() => {\n if (serverUrlProp && serverNameProp) {\n return createDocsRegistry({\n serverUrl: serverUrlProp,\n serverName: serverNameProp,\n });\n }\n if (pluginMcp) {\n return pluginMcp;\n }\n return {\n registry: new MCPConfigRegistry(),\n config: { serverUrl: '', serverName: '' } as McpConfig,\n };\n }, [serverUrlProp, serverNameProp, pluginMcp]);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n }\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // Validate configuration\n if (!config.serverUrl || !config.serverName) {\n console.error(\n '[McpInstallButton] Missing serverUrl or serverName. ' +\n 'Either pass them as props or configure the docusaurus-plugin-mcp-server plugin.'\n );\n return null;\n }\n\n // Get clients to display - dynamic from registry, sorted alphabetically\n const clientConfigs = useMemo(() => {\n let clients: MCPClientConfig[];\n if (clientsProp) {\n clients = clientsProp\n .map((id) => registry.getConfig(id))\n .filter((c): c is MCPClientConfig => c !== undefined);\n } else {\n clients = registry.getNativeHttpClients();\n }\n // Sort alphabetically by display name\n return clients.sort((a, b) => a.displayName.localeCompare(b.displayName));\n }, [registry, clientsProp]);\n\n const copyToClipboard = useCallback(async (text: string, clientId: string) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopiedClient(clientId);\n setTimeout(() => setCopiedClient(null), 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n }, []);\n\n const getConfigForClient = useCallback(\n (clientId: ClientId): string | null => {\n try {\n const builder = registry.createBuilder(clientId);\n const clientConfig = builder.buildConfiguration({\n transport: 'http',\n serverUrl: config.serverUrl,\n serverName: config.serverName,\n });\n return JSON.stringify(clientConfig, null, 2);\n } catch {\n // Client doesn't support local configuration\n return null;\n }\n },\n [registry, config.serverUrl, config.serverName]\n );\n\n const getCommandForClient = useCallback(\n (clientId: ClientId): string | null => {\n try {\n const builder = registry.createBuilder(clientId);\n const cliStatus = builder.supportsCliInstallation();\n if (!cliStatus.supported) {\n return null;\n }\n return builder.buildCommand({\n transport: 'http',\n serverUrl: config.serverUrl,\n serverName: config.serverName,\n });\n } catch {\n return null;\n }\n },\n [registry, config.serverUrl, config.serverName]\n );\n\n // Using Infima dropdown classes\n const dropdownClasses = [\n 'dropdown',\n 'dropdown--right',\n isOpen ? 'dropdown--show' : '',\n 'mcp-install-dropdown',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div ref={dropdownRef} className={dropdownClasses}>\n {/* Infima button classes */}\n <button\n className={`button button--primary mcp-install-dropdown__button${label ? '' : ' mcp-install-dropdown__button--icon-only'}`}\n onClick={() => setIsOpen(!isOpen)}\n aria-expanded={isOpen}\n aria-haspopup=\"true\"\n aria-label={label || 'Install MCP'}\n >\n <IconMcp size={16} />\n {label && <span>{label}</span>}\n <IconChevron isOpen={isOpen} />\n </button>\n\n {/* Dropdown menu using Infima classes */}\n <ul className=\"dropdown__menu mcp-install-dropdown__menu\">\n <li className=\"mcp-install-dropdown__header\">{headerText}</li>\n\n {clientConfigs.map((client) => {\n const command = getCommandForClient(client.id);\n const clientConfig = getConfigForClient(client.id);\n const isCopied = copiedClient === client.id;\n\n if (!command && !clientConfig) {\n return null;\n }\n\n return (\n <li key={client.id} className=\"mcp-install-dropdown__item\">\n <div className=\"mcp-install-dropdown__client-header\">\n <span className=\"mcp-install-dropdown__client-name\">{client.displayName}</span>\n {command && <span className=\"badge badge--success\">CLI</span>}\n </div>\n\n {command ? (\n <CodeBlock\n code={command}\n isCopied={isCopied}\n onCopy={() => copyToClipboard(command, client.id)}\n />\n ) : clientConfig ? (\n <CodeBlock\n code={clientConfig}\n isMultiline\n isCopied={isCopied}\n onCopy={() => copyToClipboard(clientConfig, client.id)}\n />\n ) : null}\n\n {client.localConfigNotes && (\n <p className=\"mcp-install-dropdown__notes\">{client.localConfigNotes}</p>\n )}\n </li>\n );\n })}\n\n <li className=\"mcp-install-dropdown__footer\">\n <a\n href=\"https://modelcontextprotocol.io/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mcp-install-dropdown__learn-more\"\n >\n Learn more about MCP\n <IconExternalLink />\n </a>\n </li>\n </ul>\n\n {/* Scoped styles using Docusaurus/Infima CSS variables */}\n <style>{`\n .mcp-install-dropdown__button {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n }\n\n .mcp-install-dropdown__button--icon-only {\n padding: 0.5rem 0.75rem;\n gap: 0.25rem;\n }\n\n .mcp-install-dropdown__menu {\n width: 520px;\n padding: 0;\n top: calc(100% + 0.25rem);\n }\n\n .mcp-install-dropdown__header {\n padding: 0.75rem 1rem;\n font-size: var(--ifm-font-size-small);\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-color-emphasis-700);\n background-color: var(--ifm-background-color);\n border-bottom: 1px solid var(--ifm-toc-border-color);\n }\n\n .mcp-install-dropdown__item {\n padding: 0.875rem 1rem;\n border-bottom: 1px solid var(--ifm-toc-border-color);\n }\n\n .mcp-install-dropdown__client-header {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-bottom: 0.625rem;\n }\n\n .mcp-install-dropdown__client-name {\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-font-color-base);\n }\n\n .mcp-install-dropdown__notes {\n margin: 0.5rem 0 0;\n font-size: var(--ifm-font-size-small);\n color: var(--ifm-color-emphasis-700);\n line-height: 1.4;\n }\n\n .mcp-install-dropdown__footer {\n padding: 0.75rem 1rem;\n text-align: center;\n background-color: var(--ifm-background-color);\n }\n\n .mcp-install-dropdown__learn-more {\n display: inline-flex;\n align-items: center;\n font-size: var(--ifm-font-size-small);\n font-weight: var(--ifm-font-weight-semibold);\n color: var(--ifm-color-primary);\n text-decoration: none;\n }\n\n .mcp-install-dropdown__learn-more:hover {\n color: var(--ifm-color-primary-dark);\n text-decoration: none;\n }\n\n /* Code block styles - uses Docusaurus pre/code variables */\n .mcp-code-block {\n display: flex;\n border-radius: var(--ifm-code-border-radius);\n overflow: hidden;\n }\n\n .mcp-code-block__content {\n flex: 1;\n background-color: var(--ifm-pre-background);\n padding: 0.75rem 1rem;\n overflow-x: auto;\n }\n\n .mcp-code-block__content code {\n font-family: var(--ifm-font-family-monospace);\n font-size: var(--ifm-code-font-size);\n color: var(--ifm-pre-color);\n background: none;\n padding: 0;\n border: none;\n white-space: nowrap;\n }\n\n .mcp-code-block__pre {\n margin: 0;\n background: none;\n max-height: 120px;\n overflow-y: auto;\n }\n\n .mcp-code-block__pre code {\n white-space: pre;\n }\n\n .mcp-code-block__copy {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.75rem;\n background-color: var(--ifm-color-emphasis-200);\n border: none;\n cursor: pointer;\n color: var(--ifm-color-emphasis-700);\n transition: background-color var(--ifm-transition-fast);\n }\n\n .mcp-code-block__copy:hover {\n background-color: var(--ifm-color-emphasis-300);\n }\n\n .mcp-code-block__icon {\n width: 16px;\n height: 16px;\n display: block;\n }\n\n .mcp-code-block__icon--success {\n color: var(--ifm-color-success);\n }\n `}</style>\n </div>\n );\n}\n\nexport default McpInstallButton;\n"]}
|
package/package.json
CHANGED