sap_docs_search
Search SAP documentation and UI5 control APIs to find specific controls, concepts, or development topics. Provides ranked results for use in retrieving detailed SAP development information.
Instructions
Search across SAP documentation and UI5 control APIs. Searches through SAPUI5 documentation, CAP documentation, wdi5 testing framework, OpenUI5 control APIs, Cloud MTA Build Tool documentation, UI5 Tooling documentation, UI5 Web Components documentation, SAP Cloud SDK documentation and SAP Cloud SDK AI documentation. Use this to find specific controls (like Button, Table, Wizard), concepts (like annotations, routing, authentication), testing topics (like wdi5, e2e testing, browser automation), or any SAP development topic. Returns a ranked list of matching documentation and controls with their IDs for use in sap_docs_get.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | What to search for. Examples: 'button' (finds UI5 Button controls), 'wizard' (finds Wizard controls and docs), 'annotation' (finds annotation docs across CAP/UI5), 'wdi5' (finds testing framework docs), 'testing' (finds testing and automation docs), 'routing', 'authentication', 'table', 'odata', 'fiori elements', 'cds', 'UI5 Tooling', 'Cloud MTA Build Tool', 'MTA', 'UI5 Web Components', 'SAP Cloud SDK', 'SAP Cloud SDK AI' or any SAP development concept. Can be UI5 control names, technical concepts, testing topics, or general topics. |
Implementation Reference
- src/lib/BaseServerHandler.ts:400-493 (handler)MCP CallTool handler specifically for 'sap_docs_search' (legacy alias for 'search'). Invokes the core search() function, applies fallback logic if hybrid search fails, transforms results to ChatGPT-compatible JSON format with id, title, url, snippet, metadata.if (name === "sap_docs_search" || name === "search") { const { query } = args as { query: string }; // Enhanced logging with timing const timing = logger.logToolStart(name, query, clientMetadata); try { // Use hybrid search with reranking const results = await search(query, { k: CONFIG.RETURN_K }); const topResults = results; if (topResults.length === 0) { logger.logToolSuccess(name, timing.requestId, timing.startTime, 0, { fallback: false }); return createErrorResponse( `No results for "${query}". Try UI5 controls ("button", "table"), CAP topics ("actions", "binary"), testing ("wdi5", "e2e"), ABAP with versions ("SELECT 7.58"), or include error codes ("415 error").`, timing.requestId ); } // Transform results to ChatGPT-compatible format with id, title, url const searchResults: SearchResult[] = topResults.map((r, index) => { // Extract library_id and topic from document ID const libraryIdMatch = r.id.match(/^(\/[^\/]+)/); const libraryId = libraryIdMatch ? libraryIdMatch[1] : (r.sourceId ? `/${r.sourceId}` : r.id); const topic = r.id.startsWith(libraryId) ? r.id.slice(libraryId.length + 1) : ''; const config = getDocUrlConfig(libraryId); const docUrl = config ? generateDocumentationUrl(libraryId, '', r.text, config) : null; return { // ChatGPT-required format: id, title, url id: r.id, // Use full document ID as required by ChatGPT title: r.text.split('\n')[0] || r.id, url: docUrl || `#${r.id}`, // Additional fields for backward compatibility library_id: libraryId, topic: topic, snippet: r.text ? r.text.substring(0, CONFIG.EXCERPT_LENGTH_MAIN) + '...' : '', score: r.finalScore, metadata: { source: r.sourceId || 'sap-docs', library: libraryId, bm25Score: r.bm25, rank: index + 1 } }; }); logger.logToolSuccess(name, timing.requestId, timing.startTime, topResults.length, { fallback: false }); return createSearchResponse(searchResults); } catch (error) { logger.logToolError(name, timing.requestId, timing.startTime, error, false); logger.info('Attempting fallback to original search after hybrid search failure'); // Fallback to original search try { const res: SearchResponse = await searchLibraries(query); if (!res.results.length) { logger.logToolSuccess(name, timing.requestId, timing.startTime, 0, { fallback: true }); return createErrorResponse( res.error || `No fallback results for "${query}". Try UI5 controls ("button", "table"), CAP topics ("actions", "binary"), testing ("wdi5", "e2e"), ABAP with versions ("SELECT 7.58"), or include error codes.`, timing.requestId ); } // Transform fallback results to structured format const fallbackResults: SearchResult[] = res.results.map((r, index) => ({ id: r.id || `fallback-${index}`, title: r.title || 'SAP Documentation', url: r.url || `#${r.id}`, snippet: r.description ? r.description.substring(0, 200) + '...' : '', metadata: { source: 'fallback-search', rank: index + 1 } })); logger.logToolSuccess(name, timing.requestId, timing.startTime, res.results.length, { fallback: true }); return createSearchResponse(fallbackResults); } catch (fallbackError) { logger.logToolError(name, timing.requestId, timing.startTime, fallbackError, true); return createErrorResponse( `Search temporarily unavailable. Wait 30 seconds and retry, try sap_community_search instead, or use more specific search terms.`, timing.requestId ); } } }
- src/lib/BaseServerHandler.ts:323-390 (schema)Tool schema definition for 'search' tool (sap_docs_search is legacy alias). Defines input schema with 'query' parameter and detailed description/usage examples.{ name: "search", description: `SEARCH SAP DOCS: search(query="search terms") FUNCTION NAME: search COVERS: ABAP (all versions), UI5, CAP, wdi5, OpenUI5 APIs, Cloud SDK AUTO-DETECTS: ABAP versions from query (e.g. "LOOP 7.57", defaults to 7.58) TYPICAL WORKFLOW: 1. search(query="your search terms") 2. fetch(id="result_id_from_step_1") QUERY TIPS: • Be specific: "CAP action binary parameter" not just "CAP" • Include error codes: "415 error CAP action" • Use technical terms: "LargeBinary MediaType XMLHttpRequest" • For ABAP: Include version like "7.58" or "latest"`, inputSchema: { type: "object", properties: { query: { type: "string", description: "Search terms using natural language. Be specific and include technical terms.", examples: [ "CAP binary data LargeBinary MediaType", "UI5 button properties", "wdi5 testing locators", "ABAP SELECT statements 7.58", "415 error CAP action parameter" ] } }, required: ["query"] } }, { name: "fetch", description: `GET SPECIFIC DOCS: fetch(id="result_id") FUNCTION NAME: fetch RETRIEVES: Full content from search results WORKS WITH: Document IDs returned by search ChatGPT COMPATIBLE: • Uses "id" parameter (required by ChatGPT) • Returns structured JSON content • Includes full document text and metadata`, inputSchema: { type: "object", properties: { id: { type: "string", description: "Unique document ID from search results. Use exact IDs returned by search.", examples: [ "/cap/guides/domain-modeling", "/sapui5/controls/button-properties", "/openui5-api/sap/m/Button", "/abap-docs-758/inline-declarations", "community-12345" ] } }, required: ["id"] } },
- src/lib/search.ts:29-117 (handler)Core search implementation for SAP documentation. Performs BM25 FTS5 search with query expansion, ABAP version-aware filtering, source boosting, and result ranking. Called by the MCP handler for sap_docs_search.export async function search( query: string, { k = CONFIG.RETURN_K } = {} ): Promise<SearchResult[]> { // Load metadata for boosts and query expansion loadMetadata(); const sourceBoosts = getSourceBoosts(); // Expand query with synonyms and acronyms const queryVariants = expandQueryTerms(query); const seen = new Map<string, any>(); // Check if query contains specific ABAP version const versionMatch = query.match(/\b(7\.\d{2}|latest)\b/i); const requestedVersion = versionMatch ? versionMatch[1].toLowerCase() : null; const requestedVersionId = requestedVersion ? requestedVersion.replace('.', '') : null; // Search with all query variants (union approach) for (const variant of queryVariants) { try { const rows = searchFTS(variant, {}, k); for (const r of rows) { if (!seen.has(r.id)) { seen.set(r.id, r); } } } catch (error) { console.warn(`FTS query failed for variant "${variant}":`, error); continue; } if (seen.size >= k) break; // enough candidates } let rows = Array.from(seen.values()).slice(0, k); // Smart ABAP version filtering - only show latest unless version specified if (!requestedVersion) { // For general ABAP queries without version, aggressively filter out older versions rows = rows.filter(r => { const id = r.id || ''; // Keep all non-ABAP-docs sources if (!id.includes('/abap-docs-')) return true; // For ABAP docs, ONLY keep latest version for general queries return id.includes('/abap-docs-latest/'); }); console.log(`Filtered to latest ABAP version only: ${rows.length} results`); } else { // For version-specific queries, ONLY show the requested version and non-ABAP sources rows = rows.filter(r => { const id = r.id || ''; // Keep all non-ABAP-docs sources (style guides, cheat sheets, etc.) if (!id.includes('/abap-docs-')) return true; // For ABAP docs, ONLY keep the specifically requested version return id.includes(`/abap-docs-${requestedVersionId}/`); }); console.log(`Filtered to ABAP version ${requestedVersion} only: ${rows.length} results`); } // Convert to consistent format with source boosts const results = rows.map(r => { const sourceId = extractSourceId(r.libraryId || r.id); let boost = sourceBoosts[sourceId] || 0; // Additional boost for version-specific queries if (requestedVersionId && r.id.includes(`/abap-docs-${requestedVersionId}/`)) { boost += 1.0; // Extra boost for requested version } return { id: r.id, text: `${r.title || ""}\n\n${r.description || ""}\n\n${r.id}`, bm25: r.bm25Score, sourceId, path: r.id, finalScore: (-r.bm25Score) * (1 + boost) // Convert to descending with boost }; }); // Results are already filtered above, just sort them // Sort by final score (higher = better) return results.sort((a, b) => b.finalScore - a.finalScore); }
- src/lib/BaseServerHandler.ts:13-13 (registration)Documentation note indicating that sap_docs_search is a legacy alias for the 'search' tool, handled for backward compatibility.* Note: sap_docs_search and sap_docs_get are legacy aliases for backward compatibility.