hana-cli
Version:
HANA Developer Command Line Interface
489 lines (479 loc) • 19.4 kB
JavaScript
/**
* 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