UNPKG

hana-cli

Version:
489 lines (479 loc) 19.4 kB
/** * MCP Resources for SAP HANA CLI * * Resources are named, readable content that agents can discover and access. * They provide documentation, guides, and reference material. */ import { readFile } from 'fs/promises'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; import { docsSearch } from './docs-search.js'; import { getCommandExamples, getCommandPresets } from './examples-presets.js'; import ReadmeKnowledgeBase from './readme-knowledge-base.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); /** * List all available resources */ export function listResources() { return [ // Core Documentation { uri: 'hana://docs/overview', name: 'Project Overview', description: 'What is hana-cli? Complete overview, introduction, and capabilities', mimeType: 'text/markdown', }, { uri: 'hana://project/version', name: 'Project Version', description: 'Package metadata and current version information', mimeType: 'application/json', }, { uri: 'hana://project/changelog', name: 'Project Changelog', description: 'Structured changelog for recent releases and updates', mimeType: 'application/json', }, { uri: 'hana://docs/getting-started', name: 'Getting Started Guide', description: 'Installation, configuration, and first commands', mimeType: 'text/markdown', }, { uri: 'hana://docs/connection-guide', name: 'Connection Resolution Guide', description: '7-step guide to how hana-cli finds database credentials', mimeType: 'text/markdown', }, { uri: 'hana://docs/security', name: 'Security Best Practices', description: 'Comprehensive security guidelines for connection, SQL injection prevention, and parameter handling', mimeType: 'text/markdown', }, { uri: 'hana://docs/parameters', name: 'Standard Parameters Guide', description: 'Standardized parameter conventions by command category with aliases and examples', mimeType: 'text/markdown', }, { uri: 'hana://docs/best-practices', name: 'Best Practices & Patterns', description: 'Naming conventions, usage patterns, and real-world command examples', mimeType: 'text/markdown', }, { uri: 'hana://docs/project-structure', name: 'Project Structure', description: 'Overview of project folders, their purposes, and key resources', mimeType: 'text/markdown', }, // Category Guides { uri: 'hana://docs/categories/data-quality', name: 'Data Quality Commands', description: 'Commands for data validation, profiling, duplicate detection, and quality checks', mimeType: 'text/markdown', }, { uri: 'hana://docs/categories/performance', name: 'Performance Analysis Commands', description: 'Commands for analyzing memory, performance, and system health', mimeType: 'text/markdown', }, { uri: 'hana://docs/categories/data-operations', name: 'Data Operations Commands', description: 'Commands for import, export, copy, sync, and data manipulation', mimeType: 'text/markdown', }, { uri: 'hana://docs/categories/inspection', name: 'Inspection & Discovery Commands', description: 'Commands for exploring schemas, tables, views, functions, and database objects', mimeType: 'text/markdown', }, // Popular Command Documentation { uri: 'hana://docs/commands/import', name: 'Import Command Documentation', description: 'Detailed guide for importing data from CSV/Excel/TSV files', mimeType: 'text/markdown', }, { uri: 'hana://docs/commands/export', name: 'Export Command Documentation', description: 'Detailed guide for exporting data to CSV/Excel/TSV files', mimeType: 'text/markdown', }, { uri: 'hana://docs/commands/dataValidator', name: 'Data Validator Command Documentation', description: 'Detailed guide for validating data quality', mimeType: 'text/markdown', }, { uri: 'hana://docs/commands/dataProfile', name: 'Data Profile Command Documentation', description: 'Detailed guide for profiling data and analyzing patterns', mimeType: 'text/markdown', }, { uri: 'hana://docs/commands/duplicateDetection', name: 'Duplicate Detection Command Documentation', description: 'Detailed guide for finding duplicate rows', mimeType: 'text/markdown', }, // Prompts { uri: 'hana://prompts', name: 'Available Prompts', description: 'List of guided workflows and templates for common tasks', mimeType: 'text/plain', }, // Knowledge Base (migrated from tools for reduced context usage) { uri: 'hana://knowledge/connection-guide', name: 'Connection Resolution Guide (Knowledge Base)', description: 'Detailed 7-step connection resolution order and best practices', mimeType: 'text/markdown', }, { uri: 'hana://knowledge/security-guide', name: 'Security Guidelines (Knowledge Base)', description: 'Connection security, SQL injection protection, parameter security, environment security', mimeType: 'text/markdown', }, { uri: 'hana://knowledge/best-practices', name: 'Best Practices (Knowledge Base)', description: 'Naming conventions, alias patterns, safe operation patterns', mimeType: 'text/markdown', }, { uri: 'hana://knowledge/project-structure', name: 'Project Structure (Knowledge Base)', description: 'Overview of hana-cli project folders and documentation resources', mimeType: 'text/markdown', }, { uri: 'hana://knowledge/parameters/data-manipulation', name: 'Data Manipulation Parameters', description: 'Standard parameters for data manipulation commands (schema, table, output, format, etc.)', mimeType: 'text/markdown', }, { uri: 'hana://knowledge/parameters/batch-operations', name: 'Batch Operation Parameters', description: 'Standard parameters for batch/mass operation commands', mimeType: 'text/markdown', }, { uri: 'hana://knowledge/parameters/list-inspect', name: 'List & Inspect Parameters', description: 'Standard parameters for listing and inspection commands', mimeType: 'text/markdown', }, // Documentation Index Metadata { uri: 'hana://docs/statistics', name: 'Documentation Statistics', description: 'Total documents, categories, and document types available in the documentation index', mimeType: 'application/json', }, { uri: 'hana://docs/categories', name: 'Documentation Categories', description: 'All available documentation categories and document types with sample documents', mimeType: 'application/json', }, ]; } /** * Read a specific resource */ export async function readResource(uri) { // Core documentation if (uri === 'hana://docs/overview') { const docsOverviewPath = join(__dirname, '../../docs/README.md'); const content = await readFile(docsOverviewPath, 'utf-8'); return { uri, mimeType: 'text/markdown', text: content, }; } if (uri === 'hana://project/version') { const packagePath = join(__dirname, '../../package.json'); const packageContent = await readFile(packagePath, 'utf-8'); const packageJson = JSON.parse(packageContent); return { uri, mimeType: 'application/json', text: JSON.stringify({ name: packageJson.name, version: packageJson.version, description: packageJson.description, license: packageJson.license, engines: packageJson.engines, repository: packageJson.repository, }, null, 2), }; } if (uri === 'hana://project/changelog') { const changelogJsonPath = join(__dirname, '../../CHANGELOG.json'); try { const changelogContent = await readFile(changelogJsonPath, 'utf-8'); return { uri, mimeType: 'application/json', text: changelogContent, }; } catch { const changelogMdPath = join(__dirname, '../../CHANGELOG.md'); const changelogContent = await readFile(changelogMdPath, 'utf-8'); return { uri, mimeType: 'text/markdown', text: changelogContent, }; } } if (uri === 'hana://docs/getting-started') { const gettingStartedPath = join(__dirname, '../../docs/01-getting-started/index.md'); try { const content = await readFile(gettingStartedPath, 'utf-8'); return { uri, mimeType: 'text/markdown', text: content, }; } catch { const fallbackPath = join(__dirname, '../../docs/01-getting-started/installation.md'); const content = await readFile(fallbackPath, 'utf-8'); return { uri, mimeType: 'text/markdown', text: content, }; } } if (uri === 'hana://docs/connection-guide') { const guidePath = join(__dirname, '../../docs/01-getting-started/configuration.md'); const guide = await readFile(guidePath, 'utf-8'); return { uri, mimeType: 'text/markdown', text: guide, }; } if (uri === 'hana://docs/security') { const guidePath = join(__dirname, '../../docs/03-features/knowledge-base.md'); const guide = await readFile(guidePath, 'utf-8'); return { uri, mimeType: 'text/markdown', text: guide, }; } if (uri === 'hana://docs/parameters') { const paramsPath = join(__dirname, '../../docs/03-features/cli-features.md'); const text = await readFile(paramsPath, 'utf-8'); return { uri, mimeType: 'text/markdown', text, }; } if (uri === 'hana://docs/best-practices') { const guidePath = join(__dirname, '../../docs/03-features/knowledge-base.md'); const guide = await readFile(guidePath, 'utf-8'); return { uri, mimeType: 'text/markdown', text: guide, }; } if (uri === 'hana://docs/project-structure') { const structurePath = join(__dirname, '../../docs/05-development/index.md'); const structure = await readFile(structurePath, 'utf-8'); return { uri, mimeType: 'text/markdown', text: structure, }; } // Category guides if (uri.startsWith('hana://docs/categories/')) { const category = uri.replace('hana://docs/categories/', ''); const categoryMap = { 'data-quality': 'data-quality', 'performance': 'performance-analysis', 'data-operations': 'data-operations', 'inspection': 'inspection', }; const actualCategory = categoryMap[category] || category; const results = docsSearch.search(actualCategory, { category: 'commands', limit: 20, }); let text = `# ${category.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')} Commands\n\n`; text += `This category includes commands for ${category.replace(/-/g, ' ')}.\n\n`; if (results && results.length > 0) { text += '## Available Commands\n\n'; const baseUrl = 'https://sap-samples.github.io/hana-developer-cli-tool-example'; results.forEach((r) => { text += `### ${r.document.title}\n\n`; text += `${r.snippet}\n\n`; const docUrl = `${baseUrl}/${r.document.path.replace(/\.md$/, '.html')}`; text += `**Documentation:** ${docUrl}\n\n`; }); } return { uri, mimeType: 'text/markdown', text, }; } // Command documentation if (uri.startsWith('hana://docs/commands/')) { const command = uri.replace('hana://docs/commands/', ''); const results = docsSearch.search(command, { category: 'commands', limit: 5, }); let text = `# ${command} Command\n\n`; if (results && results.length > 0) { const mainDoc = results[0].document; text += `${mainDoc.excerpt}\n\n`; // Build URL from path const baseUrl = 'https://sap-samples.github.io/hana-developer-cli-tool-example'; const docUrl = `${baseUrl}/${mainDoc.path.replace(/\.md$/, '.html')}`; text += `**Full Documentation:** ${docUrl}\n\n`; // Add matched keywords if (results[0].matchedKeywords && results[0].matchedKeywords.length > 0) { text += `**Related Topics:** ${results[0].matchedKeywords.join(', ')}\n\n`; } } // Add examples if available try { const examples = getCommandExamples(command); if (examples && examples.length > 0) { text += '## Examples\n\n'; examples.forEach((ex, idx) => { text += `### ${idx + 1}. ${ex.scenario}\n\n`; text += '```json\n'; text += JSON.stringify(ex.parameters, null, 2); text += '\n```\n\n'; if (ex.notes) { text += `*${ex.notes}*\n\n`; } }); } } catch { // Examples not available for this command } // Add presets if available try { const presets = getCommandPresets(command); if (presets && presets.length > 0) { text += '## Parameter Presets\n\n'; presets.forEach((preset) => { text += `### ${preset.name}\n\n`; text += `${preset.description}\n\n`; text += '```json\n'; text += JSON.stringify(preset.parameters, null, 2); text += '\n```\n\n'; if (preset.whenToUse) { text += `**When to use:** ${preset.whenToUse}\n\n`; } }); } } catch { // Presets not available for this command } return { uri, mimeType: 'text/markdown', text, }; } // Prompts list if (uri === 'hana://prompts') { const text = `# Available Prompts Prompts are guided workflows for common tasks. Use them to get step-by-step instructions. ## Available Prompts 1. **explore-database** - Step-by-step guide to explore an SAP HANA database - Optional argument: schema (specific schema to explore) 2. **import-data** - Guided workflow for importing data with validation - Required argument: filename (path to file to import) - Optional argument: table (target table name) 3. **troubleshoot-connection** - Help diagnose and fix database connection problems - No arguments required 4. **validate-data-quality** - Comprehensive data quality validation workflow - Required argument: table (table to validate) - Optional argument: schema (schema name) 5. **quickstart** - Beginner's guide with recommended first commands - No arguments required ## How to Use Prompts In MCP-compatible clients, you can invoke prompts to get structured guidance. Each prompt provides a conversation template with step-by-step instructions. Example: To explore a database, invoke the "explore-database" prompt. `; return { uri, mimeType: 'text/plain', text, }; } // Knowledge Base resources if (uri === 'hana://knowledge/connection-guide') { return { uri, mimeType: 'text/markdown', text: ReadmeKnowledgeBase.getConnectionGuide() }; } if (uri === 'hana://knowledge/security-guide') { return { uri, mimeType: 'text/markdown', text: ReadmeKnowledgeBase.getSecurityGuidelines() }; } if (uri === 'hana://knowledge/best-practices') { return { uri, mimeType: 'text/markdown', text: ReadmeKnowledgeBase.getBestPractices() }; } if (uri === 'hana://knowledge/project-structure') { return { uri, mimeType: 'text/markdown', text: ReadmeKnowledgeBase.getProjectStructure() }; } if (uri.startsWith('hana://knowledge/parameters/')) { const category = uri.replace('hana://knowledge/parameters/', ''); return { uri, mimeType: 'text/markdown', text: ReadmeKnowledgeBase.getParameterGuide(category) }; } // Documentation index metadata resources if (uri === 'hana://docs/statistics') { if (!docsSearch.isAvailable()) { return { uri, mimeType: 'application/json', text: JSON.stringify({ error: 'Documentation index not available' }) }; } return { uri, mimeType: 'application/json', text: JSON.stringify(docsSearch.getStats(), null, 2) }; } if (uri === 'hana://docs/categories') { if (!docsSearch.isAvailable()) { return { uri, mimeType: 'application/json', text: JSON.stringify({ error: 'Documentation index not available' }) }; } const categories = docsSearch.getCategories(); const docTypes = docsSearch.getDocTypes(); const categorySummary = {}; categories.forEach(cat => { const docs = docsSearch.listByCategory(cat); categorySummary[cat] = { documentCount: docs.length, sampleDocuments: docs.slice(0, 3).map(d => ({ title: d.title, path: d.path })), }; }); return { uri, mimeType: 'application/json', text: JSON.stringify({ categories: categorySummary, documentTypes: docTypes }, null, 2) }; } throw new Error(`Unknown resource: ${uri}`); } //# sourceMappingURL=resources.js.map