#
tokens: 49788/50000 57/77 files (page 1/3)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 3. Use http://codebase.md/hatrigt/hana-mcp-server?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .env.example
├── .github
│   └── pull_request_template.md
├── .gitignore
├── .npmignore
├── claude_template.json
├── docs
│   ├── hana_mcp_architecture.svg
│   └── hana_mcp_ui.gif
├── hana-mcp-server.js
├── hana-mcp-ui
│   ├── .gitignore
│   ├── bin
│   │   └── cli.js
│   ├── hana_mcp_ui.gif
│   ├── index.html
│   ├── logo.png
│   ├── package.json
│   ├── postcss.config.js
│   ├── README.md
│   ├── server
│   │   └── index.js
│   ├── src
│   │   ├── App.jsx
│   │   ├── components
│   │   │   ├── ClaudeConfigTile.jsx
│   │   │   ├── ClaudeDesktopView.jsx
│   │   │   ├── ClaudeServerCard.jsx
│   │   │   ├── ConfigurationModal.jsx
│   │   │   ├── ConnectionDetailsModal.jsx
│   │   │   ├── DashboardView.jsx
│   │   │   ├── DatabaseListView.jsx
│   │   │   ├── EnhancedServerCard.jsx
│   │   │   ├── EnvironmentManager.jsx
│   │   │   ├── EnvironmentSelector.jsx
│   │   │   ├── layout
│   │   │   │   ├── index.js
│   │   │   │   └── VerticalSidebar.jsx
│   │   │   ├── MainApp.jsx
│   │   │   ├── PathConfigModal.jsx
│   │   │   ├── PathSetupModal.jsx
│   │   │   ├── SearchAndFilter.jsx
│   │   │   └── ui
│   │   │       ├── DatabaseTypeBadge.jsx
│   │   │       ├── GlassCard.jsx
│   │   │       ├── GlassWindow.jsx
│   │   │       ├── GradientButton.jsx
│   │   │       ├── IconComponent.jsx
│   │   │       ├── index.js
│   │   │       ├── LoadingSpinner.jsx
│   │   │       ├── MetricCard.jsx
│   │   │       ├── StatusBadge.jsx
│   │   │       └── Tabs.jsx
│   │   ├── index.css
│   │   ├── main.jsx
│   │   └── utils
│   │       ├── cn.js
│   │       ├── databaseTypes.js
│   │       └── theme.js
│   ├── start.js
│   ├── tailwind.config.js
│   └── vite.config.js
├── LICENSE
├── manifest.yml
├── package-lock.json
├── package.json
├── README.md
├── setup.sh
├── src
│   ├── constants
│   │   ├── mcp-constants.js
│   │   └── tool-definitions.js
│   ├── database
│   │   ├── connection-manager.js
│   │   ├── hana-client.js
│   │   └── query-executor.js
│   ├── server
│   │   ├── index.js
│   │   ├── lifecycle-manager.js
│   │   └── mcp-handler.js
│   ├── tools
│   │   ├── config-tools.js
│   │   ├── index-tools.js
│   │   ├── index.js
│   │   ├── query-tools.js
│   │   ├── schema-tools.js
│   │   └── table-tools.js
│   └── utils
│       ├── config.js
│       ├── formatters.js
│       ├── logger.js
│       └── validators.js
└── tests
    ├── automated
    │   └── test-mcp-inspector.js
    ├── manual
    │   └── manual-test.js
    ├── mcpInspector
    │   ├── mcp-inspector-config.json
    │   └── mcp-inspector-config.template.json
    ├── mcpTestingGuide.md
    └── README.md
```

# Files

--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------

```
 1 | # Server configuration
 2 | MCP_TRANSPORT=http
 3 | MCP_HOST=localhost
 4 | MCP_PORT=3000
 5 | 
 6 | # HANA connection configuration
 7 | HANA_HOST=your-hana-host
 8 | HANA_PORT=30015
 9 | HANA_USER=your-username
10 | HANA_PASSWORD=your-password
11 | HANA_ENCRYPT=true
12 | HANA_VALIDATE_CERT=true
13 | 
14 | # Security configuration
15 | MCP_READ_ONLY=true
16 | MCP_ALLOWED_SCHEMAS=SCHEMA1,SCHEMA2
17 | 
18 | # Logging configuration
19 | LOG_LEVEL=info
20 | 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Dependencies
 2 | node_modules/
 3 | npm-debug.log*
 4 | yarn-debug.log*
 5 | yarn-error.log*
 6 | 
 7 | # Production build
 8 | dist/
 9 | build/
10 | 
11 | # Environment variables
12 | .env
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 | 
18 | # IDE
19 | .vscode/
20 | .idea/
21 | *.swp
22 | *.swo
23 | 
24 | # OS
25 | .DS_Store
26 | Thumbs.db
27 | 
28 | # Logs
29 | *.log
30 | logs/
31 | 
32 | # Runtime data
33 | pids/
34 | *.pid
35 | *.seed
36 | *.pid.lock
37 | 
38 | # Application data
39 | data/
40 | 
41 | # Temporary files
42 | tmp/
43 | temp/
```

--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------

```
 1 | # Development files
 2 | tests/
 3 | docs/
 4 | setup.sh
 5 | claude_template.json
 6 | 
 7 | # Configuration files
 8 | *.config.json
 9 | *config*.json
10 | *credential*.json
11 | *secret*.json
12 | *password*.json
13 | *key*.json
14 | 
15 | # Environment files
16 | .env*
17 | *.env
18 | 
19 | # Logs
20 | *.log
21 | logs/
22 | 
23 | # Editor files
24 | .vscode/
25 | .idea/
26 | *.suo
27 | *.ntvs*
28 | *.njsproj
29 | *.sln
30 | *.sw?
31 | 
32 | # OS files
33 | .DS_Store
34 | Thumbs.db
35 | 
36 | # Git
37 | .git/
38 | .gitignore
39 | 
40 | # Temporary files
41 | *.tmp
42 | *.temp
43 | *backup*
44 | *POC*
45 | 
46 | # Build artifacts
47 | dist/
48 | build/
49 | coverage/
50 | 
51 | # Package manager files
52 | package-lock.json
53 | yarn.lock 
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Dependency directories
 2 | node_modules/
 3 | npm-debug.log
 4 | yarn-debug.log
 5 | yarn-error.log
 6 | 
 7 | # Environment variables
 8 | .env
 9 | .env.local
10 | .env.production
11 | .env.staging
12 | 
13 | # Security - Credential files
14 | *config*.json
15 | *credential*.json
16 | *secret*.json
17 | *password*.json
18 | *key*.json
19 | 
20 | # Build output
21 | dist/
22 | build/
23 | coverage/
24 | 
25 | # Editor directories and files
26 | .idea/
27 | .vscode/
28 | *.suo
29 | *.ntvs*
30 | *.njsproj
31 | *.sln
32 | *.sw?
33 | .DS_Store
34 | 
35 | # Logs
36 | logs
37 | *.log
38 | npm-debug.log*
39 | yarn-debug.log*
40 | yarn-error.log*
41 | 
42 | # Runtime data
43 | pids
44 | *.pid
45 | *.seed
46 | *.pid.lock
47 | 
48 | *claude_con*
49 | *POC
50 | *backup*
51 | image.png
52 | .qod*
53 | hana-mcp-ui/bun.lock
54 | hana-mcp-ui/bun.lockb
55 | 
```

--------------------------------------------------------------------------------
/tests/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # HANA MCP Server Tests
 2 | 
 3 | This folder contains various testing approaches for the HANA MCP Server.
 4 | 
 5 | ## Folder Structure
 6 | 
 7 | ```
 8 | tests/
 9 | ├── README.md                 # This file
10 | ├── mcpInspector/            # MCP Inspector configuration and setup
11 | │   └── mcp-inspector-config.json
12 | ├── manual/                  # Manual testing scripts
13 | │   └── manual-test.js
14 | └── automated/               # Automated testing scripts
15 |     └── test-mcp-inspector.js
16 | ```
17 | 
18 | ## Testing Approaches
19 | 
20 | ### 1. MCP Inspector (Recommended)
21 | **Location**: `tests/mcpInspector/`
22 | 
23 | The MCP Inspector provides a web-based UI for testing MCP servers.
24 | 
25 | **Setup**:
26 | 1. Open https://modelcontextprotocol.io/inspector
27 | 2. Use the configuration from `mcp-inspector-config.json`
28 | 3. Connect and test tools interactively
29 | 
30 | **Configuration**:
31 | - Command: `/opt/homebrew/bin/node`
32 | - Arguments: `/Users/Common/ProjectsRepo/tools/hana-mcp-server/hana-mcp-server.js`
33 | - Environment variables: See `mcp-inspector-config.json`
34 | 
35 | ### 2. Manual Testing
36 | **Location**: `tests/manual/`
37 | 
38 | Interactive command-line testing with menu-driven interface.
39 | 
40 | **Usage**:
41 | ```bash
42 | cd tests/manual
43 | node manual-test.js
44 | ```
45 | 
46 | ### 3. Automated Testing
47 | **Location**: `tests/automated/`
48 | 
49 | Automated test suite that runs all tools and validates responses.
50 | 
51 | **Usage**:
52 | ```bash
53 | cd tests/automated
54 | node test-mcp-inspector.js
55 | ```
56 | 
57 | ## Environment Variables Required
58 | 
59 | All tests require these environment variables:
60 | - `HANA_HOST`: HANA database host
61 | - `HANA_PORT`: HANA database port (usually 443)
62 | - `HANA_USER`: HANA database username
63 | - `HANA_PASSWORD`: HANA database password
64 | - `HANA_SCHEMA`: HANA database schema
65 | - `HANA_SSL`: SSL enabled (true/false)
66 | - `HANA_ENCRYPT`: Encryption enabled (true/false)
67 | - `HANA_VALIDATE_CERT`: Certificate validation (true/false)
68 | 
69 | ## Quick Start
70 | 
71 | 1. **For interactive testing**: Use MCP Inspector
72 | 2. **For quick validation**: Run automated tests
73 | 3. **For debugging**: Use manual testing 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # HANA MCP UI
  2 | 
  3 | [![npm version](https://img.shields.io/npm/v/hana-mcp-ui.svg)](https://www.npmjs.com/package/hana-mcp-ui)
  4 | [![npm downloads](https://img.shields.io/npm/dy/hana-mcp-ui.svg)](https://www.npmjs.com/package/hana-mcp-ui)
  5 | [![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/)
  6 | [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
  7 | 
  8 | > **Visual interface for managing HANA MCP server configurations with Claude Desktop integration**
  9 | 
 10 | ## 🚀 Quick Start
 11 | 
 12 | ### 1. Run the UI
 13 | ```bash
 14 | npx hana-mcp-ui
 15 | ```
 16 | 
 17 | That's it! The UI will:
 18 | - 📦 Install automatically (if not cached)
 19 | - 🔧 Start the backend server on port 3001
 20 | - ⚡ Start the React frontend on port 5173
 21 | - 🌐 Open your browser automatically
 22 | 
 23 | ### 2. First-Time Setup
 24 | 
 25 | On first run, you'll be prompted to set your Claude Desktop config path:
 26 | 
 27 | - **🍎 macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
 28 | - **🪟 Windows**: `%APPDATA%\Claude/claude_desktop_config.json`
 29 | - **🐧 Linux**: `~/.config/claude/claude_desktop_config.json`
 30 | 
 31 | The system suggests the correct path for your OS.
 32 | 
 33 | ## 🎯 What You Get
 34 | 
 35 | ### Visual Database Management
 36 | - **🌐 Web Interface**: Modern, responsive React UI
 37 | - **🔄 Multi-Environment**: Configure Production, Development, Staging per server
 38 | - **🤖 Claude Integration**: Deploy configurations directly to Claude Desktop
 39 | - **📊 Real-time Status**: Monitor active and configured servers
 40 | - **✅ Smart Validation**: Comprehensive form validation for database connections
 41 | 
 42 | ### Key Features
 43 | - **One-Click Deployment**: Add databases to Claude Desktop with a single click
 44 | - **Environment Management**: Switch between different database environments
 45 | - **Configuration Backup**: Automatic backups before making changes
 46 | - **Connection Testing**: Test database connectivity before deployment
 47 | - **Clean Interface**: Intuitive design with smooth animations
 48 | 
 49 | ![HANA MCP UI](hana_mcp_ui.gif)
 50 | 
 51 | ## 🛠️ How to Use
 52 | 
 53 | ### 1. Add Database Configuration
 54 | - Click **"+ Add Database"** 
 55 | - Enter database details (host, user, password, etc.)
 56 | - Configure environments (Production, Development, Staging)
 57 | 
 58 | ### 2. Add to Claude Desktop
 59 | - Select a database from your list
 60 | - Choose which environment to deploy
 61 | - Click **"Add to Claude"**
 62 | - Restart Claude Desktop to activate
 63 | 
 64 | ### 3. Manage Active Connections
 65 | - View all databases currently active in Claude
 66 | - Remove connections when no longer needed
 67 | - Monitor connection status
 68 | 
 69 | ## ⚙️ Configuration Schema
 70 | 
 71 | ### Required Fields
 72 | | Parameter | Description | Example |
 73 | |-----------|-------------|---------|
 74 | | `HANA_HOST` | Database hostname or IP address | `hana.company.com` |
 75 | | `HANA_USER` | Database username | `DBADMIN` |
 76 | | `HANA_PASSWORD` | Database password | `your-secure-password` |
 77 | 
 78 | ### Optional Fields
 79 | | Parameter | Description | Default | Options |
 80 | |-----------|-------------|---------|---------|
 81 | | `HANA_PORT` | Database port | `443` | Any valid port number |
 82 | | `HANA_SCHEMA` | Default schema name | - | Schema name |
 83 | | `HANA_CONNECTION_TYPE` | Connection type | `auto` | `auto`, `single_container`, `mdc_system`, `mdc_tenant` |
 84 | | `HANA_INSTANCE_NUMBER` | Instance number (MDC) | - | Instance number (e.g., `10`) |
 85 | | `HANA_DATABASE_NAME` | Database name (MDC tenant) | - | Database name (e.g., `HQQ`) |
 86 | | `HANA_SSL` | Enable SSL connection | `true` | `true`, `false` |
 87 | | `HANA_ENCRYPT` | Enable encryption | `true` | `true`, `false` |
 88 | | `HANA_VALIDATE_CERT` | Validate SSL certificates | `true` | `true`, `false` |
 89 | | `LOG_LEVEL` | Logging level | `info` | `error`, `warn`, `info`, `debug` |
 90 | | `ENABLE_FILE_LOGGING` | Enable file logging | `true` | `true`, `false` |
 91 | | `ENABLE_CONSOLE_LOGGING` | Enable console logging | `false` | `true`, `false` |
 92 | 
 93 | ### Database Connection Types
 94 | 
 95 | #### 1. Single-Container Database
 96 | Standard HANA database with single tenant.
 97 | 
 98 | **Required**: `HANA_HOST`, `HANA_USER`, `HANA_PASSWORD`  
 99 | **Optional**: `HANA_PORT`, `HANA_SCHEMA`
100 | 
101 | #### 2. MDC System Database
102 | Multi-tenant system database (manages tenants).
103 | 
104 | **Required**: `HANA_HOST`, `HANA_PORT`, `HANA_INSTANCE_NUMBER`, `HANA_USER`, `HANA_PASSWORD`  
105 | **Optional**: `HANA_SCHEMA`
106 | 
107 | #### 3. MDC Tenant Database
108 | Multi-tenant tenant database (specific tenant).
109 | 
110 | **Required**: `HANA_HOST`, `HANA_PORT`, `HANA_INSTANCE_NUMBER`, `HANA_DATABASE_NAME`, `HANA_USER`, `HANA_PASSWORD`  
111 | **Optional**: `HANA_SCHEMA`
112 | 
113 | #### Auto-Detection
114 | When `HANA_CONNECTION_TYPE` is set to `auto` (default), the server automatically detects the type:
115 | 
116 | - If `HANA_INSTANCE_NUMBER` + `HANA_DATABASE_NAME` → **MDC Tenant**
117 | - If only `HANA_INSTANCE_NUMBER` → **MDC System**
118 | - If neither → **Single-Container**
119 | 
120 | ## 🔌 Prerequisites
121 | 
122 | Before using the UI, install the core server:
123 | 
124 | ```bash
125 | npm install -g hana-mcp-server
126 | ```
127 | 
128 | The UI works as a management interface for the installed server.
129 | 
130 | ## 🏗️ Architecture
131 | 
132 | ### System Architecture
133 | 
134 | ### Technology Stack
135 | - **Frontend**: React 19 with Vite build system
136 | - **Backend**: Express.js REST API
137 | - **Storage**: Local file system for configurations
138 | - **Integration**: Claude Desktop configuration management
139 | - **Styling**: Tailwind CSS with custom components
140 | - **Animations**: Framer Motion for smooth interactions
141 | - **Icons**: Heroicons for consistent iconography
142 | 
143 | ### Component Architecture
144 | 
145 | ```
146 | hana-mcp-ui/
147 | ├── 📁 bin/
148 | │   └── cli.js              # NPX entry point launcher
149 | ├── 📁 server/
150 | │   └── index.js            # Express backend server
151 | ├── 📁 src/
152 | │   ├── main.jsx            # React entry point
153 | │   ├── App.jsx             # Main app component
154 | │   └── components/
155 | │       ├── 🏠 MainApp.jsx          # Main application container
156 | │       ├── 🎛️ ConfigurationModal.jsx # Server configuration modal
157 | │       ├── 📋 DatabaseListView.jsx  # Database list management
158 | │       ├── 🤖 ClaudeDesktopView.jsx # Claude integration view
159 | │       ├── 📊 DashboardView.jsx     # Dashboard overview
160 | │       ├── 🎯 EnvironmentSelector.jsx # Environment selection
161 | │       ├── 📱 VerticalSidebar.jsx   # Navigation sidebar
162 | │       └── 🎨 ui/                  # Reusable UI components
163 | │           ├── GlassWindow.jsx      # Glass morphism container
164 | │           ├── StatusBadge.jsx      # Status indicators
165 | │           ├── DatabaseTypeBadge.jsx # Database type badges
166 | │           └── LoadingSpinner.jsx   # Loading states
167 | ├── 📁 dist/                # Built React app (production)
168 | ├── 📁 data/                # Local configuration storage
169 | ├── 📄 package.json         # Dependencies and scripts
170 | ├── ⚙️ vite.config.js       # Vite build configuration
171 | └── 🌐 index.html           # HTML template
172 | ```
173 | 
174 | ## 📋 Requirements
175 | 
176 | - **Node.js**: 18.0.0 or higher
177 | - **Claude Desktop**: For deployment features
178 | - **Browser**: Chrome 90+, Firefox 88+, Safari 14+, Edge 90+
179 | 
180 | ## 🔧 Development
181 | 
182 | ### Local Development
183 | ```bash
184 | git clone https://github.com/hatrigt/hana-mcp-server.git
185 | cd hana-mcp-server/hana-mcp-ui
186 | npm install
187 | npm run dev
188 | ```
189 | 
190 | ### Build for Production
191 | ```bash
192 | npm run build
193 | npm run preview
194 | ```
195 | 
196 | ## 🚀 Performance
197 | 
198 | - **Startup**: < 5 seconds
199 | - **API Response**: < 500ms
200 | - **UI Interactions**: < 100ms
201 | - **Bundle Size**: ~264KB (gzipped: ~83KB)
202 | 
203 | ## 🔒 Security
204 | 
205 | - **Local-only API** (no external connections)
206 | - **Secure file access** patterns
207 | - **Automatic backups** before configuration changes
208 | - **Password masking** in UI forms
209 | 
210 | ## 🤝 Support
211 | 
212 | - **Issues**: [GitHub Issues](https://github.com/hatrigt/hana-mcp-server/issues)
213 | - **Main Package**: [HANA MCP Server](https://www.npmjs.com/package/hana-mcp-server)
214 | - **Documentation**: [Full Documentation](https://github.com/hatrigt/hana-mcp-server#readme)
215 | 
216 | ## 📄 License
217 | 
218 | MIT License - see LICENSE file for details.
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # HANA MCP Server
  2 | 
  3 | [![npm version](https://img.shields.io/npm/v/hana-mcp-server.svg)](https://www.npmjs.com/package/hana-mcp-server)
  4 | [![npm downloads](https://img.shields.io/npm/dy/hana-mcp-server.svg)](https://www.npmjs.com/package/hana-mcp-server)
  5 | [![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/)
  6 | [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
  7 | [![MCP](https://badge.mcpx.dev?type=server)](https://modelcontextprotocol.io/)
  8 | 
  9 | > **Model Context Protocol (MCP) server for seamless SAP HANA database integration with AI agents and development tools.**
 10 | 
 11 | ## 🚀 Quick Start
 12 | 
 13 | ### 1. Install
 14 | ```bash
 15 | npm install -g hana-mcp-server
 16 | ```
 17 | 
 18 | ### 2. Configure Claude Desktop
 19 | 
 20 | Update your Claude Desktop config file:
 21 | 
 22 | **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`  
 23 | **Windows**: `%APPDATA%\claude\claude_desktop_config.json`  
 24 | **Linux**: `~/.config/claude/claude_desktop_config.json`
 25 | 
 26 | ```json
 27 | {
 28 |   "mcpServers": {
 29 |     "HANA Database": {
 30 |       "command": "hana-mcp-server",
 31 |       "env": {
 32 |         "HANA_HOST": "your-hana-host.com",
 33 |         "HANA_PORT": "443",
 34 |         "HANA_USER": "your-username",
 35 |         "HANA_PASSWORD": "your-password",
 36 |         "HANA_SCHEMA": "your-schema",
 37 |         "HANA_SSL": "true",
 38 |         "HANA_ENCRYPT": "true",
 39 |         "HANA_VALIDATE_CERT": "true",
 40 |         "HANA_CONNECTION_TYPE": "auto",
 41 |         "HANA_INSTANCE_NUMBER": "10",
 42 |         "HANA_DATABASE_NAME": "HQQ",
 43 |         "LOG_LEVEL": "info",
 44 |         "ENABLE_FILE_LOGGING": "true",
 45 |         "ENABLE_CONSOLE_LOGGING": "false"
 46 |       }
 47 |     }
 48 |   }
 49 | }
 50 | ```
 51 | 
 52 | ### 3. Restart Claude Desktop
 53 | 
 54 | Close and reopen Claude Desktop to load the configuration.
 55 | 
 56 | ### 4. Test It!
 57 | 
 58 | Ask Claude: *"Show me the available schemas in my HANA database"*
 59 | 
 60 | ## 🎯 What You Get
 61 | 
 62 | ### Database Operations
 63 | - **Schema Exploration**: List schemas, tables, and table structures
 64 | - **Query Execution**: Run SQL queries with natural language
 65 | - **Data Sampling**: Get sample data from tables
 66 | - **System Information**: Monitor database status and performance
 67 | 
 68 | ### AI Integration
 69 | - **Natural Language Queries**: "Show me all tables in the SYSTEM schema"
 70 | - **Query Building**: "Create a query to find customers with orders > $1000"
 71 | - **Data Analysis**: "Get sample data from the ORDERS table"
 72 | - **Schema Navigation**: "Describe the structure of table CUSTOMERS"
 73 | 
 74 | ## 🖥️ Visual Configuration (Recommended)
 75 | 
 76 | For easier setup and management, use the **HANA MCP UI**:
 77 | 
 78 | ```bash
 79 | npx hana-mcp-ui
 80 | ```
 81 | 
 82 | This opens a web interface where you can:
 83 | - Configure multiple database environments
 84 | - Deploy configurations to Claude Desktop with one click
 85 | - Manage active connections
 86 | - Test database connectivity
 87 | 
 88 | ![HANA MCP UI](docs/hana_mcp_ui.gif)
 89 | 
 90 | ## 🛠️ Configuration Options
 91 | 
 92 | ### Required Parameters
 93 | | Parameter | Description | Example |
 94 | |-----------|-------------|---------|
 95 | | `HANA_HOST` | Database hostname or IP address | `hana.company.com` |
 96 | | `HANA_USER` | Database username | `DBADMIN` |
 97 | | `HANA_PASSWORD` | Database password | `your-secure-password` |
 98 | 
 99 | ### Optional Parameters
100 | | Parameter | Description | Default | Options |
101 | |-----------|-------------|---------|---------|
102 | | `HANA_PORT` | Database port | `443` | Any valid port number |
103 | | `HANA_SCHEMA` | Default schema name | - | Schema name |
104 | | `HANA_CONNECTION_TYPE` | Connection type | `auto` | `auto`, `single_container`, `mdc_system`, `mdc_tenant` |
105 | | `HANA_INSTANCE_NUMBER` | Instance number (MDC) | - | Instance number (e.g., `10`) |
106 | | `HANA_DATABASE_NAME` | Database name (MDC tenant) | - | Database name (e.g., `HQQ`) |
107 | | `HANA_SSL` | Enable SSL connection | `true` | `true`, `false` |
108 | | `HANA_ENCRYPT` | Enable encryption | `true` | `true`, `false` |
109 | | `HANA_VALIDATE_CERT` | Validate SSL certificates | `true` | `true`, `false` |
110 | | `LOG_LEVEL` | Logging level | `info` | `error`, `warn`, `info`, `debug` |
111 | | `ENABLE_FILE_LOGGING` | Enable file logging | `true` | `true`, `false` |
112 | | `ENABLE_CONSOLE_LOGGING` | Enable console logging | `false` | `true`, `false` |
113 | 
114 | ### Database Connection Types
115 | 
116 | #### 1. Single-Container Database
117 | Standard HANA database with single tenant.
118 | 
119 | **Required**: `HANA_HOST`, `HANA_USER`, `HANA_PASSWORD`  
120 | **Optional**: `HANA_PORT`, `HANA_SCHEMA`
121 | 
122 | ```json
123 | {
124 |   "HANA_HOST": "hana.company.com",
125 |   "HANA_PORT": "443",
126 |   "HANA_USER": "DBADMIN",
127 |   "HANA_PASSWORD": "password",
128 |   "HANA_SCHEMA": "SYSTEM",
129 |   "HANA_CONNECTION_TYPE": "single_container"
130 | }
131 | ```
132 | 
133 | #### 2. MDC System Database
134 | Multi-tenant system database (manages tenants).
135 | 
136 | **Required**: `HANA_HOST`, `HANA_PORT`, `HANA_INSTANCE_NUMBER`, `HANA_USER`, `HANA_PASSWORD`  
137 | **Optional**: `HANA_SCHEMA`
138 | 
139 | ```json
140 | {
141 |   "HANA_HOST": "192.168.1.100",
142 |   "HANA_PORT": "31013",
143 |   "HANA_INSTANCE_NUMBER": "10",
144 |   "HANA_USER": "SYSTEM",
145 |   "HANA_PASSWORD": "password",
146 |   "HANA_SCHEMA": "SYSTEM",
147 |   "HANA_CONNECTION_TYPE": "mdc_system"
148 | }
149 | ```
150 | 
151 | #### 3. MDC Tenant Database
152 | Multi-tenant tenant database (specific tenant).
153 | 
154 | **Required**: `HANA_HOST`, `HANA_PORT`, `HANA_INSTANCE_NUMBER`, `HANA_DATABASE_NAME`, `HANA_USER`, `HANA_PASSWORD`  
155 | **Optional**: `HANA_SCHEMA`
156 | 
157 | ```json
158 | {
159 |   "HANA_HOST": "192.168.1.100",
160 |   "HANA_PORT": "31013",
161 |   "HANA_INSTANCE_NUMBER": "10",
162 |   "HANA_DATABASE_NAME": "HQQ",
163 |   "HANA_USER": "DBADMIN",
164 |   "HANA_PASSWORD": "password",
165 |   "HANA_SCHEMA": "SYSTEM",
166 |   "HANA_CONNECTION_TYPE": "mdc_tenant"
167 | }
168 | ```
169 | 
170 | #### Auto-Detection
171 | When `HANA_CONNECTION_TYPE` is set to `auto` (default), the server automatically detects the type:
172 | 
173 | - If `HANA_INSTANCE_NUMBER` + `HANA_DATABASE_NAME` → **MDC Tenant**
174 | - If only `HANA_INSTANCE_NUMBER` → **MDC System**
175 | - If neither → **Single-Container**
176 | 
177 | ## 🏗️ Architecture
178 | 
179 | ### System Architecture
180 | 
181 | ![HANA MCP Server Architecture](docs/hana_mcp_architecture.svg)
182 | 
183 | ### Component Structure
184 | 
185 | ```
186 | hana-mcp-server/
187 | ├── 📁 src/
188 | │   ├── 🏗️ server/           # MCP Protocol & Server Management
189 | │   │   ├── index.js         # Main server entry point
190 | │   │   ├── mcp-handler.js   # JSON-RPC 2.0 implementation
191 | │   │   └── lifecycle-manager.js # Server lifecycle management
192 | │   ├── 🛠️ tools/            # Tool Implementations
193 | │   │   ├── index.js         # Tool registry & discovery
194 | │   │   ├── config-tools.js  # Configuration management
195 | │   │   ├── schema-tools.js  # Schema exploration
196 | │   │   ├── table-tools.js   # Table operations
197 | │   │   ├── index-tools.js   # Index management
198 | │   │   └── query-tools.js   # Query execution
199 | │   ├── 🗄️ database/         # Database Layer
200 | │   │   ├── hana-client.js   # HANA client wrapper
201 | │   │   ├── connection-manager.js # Connection management
202 | │   │   └── query-executor.js # Query execution utilities
203 | │   ├── 🔧 utils/            # Shared Utilities
204 | │   │   ├── logger.js        # Structured logging
205 | │   │   ├── config.js        # Configuration management
206 | │   │   ├── validators.js    # Input validation
207 | │   │   └── formatters.js    # Response formatting
208 | │   └── 📋 constants/        # Constants & Definitions
209 | │       ├── mcp-constants.js # MCP protocol constants
210 | │       └── tool-definitions.js # Tool schemas
211 | ├── 🧪 tests/                # Testing Framework
212 | ├── 📚 docs/                 # Documentation
213 | ├── 📦 package.json          # Dependencies & Scripts
214 | └── 🚀 hana-mcp-server.js    # Main entry point
215 | ```
216 | 
217 | ## 📚 Available Commands
218 | 
219 | Once configured, you can ask Claude to:
220 | 
221 | - *"List all schemas in the database"*
222 | - *"Show me tables in the SYSTEM schema"*
223 | - *"Describe the CUSTOMERS table structure"*
224 | - *"Execute: SELECT * FROM SYSTEM.TABLES LIMIT 10"*
225 | - *"Get sample data from ORDERS table"*
226 | - *"Count rows in CUSTOMERS table"*
227 | 
228 | ## 🔧 Troubleshooting
229 | 
230 | ### Connection Issues
231 | - **"Connection refused"**: Check HANA host and port
232 | - **"Authentication failed"**: Verify username/password
233 | - **"SSL certificate error"**: Set `HANA_VALIDATE_CERT=false` or install valid certificates
234 | 
235 | ### Debug Mode
236 | ```bash
237 | export LOG_LEVEL="debug"
238 | export ENABLE_CONSOLE_LOGGING="true"
239 | hana-mcp-server
240 | ```
241 | 
242 | ## 📦 Package Info
243 | 
244 | - **Size**: 21.7 kB
245 | - **Dependencies**: @sap/hana-client, axios
246 | - **Node.js**: 18+ required
247 | - **Platforms**: macOS, Linux, Windows
248 | 
249 | ## 🤝 Support
250 | 
251 | - **Issues**: [GitHub Issues](https://github.com/hatrigt/hana-mcp-server/issues)
252 | - **UI Tool**: [HANA MCP UI](https://www.npmjs.com/package/hana-mcp-ui)
253 | 
254 | ## 📄 License
255 | 
256 | MIT License - see [LICENSE](LICENSE) file for details.
```

--------------------------------------------------------------------------------
/hana-mcp-ui/postcss.config.js:
--------------------------------------------------------------------------------

```javascript
1 | export default {
2 |   plugins: {
3 |     tailwindcss: {},
4 |     autoprefixer: {},
5 |   },
6 | }
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/layout/index.js:
--------------------------------------------------------------------------------

```javascript
1 | // Layout Components Exports
2 | export { default as VerticalSidebar } from './VerticalSidebar'
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/utils/cn.js:
--------------------------------------------------------------------------------

```javascript
1 | import { clsx } from 'clsx'
2 | import { twMerge } from 'tailwind-merge'
3 | 
4 | export function cn(...inputs) {
5 |   return twMerge(clsx(inputs))
6 | }
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/main.jsx:
--------------------------------------------------------------------------------

```javascript
 1 | import { StrictMode } from 'react'
 2 | import { createRoot } from 'react-dom/client'
 3 | import App from './App.jsx'
 4 | import './index.css'
 5 | 
 6 | createRoot(document.getElementById('root')).render(
 7 |   <StrictMode>
 8 |     <App />
 9 |   </StrictMode>,
10 | )
```

--------------------------------------------------------------------------------
/hana-mcp-ui/vite.config.js:
--------------------------------------------------------------------------------

```javascript
 1 | import { defineConfig } from 'vite'
 2 | import react from '@vitejs/plugin-react'
 3 | 
 4 | export default defineConfig({
 5 |   plugins: [react()],
 6 |   server: {
 7 |     port: 5173,
 8 |     host: '0.0.0.0',
 9 |     strictPort: true
10 |   },
11 |   build: {
12 |     outDir: 'dist'
13 |   }
14 | })
```

--------------------------------------------------------------------------------
/hana-mcp-server.js:
--------------------------------------------------------------------------------

```javascript
 1 | #!/usr/bin/env node
 2 | 
 3 | /**
 4 |  * HANA MCP Server - Main Entry Point
 5 |  * 
 6 |  * This is a thin wrapper that starts the modular MCP server.
 7 |  * The actual implementation is in src/server/index.js
 8 |  */
 9 | 
10 | // Start the modular server
11 | require('./src/server/index.js'); 
```

--------------------------------------------------------------------------------
/manifest.yml:
--------------------------------------------------------------------------------

```yaml
 1 | applications:
 2 | - name: hana-mcp-server
 3 |   memory: 256M
 4 |   disk_quota: 512M
 5 |   instances: 1
 6 |   buildpack: nodejs_buildpack
 7 |   command: node hana-mcp-server.js
 8 |   env:
 9 |     NODE_ENV: production
10 |     PORT: 8080
11 |   services:
12 |     - hana-service  # Your HANA service instance name 
```

--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------

```markdown
 1 | ## 📝 Description
 2 | 
 3 | Brief description of changes
 4 | 
 5 | ## 🔄 Type of Change
 6 | 
 7 | - [ ] Bug fix
 8 | - [ ] New feature
 9 | - [ ] Documentation update
10 | - [ ] Performance improvement
11 | 
12 | ## 🧪 Testing
13 | 
14 | - [ ] MCP Inspector tests pass
15 | - [ ] Manual testing completed
16 | - [ ] No breaking changes
17 | 
18 | ## ✅ Checklist
19 | 
20 | - [ ] Code follows existing patterns
21 | - [ ] Self-review completed
22 | - [ ] Documentation updated
23 | - [ ] No breaking changes
24 | 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/App.jsx:
--------------------------------------------------------------------------------

```javascript
 1 | 
 2 | import { Toaster } from 'react-hot-toast'
 3 | import MainApp from './components/MainApp'
 4 | 
 5 | function App() {
 6 |   return (
 7 |     <>
 8 |       <MainApp />
 9 |       
10 |       <Toaster
11 |         position="top-right"
12 |         toastOptions={{
13 |           duration: 4000,
14 |           style: {
15 |             background: '#363636',
16 |             color: '#fff',
17 |             borderRadius: '8px',
18 |           },
19 |         }}
20 |       />
21 |     </>
22 |   )
23 | }
24 | 
25 | export default App
```

--------------------------------------------------------------------------------
/tests/mcpInspector/mcp-inspector-config.template.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "mcpServers": {
 3 |     "HANA Database": {
 4 |       "command": "/opt/homebrew/bin/node",
 5 |       "args": [
 6 |         "/path/to/your/hana-mcp-server/hana-mcp-server.js"
 7 |       ],
 8 |       "env": {
 9 |         "HANA_HOST": "your-hana-host.com",
10 |         "HANA_PORT": "443",
11 |         "HANA_USER": "your-username",
12 |         "HANA_PASSWORD": "your-password",
13 |         "HANA_SCHEMA": "your-schema",
14 |         "HANA_SSL": "true",
15 |         "HANA_ENCRYPT": "true",
16 |         "HANA_VALIDATE_CERT": "true"
17 |       }
18 |     }
19 |   }
20 | } 
```

--------------------------------------------------------------------------------
/tests/mcpInspector/mcp-inspector-config.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "mcpServers": {
 3 |     "HANA Database": {
 4 |       "command": "/opt/homebrew/bin/node",
 5 |       "args": [
 6 |         "/Users/Common/ProjectsRepo/tools/hana-mcp-server/hana-mcp-server.js"
 7 |       ],
 8 |       "env": {
 9 |         "HANA_HOST": "your-hana-host.com",
10 |         "HANA_PORT": "443",
11 |         "HANA_USER": "your-username",
12 |         "HANA_PASSWORD": "your-password",
13 |         "HANA_SCHEMA": "your-schema",
14 |         "HANA_SSL": "true",
15 |         "HANA_ENCRYPT": "true",
16 |         "HANA_VALIDATE_CERT": "true"
17 |       }
18 |     }
19 |   }
20 | } 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/index.html:
--------------------------------------------------------------------------------

```html
 1 | <!doctype html>
 2 | <html lang="en">
 3 |   <head>
 4 |     <meta charset="UTF-8" />
 5 |     <link rel="icon" type="image/png" href="/logo.png" />
 6 |     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 7 |     <title>HANA MCP UI - Database Configuration Manager</title>
 8 |     <style>
 9 |       body {
10 |         margin: 0;
11 |         padding: 0;
12 |         font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, Roboto, sans-serif;
13 |         background: #f8fafc;
14 |       }
15 |     </style>
16 |   </head>
17 |   <body>
18 |     <div id="root"></div>
19 |     <script type="module" src="/src/main.jsx"></script>
20 |   </body>
21 | </html>
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/ui/index.js:
--------------------------------------------------------------------------------

```javascript
 1 | // UI Components Exports
 2 | export { default as GlassCard } from './GlassCard'
 3 | export { default as GlassWindow } from './GlassWindow'
 4 | export { default as GradientButton } from './GradientButton'
 5 | export { default as StatusBadge, EnvironmentBadge } from './StatusBadge'
 6 | export { default as LoadingSpinner, LoadingOverlay } from './LoadingSpinner'
 7 | export { default as MetricCard } from './MetricCard'
 8 | export { default as IconComponent } from './IconComponent'
 9 | export { default as Tabs } from './Tabs'
10 | export { default as DatabaseTypeBadge } from './DatabaseTypeBadge'
11 | export { default as PathConfigModal } from '../PathConfigModal'
12 | 
13 | 
```

--------------------------------------------------------------------------------
/claude_template.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "mcpServers": {
 3 |     "HANA Database": {
 4 |       "command": "/opt/homebrew/bin/node",
 5 |       "args": [
 6 |         "/path/to/hana-mcp-server/hana-mcp-server.js"
 7 |       ],
 8 |       "env": {
 9 |         "HANA_HOST": "your-hana-host.com",
10 |         "HANA_PORT": "443",
11 |         "HANA_USER": "your-username",
12 |         "HANA_PASSWORD": "your-password",
13 |         "HANA_SCHEMA": "your-schema",
14 |         "HANA_INSTANCE_NUMBER": "10",
15 |         "HANA_DATABASE_NAME": "HQQ",
16 |         "HANA_CONNECTION_TYPE": "auto",
17 |         "HANA_SSL": "true",
18 |         "LOG_LEVEL": "info",
19 |         "ENABLE_FILE_LOGGING": "true",
20 |         "ENABLE_CONSOLE_LOGGING": "false"
21 |       }
22 |     }
23 |   }
24 | } 
```

--------------------------------------------------------------------------------
/src/tools/schema-tools.js:
--------------------------------------------------------------------------------

```javascript
 1 | /**
 2 |  * Schema exploration tools for HANA MCP Server
 3 |  */
 4 | 
 5 | const { logger } = require('../utils/logger');
 6 | const QueryExecutor = require('../database/query-executor');
 7 | const Formatters = require('../utils/formatters');
 8 | 
 9 | class SchemaTools {
10 |   /**
11 |    * List all schemas
12 |    */
13 |   static async listSchemas(args) {
14 |     logger.tool('hana_list_schemas');
15 |     
16 |     try {
17 |       const schemas = await QueryExecutor.getSchemas();
18 |       const formattedSchemas = Formatters.formatSchemaList(schemas);
19 |       
20 |       return Formatters.createResponse(formattedSchemas);
21 |     } catch (error) {
22 |       logger.error('Error listing schemas:', error.message);
23 |       return Formatters.createErrorResponse('Error listing schemas', error.message);
24 |     }
25 |   }
26 | }
27 | 
28 | module.exports = SchemaTools; 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/ui/MetricCard.jsx:
--------------------------------------------------------------------------------

```javascript
 1 | import { motion } from 'framer-motion'
 2 | import { cn } from '../../utils/cn'
 3 | 
 4 | const MetricCard = ({ 
 5 |   title, 
 6 |   value,
 7 |   className 
 8 | }) => {
 9 |   return (
10 |     <motion.div
11 |       className={cn(
12 |         'bg-white border border-gray-100 rounded-xl overflow-hidden',
13 |         'hover:border-gray-200 transition-all duration-300',
14 |         className
15 |       )}
16 |       whileHover={{ y: -1 }}
17 |       transition={{ duration: 0.2 }}
18 |     >
19 |       <div className="border-b border-gray-50 px-4 py-3">
20 |         <h3 className="text-xs font-medium text-gray-500 uppercase tracking-wide">{title}</h3>
21 |       </div>
22 |       <div className="px-4 py-4">
23 |         <div className="flex items-baseline">
24 |           <p className="text-2xl font-semibold text-gray-900">{value}</p>
25 |         </div>
26 |       </div>
27 |     </motion.div>
28 |   )
29 | }
30 | 
31 | export default MetricCard
```

--------------------------------------------------------------------------------
/hana-mcp-ui/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "hana-mcp-ui",
 3 |   "version": "1.0.9",
 4 |   "description": "UI for managing HANA MCP server configurations with Claude Desktop integration",
 5 |   "type": "module",
 6 |   "main": "bin/cli.js",
 7 |   "bin": {
 8 |     "hana-mcp-ui": "bin/cli.js"
 9 |   },
10 |   "engines": {
11 |     "node": ">=18.0.0"
12 |   },
13 |   "scripts": {
14 |     "dev": "node start.js",
15 |     "dev:safe": "./start-dev.sh",
16 |     "dev:old": "node bin/cli.js",
17 |     "vite": "vite",
18 |     "build": "bun run vite build",
19 |     "preview": "bun run vite preview"
20 |   },
21 |   "dependencies": {
22 |     "@heroicons/react": "^2.2.0",
23 |     "@tailwindcss/forms": "^0.5.7",
24 |     "@vitejs/plugin-react": "^4.7.0",
25 |     "autoprefixer": "^10.4.16",
26 |     "axios": "^1.11.0",
27 |     "chalk": "^5.5.0",
28 |     "clsx": "^2.0.0",
29 |     "cors": "^2.8.5",
30 |     "express": "^5.1.0",
31 |     "framer-motion": "^12.23.12",
32 |     "fs-extra": "^11.3.1",
33 |     "open": "^10.2.0",
34 |     "postcss": "^8.4.32",
35 |     "react": "^19.1.1",
36 |     "react-dom": "^19.1.1",
37 |     "react-hot-toast": "^2.5.2",
38 |     "tailwind-merge": "^2.3.0",
39 |     "tailwindcss": "^3.4.0",
40 |     "vite": "^7.1.3"
41 |   },
42 |   "keywords": [
43 |     "hana",
44 |     "mcp",
45 |     "claude",
46 |     "database",
47 |     "ui",
48 |     "react",
49 |     "management"
50 |   ],
51 |   "author": "HANA MCP Team",
52 |   "license": "MIT"
53 | }
54 | 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/ui/Tabs.jsx:
--------------------------------------------------------------------------------

```javascript
 1 | import { useState } from 'react';
 2 | import { cn } from '../../utils/cn';
 3 | 
 4 | const Tabs = ({ 
 5 |   tabs, 
 6 |   activeTab, 
 7 |   onChange,
 8 |   className
 9 | }) => {
10 |   return (
11 |     <div className={cn("border-b border-gray-200", className)}>
12 |       <nav className="flex -mb-px space-x-6">
13 |         {tabs.map((tab) => (
14 |           <button
15 |             key={tab.id}
16 |             onClick={() => onChange(tab.id)}
17 |             className={cn(
18 |               "py-3 px-4 border-b-2 font-medium text-sm whitespace-nowrap transition-all",
19 |               activeTab === tab.id
20 |                 ? "border-blue-600 text-blue-700 bg-blue-50/50"
21 |                 : "border-transparent text-gray-500 hover:text-gray-800 hover:border-gray-300 hover:bg-gray-50/50"
22 |             )}
23 |             aria-current={activeTab === tab.id ? "page" : undefined}
24 |           >
25 |             {tab.icon && (
26 |               <span className="mr-2">{tab.icon}</span>
27 |             )}
28 |             {tab.label}
29 |             {tab.count !== undefined && (
30 |               <span className={cn(
31 |                 "ml-2 py-0.5 px-2 rounded-full text-xs font-semibold",
32 |                 activeTab === tab.id
33 |                   ? "bg-blue-100 text-blue-700"
34 |                   : "bg-gray-100 text-gray-600"
35 |               )}>
36 |                 {tab.count}
37 |               </span>
38 |             )}
39 |           </button>
40 |         ))}
41 |       </nav>
42 |     </div>
43 |   );
44 | };
45 | 
46 | export default Tabs;
47 | 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/ui/IconComponent.jsx:
--------------------------------------------------------------------------------

```javascript
 1 | import React from 'react';
 2 | import { cn } from '../../utils/cn';
 3 | 
 4 | /**
 5 |  * IconComponent - A standardized wrapper for icons
 6 |  * 
 7 |  * @param {Object} props - Component props
 8 |  * @param {React.ElementType} props.icon - The icon component to render
 9 |  * @param {string} props.size - Size of the icon (sm, md, lg)
10 |  * @param {string} props.variant - Visual variant (default, primary, secondary, etc.)
11 |  * @param {string} props.className - Additional CSS classes
12 |  * @param {string} props.label - Accessibility label (for icon-only buttons)
13 |  * @returns {JSX.Element} - Rendered icon component
14 |  */
15 | const IconComponent = ({ 
16 |   icon: Icon,
17 |   size = 'md',
18 |   variant = 'default',
19 |   className,
20 |   label,
21 |   ...props 
22 | }) => {
23 |   // Size mappings
24 |   const sizes = {
25 |     xs: 'w-3 h-3',
26 |     sm: 'w-4 h-4',
27 |     md: 'w-5 h-5',
28 |     lg: 'w-6 h-6',
29 |     xl: 'w-8 h-8'
30 |   };
31 |   
32 |   // Variant mappings
33 |   const variants = {
34 |     default: 'text-gray-600',
35 |     primary: 'text-[#86a0ff]',
36 |     secondary: 'text-gray-500',
37 |     success: 'text-green-600',
38 |     warning: 'text-amber-600',
39 |     danger: 'text-red-500',
40 |     white: 'text-white'
41 |   };
42 |   
43 |   // If no Icon is provided, return null
44 |   if (!Icon) return null;
45 |   
46 |   return (
47 |     <Icon 
48 |       className={cn(
49 |         sizes[size],
50 |         variants[variant],
51 |         className
52 |       )}
53 |       aria-label={label}
54 |       aria-hidden={!label}
55 |       role={label ? 'img' : undefined}
56 |       {...props}
57 |     />
58 |   );
59 | };
60 | 
61 | export default IconComponent;
62 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "hana-mcp-server",
 3 |   "version": "0.1.4",
 4 |   "description": "🚀 Easy-to-use MCP server for SAP HANA database integration with AI agents like Claude Desktop. Connect to HANA databases with natural language queries.",
 5 |   "main": "hana-mcp-server.js",
 6 |   "bin": {
 7 |     "hana-mcp-server": "hana-mcp-server.js"
 8 |   },
 9 |   "scripts": {
10 |     "start": "node hana-mcp-server.js",
11 |     "dev": "nodemon hana-mcp-server.js",
12 |     "test": "node tests/automated/test-mcp-inspector.js"
13 |   },
14 |   "keywords": [
15 |     "sap",
16 |     "hana",
17 |     "mcp",
18 |     "btp",
19 |     "hana-mcp",
20 |     "mcp-server",
21 |     "database",
22 |     "ai",
23 |     "model",
24 |     "context",
25 |     "protocol",
26 |     "claude",
27 |     "anthropic",
28 |     "enterprise",
29 |     "sql",
30 |     "query"
31 |   ],
32 |   "author": {
33 |     "name": "HANA MCP Server Contributors",
34 |     "email": "[email protected]"
35 |   },
36 |   "license": "MIT",
37 |   "repository": {
38 |     "type": "git",
39 |     "url": "git+https://github.com/hatrigt/hana-mcp-server.git"
40 |   },
41 |   "homepage": "https://github.com/hatrigt/hana-mcp-server#readme",
42 |   "bugs": {
43 |     "url": "https://github.com/hatrigt/hana-mcp-server/issues"
44 |   },
45 |   "readme": "README.md",
46 |   "engines": {
47 |     "node": ">=18.0.0"
48 |   },
49 |   "os": [
50 |     "darwin",
51 |     "linux",
52 |     "win32"
53 |   ],
54 |   "dependencies": {
55 |     "@sap/hana-client": "^2.17.22",
56 |     "axios": "^1.12.2"
57 |   },
58 |   "devDependencies": {
59 |     "nodemon": "^3.0.2"
60 |   },
61 |   "files": [
62 |     "hana-mcp-server.js",
63 |     "src/",
64 |     "README.md",
65 |     "LICENSE"
66 |   ]
67 | }
68 | 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/ui/LoadingSpinner.jsx:
--------------------------------------------------------------------------------

```javascript
 1 | import { motion } from 'framer-motion'
 2 | import { cn } from '../../utils/cn'
 3 | 
 4 | const LoadingSpinner = ({ 
 5 |   size = 'md', 
 6 |   color = 'white',
 7 |   className 
 8 | }) => {
 9 |   const sizes = {
10 |     sm: 'w-4 h-4',
11 |     md: 'w-6 h-6', 
12 |     lg: 'w-8 h-8',
13 |     xl: 'w-12 h-12'
14 |   }
15 |   
16 |   const colors = {
17 |     white: 'border-gray-200 border-t-blue-600',
18 |     primary: 'border-blue-200 border-t-blue-600',
19 |     success: 'border-emerald-200 border-t-emerald-600',
20 |     warning: 'border-amber-200 border-t-amber-600',
21 |     danger: 'border-red-200 border-t-red-600'
22 |   }
23 |   
24 |   return (
25 |     <motion.div
26 |       className={cn(
27 |         'inline-block rounded-full border-2',
28 |         sizes[size],
29 |         colors[color] || colors.white,
30 |         className
31 |       )}
32 |       animate={{ rotate: 360 }}
33 |       transition={{ duration: 1, repeat: Infinity, ease: "linear" }}
34 |     />
35 |   )
36 | }
37 | 
38 | // Full page loading overlay
39 | export const LoadingOverlay = ({ message = "Loading..." }) => (
40 |   <motion.div 
41 |     className="fixed inset-0 bg-gray-900/20 backdrop-blur-sm z-50 flex items-center justify-center"
42 |     initial={{ opacity: 0 }}
43 |     animate={{ opacity: 1 }}
44 |     exit={{ opacity: 0 }}
45 |   >
46 |     <motion.div 
47 |       className="glass-card p-8 text-center"
48 |       initial={{ scale: 0.8, opacity: 0 }}
49 |       animate={{ scale: 1, opacity: 1 }}
50 |       transition={{ delay: 0.1 }}
51 |     >
52 |       <LoadingSpinner size="xl" color="primary" className="mx-auto mb-4" />
53 |       <p className="text-gray-700">{message}</p>
54 |     </motion.div>
55 |   </motion.div>
56 | )
57 | 
58 | export default LoadingSpinner
```

--------------------------------------------------------------------------------
/src/utils/logger.js:
--------------------------------------------------------------------------------

```javascript
 1 | /**
 2 |  * Centralized logging utility for HANA MCP Server
 3 |  * Uses console.error to avoid interfering with JSON-RPC stdout
 4 |  */
 5 | 
 6 | const LOG_LEVELS = {
 7 |   ERROR: 0,
 8 |   WARN: 1,
 9 |   INFO: 2,
10 |   DEBUG: 3
11 | };
12 | 
13 | const LOG_LEVEL_NAMES = {
14 |   0: 'ERROR',
15 |   1: 'WARN', 
16 |   2: 'INFO',
17 |   3: 'DEBUG'
18 | };
19 | 
20 | class Logger {
21 |   constructor(level = 'INFO') {
22 |     this.level = LOG_LEVELS[level.toUpperCase()] || LOG_LEVELS.INFO;
23 |     this.prefix = '[HANA MCP Server]';
24 |   }
25 | 
26 |   _log(level, message, ...args) {
27 |     if (level <= this.level) {
28 |       const timestamp = new Date().toISOString();
29 |       const levelName = LOG_LEVEL_NAMES[level];
30 |       const formattedMessage = `${this.prefix} ${timestamp} [${levelName}]: ${message}`;
31 |       
32 |       // Use console.error to avoid interfering with JSON-RPC stdout
33 |       console.error(formattedMessage, ...args);
34 |     }
35 |   }
36 | 
37 |   error(message, ...args) {
38 |     this._log(LOG_LEVELS.ERROR, message, ...args);
39 |   }
40 | 
41 |   warn(message, ...args) {
42 |     this._log(LOG_LEVELS.WARN, message, ...args);
43 |   }
44 | 
45 |   info(message, ...args) {
46 |     this._log(LOG_LEVELS.INFO, message, ...args);
47 |   }
48 | 
49 |   debug(message, ...args) {
50 |     this._log(LOG_LEVELS.DEBUG, message, ...args);
51 |   }
52 | 
53 |   // Convenience method for method calls
54 |   method(methodName, ...args) {
55 |     this.info(`Handling method: ${methodName}`, ...args);
56 |   }
57 | 
58 |   // Convenience method for tool calls
59 |   tool(toolName, ...args) {
60 |     this.info(`Calling tool: ${toolName}`, ...args);
61 |   }
62 | }
63 | 
64 | // Create default logger instance
65 | const logger = new Logger(process.env.LOG_LEVEL || 'INFO');
66 | 
67 | module.exports = { Logger, logger }; 
```

--------------------------------------------------------------------------------
/src/tools/query-tools.js:
--------------------------------------------------------------------------------

```javascript
 1 | /**
 2 |  * Query execution tools for HANA MCP Server
 3 |  */
 4 | 
 5 | const { logger } = require('../utils/logger');
 6 | const QueryExecutor = require('../database/query-executor');
 7 | const Validators = require('../utils/validators');
 8 | const Formatters = require('../utils/formatters');
 9 | 
10 | class QueryTools {
11 |   /**
12 |    * Execute a custom SQL query
13 |    */
14 |   static async executeQuery(args) {
15 |     logger.tool('hana_execute_query', args);
16 |     
17 |     const { query, parameters = [] } = args || {};
18 |     
19 |     // Validate required parameters
20 |     const validation = Validators.validateRequired(args, ['query'], 'hana_execute_query');
21 |     if (!validation.valid) {
22 |       return Formatters.createErrorResponse('Error: query parameter is required', validation.error);
23 |     }
24 |     
25 |     // Validate query
26 |     const queryValidation = Validators.validateQuery(query);
27 |     if (!queryValidation.valid) {
28 |       return Formatters.createErrorResponse('Invalid query', queryValidation.error);
29 |     }
30 |     
31 |     // Validate parameters
32 |     const paramValidation = Validators.validateParameters(parameters);
33 |     if (!paramValidation.valid) {
34 |       return Formatters.createErrorResponse('Invalid parameters', paramValidation.error);
35 |     }
36 |     
37 |     try {
38 |       const results = await QueryExecutor.executeQuery(query, parameters);
39 |       const formattedResults = Formatters.formatQueryResults(results, query);
40 |       
41 |       return Formatters.createResponse(formattedResults);
42 |     } catch (error) {
43 |       logger.error('Query execution failed:', error.message);
44 |       return Formatters.createErrorResponse('Query execution failed', error.message);
45 |     }
46 |   }
47 | }
48 | 
49 | module.exports = QueryTools; 
```

--------------------------------------------------------------------------------
/setup.sh:
--------------------------------------------------------------------------------

```bash
 1 | #!/bin/bash
 2 | 
 3 | # HANA MCP Server Setup Script
 4 | echo "🚀 Setting up HANA MCP Server"
 5 | echo "============================="
 6 | 
 7 | # Get the current directory
 8 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 9 | echo "📁 Working directory: $SCRIPT_DIR"
10 | 
11 | # Check if Node.js is available
12 | NODE_PATH="/opt/homebrew/bin/node"
13 | if [ ! -f "$NODE_PATH" ]; then
14 |     # Try alternative paths
15 |     if command -v node >/dev/null 2>&1; then
16 |         NODE_PATH=$(which node)
17 |     else
18 |         echo "❌ Node.js not found"
19 |         echo "Please install Node.js or update the path in this script"
20 |         exit 1
21 |     fi
22 | fi
23 | 
24 | echo "✅ Node.js found: $($NODE_PATH --version)"
25 | 
26 | # Check if dependencies are installed
27 | if [ ! -d "node_modules" ]; then
28 |     echo "📦 Installing dependencies..."
29 |     npm install
30 |     if [ $? -eq 0 ]; then
31 |         echo "✅ Dependencies installed successfully"
32 |     else
33 |         echo "❌ Failed to install dependencies"
34 |         echo "Please run 'npm install' manually"
35 |         exit 1
36 |     fi
37 | else
38 |     echo "✅ Dependencies already installed"
39 | fi
40 | 
41 | # Make the server executable
42 | chmod +x "$SCRIPT_DIR/hana-mcp-server.js"
43 | echo "✅ Made server executable"
44 | 
45 | # Display configuration instructions
46 | echo ""
47 | echo "📖 Configuration Instructions:"
48 | echo "=============================="
49 | echo ""
50 | echo "1. Copy the configuration template:"
51 | echo "   cp $SCRIPT_DIR/claude_config_template.json ~/.config/claude/claude_desktop_config.json"
52 | echo ""
53 | echo "2. Edit the configuration file with your HANA database details:"
54 | echo "   - Update the path to hana-mcp-server.js"
55 | echo "   - Set your HANA_HOST, HANA_USER, HANA_PASSWORD, etc."
56 | echo ""
57 | echo "3. Restart Claude Desktop"
58 | echo ""
59 | echo "4. Test the connection using the hana_test_connection tool"
60 | echo ""
61 | echo "📚 For more information, see README.md"
62 | echo ""
63 | echo "✅ Setup complete!" 
```

--------------------------------------------------------------------------------
/src/constants/mcp-constants.js:
--------------------------------------------------------------------------------

```javascript
 1 | /**
 2 |  * MCP Protocol Constants
 3 |  */
 4 | 
 5 | // MCP Protocol versions
 6 | const PROTOCOL_VERSIONS = {
 7 |   LATEST: '2024-11-05',
 8 |   SUPPORTED: ['2024-11-05', '2025-03-26']
 9 | };
10 | 
11 | // MCP Methods
12 | const METHODS = {
13 |   // Lifecycle
14 |   INITIALIZE: 'initialize',
15 |   NOTIFICATIONS_INITIALIZED: 'notifications/initialized',
16 |   
17 |   // Tools
18 |   TOOLS_LIST: 'tools/list',
19 |   TOOLS_CALL: 'tools/call',
20 |   
21 |   // Prompts
22 |   PROMPTS_LIST: 'prompts/list',
23 |   
24 |   // Resources
25 |   RESOURCES_LIST: 'resources/list',
26 |   RESOURCES_READ: 'resources/read'
27 | };
28 | 
29 | // JSON-RPC Error Codes
30 | const ERROR_CODES = {
31 |   // JSON-RPC 2.0 Standard Errors
32 |   PARSE_ERROR: -32700,
33 |   INVALID_REQUEST: -32600,
34 |   METHOD_NOT_FOUND: -32601,
35 |   INVALID_PARAMS: -32602,
36 |   INTERNAL_ERROR: -32603,
37 |   
38 |   // MCP Specific Errors
39 |   TOOL_NOT_FOUND: -32601,
40 |   INVALID_TOOL_ARGS: -32602,
41 |   DATABASE_ERROR: -32000,
42 |   CONNECTION_ERROR: -32001,
43 |   VALIDATION_ERROR: -32002
44 | };
45 | 
46 | // Error Messages
47 | const ERROR_MESSAGES = {
48 |   [ERROR_CODES.PARSE_ERROR]: 'Parse error',
49 |   [ERROR_CODES.INVALID_REQUEST]: 'Invalid Request',
50 |   [ERROR_CODES.METHOD_NOT_FOUND]: 'Method not found',
51 |   [ERROR_CODES.INVALID_PARAMS]: 'Invalid params',
52 |   [ERROR_CODES.INTERNAL_ERROR]: 'Internal error',
53 |   [ERROR_CODES.TOOL_NOT_FOUND]: 'Tool not found',
54 |   [ERROR_CODES.INVALID_TOOL_ARGS]: 'Invalid tool arguments',
55 |   [ERROR_CODES.DATABASE_ERROR]: 'Database error',
56 |   [ERROR_CODES.CONNECTION_ERROR]: 'Connection error',
57 |   [ERROR_CODES.VALIDATION_ERROR]: 'Validation error'
58 | };
59 | 
60 | // Server Information
61 | const SERVER_INFO = {
62 |   name: 'HANA MCP Server',
63 |   version: '1.0.0',
64 |   description: 'Model Context Protocol server for SAP HANA databases'
65 | };
66 | 
67 | // Capabilities
68 | const CAPABILITIES = {
69 |   tools: {},
70 |   resources: {},
71 |   prompts: {}
72 | };
73 | 
74 | module.exports = {
75 |   PROTOCOL_VERSIONS,
76 |   METHODS,
77 |   ERROR_CODES,
78 |   ERROR_MESSAGES,
79 |   SERVER_INFO,
80 |   CAPABILITIES
81 | }; 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/bin/cli.js:
--------------------------------------------------------------------------------

```javascript
 1 | #!/usr/bin/env node
 2 | 
 3 | import { spawn } from 'child_process';
 4 | import { fileURLToPath } from 'url';
 5 | import { dirname, join } from 'path';
 6 | import chalk from 'chalk';
 7 | import open from 'open';
 8 | import fs from 'fs-extra';
 9 | 
10 | const __filename = fileURLToPath(import.meta.url);
11 | const __dirname = dirname(__filename);
12 | const rootDir = dirname(__dirname);
13 | 
14 | console.log(chalk.blue.bold('🚀 Starting HANA MCP UI...'));
15 | console.log(chalk.gray('Professional database configuration management'));
16 | 
17 | // Check if we're in development or production
18 | const isDev = process.env.NODE_ENV === 'development' || fs.existsSync(join(rootDir, 'src'));
19 | 
20 | let backendProcess, frontendProcess;
21 | 
22 | // Graceful shutdown
23 | process.on('SIGINT', () => {
24 |   console.log(chalk.yellow('\n🛑 Shutting down servers...'));
25 |   if (backendProcess) backendProcess.kill();
26 |   if (frontendProcess) frontendProcess.kill();
27 |   process.exit(0);
28 | });
29 | 
30 | // Start backend server
31 | console.log(chalk.cyan('🔧 Starting backend server...'));
32 | backendProcess = spawn('node', [join(rootDir, 'server', 'index.js')], {
33 |   stdio: 'inherit',
34 |   env: { ...process.env, PORT: '3001' }
35 | });
36 | 
37 | backendProcess.on('error', (err) => {
38 |   console.error(chalk.red('Backend server error:'), err);
39 | });
40 | 
41 | // Wait for backend to start
42 | setTimeout(() => {
43 |   if (isDev) {
44 |     // Development mode - start Vite dev server
45 |     console.log(chalk.cyan('⚛️  Starting React dev server...'));
46 |     frontendProcess = spawn('bun', ['vite', '--port', '5173', '--host'], {
47 |       stdio: 'inherit',
48 |       cwd: rootDir,
49 |       shell: true
50 |     });
51 |   } else {
52 |     // Production mode - serve built files
53 |     console.log(chalk.cyan('📦 Serving production build...'));
54 |     frontendProcess = spawn('bun', ['vite', 'preview', '--port', '5173', '--host'], {
55 |       stdio: 'inherit',
56 |       cwd: rootDir,
57 |       shell: true
58 |     });
59 |   }
60 | 
61 |   frontendProcess.on('error', (err) => {
62 |     console.error(chalk.red('Frontend server error:'), err);
63 |   });
64 | 
65 |   // Open browser after frontend starts
66 |   setTimeout(() => {
67 |     console.log(chalk.green.bold('\n✨ HANA MCP UI is ready!'));
68 |     console.log(chalk.gray('Opening browser at http://localhost:5173'));
69 |     open('http://localhost:5173');
70 |   }, 3000);
71 | }, 2000);
```

--------------------------------------------------------------------------------
/src/tools/config-tools.js:
--------------------------------------------------------------------------------

```javascript
 1 | /**
 2 |  * Configuration-related tools for HANA MCP Server
 3 |  */
 4 | 
 5 | const { logger } = require('../utils/logger');
 6 | const { config } = require('../utils/config');
 7 | const { connectionManager } = require('../database/connection-manager');
 8 | const Formatters = require('../utils/formatters');
 9 | 
10 | class ConfigTools {
11 |   /**
12 |    * Show HANA configuration
13 |    */
14 |   static async showConfig(args) {
15 |     logger.tool('hana_show_config');
16 |     
17 |     const displayConfig = config.getDisplayConfig();
18 |     const formattedConfig = Formatters.formatConfig(displayConfig);
19 |     
20 |     return Formatters.createResponse(formattedConfig);
21 |   }
22 | 
23 |   /**
24 |    * Test HANA connection
25 |    */
26 |   static async testConnection(args) {
27 |     logger.tool('hana_test_connection');
28 |     
29 |     if (!config.isHanaConfigured()) {
30 |       const missingConfig = config.getDisplayConfig();
31 |       const errorMessage = Formatters.formatConnectionTest(missingConfig, false, 'Missing required configuration');
32 |       return Formatters.createErrorResponse('Connection test failed!', errorMessage);
33 |     }
34 |     
35 |     try {
36 |       const testResult = await connectionManager.testConnection();
37 |       const displayConfig = config.getDisplayConfig();
38 |       
39 |       if (testResult.success) {
40 |         const successMessage = Formatters.formatConnectionTest(displayConfig, true, null, testResult.result);
41 |         return Formatters.createResponse(successMessage);
42 |       } else {
43 |         const errorMessage = Formatters.formatConnectionTest(displayConfig, false, testResult.error);
44 |         return Formatters.createErrorResponse('Connection test failed!', errorMessage);
45 |       }
46 |     } catch (error) {
47 |       logger.error('Connection test error:', error.message);
48 |       const displayConfig = config.getDisplayConfig();
49 |       const errorMessage = Formatters.formatConnectionTest(displayConfig, false, error.message);
50 |       return Formatters.createErrorResponse('Connection test failed!', errorMessage);
51 |     }
52 |   }
53 | 
54 |   /**
55 |    * Show environment variables
56 |    */
57 |   static async showEnvVars(args) {
58 |     logger.tool('hana_show_env_vars');
59 |     
60 |     const envVars = config.getEnvironmentVars();
61 |     const formattedEnvVars = Formatters.formatEnvironmentVars(envVars);
62 |     
63 |     return Formatters.createResponse(formattedEnvVars);
64 |   }
65 | }
66 | 
67 | module.exports = ConfigTools; 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/ui/GlassCard.jsx:
--------------------------------------------------------------------------------

```javascript
 1 | import { motion } from 'framer-motion'
 2 | import { cn } from '../../utils/cn'
 3 | import { colors, shadows, borderRadius } from '../../utils/theme'
 4 | 
 5 | /**
 6 |  * GlassCard - A versatile card component with multiple variants
 7 |  * 
 8 |  * @param {Object} props - Component props
 9 |  * @param {React.ReactNode} props.children - Card content
10 |  * @param {string} props.variant - Visual variant (default, primary, success, warning, danger)
11 |  * @param {boolean} props.hover - Whether to apply hover effects
12 |  * @param {boolean} props.glow - Whether to apply glow effect on hover
13 |  * @param {string} props.className - Additional CSS classes
14 |  * @param {Object} props.headerProps - Props for the card header
15 |  * @param {React.ReactNode} props.header - Card header content
16 |  * @returns {JSX.Element} - Rendered card component
17 |  */
18 | const GlassCard = ({ 
19 |   children, 
20 |   variant = 'default', 
21 |   hover = true, 
22 |   glow = false,
23 |   className,
24 |   header,
25 |   headerProps = {},
26 |   ...props 
27 | }) => {
28 |   // Card variants - enhanced with better shadows and borders
29 |   const variants = {
30 |     default: 'bg-white border border-gray-200 shadow-[0_2px_8px_rgba(0,0,0,0.08)] rounded-xl overflow-hidden',
31 |     primary: 'bg-white border border-gray-200 shadow-[0_2px_8px_rgba(0,0,0,0.08)] rounded-xl overflow-hidden',
32 |     success: 'bg-white border border-gray-200 shadow-[0_2px_8px_rgba(0,0,0,0.08)] rounded-xl overflow-hidden', 
33 |     warning: 'bg-white border border-gray-200 shadow-[0_2px_8px_rgba(0,0,0,0.08)] rounded-xl overflow-hidden',
34 |     danger: 'bg-white border border-gray-200 shadow-[0_2px_8px_rgba(0,0,0,0.08)] rounded-xl overflow-hidden'
35 |   }
36 |   
37 |   // Header variants - with improved styling
38 |   const headerVariants = {
39 |     default: 'border-b border-gray-200 bg-white p-6',
40 |     primary: 'border-b border-gray-200 bg-white p-6',
41 |     success: 'border-b border-gray-200 bg-white p-6',
42 |     warning: 'border-b border-gray-200 bg-white p-6',
43 |     danger: 'border-b border-gray-200 bg-white p-6'
44 |   }
45 |   
46 |   return (
47 |     <motion.div
48 |       className={cn(
49 |         variants[variant],
50 |         hover && 'hover:shadow-md hover:-translate-y-0.5',
51 |         glow && 'hover:shadow-gray-200',
52 |         className
53 |       )}
54 |       whileHover={hover ? { y: -3, boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.1)' } : {}}
55 |       transition={{ type: "spring", stiffness: 300, damping: 20 }}
56 |       {...props}
57 |     >
58 |       {header && (
59 |         <div className={cn(headerVariants[variant], headerProps.className)} {...headerProps}>
60 |           {header}
61 |         </div>
62 |       )}
63 |       <div className="relative z-10">
64 |         {children}
65 |       </div>
66 |     </motion.div>
67 |   )
68 | }
69 | 
70 | export default GlassCard
```

--------------------------------------------------------------------------------
/src/tools/index.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Tool registry and management for HANA MCP Server
  3 |  */
  4 | 
  5 | const { logger } = require('../utils/logger');
  6 | const { TOOLS } = require('../constants/tool-definitions');
  7 | const ConfigTools = require('./config-tools');
  8 | const SchemaTools = require('./schema-tools');
  9 | const TableTools = require('./table-tools');
 10 | const IndexTools = require('./index-tools');
 11 | const QueryTools = require('./query-tools');
 12 | 
 13 | // Tool implementations mapping
 14 | const TOOL_IMPLEMENTATIONS = {
 15 |   hana_show_config: ConfigTools.showConfig,
 16 |   hana_test_connection: ConfigTools.testConnection,
 17 |   hana_show_env_vars: ConfigTools.showEnvVars,
 18 |   hana_list_schemas: SchemaTools.listSchemas,
 19 |   hana_list_tables: TableTools.listTables,
 20 |   hana_describe_table: TableTools.describeTable,
 21 |   hana_list_indexes: IndexTools.listIndexes,
 22 |   hana_describe_index: IndexTools.describeIndex,
 23 |   hana_execute_query: QueryTools.executeQuery
 24 | };
 25 | 
 26 | class ToolRegistry {
 27 |   /**
 28 |    * Get all available tools
 29 |    */
 30 |   static getTools() {
 31 |     return TOOLS;
 32 |   }
 33 | 
 34 |   /**
 35 |    * Get tool by name
 36 |    */
 37 |   static getTool(name) {
 38 |     return TOOLS.find(tool => tool.name === name);
 39 |   }
 40 | 
 41 |   /**
 42 |    * Check if tool exists
 43 |    */
 44 |   static hasTool(name) {
 45 |     return TOOL_IMPLEMENTATIONS.hasOwnProperty(name);
 46 |   }
 47 | 
 48 |   /**
 49 |    * Execute a tool
 50 |    */
 51 |   static async executeTool(name, args) {
 52 |     if (!this.hasTool(name)) {
 53 |       throw new Error(`Tool not found: ${name}`);
 54 |     }
 55 | 
 56 |     const implementation = TOOL_IMPLEMENTATIONS[name];
 57 |     if (typeof implementation !== 'function') {
 58 |       throw new Error(`Tool implementation not found: ${name}`);
 59 |     }
 60 | 
 61 |     try {
 62 |       logger.debug(`Executing tool: ${name}`, args);
 63 |       const result = await implementation(args);
 64 |       logger.debug(`Tool ${name} executed successfully`);
 65 |       return result;
 66 |     } catch (error) {
 67 |       logger.error(`Tool ${name} execution failed:`, error.message);
 68 |       throw error;
 69 |     }
 70 |   }
 71 | 
 72 |   /**
 73 |    * Get tool implementation
 74 |    */
 75 |   static getToolImplementation(name) {
 76 |     return TOOL_IMPLEMENTATIONS[name];
 77 |   }
 78 | 
 79 |   /**
 80 |    * Get all tool names
 81 |    */
 82 |   static getAllToolNames() {
 83 |     return Object.keys(TOOL_IMPLEMENTATIONS);
 84 |   }
 85 | 
 86 |   /**
 87 |    * Validate tool arguments against schema
 88 |    */
 89 |   static validateToolArgs(name, args) {
 90 |     const tool = this.getTool(name);
 91 |     if (!tool) {
 92 |       return { valid: false, error: `Tool not found: ${name}` };
 93 |     }
 94 | 
 95 |     const schema = tool.inputSchema;
 96 |     if (!schema || !schema.required) {
 97 |       return { valid: true }; // No validation required
 98 |     }
 99 | 
100 |     const missing = [];
101 |     for (const field of schema.required) {
102 |       if (!args || args[field] === undefined || args[field] === null || args[field] === '') {
103 |         missing.push(field);
104 |       }
105 |     }
106 | 
107 |     if (missing.length > 0) {
108 |       return { 
109 |         valid: false, 
110 |         error: `Missing required parameters: ${missing.join(', ')}` 
111 |       };
112 |     }
113 | 
114 |     return { valid: true };
115 |   }
116 | }
117 | 
118 | module.exports = ToolRegistry; 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/ui/GlassWindow.jsx:
--------------------------------------------------------------------------------

```javascript
 1 | import React from 'react';
 2 | import { motion } from 'framer-motion';
 3 | 
 4 | const GlassWindow = ({ children, className = '', maxWidth = '7xl', maxHeight = '6xl' }) => {
 5 |   // Convert maxWidth to actual Tailwind class
 6 |   const getMaxWidthClass = (width) => {
 7 |     const widthMap = {
 8 |       'sm': 'max-w-sm',
 9 |       'md': 'max-w-md', 
10 |       'lg': 'max-w-lg',
11 |       'xl': 'max-w-xl',
12 |       '2xl': 'max-w-2xl',
13 |       '3xl': 'max-w-3xl',
14 |       '4xl': 'max-w-4xl',
15 |       '5xl': 'max-w-5xl',
16 |       '6xl': 'max-w-6xl',
17 |       '7xl': 'max-w-7xl',
18 |       'full': 'max-w-full'
19 |     };
20 |     return widthMap[width] || 'max-w-7xl';
21 |   };
22 | 
23 |   const getMaxHeightClass = (height) => {
24 |     const heightMap = {
25 |       'sm': 'max-h-sm',
26 |       'md': 'max-h-md',
27 |       'lg': 'max-h-lg', 
28 |       'xl': 'max-h-xl',
29 |       '2xl': 'max-h-2xl',
30 |       '3xl': 'max-h-3xl',
31 |       '4xl': 'max-h-4xl',
32 |       '5xl': 'max-h-5xl',
33 |       '6xl': 'max-h-6xl',
34 |       'full': 'max-h-full'
35 |     };
36 |     return heightMap[height] || 'max-h-6xl';
37 |   };
38 | 
39 |   return (
40 |     <div className="glass-window-container bg-gradient-to-br from-gray-50 via-blue-50/30 to-indigo-50/20 overflow-hidden">
41 |       {/* Background Pattern */}
42 |       <div className="fixed inset-0 bg-dots opacity-20 sm:opacity-30 pointer-events-none" />
43 |       
44 |       {/* Glass Window Container */}
45 |       <motion.div
46 |         initial={{ opacity: 0, scale: 0.95, y: 20 }}
47 |         animate={{ opacity: 1, scale: 1, y: 0 }}
48 |         transition={{ duration: 0.5, ease: "easeOut" }}
49 |         className={`
50 |           glass-window-content
51 |           relative bg-white/80 backdrop-blur-xl
52 |           border border-white/20
53 |           rounded-2xl sm:rounded-3xl shadow-xl sm:shadow-2xl shadow-gray-900/10
54 |           overflow-hidden
55 |           ${className}
56 |         `}
57 |         style={{
58 |           backdropFilter: 'blur(20px)',
59 |           WebkitBackdropFilter: 'blur(20px)',
60 |           minHeight: '600px'
61 |         }}
62 |       >
63 |         {/* Glass Window Header */}
64 |         <div className="absolute top-0 left-0 right-0 h-12 sm:h-14 bg-gradient-to-r from-white/40 to-white/20 border-b border-white/20 backdrop-blur-sm">
65 |           {/* Window Controls */}
66 |           <div className="flex items-center h-full px-4 sm:px-6 gap-2 sm:gap-3">
67 |             <div className="w-3 h-3 sm:w-4 sm:h-4 rounded-full bg-red-400/80 shadow-sm hover:bg-red-500/90 transition-colors" />
68 |             <div className="w-3 h-3 sm:w-4 sm:h-4 rounded-full bg-yellow-400/80 shadow-sm hover:bg-yellow-500/90 transition-colors" />
69 |             <div className="w-3 h-3 sm:w-4 sm:h-4 rounded-full bg-green-400/80 shadow-sm hover:bg-green-500/90 transition-colors" />
70 |           </div>
71 |         </div>
72 | 
73 |         {/* Content Area */}
74 |         <div className="pt-12 sm:pt-14 h-full p-3 pb-4">
75 |           {children}
76 |         </div>
77 | 
78 |         {/* Subtle glow effect */}
79 |         <div className="absolute inset-0 rounded-3xl bg-gradient-to-br from-white/10 via-transparent to-blue-100/20 pointer-events-none" />
80 |       </motion.div>
81 |     </div>
82 |   );
83 | };
84 | 
85 | export default GlassWindow;
86 | 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/ui/DatabaseTypeBadge.jsx:
--------------------------------------------------------------------------------

```javascript
 1 | import { getDatabaseTypeColor, getDatabaseTypeShortName } from '../../utils/databaseTypes'
 2 | 
 3 | const DatabaseTypeBadge = ({ 
 4 |   type, 
 5 |   size = 'md', 
 6 |   showIcon = true,
 7 |   className = '' 
 8 | }) => {
 9 |   const color = getDatabaseTypeColor(type)
10 |   const shortName = getDatabaseTypeShortName(type)
11 |   
12 |   const sizeClasses = {
13 |     xs: 'px-2 py-1 text-xs',
14 |     sm: 'px-2.5 py-1 text-sm',
15 |     md: 'px-3 py-1.5 text-sm',
16 |     lg: 'px-4 py-2 text-base'
17 |   }
18 |   
19 |   const colorClasses = {
20 |     blue: 'bg-gradient-to-r from-blue-100 to-blue-50 text-blue-800 border-blue-200 shadow-sm',
21 |     amber: 'bg-gradient-to-r from-amber-100 to-amber-50 text-amber-800 border-amber-200 shadow-sm',
22 |     green: 'bg-gradient-to-r from-green-100 to-green-50 text-green-800 border-green-200 shadow-sm',
23 |     gray: 'bg-gradient-to-r from-gray-100 to-gray-50 text-gray-800 border-gray-200 shadow-sm'
24 |   }
25 |   
26 |   const iconClasses = {
27 |     xs: 'w-3 h-3',
28 |     sm: 'w-3.5 h-3.5',
29 |     md: 'w-4 h-4',
30 |     lg: 'w-5 h-5'
31 |   }
32 |   
33 |   const getIcon = () => {
34 |     switch (type) {
35 |       case 'single_container':
36 |         return (
37 |           <svg className={iconClasses[size]} fill="none" stroke="currentColor" viewBox="0 0 24 24">
38 |             <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" />
39 |           </svg>
40 |         )
41 |       case 'mdc_system':
42 |         return (
43 |           <svg className={iconClasses[size]} fill="none" stroke="currentColor" viewBox="0 0 24 24">
44 |             <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
45 |           </svg>
46 |         )
47 |       case 'mdc_tenant':
48 |         return (
49 |           <svg className={iconClasses[size]} fill="none" stroke="currentColor" viewBox="0 0 24 24">
50 |             <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
51 |           </svg>
52 |         )
53 |       default:
54 |         return (
55 |           <svg className={iconClasses[size]} fill="none" stroke="currentColor" viewBox="0 0 24 24">
56 |             <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
57 |           </svg>
58 |         )
59 |     }
60 |   }
61 |   
62 |   return (
63 |     <span 
64 |       className={`
65 |         inline-flex items-center gap-1.5 font-semibold rounded-full border transition-all duration-200
66 |         hover:shadow-md hover:scale-105
67 |         ${sizeClasses[size]}
68 |         ${colorClasses[color]}
69 |         ${className}
70 |       `}
71 |       title={shortName}
72 |     >
73 |       {showIcon && getIcon()}
74 |       <span className='tracking-wide'>{shortName}</span>
75 |     </span>
76 |   )
77 | }
78 | 
79 | export default DatabaseTypeBadge
80 | 
```

--------------------------------------------------------------------------------
/src/server/index.js:
--------------------------------------------------------------------------------

```javascript
  1 | #!/usr/bin/env node
  2 | 
  3 | /**
  4 |  * Main HANA MCP Server Entry Point
  5 |  */
  6 | 
  7 | const readline = require('readline');
  8 | const { logger } = require('../utils/logger');
  9 | const { lifecycleManager } = require('./lifecycle-manager');
 10 | const MCPHandler = require('./mcp-handler');
 11 | const { ERROR_CODES } = require('../constants/mcp-constants');
 12 | 
 13 | class MCPServer {
 14 |   constructor() {
 15 |     this.rl = null;
 16 |     this.isShuttingDown = false;
 17 |   }
 18 | 
 19 |   /**
 20 |    * Start the MCP server
 21 |    */
 22 |   async start() {
 23 |     try {
 24 |       // Setup lifecycle management
 25 |       lifecycleManager.setupEventHandlers();
 26 |       await lifecycleManager.start();
 27 | 
 28 |       // Setup readline interface for STDIO
 29 |       this.setupReadline();
 30 | 
 31 |       logger.info('Server ready for requests');
 32 |     } catch (error) {
 33 |       logger.error('Failed to start server:', error.message);
 34 |       process.exit(1);
 35 |     }
 36 |   }
 37 | 
 38 |   /**
 39 |    * Setup readline interface for STDIO communication
 40 |    */
 41 |   setupReadline() {
 42 |     this.rl = readline.createInterface({
 43 |       input: process.stdin,
 44 |       output: process.stdout,
 45 |       terminal: false
 46 |     });
 47 | 
 48 |     // Handle incoming lines
 49 |     this.rl.on('line', async (line) => {
 50 |       if (this.isShuttingDown) return;
 51 |       
 52 |       await this.handleLine(line);
 53 |     });
 54 | 
 55 |     // Handle readline close
 56 |     this.rl.on('close', async () => {
 57 |       if (!this.isShuttingDown) {
 58 |         logger.info('Readline closed, but keeping process alive');
 59 |       } else {
 60 |         logger.info('Server shutting down');
 61 |         await lifecycleManager.shutdown();
 62 |       }
 63 |     });
 64 |   }
 65 | 
 66 |   /**
 67 |    * Handle incoming line from STDIO
 68 |    */
 69 |   async handleLine(line) {
 70 |     try {
 71 |       const request = JSON.parse(line);
 72 |       const response = await this.handleRequest(request);
 73 |       
 74 |       if (response) {
 75 |         console.log(JSON.stringify(response));
 76 |       }
 77 |     } catch (error) {
 78 |       logger.error(`Parse error: ${error.message}`);
 79 |       const errorResponse = {
 80 |         jsonrpc: '2.0',
 81 |         id: null,
 82 |         error: {
 83 |           code: ERROR_CODES.PARSE_ERROR,
 84 |           message: 'Parse error'
 85 |         }
 86 |       };
 87 |       console.log(JSON.stringify(errorResponse));
 88 |     }
 89 |   }
 90 | 
 91 |   /**
 92 |    * Handle MCP request
 93 |    */
 94 |   async handleRequest(request) {
 95 |     // Validate request
 96 |     const validation = MCPHandler.validateRequest(request);
 97 |     if (!validation.valid) {
 98 |       return {
 99 |         jsonrpc: '2.0',
100 |         id: request.id || null,
101 |         error: {
102 |           code: ERROR_CODES.INVALID_REQUEST,
103 |           message: validation.error
104 |         }
105 |       };
106 |     }
107 | 
108 |     // Handle request
109 |     return await MCPHandler.handleRequest(request);
110 |   }
111 | 
112 |   /**
113 |    * Shutdown the server
114 |    */
115 |   async shutdown() {
116 |     this.isShuttingDown = true;
117 |     
118 |     if (this.rl) {
119 |       this.rl.close();
120 |     }
121 |     
122 |     await lifecycleManager.shutdown();
123 |   }
124 | }
125 | 
126 | // Create and start server
127 | const server = new MCPServer();
128 | 
129 | // Handle process termination
130 | process.on('SIGINT', async () => {
131 |   logger.info('Received SIGINT');
132 |   await server.shutdown();
133 | });
134 | 
135 | process.on('SIGTERM', async () => {
136 |   logger.info('Received SIGTERM');
137 |   await server.shutdown();
138 | });
139 | 
140 | // Start the server
141 | server.start().catch(error => {
142 |   logger.error('Failed to start server:', error.message);
143 |   process.exit(1);
144 | }); 
```

--------------------------------------------------------------------------------
/src/server/lifecycle-manager.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Server lifecycle management for HANA MCP Server
  3 |  */
  4 | 
  5 | const { logger } = require('../utils/logger');
  6 | const { connectionManager } = require('../database/connection-manager');
  7 | 
  8 | class LifecycleManager {
  9 |   constructor() {
 10 |     this.isShuttingDown = false;
 11 |     this.isInitialized = false;
 12 |   }
 13 | 
 14 |   /**
 15 |    * Initialize the server
 16 |    */
 17 |   async initialize() {
 18 |     if (this.isInitialized) {
 19 |       logger.warn('Server already initialized');
 20 |       return;
 21 |     }
 22 | 
 23 |     logger.info('Initializing HANA MCP Server...');
 24 |     
 25 |     try {
 26 |       // Validate configuration
 27 |       const { config } = require('../utils/config');
 28 |       if (!config.validate()) {
 29 |         logger.warn('Configuration validation failed, but continuing...');
 30 |       }
 31 |       
 32 |       this.isInitialized = true;
 33 |       logger.info('HANA MCP Server initialized successfully');
 34 |     } catch (error) {
 35 |       logger.error('Failed to initialize server:', error.message);
 36 |       throw error;
 37 |     }
 38 |   }
 39 | 
 40 |   /**
 41 |    * Start the server
 42 |    */
 43 |   async start() {
 44 |     logger.info('Starting HANA MCP Server...');
 45 |     
 46 |     try {
 47 |       await this.initialize();
 48 |       
 49 |       // Keep process alive
 50 |       this.keepAlive();
 51 |       
 52 |       logger.info('HANA MCP Server started successfully');
 53 |     } catch (error) {
 54 |       logger.error('Failed to start server:', error.message);
 55 |       throw error;
 56 |     }
 57 |   }
 58 | 
 59 |   /**
 60 |    * Shutdown the server gracefully
 61 |    */
 62 |   async shutdown() {
 63 |     if (this.isShuttingDown) {
 64 |       logger.warn('Shutdown already in progress');
 65 |       return;
 66 |     }
 67 | 
 68 |     logger.info('Shutting down HANA MCP Server...');
 69 |     this.isShuttingDown = true;
 70 | 
 71 |     try {
 72 |       // Disconnect from HANA database
 73 |       await connectionManager.disconnect();
 74 |       
 75 |       logger.info('HANA MCP Server shutdown completed');
 76 |     } catch (error) {
 77 |       logger.error('Error during shutdown:', error.message);
 78 |     } finally {
 79 |       process.exit(0);
 80 |     }
 81 |   }
 82 | 
 83 |   /**
 84 |    * Keep the process alive
 85 |    */
 86 |   keepAlive() {
 87 |     // Keep stdin open
 88 |     process.stdin.resume();
 89 |     
 90 |     // Keep process alive with interval
 91 |     setInterval(() => {
 92 |       // This keeps the event loop active
 93 |     }, 1000);
 94 |   }
 95 | 
 96 |   /**
 97 |    * Setup process event handlers
 98 |    */
 99 |   setupEventHandlers() {
100 |     // Handle SIGINT (Ctrl+C)
101 |     process.on('SIGINT', async () => {
102 |       logger.info('Received SIGINT');
103 |       await this.shutdown();
104 |     });
105 | 
106 |     // Handle SIGTERM
107 |     process.on('SIGTERM', async () => {
108 |       logger.info('Received SIGTERM');
109 |       await this.shutdown();
110 |     });
111 | 
112 |     // Handle uncaught exceptions
113 |     process.on('uncaughtException', (error) => {
114 |       logger.error('Uncaught exception:', error.message);
115 |       this.shutdown();
116 |     });
117 | 
118 |     // Handle unhandled promise rejections
119 |     process.on('unhandledRejection', (reason, promise) => {
120 |       logger.error('Unhandled promise rejection:', reason);
121 |       this.shutdown();
122 |     });
123 |   }
124 | 
125 |   /**
126 |    * Get server status
127 |    */
128 |   getStatus() {
129 |     return {
130 |       isInitialized: this.isInitialized,
131 |       isShuttingDown: this.isShuttingDown,
132 |       connectionStatus: connectionManager.getStatus()
133 |     };
134 |   }
135 | }
136 | 
137 | // Create singleton instance
138 | const lifecycleManager = new LifecycleManager();
139 | 
140 | module.exports = { LifecycleManager, lifecycleManager }; 
```

--------------------------------------------------------------------------------
/tests/automated/test-mcp-inspector.js:
--------------------------------------------------------------------------------

```javascript
  1 | const { spawn } = require('child_process');
  2 | 
  3 | console.log('🔍 HANA MCP Server Inspector');
  4 | console.log('============================\n');
  5 | 
  6 | // Spawn the MCP server process
  7 | const server = spawn('/opt/homebrew/opt/node@20/bin/node', ['../../hana-mcp-server.js'], {
  8 |   stdio: ['pipe', 'pipe', 'pipe'],
  9 |   env: {
 10 |     HANA_HOST: "your-hana-host.com",
 11 |     HANA_PORT: "443",
 12 |     HANA_USER: "your-username",
 13 |     HANA_PASSWORD: "your-password",
 14 |     HANA_SCHEMA: "your-schema",
 15 |     HANA_SSL: "true",
 16 |     HANA_ENCRYPT: "true",
 17 |     HANA_VALIDATE_CERT: "true"
 18 |   }
 19 | });
 20 | 
 21 | // Handle server output
 22 | server.stdout.on('data', (data) => {
 23 |   try {
 24 |     const response = JSON.parse(data.toString().trim());
 25 |     console.log('📤 Response:', JSON.stringify(response, null, 2));
 26 |   } catch (error) {
 27 |     console.log('🔧 Server Log:', data.toString().trim());
 28 |   }
 29 | });
 30 | 
 31 | server.stderr.on('data', (data) => {
 32 |   console.log('🔧 Server Log:', data.toString().trim());
 33 | });
 34 | 
 35 | // Send request function
 36 | function sendRequest(method, params = {}) {
 37 |   const request = {
 38 |     jsonrpc: '2.0',
 39 |     id: Date.now(),
 40 |     method,
 41 |     params
 42 |   };
 43 |   
 44 |   server.stdin.write(JSON.stringify(request) + '\n');
 45 | }
 46 | 
 47 | // Test functions
 48 | async function testInitialize() {
 49 |   console.log('\n🧪 Testing: Initialize');
 50 |   sendRequest('initialize', {
 51 |     protocolVersion: '2024-11-05',
 52 |     capabilities: {},
 53 |     clientInfo: { name: 'test-client', version: '1.0.0' }
 54 |   });
 55 |   await new Promise(resolve => setTimeout(resolve, 1000));
 56 | }
 57 | 
 58 | async function testToolsList() {
 59 |   console.log('\n🧪 Testing: Tools List');
 60 |   sendRequest('tools/list', {});
 61 |   await new Promise(resolve => setTimeout(resolve, 1000));
 62 | }
 63 | 
 64 | async function testShowConfig() {
 65 |   console.log('\n🧪 Testing: Show Config');
 66 |   sendRequest('tools/call', {
 67 |     name: "hana_show_config",
 68 |     arguments: {}
 69 |   });
 70 |   await new Promise(resolve => setTimeout(resolve, 1000));
 71 | }
 72 | 
 73 | async function testListSchemas() {
 74 |   console.log('\n🧪 Testing: List Schemas');
 75 |   sendRequest('tools/call', {
 76 |     name: "hana_list_schemas",
 77 |     arguments: {}
 78 |   });
 79 |   await new Promise(resolve => setTimeout(resolve, 1000));
 80 | }
 81 | 
 82 | async function testListTables() {
 83 |   console.log('\n🧪 Testing: List Tables');
 84 |   sendRequest('tools/call', {
 85 |     name: "hana_list_tables",
 86 |     arguments: { schema_name: "SYSTEM" }
 87 |   });
 88 |   await new Promise(resolve => setTimeout(resolve, 1000));
 89 | }
 90 | 
 91 | async function testExecuteQuery() {
 92 |   console.log('\n🧪 Testing: Execute Query');
 93 |   sendRequest('tools/call', {
 94 |     name: "hana_execute_query",
 95 |     arguments: {
 96 |       query: "SELECT 1 as test_value FROM DUMMY"
 97 |     }
 98 |   });
 99 |   await new Promise(resolve => setTimeout(resolve, 1000));
100 | }
101 | 
102 | // Main test runner
103 | async function runTests() {
104 |   try {
105 |     await testInitialize();
106 |     await testToolsList();
107 |     await testShowConfig();
108 |     await testListSchemas();
109 |     await testListTables();
110 |     await testExecuteQuery();
111 |     
112 |     console.log('\n✅ Tests completed!');
113 |     
114 |     // Close server
115 |     server.stdin.end();
116 |     server.kill();
117 |     
118 |   } catch (error) {
119 |     console.error('❌ Test error:', error);
120 |     server.kill();
121 |   }
122 | }
123 | 
124 | // Handle server exit
125 | server.on('close', (code) => {
126 |   console.log(`\n🔚 Server closed with code ${code}`);
127 | });
128 | 
129 | server.on('error', (error) => {
130 |   console.error('❌ Server error:', error);
131 | });
132 | 
133 | // Start tests
134 | runTests().catch(console.error); 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/ClaudeConfigTile.jsx:
--------------------------------------------------------------------------------

```javascript
 1 | import { useState } from 'react';
 2 | import { motion } from 'framer-motion';
 3 | import { cn } from '../utils/cn';
 4 | import PathConfigModal from './PathConfigModal';
 5 | 
 6 | const ClaudeConfigTile = ({ 
 7 |   claudeConfigPath, 
 8 |   claudeServers, 
 9 |   onSetupPath,
10 |   onConfigPathChange
11 | }) => {
12 |   const [showPathModal, setShowPathModal] = useState(false);
13 | 
14 |   const handleEditPath = () => {
15 |     setShowPathModal(true);
16 |   };
17 | 
18 |   return (
19 |     <>
20 |       <motion.div
21 |         className="bg-white rounded-xl border border-gray-100 overflow-hidden"
22 |         initial={{ opacity: 0, y: 20 }}
23 |         animate={{ opacity: 1, y: 0 }}
24 |         transition={{ duration: 0.3 }}
25 |       >
26 |         <div className="border-b border-gray-100 px-4 py-3">
27 |           <div className="flex items-center justify-between">
28 |             <div>
29 |               <h3 className="text-sm font-medium text-gray-900">Claude Desktop Configuration</h3>
30 |               <p className="text-xs text-gray-500">Integration Status</p>
31 |             </div>
32 |             <div className="flex items-center gap-2">
33 |               <div className={cn(
34 |                 'w-2 h-2 rounded-full',
35 |                 claudeServers.length > 0 ? 'bg-green-500' : 'bg-gray-300'
36 |               )}></div>
37 |               <span className="text-xs text-gray-600">
38 |                 {claudeServers.length > 0 ? 'Online' : 'Offline'}
39 |               </span>
40 |             </div>
41 |           </div>
42 |         </div>
43 |         
44 |         <div className="p-4">
45 |           
46 |           {claudeConfigPath ? (
47 |             <div className="bg-gray-50 rounded-lg p-3">
48 |               <div className="flex items-center justify-between mb-1">
49 |                 <div className="text-xs font-medium text-gray-600">
50 |                   Config Path
51 |                 </div>
52 |                 <button
53 |                   onClick={handleEditPath}
54 |                   className="flex items-center gap-2 px-4 py-2 text-sm font-semibold text-white bg-[#86a0ff] hover:bg-[#7990e6] rounded-lg transition-colors shadow-sm hover:shadow-md focus:outline-none focus:ring-2 focus:ring-[#86a0ff] focus:ring-offset-2"
55 |                   title="Change config path"
56 |                 >
57 |                   <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
58 |                     <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
59 |                   </svg>
60 |                   Edit
61 |                 </button>
62 |               </div>
63 |               <div className="text-xs font-mono text-gray-700 break-all">
64 |                 {claudeConfigPath}
65 |               </div>
66 |             </div>
67 |           ) : (
68 |             <div className="text-center py-4">
69 |               <p className="text-sm text-gray-500">
70 |                 Claude Desktop configuration path not set
71 |               </p>
72 |               <button
73 |                 onClick={onSetupPath}
74 |                 className="mt-2 text-sm text-blue-600 hover:text-blue-800"
75 |               >
76 |                 Set Configuration Path
77 |               </button>
78 |             </div>
79 |           )}
80 |         </div>
81 |       </motion.div>
82 | 
83 |       {/* Path Configuration Modal */}
84 |       <PathConfigModal
85 |         isOpen={showPathModal}
86 |         onClose={() => setShowPathModal(false)}
87 |         onConfigPathChange={onConfigPathChange}
88 |         currentPath={claudeConfigPath}
89 |       />
90 |     </>
91 |   );
92 | };
93 | 
94 | export default ClaudeConfigTile;
95 | 
```

--------------------------------------------------------------------------------
/src/tools/table-tools.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Table management tools for HANA MCP Server
  3 |  */
  4 | 
  5 | const { logger } = require('../utils/logger');
  6 | const { config } = require('../utils/config');
  7 | const QueryExecutor = require('../database/query-executor');
  8 | const Validators = require('../utils/validators');
  9 | const Formatters = require('../utils/formatters');
 10 | 
 11 | class TableTools {
 12 |   /**
 13 |    * List tables in a schema
 14 |    */
 15 |   static async listTables(args) {
 16 |     logger.tool('hana_list_tables', args);
 17 |     
 18 |     let { schema_name } = args || {};
 19 |     
 20 |     // Use default schema if not provided
 21 |     if (!schema_name) {
 22 |       if (config.hasDefaultSchema()) {
 23 |         schema_name = config.getDefaultSchema();
 24 |         logger.info(`Using default schema: ${schema_name}`);
 25 |       } else {
 26 |         return Formatters.createErrorResponse(
 27 |           'Schema name is required', 
 28 |           'Please provide schema_name parameter or set HANA_SCHEMA environment variable'
 29 |         );
 30 |       }
 31 |     }
 32 |     
 33 |     // Validate schema name
 34 |     const schemaValidation = Validators.validateSchemaName(schema_name);
 35 |     if (!schemaValidation.valid) {
 36 |       return Formatters.createErrorResponse('Invalid schema name', schemaValidation.error);
 37 |     }
 38 |     
 39 |     try {
 40 |       const tables = await QueryExecutor.getTables(schema_name);
 41 |       const formattedTables = Formatters.formatTableList(tables, schema_name);
 42 |       
 43 |       return Formatters.createResponse(formattedTables);
 44 |     } catch (error) {
 45 |       logger.error('Error listing tables:', error.message);
 46 |       return Formatters.createErrorResponse('Error listing tables', error.message);
 47 |     }
 48 |   }
 49 | 
 50 |   /**
 51 |    * Describe table structure
 52 |    */
 53 |   static async describeTable(args) {
 54 |     logger.tool('hana_describe_table', args);
 55 |     
 56 |     let { schema_name, table_name } = args || {};
 57 |     
 58 |     // Use default schema if not provided
 59 |     if (!schema_name) {
 60 |       if (config.hasDefaultSchema()) {
 61 |         schema_name = config.getDefaultSchema();
 62 |         logger.info(`Using default schema: ${schema_name}`);
 63 |       } else {
 64 |         return Formatters.createErrorResponse(
 65 |           'Schema name is required', 
 66 |           'Please provide schema_name parameter or set HANA_SCHEMA environment variable'
 67 |         );
 68 |       }
 69 |     }
 70 |     
 71 |     // Validate required parameters
 72 |     const validation = Validators.validateRequired(args, ['table_name'], 'hana_describe_table');
 73 |     if (!validation.valid) {
 74 |       return Formatters.createErrorResponse('Error: table_name parameter is required', validation.error);
 75 |     }
 76 |     
 77 |     // Validate schema and table names
 78 |     const schemaValidation = Validators.validateSchemaName(schema_name);
 79 |     if (!schemaValidation.valid) {
 80 |       return Formatters.createErrorResponse('Invalid schema name', schemaValidation.error);
 81 |     }
 82 |     
 83 |     const tableValidation = Validators.validateTableName(table_name);
 84 |     if (!tableValidation.valid) {
 85 |       return Formatters.createErrorResponse('Invalid table name', tableValidation.error);
 86 |     }
 87 |     
 88 |     try {
 89 |       const columns = await QueryExecutor.getTableColumns(schema_name, table_name);
 90 |       
 91 |       if (columns.length === 0) {
 92 |         return Formatters.createErrorResponse(`Table '${schema_name}.${table_name}' not found or no columns available`);
 93 |       }
 94 |       
 95 |       const formattedStructure = Formatters.formatTableStructure(columns, schema_name, table_name);
 96 |       
 97 |       return Formatters.createResponse(formattedStructure);
 98 |     } catch (error) {
 99 |       logger.error('Error describing table:', error.message);
100 |       return Formatters.createErrorResponse('Error describing table', error.message);
101 |     }
102 |   }
103 | }
104 | 
105 | module.exports = TableTools; 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/start.js:
--------------------------------------------------------------------------------

```javascript
  1 | #!/usr/bin/env node
  2 | 
  3 | import { spawn, execSync } from 'child_process';
  4 | import { fileURLToPath } from 'url';
  5 | import { dirname, join } from 'path';
  6 | import chalk from 'chalk';
  7 | import open from 'open';
  8 | import { networkInterfaces } from 'os';
  9 | 
 10 | const __filename = fileURLToPath(import.meta.url);
 11 | const __dirname = dirname(__filename);
 12 | 
 13 | console.log(chalk.blue.bold('🚀 Starting HANA MCP UI...'));
 14 | console.log(chalk.gray('Professional database configuration management'));
 15 | 
 16 | let backendProcess, frontendProcess;
 17 | 
 18 | // Graceful shutdown
 19 | process.on('SIGINT', () => {
 20 |   console.log(chalk.yellow('\n🛑 Shutting down servers...'));
 21 |   if (backendProcess) backendProcess.kill();
 22 |   if (frontendProcess) frontendProcess.kill();
 23 |   process.exit(0);
 24 | });
 25 | 
 26 | // Start backend server
 27 | console.log(chalk.cyan('🔧 Starting backend server...'));
 28 | backendProcess = spawn('node', [join(__dirname, 'server', 'index.js')], {
 29 |   stdio: 'inherit',
 30 |   env: { ...process.env, PORT: '3001' }
 31 | });
 32 | 
 33 | backendProcess.on('error', (err) => {
 34 |   console.error(chalk.red('Backend server error:'), err);
 35 | });
 36 | 
 37 | // Function to check if port is in use and kill the process if needed
 38 | function checkPortAndKillProcess(port) {
 39 |   try {
 40 |     console.log(chalk.yellow(`🔍 Checking if port ${port} is already in use...`));
 41 |     
 42 |     // Check if the port is in use
 43 |     const checkCommand = process.platform === 'win32' 
 44 |       ? `netstat -ano | findstr :${port}`
 45 |       : `lsof -i :${port}`;
 46 |     
 47 |     try {
 48 |       const result = execSync(checkCommand, { encoding: 'utf8' });
 49 |       
 50 |       if (result) {
 51 |         console.log(chalk.yellow(`⚠️  Port ${port} is already in use. Finding the process...`));
 52 |         
 53 |         // Get the PID of the process using the port
 54 |         let pid;
 55 |         if (process.platform === 'win32') {
 56 |           // Extract PID from Windows netstat output
 57 |           const lines = result.split('\n');
 58 |           for (const line of lines) {
 59 |             if (line.includes(`LISTENING`)) {
 60 |               pid = line.trim().split(/\s+/).pop();
 61 |               break;
 62 |             }
 63 |           }
 64 |         } else {
 65 |           // Extract PID from lsof output
 66 |           const pidMatch = result.match(/\s+(\d+)\s+/);
 67 |           if (pidMatch && pidMatch[1]) {
 68 |             pid = pidMatch[1];
 69 |           }
 70 |         }
 71 |         
 72 |         if (pid) {
 73 |           console.log(chalk.yellow(`🛑 Killing process ${pid} that's using port ${port}...`));
 74 |           
 75 |           // Kill the process
 76 |           const killCommand = process.platform === 'win32'
 77 |             ? `taskkill /F /PID ${pid}`
 78 |             : `kill -9 ${pid}`;
 79 |           
 80 |           execSync(killCommand);
 81 |           console.log(chalk.green(`✅ Process terminated.`));
 82 |           
 83 |           // Wait a moment for the port to be released
 84 |           execSync('sleep 1');
 85 |         } else {
 86 |           console.log(chalk.red(`❌ Could not find the process using port ${port}.`));
 87 |         }
 88 |       }
 89 |     } catch (error) {
 90 |       // If the command fails, it likely means no process is using the port
 91 |       console.log(chalk.green(`✅ Port ${port} is available.`));
 92 |     }
 93 |   } catch (error) {
 94 |     console.error(chalk.red(`Error checking port ${port}:`, error.message));
 95 |   }
 96 | }
 97 | 
 98 | // Check and clear port 5173 if needed
 99 | checkPortAndKillProcess(5173);
100 | 
101 | // Start frontend server
102 | console.log(chalk.cyan('⚛️  Starting React dev server...'));
103 | frontendProcess = spawn('vite', ['--port', '5173', '--host', '0.0.0.0'], {
104 |   stdio: 'inherit',
105 |   cwd: __dirname,
106 |   shell: true
107 | });
108 | 
109 | frontendProcess.on('error', (err) => {
110 |   console.error(chalk.red('Frontend server error:'), err);
111 | });
112 | 
113 | // Open browser after a delay
114 | setTimeout(() => {
115 |   console.log(chalk.green.bold('\n✨ HANA MCP UI is ready!'));
116 |   console.log(chalk.gray('Opening browser at http://localhost:5173'));
117 |   open('http://localhost:5173');
118 | }, 5000);
119 | 
120 | 
121 | 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/utils/theme.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Design tokens for the HANA MCP UI
  3 |  * This file defines the core design values used throughout the application
  4 |  */
  5 | 
  6 | // Color palette
  7 | export const colors = {
  8 |   // Primary brand colors
  9 |   primary: {
 10 |     50: '#eef2ff',
 11 |     100: '#e0e7ff',
 12 |     200: '#c7d2fe',
 13 |     300: '#a5b4fc',
 14 |     400: '#818cf8',
 15 |     500: '#6366f1',
 16 |     600: '#4f46e5',
 17 |     700: '#4338ca',
 18 |     800: '#3730a3',
 19 |     900: '#312e81',
 20 |     950: '#1e1b4b',
 21 |   },
 22 |   
 23 |   // Secondary accent colors
 24 |   secondary: {
 25 |     50: '#f0f9ff',
 26 |     100: '#e0f2fe',
 27 |     200: '#bae6fd',
 28 |     300: '#7dd3fc',
 29 |     400: '#38bdf8',
 30 |     500: '#0ea5e9',
 31 |     600: '#0284c7',
 32 |     700: '#0369a1',
 33 |     800: '#075985',
 34 |     900: '#0c4a6e',
 35 |     950: '#082f49',
 36 |   },
 37 |   
 38 |   // Neutral colors for text, backgrounds
 39 |   gray: {
 40 |     50: '#f9fafb',
 41 |     100: '#f3f4f6',
 42 |     200: '#e5e7eb',
 43 |     300: '#d1d5db',
 44 |     400: '#9ca3af',
 45 |     500: '#6b7280',
 46 |     600: '#4b5563',
 47 |     700: '#374151',
 48 |     800: '#1f2937',
 49 |     900: '#111827',
 50 |     950: '#030712',
 51 |   },
 52 |   
 53 |   // Semantic colors
 54 |   success: {
 55 |     50: '#f0fdf4',
 56 |     100: '#dcfce7',
 57 |     200: '#bbf7d0',
 58 |     300: '#86efac',
 59 |     400: '#4ade80',
 60 |     500: '#22c55e',
 61 |     600: '#16a34a',
 62 |     700: '#15803d',
 63 |     800: '#166534',
 64 |     900: '#14532d',
 65 |     950: '#052e16',
 66 |   },
 67 |   
 68 |   warning: {
 69 |     50: '#fffbeb',
 70 |     100: '#fef3c7',
 71 |     200: '#fde68a',
 72 |     300: '#fcd34d',
 73 |     400: '#fbbf24',
 74 |     500: '#f59e0b',
 75 |     600: '#d97706',
 76 |     700: '#b45309',
 77 |     800: '#92400e',
 78 |     900: '#78350f',
 79 |     950: '#451a03',
 80 |   },
 81 |   
 82 |   danger: {
 83 |     50: '#fef2f2',
 84 |     100: '#fee2e2',
 85 |     200: '#fecaca',
 86 |     300: '#fca5a5',
 87 |     400: '#f87171',
 88 |     500: '#ef4444',
 89 |     600: '#dc2626',
 90 |     700: '#b91c1c',
 91 |     800: '#991b1b',
 92 |     900: '#7f1d1d',
 93 |     950: '#450a0a',
 94 |   },
 95 | };
 96 | 
 97 | // Spacing system (in pixels, following 8pt grid)
 98 | export const spacing = {
 99 |   0: '0',
100 |   1: '0.25rem',   // 4px
101 |   2: '0.5rem',    // 8px
102 |   3: '0.75rem',   // 12px
103 |   4: '1rem',      // 16px
104 |   5: '1.25rem',   // 20px
105 |   6: '1.5rem',    // 24px
106 |   8: '2rem',      // 32px
107 |   10: '2.5rem',   // 40px
108 |   12: '3rem',     // 48px
109 |   16: '4rem',     // 64px
110 |   20: '5rem',     // 80px
111 |   24: '6rem',     // 96px
112 | };
113 | 
114 | // Typography scale
115 | export const typography = {
116 |   fontFamily: {
117 |     sans: 'Inter, system-ui, -apple-system, sans-serif',
118 |     mono: 'ui-monospace, SFMono-Regular, Menlo, monospace',
119 |   },
120 |   fontSize: {
121 |     xs: '0.75rem',     // 12px
122 |     sm: '0.875rem',    // 14px
123 |     base: '1rem',      // 16px
124 |     lg: '1.125rem',    // 18px
125 |     xl: '1.25rem',     // 20px
126 |     '2xl': '1.5rem',   // 24px
127 |     '3xl': '1.875rem', // 30px
128 |     '4xl': '2.25rem',  // 36px
129 |   },
130 |   fontWeight: {
131 |     normal: '400',
132 |     medium: '500',
133 |     semibold: '600',
134 |     bold: '700',
135 |   },
136 |   lineHeight: {
137 |     none: '1',
138 |     tight: '1.25',
139 |     snug: '1.375',
140 |     normal: '1.5',
141 |     relaxed: '1.625',
142 |     loose: '2',
143 |   },
144 | };
145 | 
146 | // Border radius
147 | export const borderRadius = {
148 |   none: '0',
149 |   sm: '0.125rem',    // 2px
150 |   DEFAULT: '0.25rem', // 4px
151 |   md: '0.375rem',    // 6px
152 |   lg: '0.5rem',      // 8px
153 |   xl: '0.75rem',     // 12px
154 |   '2xl': '1rem',     // 16px
155 |   '3xl': '1.5rem',   // 24px
156 |   full: '9999px',
157 | };
158 | 
159 | // Shadows
160 | export const shadows = {
161 |   sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
162 |   DEFAULT: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
163 |   md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
164 |   lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
165 |   xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
166 | };
167 | 
168 | // Z-index scale
169 | export const zIndex = {
170 |   0: '0',
171 |   10: '10',
172 |   20: '20',
173 |   30: '30',
174 |   40: '40',
175 |   50: '50',
176 |   auto: 'auto',
177 |   modal: '100',
178 |   tooltip: '110',
179 |   popover: '90',
180 | };
181 | 
182 | // Transitions
183 | export const transitions = {
184 |   DEFAULT: '150ms cubic-bezier(0.4, 0, 0.2, 1)',
185 |   fast: '100ms cubic-bezier(0.4, 0, 0.2, 1)',
186 |   slow: '300ms cubic-bezier(0.4, 0, 0.2, 1)',
187 | };
188 | 
189 | // Export the full theme
190 | export const theme = {
191 |   colors,
192 |   spacing,
193 |   typography,
194 |   borderRadius,
195 |   shadows,
196 |   zIndex,
197 |   transitions,
198 | };
199 | 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/EnhancedServerCard.jsx:
--------------------------------------------------------------------------------

```javascript
  1 | import { useState } from 'react';
  2 | import { motion } from 'framer-motion';
  3 | import { GradientButton, EnvironmentBadge, DatabaseTypeBadge } from './ui';
  4 | import { cn } from '../utils/cn';
  5 | import { detectDatabaseType, getDatabaseTypeDisplayName } from '../utils/databaseTypes';
  6 | 
  7 | const EnhancedServerCard = ({
  8 |   name,
  9 |   server,
 10 |   index,
 11 |   activeEnvironment,
 12 |   isSelected = false,
 13 |   onSelect,
 14 |   onEdit,
 15 |   onAddToClaude,
 16 |   onDelete
 17 | }) => {
 18 |   const environmentCount = Object.keys(server.environments || {}).length;
 19 |   const hasActiveConnection = !!activeEnvironment;
 20 |   
 21 |   // Real connection status
 22 |   const connectionStatus = hasActiveConnection ? 'active' : 'configured';
 23 |   const lastModified = server.modified ? new Date(server.modified).toLocaleDateString() : 'Unknown';
 24 | 
 25 |   // Count environments connected to Claude
 26 |   const claudeActiveCount = hasActiveConnection ? 1 : 0;
 27 |   
 28 |   // Detect database type from active environment
 29 |   const activeEnvData = activeEnvironment ? server.environments[activeEnvironment] : {};
 30 |   const databaseType = detectDatabaseType(activeEnvData);
 31 | 
 32 |   const handleRowClick = () => {
 33 |     if (onSelect) {
 34 |       onSelect(name);
 35 |     }
 36 |   };
 37 | 
 38 |   const handleRadioChange = (e) => {
 39 |     e.stopPropagation();
 40 |     if (onSelect) {
 41 |       onSelect(name);
 42 |     }
 43 |   };
 44 | 
 45 |   const getConnectionStatusColor = () => {
 46 |     switch (connectionStatus) {
 47 |       case 'active': return 'text-green-600';
 48 |       case 'configured': return 'text-[#86a0ff]';
 49 |       case 'error': return 'text-red-600';
 50 |       default: return 'text-gray-400';
 51 |     }
 52 |   };
 53 | 
 54 |   return (
 55 |     <motion.div
 56 |       className={cn(
 57 |         "border-b border-gray-200 transition-colors cursor-pointer",
 58 |         isSelected 
 59 |           ? "bg-blue-50 border-blue-200" 
 60 |           : "bg-white hover:bg-gray-50"
 61 |       )}
 62 |       initial={{ opacity: 0, x: -10 }}
 63 |       animate={{ opacity: 1, x: 0 }}
 64 |       transition={{ duration: 0.2, delay: index * 0.02 }}
 65 |       onClick={handleRowClick}
 66 |     >
 67 |       <div className="px-6 py-4">
 68 |         <div className="grid grid-cols-12 gap-4 items-center">
 69 |           {/* Selection Radio */}
 70 |           <div className="col-span-1">
 71 |             <input
 72 |               type="radio"
 73 |               name="database-selection"
 74 |               checked={isSelected}
 75 |               onChange={handleRadioChange}
 76 |               className="w-4 h-4 text-[#86a0ff] border-gray-300 focus:ring-[#86a0ff]"
 77 |             />
 78 |           </div>
 79 |           
 80 |           {/* Database Info */}
 81 |           <div className="col-span-4">
 82 |             <div className="flex items-center space-x-3">
 83 |               <div className="w-8 h-8 bg-blue-50 rounded-lg flex items-center justify-center flex-shrink-0">
 84 |                 <svg className="h-4 w-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
 85 |                   <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" />
 86 |                 </svg>
 87 |               </div>
 88 |               <div className="min-w-0">
 89 |                 <h3 className="text-base font-semibold text-gray-900 truncate">{name}</h3>
 90 |               </div>
 91 |             </div>
 92 |           </div>
 93 |           
 94 |           {/* Active Environment */}
 95 |           <div className="col-span-2">
 96 |             {hasActiveConnection && activeEnvironment ? (
 97 |               <EnvironmentBadge environment={activeEnvironment} active size="sm" />
 98 |             ) : (
 99 |               <span className="text-sm text-gray-500">None</span>
100 |             )}
101 |           </div>
102 |           
103 |           {/* Environment Count */}
104 |           <div className="col-span-2">
105 |             <span className="text-sm font-medium text-gray-600">{environmentCount}</span>
106 |           </div>
107 |           
108 |           {/* Description */}
109 |           <div className="col-span-3">
110 |             {server.description && (
111 |               <span className="text-sm text-gray-500 truncate block">{server.description}</span>
112 |             )}
113 |           </div>
114 |         </div>
115 |       </div>
116 |     </motion.div>
117 |   );
118 | 
119 | };
120 | 
121 | export default EnhancedServerCard;
122 | 
```

--------------------------------------------------------------------------------
/src/constants/tool-definitions.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Tool definitions for HANA MCP Server
  3 |  * 
  4 |  * Note: For tools that accept schema_name as an optional parameter, 
  5 |  * the HANA_SCHEMA environment variable will be used if schema_name is not provided.
  6 |  */
  7 | 
  8 | const TOOLS = [
  9 |   {
 10 |     name: "hana_show_config",
 11 |     description: "Show the HANA database configuration",
 12 |     inputSchema: {
 13 |       type: "object",
 14 |       properties: {},
 15 |       required: []
 16 |     }
 17 |   },
 18 |   {
 19 |     name: "hana_test_connection",
 20 |     description: "Test connection to HANA database",
 21 |     inputSchema: {
 22 |       type: "object",
 23 |       properties: {},
 24 |       required: []
 25 |     }
 26 |   },
 27 |   {
 28 |     name: "hana_list_schemas",
 29 |     description: "List all schemas in the HANA database",
 30 |     inputSchema: {
 31 |       type: "object",
 32 |       properties: {},
 33 |       required: []
 34 |     }
 35 |   },
 36 |   {
 37 |     name: "hana_show_env_vars",
 38 |     description: "Show all HANA-related environment variables (for debugging)",
 39 |     inputSchema: {
 40 |       type: "object",
 41 |       properties: {},
 42 |       required: []
 43 |     }
 44 |   },
 45 |   {
 46 |     name: "hana_list_tables",
 47 |     description: "List all tables in a specific schema",
 48 |     inputSchema: {
 49 |       type: "object",
 50 |       properties: {
 51 |         schema_name: {
 52 |           type: "string",
 53 |           description: "Name of the schema to list tables from (optional)"
 54 |         }
 55 |       },
 56 |       required: []
 57 |     }
 58 |   },
 59 |   {
 60 |     name: "hana_describe_table",
 61 |     description: "Describe the structure of a specific table",
 62 |     inputSchema: {
 63 |       type: "object",
 64 |       properties: {
 65 |         schema_name: {
 66 |           type: "string",
 67 |           description: "Name of the schema containing the table (optional)"
 68 |         },
 69 |         table_name: {
 70 |           type: "string",
 71 |           description: "Name of the table to describe"
 72 |         }
 73 |       },
 74 |       required: ["table_name"]
 75 |     }
 76 |   },
 77 |   {
 78 |     name: "hana_list_indexes",
 79 |     description: "List all indexes for a specific table",
 80 |     inputSchema: {
 81 |       type: "object",
 82 |       properties: {
 83 |         schema_name: {
 84 |           type: "string",
 85 |           description: "Name of the schema containing the table (optional)"
 86 |         },
 87 |         table_name: {
 88 |           type: "string",
 89 |           description: "Name of the table to list indexes for"
 90 |         }
 91 |       },
 92 |       required: ["table_name"]
 93 |     }
 94 |   },
 95 |   {
 96 |     name: "hana_describe_index",
 97 |     description: "Describe the structure of a specific index",
 98 |     inputSchema: {
 99 |       type: "object",
100 |       properties: {
101 |         schema_name: {
102 |           type: "string",
103 |           description: "Name of the schema containing the table (optional)"
104 |         },
105 |         table_name: {
106 |           type: "string",
107 |           description: "Name of the table containing the index"
108 |         },
109 |         index_name: {
110 |           type: "string",
111 |           description: "Name of the index to describe"
112 |         }
113 |       },
114 |       required: ["table_name", "index_name"]
115 |     }
116 |   },
117 |   {
118 |     name: "hana_execute_query",
119 |     description: "Execute a custom SQL query against the HANA database",
120 |     inputSchema: {
121 |       type: "object",
122 |       properties: {
123 |         query: {
124 |           type: "string",
125 |           description: "The SQL query to execute"
126 |         },
127 |         parameters: {
128 |           type: "array",
129 |           description: "Optional parameters for the query (for prepared statements)",
130 |           items: {
131 |             type: "string"
132 |           }
133 |         }
134 |       },
135 |       required: ["query"]
136 |     }
137 |   }
138 | ];
139 | 
140 | // Tool categories for organization
141 | const TOOL_CATEGORIES = {
142 |   CONFIGURATION: ['hana_show_config', 'hana_test_connection', 'hana_show_env_vars'],
143 |   SCHEMA: ['hana_list_schemas'],
144 |   TABLE: ['hana_list_tables', 'hana_describe_table'],
145 |   INDEX: ['hana_list_indexes', 'hana_describe_index'],
146 |   QUERY: ['hana_execute_query']
147 | };
148 | 
149 | // Get tool by name
150 | function getTool(name) {
151 |   return TOOLS.find(tool => tool.name === name);
152 | }
153 | 
154 | // Get tools by category
155 | function getToolsByCategory(category) {
156 |   const toolNames = TOOL_CATEGORIES[category] || [];
157 |   return TOOLS.filter(tool => toolNames.includes(tool.name));
158 | }
159 | 
160 | // Get all tool names
161 | function getAllToolNames() {
162 |   return TOOLS.map(tool => tool.name);
163 | }
164 | 
165 | module.exports = {
166 |   TOOLS,
167 |   TOOL_CATEGORIES,
168 |   getTool,
169 |   getToolsByCategory,
170 |   getAllToolNames
171 | }; 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/utils/databaseTypes.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Database type detection and display utilities for HANA MCP UI
  3 |  */
  4 | 
  5 | export const DATABASE_TYPES = {
  6 |   SINGLE_CONTAINER: 'single_container',
  7 |   MDC_SYSTEM: 'mdc_system', 
  8 |   MDC_TENANT: 'mdc_tenant'
  9 | }
 10 | 
 11 | /**
 12 |  * Detect database type based on configuration data
 13 |  * @param {Object} data - Configuration data
 14 |  * @returns {string} Database type
 15 |  */
 16 | export const detectDatabaseType = (data) => {
 17 |   if (!data) return DATABASE_TYPES.SINGLE_CONTAINER
 18 |   
 19 |   if (data.HANA_INSTANCE_NUMBER && data.HANA_DATABASE_NAME) {
 20 |     return DATABASE_TYPES.MDC_TENANT
 21 |   } else if (data.HANA_INSTANCE_NUMBER && !data.HANA_DATABASE_NAME) {
 22 |     return DATABASE_TYPES.MDC_SYSTEM
 23 |   } else {
 24 |     return DATABASE_TYPES.SINGLE_CONTAINER
 25 |   }
 26 | }
 27 | 
 28 | /**
 29 |  * Get display name for database type
 30 |  * @param {string} type - Database type
 31 |  * @returns {string} Display name
 32 |  */
 33 | export const getDatabaseTypeDisplayName = (type) => {
 34 |   const displayNames = {
 35 |     [DATABASE_TYPES.SINGLE_CONTAINER]: 'Single-Container Database',
 36 |     [DATABASE_TYPES.MDC_SYSTEM]: 'MDC System Database',
 37 |     [DATABASE_TYPES.MDC_TENANT]: 'MDC Tenant Database'
 38 |   }
 39 |   return displayNames[type] || 'Unknown Database Type'
 40 | }
 41 | 
 42 | /**
 43 |  * Get short display name for database type
 44 |  * @param {string} type - Database type
 45 |  * @returns {string} Short display name
 46 |  */
 47 | export const getDatabaseTypeShortName = (type) => {
 48 |   const shortNames = {
 49 |     [DATABASE_TYPES.SINGLE_CONTAINER]: 'Single-Container',
 50 |     [DATABASE_TYPES.MDC_SYSTEM]: 'MDC System',
 51 |     [DATABASE_TYPES.MDC_TENANT]: 'MDC Tenant'
 52 |   }
 53 |   return shortNames[type] || 'Unknown'
 54 | }
 55 | 
 56 | /**
 57 |  * Get color for database type badge
 58 |  * @param {string} type - Database type
 59 |  * @returns {string} Color class
 60 |  */
 61 | export const getDatabaseTypeColor = (type) => {
 62 |   const colors = {
 63 |     [DATABASE_TYPES.SINGLE_CONTAINER]: 'blue',
 64 |     [DATABASE_TYPES.MDC_SYSTEM]: 'amber', 
 65 |     [DATABASE_TYPES.MDC_TENANT]: 'green'
 66 |   }
 67 |   return colors[type] || 'gray'
 68 | }
 69 | 
 70 | /**
 71 |  * Check if MDC fields should be shown
 72 |  * @param {string} detectedType - Auto-detected type
 73 |  * @param {string} manualType - Manually selected type
 74 |  * @returns {boolean} Should show MDC fields
 75 |  */
 76 | export const shouldShowMDCFields = (detectedType, manualType) => {
 77 |   // Show MDC fields only for MDC system or tenant types
 78 |   return manualType === DATABASE_TYPES.MDC_SYSTEM || 
 79 |          manualType === DATABASE_TYPES.MDC_TENANT
 80 | }
 81 | 
 82 | /**
 83 |  * Get required fields for database type
 84 |  * @param {string} type - Database type
 85 |  * @returns {Array} Required field names
 86 |  */
 87 | export const getRequiredFieldsForType = (type) => {
 88 |   const baseFields = ['HANA_HOST', 'HANA_USER', 'HANA_PASSWORD']
 89 |   
 90 |   switch (type) {
 91 |     case DATABASE_TYPES.MDC_TENANT:
 92 |       return [...baseFields, 'HANA_INSTANCE_NUMBER', 'HANA_DATABASE_NAME']
 93 |     case DATABASE_TYPES.MDC_SYSTEM:
 94 |       return [...baseFields, 'HANA_INSTANCE_NUMBER']
 95 |     case DATABASE_TYPES.SINGLE_CONTAINER:
 96 |     default:
 97 |       return baseFields
 98 |   }
 99 | }
100 | 
101 | /**
102 |  * Get recommended fields for database type
103 |  * @param {string} type - Database type
104 |  * @returns {Array} Recommended field names
105 |  */
106 | export const getRecommendedFieldsForType = (type) => {
107 |   switch (type) {
108 |     case DATABASE_TYPES.SINGLE_CONTAINER:
109 |       return ['HANA_SCHEMA']
110 |     default:
111 |       return []
112 |   }
113 | }
114 | 
115 | /**
116 |  * Validate configuration for specific database type
117 |  * @param {Object} data - Configuration data
118 |  * @param {string} type - Database type
119 |  * @returns {Object} Validation result
120 |  */
121 | export const validateForDatabaseType = (data, type) => {
122 |   const errors = {}
123 |   const requiredFields = getRequiredFieldsForType(type)
124 |   const recommendedFields = getRecommendedFieldsForType(type)
125 |   
126 |   // Check required fields
127 |   requiredFields.forEach(field => {
128 |     if (!data[field] || data[field].toString().trim() === '') {
129 |       errors[field] = `${field.replace('HANA_', '')} is required for ${getDatabaseTypeShortName(type)}`
130 |     }
131 |   })
132 |   
133 |   // Check recommended fields
134 |   recommendedFields.forEach(field => {
135 |     if (!data[field] || data[field].toString().trim() === '') {
136 |       errors[field] = `${field.replace('HANA_', '')} is recommended for ${getDatabaseTypeShortName(type)}`
137 |     }
138 |   })
139 |   
140 |   return {
141 |     valid: Object.keys(errors).length === 0,
142 |     errors,
143 |     databaseType: type
144 |   }
145 | }
146 | 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/ClaudeServerCard.jsx:
--------------------------------------------------------------------------------

```javascript
  1 | import { motion } from 'framer-motion'  
  2 | import { EnvironmentBadge, DatabaseTypeBadge } from './ui'
  3 | import { detectDatabaseType, getDatabaseTypeDisplayName } from '../utils/databaseTypes'
  4 | 
  5 | const ClaudeServerCard = ({ 
  6 |   server, 
  7 |   index, 
  8 |   activeEnvironment, 
  9 |   onRemove 
 10 | }) => {
 11 |   // Detect database type from server environment data
 12 |   const databaseType = detectDatabaseType(server.env || {})
 13 |   
 14 |   return (
 15 |     <motion.div
 16 |       className="bg-gray-50 border border-gray-100 rounded-lg p-3 hover:bg-gray-100 transition-all duration-200"
 17 |       initial={{ opacity: 0, y: 10 }}
 18 |       animate={{ opacity: 1, y: 0 }}
 19 |       transition={{ duration: 0.2, delay: index * 0.05 }}
 20 |       whileHover={{ y: -1 }}
 21 |     >
 22 |       {/* Header */}
 23 |       <div className="flex items-start justify-between mb-2">
 24 |         <div className="flex-1 min-w-0">
 25 |           <div className="flex items-center gap-2 mb-1">
 26 |             <div className="w-1.5 h-1.5 bg-green-500 rounded-full"></div>
 27 |             <h4 className="text-sm font-medium text-gray-900 truncate">{server.name}</h4>
 28 |             <DatabaseTypeBadge type={databaseType} size="xs" />
 29 |           </div>
 30 |           
 31 |           {activeEnvironment && (
 32 |             <EnvironmentBadge environment={activeEnvironment} active size="xs" />
 33 |           )}
 34 |         </div>
 35 |         
 36 |         <button
 37 |           onClick={onRemove}
 38 |           className="text-gray-400 hover:text-red-500 transition-colors duration-200 p-1 rounded hover:bg-white/60"
 39 |           title="Remove from Claude"
 40 |         >
 41 |           <svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
 42 |             <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
 43 |           </svg>
 44 |         </button>
 45 |       </div>
 46 | 
 47 |       {/* Connection Info */}
 48 |       <div className="space-y-1">
 49 |         <div className="flex items-center justify-between text-xs">
 50 |           <span className="text-gray-500">Host:</span>
 51 |           <span className="font-mono text-gray-700 bg-white/70 px-1.5 py-0.5 rounded text-xs truncate max-w-[100px]" title={server.env.HANA_HOST}>
 52 |             {server.env.HANA_HOST}
 53 |           </span>
 54 |         </div>
 55 |         
 56 |         {/* Show MDC-specific info when applicable */}
 57 |         {databaseType === 'mdc_tenant' && server.env.HANA_DATABASE_NAME && (
 58 |           <div className="flex items-center justify-between text-xs">
 59 |             <span className="text-gray-500">Database:</span>
 60 |             <span className="font-mono text-gray-700 bg-white/70 px-1.5 py-0.5 rounded text-xs truncate max-w-[100px]" title={server.env.HANA_DATABASE_NAME}>
 61 |               {server.env.HANA_DATABASE_NAME}
 62 |             </span>
 63 |           </div>
 64 |         )}
 65 |         
 66 |         {databaseType === 'mdc_system' && server.env.HANA_INSTANCE_NUMBER && (
 67 |           <div className="flex items-center justify-between text-xs">
 68 |             <span className="text-gray-500">Instance:</span>
 69 |             <span className="font-mono text-gray-700 bg-white/70 px-1.5 py-0.5 rounded text-xs">
 70 |               {server.env.HANA_INSTANCE_NUMBER}
 71 |             </span>
 72 |           </div>
 73 |         )}
 74 |         
 75 |         <div className="flex items-center justify-between text-xs">
 76 |           <span className="text-gray-500">Schema:</span>
 77 |           <span className="font-mono text-gray-700 bg-white/70 px-1.5 py-0.5 rounded text-xs truncate max-w-[100px]" title={server.env.HANA_SCHEMA}>
 78 |             {server.env.HANA_SCHEMA}
 79 |           </span>
 80 |         </div>
 81 |       </div>
 82 | 
 83 |       {/* Status */}
 84 |       <div className="mt-2 pt-2 border-t border-gray-200">
 85 |         <div className="flex items-center justify-between">
 86 |           <span className="text-xs text-green-700 font-medium flex items-center gap-1">
 87 |             <svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
 88 |               <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
 89 |             </svg>
 90 |             Connected
 91 |           </span>
 92 |           <span className="text-xs text-gray-400">
 93 |             Active
 94 |           </span>
 95 |         </div>
 96 |       </div>
 97 |     </motion.div>
 98 |   )
 99 | }
100 | 
101 | export default ClaudeServerCard
```

--------------------------------------------------------------------------------
/src/database/hana-client.js:
--------------------------------------------------------------------------------

```javascript
  1 | const hana = require('@sap/hana-client');
  2 | 
  3 | // Simple logger that doesn't interfere with JSON-RPC
  4 | const log = (msg) => console.error(`[HANA Client] ${new Date().toISOString()}: ${msg}`);
  5 | 
  6 | /**
  7 |  * Create and configure a HANA client
  8 |  * @param {Object} config - HANA connection configuration
  9 |  * @returns {Object} HANA client wrapper
 10 |  */
 11 | async function createHanaClient(config) {
 12 |   try {
 13 |     // Create connection
 14 |     const connection = hana.createConnection();
 15 |     
 16 |     // Use connection parameter building if available
 17 |     const connectionParams = config.getConnectionParams ? 
 18 |       config.getConnectionParams() : 
 19 |       buildLegacyConnectionParams(config);
 20 |     
 21 |     // Log database type information
 22 |     const dbType = config.getHanaDatabaseType ? config.getHanaDatabaseType() : 'single_container';
 23 |     log(`Connecting to HANA ${dbType} database...`);
 24 |     
 25 |     // Connect to HANA
 26 |     await connect(connection, connectionParams);
 27 |     
 28 |     log(`Successfully connected to HANA ${dbType} database`);
 29 |     
 30 |     // Return client wrapper with utility methods
 31 |     return {
 32 |       /**
 33 |        * Execute a SQL query
 34 |        * @param {string} sql - SQL query to execute
 35 |        * @param {Array} params - Query parameters
 36 |        * @returns {Promise<Array>} Query results
 37 |        */
 38 |       async query(sql, params = []) {
 39 |         try {
 40 |           const statement = connection.prepare(sql);
 41 |           const results = await executeStatement(statement, params);
 42 |           statement.drop();
 43 |           return results;
 44 |         } catch (error) {
 45 |           log('Query execution error:', error);
 46 |           throw new Error(`Query execution failed: ${error.message}`);
 47 |         }
 48 |       },
 49 |       
 50 |       /**
 51 |        * Execute a SQL query that returns a single value
 52 |        * @param {string} sql - SQL query to execute
 53 |        * @param {Array} params - Query parameters
 54 |        * @returns {Promise<any>} Query result
 55 |        */
 56 |       async queryScalar(sql, params = []) {
 57 |         const results = await this.query(sql, params);
 58 |         if (results.length === 0) return null;
 59 |         
 60 |         const firstRow = results[0];
 61 |         const keys = Object.keys(firstRow);
 62 |         if (keys.length === 0) return null;
 63 |         
 64 |         return firstRow[keys[0]];
 65 |       },
 66 |       
 67 |       /**
 68 |        * Disconnect from HANA database
 69 |        * @returns {Promise<void>}
 70 |        */
 71 |       async disconnect() {
 72 |         return new Promise((resolve, reject) => {
 73 |           connection.disconnect(err => {
 74 |             if (err) {
 75 |               log('Error disconnecting from HANA:', err);
 76 |               reject(err);
 77 |             } else {
 78 |               log('Disconnected from HANA database');
 79 |               resolve();
 80 |             }
 81 |           });
 82 |         });
 83 |       }
 84 |     };
 85 |   } catch (error) {
 86 |     log(`Failed to create HANA client: ${error.message}`);
 87 |     throw error;
 88 |   }
 89 | }
 90 | 
 91 | /**
 92 |  * Build legacy connection parameters for backward compatibility
 93 |  */
 94 | function buildLegacyConnectionParams(config) {
 95 |   return {
 96 |     serverNode: `${config.host}:${config.port}`,
 97 |     uid: config.user,
 98 |     pwd: config.password,
 99 |     encrypt: config.encrypt !== false,
100 |     sslValidateCertificate: config.validateCert !== false,
101 |     ...config.additionalParams
102 |   };
103 | }
104 | 
105 | /**
106 |  * Connect to HANA database
107 |  * @param {Object} connection - HANA connection object
108 |  * @param {Object} params - Connection parameters
109 |  * @returns {Promise<void>}
110 |  */
111 | function connect(connection, params) {
112 |   return new Promise((resolve, reject) => {
113 |     connection.connect(params, (err) => {
114 |       if (err) {
115 |         reject(new Error(`HANA connection failed: ${err.message}`));
116 |       } else {
117 |         resolve();
118 |       }
119 |     });
120 |   });
121 | }
122 | 
123 | /**
124 |  * Execute a prepared statement
125 |  * @param {Object} statement - Prepared statement
126 |  * @param {Array} params - Statement parameters
127 |  * @returns {Promise<Array>} Query results
128 |  */
129 | function executeStatement(statement, params) {
130 |   return new Promise((resolve, reject) => {
131 |     statement.execQuery(params, (err, results) => {
132 |       if (err) {
133 |         reject(err);
134 |       } else {
135 |         // Convert results to array of objects
136 |         const rows = [];
137 |         while (results.next()) {
138 |           rows.push(results.getValues());
139 |         }
140 |         resolve(rows);
141 |       }
142 |     });
143 |   });
144 | }
145 | 
146 | module.exports = {
147 |   createHanaClient
148 | };
149 | 
```

--------------------------------------------------------------------------------
/src/database/connection-manager.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * HANA Database Connection Manager
  3 |  */
  4 | 
  5 | const { logger } = require('../utils/logger');
  6 | const { config } = require('../utils/config');
  7 | const { createHanaClient } = require('./hana-client');
  8 | 
  9 | class ConnectionManager {
 10 |   constructor() {
 11 |     this.client = null;
 12 |     this.isConnecting = false;
 13 |     this.lastConnectionAttempt = null;
 14 |     this.connectionRetries = 0;
 15 |     this.maxRetries = 3;
 16 |   }
 17 | 
 18 |   /**
 19 |    * Get or create HANA client connection
 20 |    */
 21 |   async getClient() {
 22 |     // Return existing client if available
 23 |     if (this.client) {
 24 |       return this.client;
 25 |     }
 26 | 
 27 |     // Prevent multiple simultaneous connection attempts
 28 |     if (this.isConnecting) {
 29 |       logger.debug('Connection already in progress, waiting...');
 30 |       while (this.isConnecting) {
 31 |         await new Promise(resolve => setTimeout(resolve, 100));
 32 |       }
 33 |       return this.client;
 34 |     }
 35 | 
 36 |     // Check if configuration is valid
 37 |     if (!config.isHanaConfigured()) {
 38 |       logger.warn('HANA configuration is incomplete');
 39 |       return null;
 40 |     }
 41 | 
 42 |     return this.connect();
 43 |   }
 44 | 
 45 |   /**
 46 |    * Establish connection to HANA database
 47 |    */
 48 |   async connect() {
 49 |     this.isConnecting = true;
 50 |     this.lastConnectionAttempt = new Date();
 51 | 
 52 |     try {
 53 |       logger.info('Connecting to HANA database...');
 54 |       
 55 |       const hanaConfig = config.getHanaConfig();
 56 |       const dbType = config.getHanaDatabaseType();
 57 |       
 58 |       logger.info(`Detected HANA database type: ${dbType}`);
 59 |       
 60 |       // Pass the full config object so the client can access the methods
 61 |       this.client = await createHanaClient(config);
 62 |       
 63 |       this.connectionRetries = 0;
 64 |       logger.info(`HANA client connected successfully to ${dbType} database`);
 65 |       
 66 |       return this.client;
 67 |     } catch (error) {
 68 |       this.connectionRetries++;
 69 |       logger.error(`Failed to connect to HANA (attempt ${this.connectionRetries}):`, error.message);
 70 |       
 71 |       if (this.connectionRetries < this.maxRetries) {
 72 |         logger.info(`Retrying connection in 2 seconds...`);
 73 |         await new Promise(resolve => setTimeout(resolve, 2000));
 74 |         this.isConnecting = false;
 75 |         return this.connect();
 76 |       } else {
 77 |         logger.error('Max connection retries reached');
 78 |         this.isConnecting = false;
 79 |         return null;
 80 |       }
 81 |     }
 82 |   }
 83 | 
 84 |   /**
 85 |    * Test the connection
 86 |    */
 87 |   async testConnection() {
 88 |     const client = await this.getClient();
 89 |     if (!client) {
 90 |       return { success: false, error: 'No client available' };
 91 |     }
 92 | 
 93 |     try {
 94 |       const testQuery = 'SELECT 1 as test_value FROM DUMMY';
 95 |       const result = await client.query(testQuery);
 96 |       
 97 |       if (result && result.length > 0) {
 98 |         return { 
 99 |           success: true, 
100 |           result: result[0].TEST_VALUE 
101 |         };
102 |       } else {
103 |         return { 
104 |           success: false, 
105 |           error: 'Connection test returned no results' 
106 |         };
107 |       }
108 |     } catch (error) {
109 |       logger.error('Connection test failed:', error.message);
110 |       return { 
111 |         success: false, 
112 |         error: error.message 
113 |       };
114 |     }
115 |   }
116 | 
117 |   /**
118 |    * Check if connection is healthy
119 |    */
120 |   async isHealthy() {
121 |     const test = await this.testConnection();
122 |     return test.success;
123 |   }
124 | 
125 |   /**
126 |    * Disconnect from HANA database
127 |    */
128 |   async disconnect() {
129 |     if (this.client) {
130 |       try {
131 |         await this.client.disconnect();
132 |         logger.info('HANA client disconnected');
133 |       } catch (error) {
134 |         logger.error('Error disconnecting HANA client:', error.message);
135 |       } finally {
136 |         this.client = null;
137 |         this.connectionRetries = 0;
138 |       }
139 |     }
140 |   }
141 | 
142 |   /**
143 |    * Reset connection (disconnect and reconnect)
144 |    */
145 |   async resetConnection() {
146 |     logger.info('Resetting HANA connection...');
147 |     await this.disconnect();
148 |     this.connectionRetries = 0;
149 |     return this.getClient();
150 |   }
151 | 
152 |   /**
153 |    * Get connection status
154 |    */
155 |   getStatus() {
156 |     const dbType = config.getHanaDatabaseType();
157 |     
158 |     return {
159 |       connected: !!this.client,
160 |       isConnecting: this.isConnecting,
161 |       lastConnectionAttempt: this.lastConnectionAttempt,
162 |       connectionRetries: this.connectionRetries,
163 |       maxRetries: this.maxRetries,
164 |       databaseType: dbType
165 |     };
166 |   }
167 | }
168 | 
169 | // Create singleton instance
170 | const connectionManager = new ConnectionManager();
171 | 
172 | module.exports = { ConnectionManager, connectionManager }; 
```

--------------------------------------------------------------------------------
/src/server/mcp-handler.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * MCP Protocol Handler for JSON-RPC 2.0 communication
  3 |  */
  4 | 
  5 | const { logger } = require('../utils/logger');
  6 | const { METHODS, ERROR_CODES, ERROR_MESSAGES, PROTOCOL_VERSIONS, SERVER_INFO, CAPABILITIES } = require('../constants/mcp-constants');
  7 | const ToolRegistry = require('../tools');
  8 | 
  9 | class MCPHandler {
 10 |   /**
 11 |    * Handle MCP request
 12 |    */
 13 |   static async handleRequest(request) {
 14 |     const { id, method, params } = request;
 15 |     
 16 |     logger.method(method);
 17 |     
 18 |     try {
 19 |       switch (method) {
 20 |         case METHODS.INITIALIZE:
 21 |           return this.handleInitialize(id, params);
 22 |           
 23 |         case METHODS.TOOLS_LIST:
 24 |           return this.handleToolsList(id, params);
 25 |           
 26 |         case METHODS.TOOLS_CALL:
 27 |           return this.handleToolsCall(id, params);
 28 |           
 29 |         case METHODS.NOTIFICATIONS_INITIALIZED:
 30 |           return this.handleInitialized(id, params);
 31 |           
 32 |         case METHODS.PROMPTS_LIST:
 33 |           return this.handlePromptsList(id, params);
 34 |           
 35 |         default:
 36 |           return this.createErrorResponse(id, ERROR_CODES.METHOD_NOT_FOUND, `Method not found: ${method}`);
 37 |       }
 38 |     } catch (error) {
 39 |       logger.error(`Error handling request: ${error.message}`);
 40 |       return this.createErrorResponse(id, ERROR_CODES.INTERNAL_ERROR, error.message);
 41 |     }
 42 |   }
 43 | 
 44 |   /**
 45 |    * Handle initialize request
 46 |    */
 47 |   static handleInitialize(id, params) {
 48 |     logger.info('Initializing server');
 49 |     
 50 |     return {
 51 |       jsonrpc: '2.0',
 52 |       id,
 53 |       result: {
 54 |         protocolVersion: PROTOCOL_VERSIONS.LATEST,
 55 |         capabilities: CAPABILITIES,
 56 |         serverInfo: SERVER_INFO
 57 |       }
 58 |     };
 59 |   }
 60 | 
 61 |   /**
 62 |    * Handle tools/list request
 63 |    */
 64 |   static handleToolsList(id, params) {
 65 |     logger.info('Listing tools');
 66 |     
 67 |     const tools = ToolRegistry.getTools();
 68 |     
 69 |     return {
 70 |       jsonrpc: '2.0',
 71 |       id,
 72 |       result: { tools }
 73 |     };
 74 |   }
 75 | 
 76 |   /**
 77 |    * Handle tools/call request
 78 |    */
 79 |   static async handleToolsCall(id, params) {
 80 |     const { name, arguments: args } = params;
 81 |     
 82 |     logger.tool(name, args);
 83 |     
 84 |     // Validate tool exists
 85 |     if (!ToolRegistry.hasTool(name)) {
 86 |       return this.createErrorResponse(id, ERROR_CODES.TOOL_NOT_FOUND, `Tool not found: ${name}`);
 87 |     }
 88 |     
 89 |     // Validate tool arguments
 90 |     const validation = ToolRegistry.validateToolArgs(name, args);
 91 |     if (!validation.valid) {
 92 |       return this.createErrorResponse(id, ERROR_CODES.INVALID_PARAMS, validation.error);
 93 |     }
 94 |     
 95 |     try {
 96 |       const result = await ToolRegistry.executeTool(name, args);
 97 |       
 98 |       return {
 99 |         jsonrpc: '2.0',
100 |         id,
101 |         result
102 |       };
103 |     } catch (error) {
104 |       logger.error(`Tool execution failed: ${error.message}`);
105 |       return this.createErrorResponse(id, ERROR_CODES.INTERNAL_ERROR, error.message);
106 |     }
107 |   }
108 | 
109 |   /**
110 |    * Handle notifications/initialized
111 |    */
112 |   static handleInitialized(id, params) {
113 |     logger.info('Server initialized');
114 |     return null; // No response for notifications
115 |   }
116 | 
117 |   /**
118 |    * Handle prompts/list request
119 |    */
120 |   static handlePromptsList(id, params) {
121 |     logger.info('Listing prompts');
122 |     
123 |     const prompts = [
124 |       {
125 |         name: "hana_query_builder",
126 |         description: "Build a SQL query for HANA database",
127 |         template: "I need to build a SQL query for HANA database that {{goal}}."
128 |       },
129 |       {
130 |         name: "hana_schema_explorer",
131 |         description: "Explore HANA database schemas and tables",
132 |         template: "I want to explore the schemas and tables in my HANA database."
133 |       },
134 |       {
135 |         name: "hana_connection_test",
136 |         description: "Test HANA database connection",
137 |         template: "Please test my HANA database connection and show the configuration."
138 |       }
139 |     ];
140 |     
141 |     return {
142 |       jsonrpc: '2.0',
143 |       id,
144 |       result: { prompts }
145 |     };
146 |   }
147 | 
148 |   /**
149 |    * Create error response
150 |    */
151 |   static createErrorResponse(id, code, message) {
152 |     return {
153 |       jsonrpc: '2.0',
154 |       id,
155 |       error: {
156 |         code,
157 |         message: message || ERROR_MESSAGES[code] || 'Unknown error'
158 |       }
159 |     };
160 |   }
161 | 
162 |   /**
163 |    * Validate JSON-RPC request
164 |    */
165 |   static validateRequest(request) {
166 |     if (!request || typeof request !== 'object') {
167 |       return { valid: false, error: 'Invalid request: must be an object' };
168 |     }
169 | 
170 |     if (request.jsonrpc !== '2.0') {
171 |       return { valid: false, error: 'Invalid JSON-RPC version' };
172 |     }
173 | 
174 |     if (!request.method) {
175 |       return { valid: false, error: 'Missing method' };
176 |     }
177 | 
178 |     if (typeof request.method !== 'string') {
179 |       return { valid: false, error: 'Method must be a string' };
180 |     }
181 | 
182 |     return { valid: true };
183 |   }
184 | }
185 | 
186 | module.exports = MCPHandler; 
```

--------------------------------------------------------------------------------
/src/tools/index-tools.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Index management tools for HANA MCP Server
  3 |  */
  4 | 
  5 | const { logger } = require('../utils/logger');
  6 | const { config } = require('../utils/config');
  7 | const QueryExecutor = require('../database/query-executor');
  8 | const Validators = require('../utils/validators');
  9 | const Formatters = require('../utils/formatters');
 10 | 
 11 | class IndexTools {
 12 |   /**
 13 |    * List indexes for a table
 14 |    */
 15 |   static async listIndexes(args) {
 16 |     logger.tool('hana_list_indexes', args);
 17 |     
 18 |     let { schema_name, table_name } = args || {};
 19 |     
 20 |     // Use default schema if not provided
 21 |     if (!schema_name) {
 22 |       if (config.hasDefaultSchema()) {
 23 |         schema_name = config.getDefaultSchema();
 24 |         logger.info(`Using default schema: ${schema_name}`);
 25 |       } else {
 26 |         return Formatters.createErrorResponse(
 27 |           'Schema name is required', 
 28 |           'Please provide schema_name parameter or set HANA_SCHEMA environment variable'
 29 |         );
 30 |       }
 31 |     }
 32 |     
 33 |     // Validate required parameters
 34 |     const validation = Validators.validateRequired(args, ['table_name'], 'hana_list_indexes');
 35 |     if (!validation.valid) {
 36 |       return Formatters.createErrorResponse('Error: table_name parameter is required', validation.error);
 37 |     }
 38 |     
 39 |     // Validate schema and table names
 40 |     const schemaValidation = Validators.validateSchemaName(schema_name);
 41 |     if (!schemaValidation.valid) {
 42 |       return Formatters.createErrorResponse('Invalid schema name', schemaValidation.error);
 43 |     }
 44 |     
 45 |     const tableValidation = Validators.validateTableName(table_name);
 46 |     if (!tableValidation.valid) {
 47 |       return Formatters.createErrorResponse('Invalid table name', tableValidation.error);
 48 |     }
 49 |     
 50 |     try {
 51 |       const results = await QueryExecutor.getTableIndexes(schema_name, table_name);
 52 |       
 53 |       if (results.length === 0) {
 54 |         return Formatters.createResponse(`📋 No indexes found for table '${schema_name}.${table_name}'.`);
 55 |       }
 56 |       
 57 |       // Group by index name
 58 |       const indexMap = {};
 59 |       results.forEach(row => {
 60 |         if (!indexMap[row.INDEX_NAME]) {
 61 |           indexMap[row.INDEX_NAME] = {
 62 |             type: row.INDEX_TYPE,
 63 |             isUnique: row.IS_UNIQUE === 'TRUE',
 64 |             columns: []
 65 |           };
 66 |         }
 67 |         indexMap[row.INDEX_NAME].columns.push(row.COLUMN_NAME);
 68 |       });
 69 |       
 70 |       const formattedIndexes = Formatters.formatIndexList(indexMap, schema_name, table_name);
 71 |       
 72 |       return Formatters.createResponse(formattedIndexes);
 73 |     } catch (error) {
 74 |       logger.error('Error listing indexes:', error.message);
 75 |       return Formatters.createErrorResponse('Error listing indexes', error.message);
 76 |     }
 77 |   }
 78 | 
 79 |   /**
 80 |    * Describe index details
 81 |    */
 82 |   static async describeIndex(args) {
 83 |     logger.tool('hana_describe_index', args);
 84 |     
 85 |     let { schema_name, table_name, index_name } = args || {};
 86 |     
 87 |     // Use default schema if not provided
 88 |     if (!schema_name) {
 89 |       if (config.hasDefaultSchema()) {
 90 |         schema_name = config.getDefaultSchema();
 91 |         logger.info(`Using default schema: ${schema_name}`);
 92 |       } else {
 93 |         return Formatters.createErrorResponse(
 94 |           'Schema name is required', 
 95 |           'Please provide schema_name parameter or set HANA_SCHEMA environment variable'
 96 |         );
 97 |       }
 98 |     }
 99 |     
100 |     // Validate required parameters
101 |     const validation = Validators.validateRequired(args, ['table_name', 'index_name'], 'hana_describe_index');
102 |     if (!validation.valid) {
103 |       return Formatters.createErrorResponse('Error: table_name and index_name parameters are required', validation.error);
104 |     }
105 |     
106 |     // Validate schema, table, and index names
107 |     const schemaValidation = Validators.validateSchemaName(schema_name);
108 |     if (!schemaValidation.valid) {
109 |       return Formatters.createErrorResponse('Invalid schema name', schemaValidation.error);
110 |     }
111 |     
112 |     const tableValidation = Validators.validateTableName(table_name);
113 |     if (!tableValidation.valid) {
114 |       return Formatters.createErrorResponse('Invalid table name', tableValidation.error);
115 |     }
116 |     
117 |     const indexValidation = Validators.validateIndexName(index_name);
118 |     if (!indexValidation.valid) {
119 |       return Formatters.createErrorResponse('Invalid index name', indexValidation.error);
120 |     }
121 |     
122 |     try {
123 |       const results = await QueryExecutor.getIndexDetails(schema_name, table_name, index_name);
124 |       
125 |       const formattedDetails = Formatters.formatIndexDetails(results, schema_name, table_name, index_name);
126 |       
127 |       return Formatters.createResponse(formattedDetails);
128 |     } catch (error) {
129 |       logger.error('Error describing index:', error.message);
130 |       return Formatters.createErrorResponse('Error describing index', error.message);
131 |     }
132 |   }
133 | }
134 | 
135 | module.exports = IndexTools; 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/EnvironmentSelector.jsx:
--------------------------------------------------------------------------------

```javascript
  1 | import { motion } from 'framer-motion'
  2 | import { useEffect } from 'react'
  3 | import { XMarkIcon, PlusIcon, CheckCircleIcon } from '@heroicons/react/24/outline'
  4 | import { EnvironmentBadge } from './ui'
  5 | 
  6 | const EnvironmentSelector = ({
  7 |   isOpen,
  8 |   onClose,
  9 |   serverName,
 10 |   environments,
 11 |   activeEnvironment,
 12 |   onDeploy,
 13 |   isLoading
 14 | }) => {
 15 |   useEffect(() => {
 16 |     if (!isOpen) return
 17 |     const onKeyDown = (e) => {
 18 |       if (e.key === 'Escape') onClose()
 19 |     }
 20 |     window.addEventListener('keydown', onKeyDown)
 21 |     return () => window.removeEventListener('keydown', onKeyDown)
 22 |   }, [isOpen, onClose])
 23 | 
 24 |   if (!isOpen) return null
 25 | 
 26 |   return (
 27 |     <motion.div
 28 |       className="fixed inset-0 bg-gray-900/20 backdrop-blur-sm z-50 flex items-center justify-center p-4"
 29 |       initial={{ opacity: 0 }}
 30 |       animate={{ opacity: 1 }}
 31 |       exit={{ opacity: 0 }}
 32 |       onClick={onClose}
 33 |     >
 34 |       <motion.div
 35 |         className="bg-white rounded-2xl shadow-xl max-w-2xl w-full border border-gray-200 overflow-hidden"
 36 |         initial={{ scale: 0.9, opacity: 0, y: 20 }}
 37 |         animate={{ scale: 1, opacity: 1, y: 0 }}
 38 |         exit={{ scale: 0.9, opacity: 0, y: 20 }}
 39 |         transition={{ type: "spring", stiffness: 300, damping: 25 }}
 40 |         onClick={(e) => e.stopPropagation()}
 41 |       >
 42 |         {/* Header */}
 43 |         <div className="px-6 py-4 border-b border-gray-100">
 44 |           <div className="flex items-center justify-between">
 45 |             <div className="flex items-center gap-3">
 46 |               <div className="p-2 bg-gray-100 rounded-lg">
 47 |                 <PlusIcon className="w-5 h-5 text-gray-600" />
 48 |               </div>
 49 |               <div>
 50 |                 <h2 className="text-xl font-semibold text-gray-900">Add to Claude Config</h2>
 51 |                 <p className="text-sm text-gray-500 mt-0.5">Select environment for {serverName}</p>
 52 |               </div>
 53 |             </div>
 54 |             <button
 55 |               onClick={onClose}
 56 |               className="p-2 rounded-lg text-gray-400 hover:text-gray-600 hover:bg-gray-50 transition-colors"
 57 |             >
 58 |               <XMarkIcon className="w-5 h-5" />
 59 |             </button>
 60 |           </div>
 61 |         </div>
 62 | 
 63 |         {/* Body */}
 64 |         <div className="p-6">
 65 |           <p className="text-gray-600 mb-6 text-sm">
 66 |             Choose which environment configuration to add to Claude Desktop. Multiple environments from different databases can be active simultaneously. Each environment will be added as a separate connection.
 67 |           </p>
 68 |           
 69 |           <div className="space-y-3">
 70 |             {Object.entries(environments).map(([env, config], index) => (
 71 |               <motion.button
 72 |                 key={env}
 73 |                 onClick={() => onDeploy(env)}
 74 |                 disabled={isLoading}
 75 |                 className="w-full p-4 border border-gray-200 rounded-xl text-left transition-all duration-200 hover:border-gray-300 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"
 76 |                 initial={{ opacity: 0, y: 10 }}
 77 |                 animate={{ opacity: 1, y: 0 }}
 78 |                 transition={{ duration: 0.2, delay: index * 0.05 }}
 79 |                 whileHover={!isLoading ? { y: -1 } : {}}
 80 |               >
 81 |                 <div className="flex justify-between items-center mb-3">
 82 |                   <div className="flex items-center gap-3">
 83 |                     <h3 className="text-lg font-medium text-gray-900">{env}</h3>
 84 |                     <EnvironmentBadge environment={env} size="sm" />
 85 |                   </div>
 86 |                   {activeEnvironment === env && (
 87 |                     <div className="flex items-center gap-2 px-2 py-1 bg-green-100 rounded-full">
 88 |                       <CheckCircleIcon className="w-4 h-4 text-green-600" />
 89 |                       <span className="text-green-700 text-xs font-medium">ACTIVE</span>
 90 |                     </div>
 91 |                   )}
 92 |                 </div>
 93 |                 <div className="grid grid-cols-2 gap-4 text-sm">
 94 |                   <div>
 95 |                     <span className="text-gray-500">Host:</span>
 96 |                     <p className="text-gray-700 font-mono text-xs mt-0.5">{config.HANA_HOST}</p>
 97 |                   </div>
 98 |                   <div>
 99 |                     <span className="text-gray-500">Schema:</span>
100 |                     <p className="text-gray-700 font-mono text-xs mt-0.5">{config.HANA_SCHEMA}</p>
101 |                   </div>
102 |                 </div>
103 |               </motion.button>
104 |             ))}
105 |           </div>
106 |         </div>
107 | 
108 |         {/* Footer */}
109 |         <div className="px-6 py-4 border-t border-gray-100 bg-gray-50 flex justify-end">
110 |           <button
111 |             onClick={onClose}
112 |             disabled={isLoading}
113 |             className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-1 focus:ring-gray-400 disabled:opacity-50 transition-colors"
114 |           >
115 |             Cancel
116 |           </button>
117 |         </div>
118 |       </motion.div>
119 |     </motion.div>
120 |   )
121 | }
122 | 
123 | export default EnvironmentSelector
```

--------------------------------------------------------------------------------
/src/utils/validators.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Input validation utilities for HANA MCP Server
  3 |  */
  4 | 
  5 | const { logger } = require('./logger');
  6 | 
  7 | class Validators {
  8 |   /**
  9 |    * Validate required parameters
 10 |    */
 11 |   static validateRequired(params, requiredFields, toolName) {
 12 |     const missing = [];
 13 |     
 14 |     for (const field of requiredFields) {
 15 |       if (!params || params[field] === undefined || params[field] === null || params[field] === '') {
 16 |         missing.push(field);
 17 |       }
 18 |     }
 19 |     
 20 |     if (missing.length > 0) {
 21 |       const error = `Missing required parameters: ${missing.join(', ')}`;
 22 |       logger.warn(`Validation failed for ${toolName}:`, error);
 23 |       return { valid: false, error };
 24 |     }
 25 |     
 26 |     return { valid: true };
 27 |   }
 28 | 
 29 |   /**
 30 |    * Validate schema name
 31 |    */
 32 |   static validateSchemaName(schemaName) {
 33 |     if (!schemaName || typeof schemaName !== 'string') {
 34 |       return { valid: false, error: 'Schema name must be a non-empty string' };
 35 |     }
 36 |     
 37 |     if (schemaName.length > 128) {
 38 |       return { valid: false, error: 'Schema name too long (max 128 characters)' };
 39 |     }
 40 |     
 41 |     // Basic SQL identifier validation
 42 |     if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(schemaName)) {
 43 |       return { valid: false, error: 'Invalid schema name format' };
 44 |     }
 45 |     
 46 |     return { valid: true };
 47 |   }
 48 | 
 49 |   /**
 50 |    * Validate table name
 51 |    */
 52 |   static validateTableName(tableName) {
 53 |     if (!tableName || typeof tableName !== 'string') {
 54 |       return { valid: false, error: 'Table name must be a non-empty string' };
 55 |     }
 56 |     
 57 |     if (tableName.length > 128) {
 58 |       return { valid: false, error: 'Table name too long (max 128 characters)' };
 59 |     }
 60 |     
 61 |     // Basic SQL identifier validation
 62 |     if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(tableName)) {
 63 |       return { valid: false, error: 'Invalid table name format' };
 64 |     }
 65 |     
 66 |     return { valid: true };
 67 |   }
 68 | 
 69 |   /**
 70 |    * Validate index name
 71 |    */
 72 |   static validateIndexName(indexName) {
 73 |     if (!indexName || typeof indexName !== 'string') {
 74 |       return { valid: false, error: 'Index name must be a non-empty string' };
 75 |     }
 76 |     
 77 |     if (indexName.length > 128) {
 78 |       return { valid: false, error: 'Index name too long (max 128 characters)' };
 79 |     }
 80 |     
 81 |     // Basic SQL identifier validation
 82 |     if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(indexName)) {
 83 |       return { valid: false, error: 'Invalid index name format' };
 84 |     }
 85 |     
 86 |     return { valid: true };
 87 |   }
 88 | 
 89 |   /**
 90 |    * Validate SQL query
 91 |    */
 92 |   static validateQuery(query) {
 93 |     if (!query || typeof query !== 'string') {
 94 |       return { valid: false, error: 'Query must be a non-empty string' };
 95 |     }
 96 |     
 97 |     if (query.trim().length === 0) {
 98 |       return { valid: false, error: 'Query cannot be empty' };
 99 |     }
100 |     
101 |     // Basic SQL injection prevention - check for suspicious patterns
102 |     const suspiciousPatterns = [
103 |       /;\s*drop\s+table/i,
104 |       /;\s*delete\s+from/i,
105 |       /;\s*truncate\s+table/i,
106 |       /;\s*alter\s+table/i,
107 |       /;\s*create\s+table/i,
108 |       /;\s*drop\s+database/i,
109 |       /;\s*shutdown/i
110 |     ];
111 |     
112 |     for (const pattern of suspiciousPatterns) {
113 |       if (pattern.test(query)) {
114 |         return { valid: false, error: 'Query contains potentially dangerous operations' };
115 |       }
116 |     }
117 |     
118 |     return { valid: true };
119 |   }
120 | 
121 |   /**
122 |    * Validate query parameters
123 |    */
124 |   static validateParameters(parameters) {
125 |     if (!parameters) {
126 |       return { valid: true }; // Parameters are optional
127 |     }
128 |     
129 |     if (!Array.isArray(parameters)) {
130 |       return { valid: false, error: 'Parameters must be an array' };
131 |     }
132 |     
133 |     for (let i = 0; i < parameters.length; i++) {
134 |       const param = parameters[i];
135 |       if (param === undefined || param === null) {
136 |         return { valid: false, error: `Parameter at index ${i} cannot be null or undefined` };
137 |       }
138 |     }
139 |     
140 |     return { valid: true };
141 |   }
142 | 
143 |   /**
144 |    * Validate tool arguments
145 |    */
146 |   static validateToolArgs(args, toolName) {
147 |     if (!args || typeof args !== 'object') {
148 |       return { valid: false, error: 'Arguments must be an object' };
149 |     }
150 |     
151 |     logger.debug(`Validating arguments for ${toolName}:`, args);
152 |     return { valid: true };
153 |   }
154 | 
155 |   /**
156 |    * Validate configuration for specific database type
157 |    */
158 |   static validateForDatabaseType(config) {
159 |     const dbType = config.getHanaDatabaseType ? config.getHanaDatabaseType() : 'single_container';
160 |     const errors = [];
161 | 
162 |     switch (dbType) {
163 |       case 'mdc_tenant':
164 |         if (!config.instanceNumber) {
165 |           errors.push('HANA_INSTANCE_NUMBER is required for MDC Tenant Database');
166 |         }
167 |         if (!config.databaseName) {
168 |           errors.push('HANA_DATABASE_NAME is required for MDC Tenant Database');
169 |         }
170 |         break;
171 |       case 'mdc_system':
172 |         if (!config.instanceNumber) {
173 |           errors.push('HANA_INSTANCE_NUMBER is required for MDC System Database');
174 |         }
175 |         break;
176 |       case 'single_container':
177 |         if (!config.schema) {
178 |           errors.push('HANA_SCHEMA is recommended for Single-Container Database');
179 |         }
180 |         break;
181 |     }
182 | 
183 |     return {
184 |       valid: errors.length === 0,
185 |       errors: errors,
186 |       databaseType: dbType
187 |     };
188 |   }
189 | }
190 | 
191 | module.exports = Validators; 
```

--------------------------------------------------------------------------------
/src/database/query-executor.js:
--------------------------------------------------------------------------------

```javascript
  1 | /**
  2 |  * Query execution utilities for HANA database
  3 |  */
  4 | 
  5 | const { logger } = require('../utils/logger');
  6 | const { connectionManager } = require('./connection-manager');
  7 | const Validators = require('../utils/validators');
  8 | 
  9 | class QueryExecutor {
 10 |   /**
 11 |    * Execute a query with parameters
 12 |    */
 13 |   static async executeQuery(query, parameters = []) {
 14 |     // Validate query
 15 |     const queryValidation = Validators.validateQuery(query);
 16 |     if (!queryValidation.valid) {
 17 |       throw new Error(queryValidation.error);
 18 |     }
 19 | 
 20 |     // Validate parameters
 21 |     const paramValidation = Validators.validateParameters(parameters);
 22 |     if (!paramValidation.valid) {
 23 |       throw new Error(paramValidation.error);
 24 |     }
 25 | 
 26 |     const client = await connectionManager.getClient();
 27 |     if (!client) {
 28 |       throw new Error('HANA client not connected. Please check your HANA configuration.');
 29 |     }
 30 | 
 31 |     try {
 32 |       logger.debug(`Executing query: ${query}`, parameters.length > 0 ? `with ${parameters.length} parameters` : '');
 33 |       const results = await client.query(query, parameters);
 34 |       logger.debug(`Query executed successfully, returned ${results.length} rows`);
 35 |       return results;
 36 |     } catch (error) {
 37 |       logger.error(`Query execution failed: ${error.message}`);
 38 |       throw error;
 39 |     }
 40 |   }
 41 | 
 42 |   /**
 43 |    * Execute a scalar query (returns single value)
 44 |    */
 45 |   static async executeScalarQuery(query, parameters = []) {
 46 |     const results = await this.executeQuery(query, parameters);
 47 |     
 48 |     if (results.length === 0) {
 49 |       return null;
 50 |     }
 51 |     
 52 |     const firstRow = results[0];
 53 |     const firstColumn = Object.keys(firstRow)[0];
 54 |     
 55 |     return firstRow[firstColumn];
 56 |   }
 57 | 
 58 |   /**
 59 |    * Get all schemas
 60 |    */
 61 |   static async getSchemas() {
 62 |     const query = `SELECT SCHEMA_NAME FROM SYS.SCHEMAS ORDER BY SCHEMA_NAME`;
 63 |     const results = await this.executeQuery(query);
 64 |     return results.map(row => row.SCHEMA_NAME);
 65 |   }
 66 | 
 67 |   /**
 68 |    * Get tables in a schema
 69 |    */
 70 |   static async getTables(schemaName) {
 71 |     const query = `
 72 |       SELECT TABLE_NAME
 73 |       FROM SYS.TABLES
 74 |       WHERE SCHEMA_NAME = ?
 75 |       ORDER BY TABLE_NAME
 76 |     `;
 77 |     
 78 |     const results = await this.executeQuery(query, [schemaName]);
 79 |     return results.map(row => row.TABLE_NAME);
 80 |   }
 81 | 
 82 |   /**
 83 |    * Get table columns
 84 |    */
 85 |   static async getTableColumns(schemaName, tableName) {
 86 |     const query = `
 87 |       SELECT 
 88 |         COLUMN_NAME,
 89 |         DATA_TYPE_NAME,
 90 |         LENGTH,
 91 |         SCALE,
 92 |         IS_NULLABLE,
 93 |         DEFAULT_VALUE,
 94 |         POSITION,
 95 |         COMMENTS
 96 |       FROM 
 97 |         SYS.TABLE_COLUMNS
 98 |       WHERE 
 99 |         SCHEMA_NAME = ? AND TABLE_NAME = ?
100 |       ORDER BY 
101 |         POSITION
102 |     `;
103 |     
104 |     return await this.executeQuery(query, [schemaName, tableName]);
105 |   }
106 | 
107 |   /**
108 |    * Get table indexes
109 |    */
110 |   static async getTableIndexes(schemaName, tableName) {
111 |     const query = `
112 |       SELECT 
113 |         INDEX_NAME,
114 |         INDEX_TYPE,
115 |         IS_UNIQUE,
116 |         COLUMN_NAME
117 |       FROM 
118 |         SYS.INDEX_COLUMNS ic
119 |       JOIN 
120 |         SYS.INDEXES i ON ic.INDEX_NAME = i.INDEX_NAME 
121 |         AND ic.SCHEMA_NAME = i.SCHEMA_NAME
122 |       WHERE 
123 |         ic.SCHEMA_NAME = ? AND ic.TABLE_NAME = ?
124 |       ORDER BY 
125 |         ic.INDEX_NAME, ic.POSITION
126 |     `;
127 |     
128 |     return await this.executeQuery(query, [schemaName, tableName]);
129 |   }
130 | 
131 |   /**
132 |    * Get index details
133 |    */
134 |   static async getIndexDetails(schemaName, tableName, indexName) {
135 |     const query = `
136 |       SELECT 
137 |         i.INDEX_NAME,
138 |         i.INDEX_TYPE,
139 |         i.IS_UNIQUE,
140 |         ic.COLUMN_NAME,
141 |         ic.POSITION,
142 |         ic.ORDER
143 |       FROM 
144 |         SYS.INDEXES i
145 |       JOIN 
146 |         SYS.INDEX_COLUMNS ic ON i.INDEX_NAME = ic.INDEX_NAME 
147 |         AND i.SCHEMA_NAME = ic.SCHEMA_NAME
148 |       WHERE 
149 |         i.SCHEMA_NAME = ? AND i.TABLE_NAME = ? AND i.INDEX_NAME = ?
150 |       ORDER BY 
151 |         ic.POSITION
152 |     `;
153 |     
154 |     return await this.executeQuery(query, [schemaName, tableName, indexName]);
155 |   }
156 | 
157 |   /**
158 |    * Test database connection
159 |    */
160 |   static async testConnection() {
161 |     return await connectionManager.testConnection();
162 |   }
163 | 
164 |   /**
165 |    * Get database information
166 |    */
167 |   static async getDatabaseInfo() {
168 |     try {
169 |       const versionQuery = 'SELECT * FROM M_DATABASE';
170 |       const version = await this.executeQuery(versionQuery);
171 |       
172 |       const userQuery = 'SELECT CURRENT_USER, CURRENT_SCHEMA FROM DUMMY';
173 |       const user = await this.executeQuery(userQuery);
174 |       
175 |       return {
176 |         version: version.length > 0 ? version[0] : null,
177 |         currentUser: user.length > 0 ? user[0].CURRENT_USER : null,
178 |         currentSchema: user.length > 0 ? user[0].CURRENT_SCHEMA : null
179 |       };
180 |     } catch (error) {
181 |       logger.error('Failed to get database info:', error.message);
182 |       return { error: error.message };
183 |     }
184 |   }
185 | 
186 |   /**
187 |    * Get table row count
188 |    */
189 |   static async getTableRowCount(schemaName, tableName) {
190 |     const query = `SELECT COUNT(*) as ROW_COUNT FROM "${schemaName}"."${tableName}"`;
191 |     const result = await this.executeScalarQuery(query);
192 |     return result;
193 |   }
194 | 
195 |   /**
196 |    * Get table sample data
197 |    */
198 |   static async getTableSample(schemaName, tableName, limit = 10) {
199 |     const query = `SELECT * FROM "${schemaName}"."${tableName}" LIMIT ?`;
200 |     return await this.executeQuery(query, [limit]);
201 |   }
202 | }
203 | 
204 | module.exports = QueryExecutor; 
```

--------------------------------------------------------------------------------
/hana-mcp-ui/src/components/ui/StatusBadge.jsx:
--------------------------------------------------------------------------------

```javascript
  1 | import { motion } from 'framer-motion'
  2 | import { cn } from '../../utils/cn'
  3 | 
  4 | const StatusBadge = ({ 
  5 |   status, 
  6 |   count, 
  7 |   showPulse = true, 
  8 |   size = 'md',
  9 |   children,
 10 |   className 
 11 | }) => {
 12 |   const statusConfig = {
 13 |     online: {
 14 |       color: 'bg-gray-700',
 15 |       glow: 'shadow-gray-200/50',
 16 |       text: 'Online',
 17 |       className: 'status-online'
 18 |     },
 19 |     offline: {
 20 |       color: 'bg-gray-400',
 21 |       glow: 'shadow-gray-200/50',
 22 |       text: 'Offline',
 23 |       className: 'status-offline'
 24 |     },
 25 |     warning: {
 26 |       color: 'bg-gray-600',
 27 |       glow: 'shadow-gray-200/50',
 28 |       text: 'Warning',
 29 |       className: 'status-warning'
 30 |     },
 31 |     error: {
 32 |       color: 'bg-gray-800', 
 33 |       glow: 'shadow-gray-200/50',
 34 |       text: 'Error',
 35 |       className: 'status-error'
 36 |     }
 37 |   }
 38 |   
 39 |   const sizes = {
 40 |     xs: { dot: 'w-1.5 h-1.5', text: 'text-xs', padding: 'px-1.5 py-0.5' },
 41 |     sm: { dot: 'w-2 h-2', text: 'text-xs', padding: 'px-2 py-1' },
 42 |     md: { dot: 'w-3 h-3', text: 'text-sm', padding: 'px-3 py-1' },
 43 |     lg: { dot: 'w-4 h-4', text: 'text-base', padding: 'px-4 py-2' }
 44 |   }
 45 |   
 46 |   const config = statusConfig[status] || statusConfig.offline
 47 |   const sizeConfig = sizes[size]
 48 |   
 49 |   return (
 50 |     <motion.div 
 51 |       className={cn(
 52 |         'inline-flex items-center gap-2 rounded-full',
 53 |         sizeConfig.padding,
 54 |         className
 55 |       )}
 56 |       initial={{ scale: 0.8, opacity: 0 }}
 57 |       animate={{ scale: 1, opacity: 1 }}
 58 |       transition={{ duration: 0.2 }}
 59 |     >
 60 |       <div className={cn('relative flex items-center justify-center rounded-full', sizeConfig.dot)}>
 61 |         <div className={cn('w-full h-full rounded-full shadow-lg', config.color, config.glow)} />
 62 |         {showPulse && status === 'online' && (
 63 |           <div className={cn(
 64 |             'absolute inset-0 rounded-full animate-ping opacity-75',
 65 |             config.color
 66 |           )} />
 67 |         )}
 68 |       </div>
 69 |       
 70 |       <span className={cn('font-medium', sizeConfig.text)}>
 71 |         {children || config.text}
 72 |         {count !== undefined && (
 73 |           <span className="ml-1 px-2 py-0.5 bg-gray-200 text-gray-700 rounded-full text-xs">
 74 |             {count}
 75 |           </span>
 76 |         )}
 77 |       </span>
 78 |     </motion.div>
 79 |   )
 80 | }
 81 | 
 82 | // Environment Badge Component
 83 | export const EnvironmentBadge = ({ environment, active = false, size = 'sm', className }) => {
 84 |   const envClasses = {
 85 |     Production: 'bg-green-50 border-green-200 text-green-800',
 86 |     Development: 'bg-[#86a0ff] border-[#86a0ff] text-white',
 87 |     Staging: 'bg-amber-50 border-amber-200 text-amber-800',
 88 |     STAGING: 'bg-amber-50 border-amber-200 text-amber-800',
 89 |     Testing: 'bg-purple-50 border-purple-200 text-purple-800',
 90 |     QA: 'bg-indigo-50 border-indigo-200 text-indigo-800'
 91 |   }
 92 |   
 93 |   const sizeClasses = {
 94 |     xs: 'px-1.5 py-0.5 text-xs',
 95 |     sm: 'px-2 py-1 text-xs',
 96 |     md: 'px-3 py-1 text-sm',
 97 |     lg: 'px-4 py-2 text-base'
 98 |   }
 99 |   
100 |   const activeRingClasses = {
101 |     Production: 'ring-2 ring-green-300 shadow-sm',
102 |     Development: 'ring-2 ring-[#86a0ff]/30 shadow-sm',
103 |     Staging: 'ring-2 ring-amber-300 shadow-sm',
104 |     STAGING: 'ring-2 ring-amber-300 shadow-sm',
105 |     Testing: 'ring-2 ring-purple-300 shadow-sm',
106 |     QA: 'ring-2 ring-indigo-300 shadow-sm'
107 |   }
108 |   
109 |   const dotClasses = {
110 |     Production: 'bg-green-600',
111 |     Development: 'bg-[#86a0ff]',
112 |     Staging: 'bg-amber-600',
113 |     STAGING: 'bg-amber-600',
114 |     Testing: 'bg-purple-600',
115 |     QA: 'bg-indigo-600'
116 |   }
117 | 
118 |   // Enhanced active state styling
119 |   const activeStateClasses = active ? {
120 |     Production: 'bg-green-100 border-green-300 text-green-900 shadow-md',
121 |     Development: 'bg-[#86a0ff]/90 border-[#86a0ff] text-white shadow-md',
122 |     Staging: 'bg-amber-100 border-amber-300 text-amber-900 shadow-md',
123 |     STAGING: 'bg-amber-100 border-amber-300 text-amber-900 shadow-md',
124 |     Testing: 'bg-purple-100 border-purple-300 text-purple-900 shadow-md',
125 |     QA: 'bg-indigo-100 border-indigo-300 text-indigo-900 shadow-md'
126 |   } : {}
127 |   
128 |   return (
129 |     <motion.span 
130 |       className={cn(
131 |         'inline-flex items-center rounded-full font-medium',
132 |         'border transition-all duration-200',
133 |         sizeClasses[size],
134 |         active ? (activeStateClasses[environment] || 'bg-green-100 border-green-300 text-green-900 shadow-md') : 
135 |                 (envClasses[environment] || 'bg-gray-50 border-gray-200 text-gray-700'),
136 |         active && (activeRingClasses[environment] || 'ring-2 ring-green-300 shadow-sm'),
137 |         className
138 |       )}
139 |       whileHover={{ scale: 1.05 }}
140 |       transition={{ duration: 0.1 }}
141 |       title={`${environment} environment${active ? ' (active)' : ''}`}
142 |     >
143 |       {environment}
144 |       {active && (
145 |         <motion.div 
146 |           className="ml-1.5 flex items-center space-x-1"
147 |           initial={{ opacity: 0, scale: 0.8 }}
148 |           animate={{ opacity: 1, scale: 1 }}
149 |           transition={{ duration: 0.2 }}
150 |         >
151 |           <div 
152 |             className={cn("w-2 h-2 rounded-full", dotClasses[environment] || 'bg-green-600')}
153 |             animate={{ opacity: [1, 0.5, 1] }}
154 |             transition={{ duration: 1.5, repeat: Infinity }}
155 |           />
156 |           <svg className="w-3 h-3 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
157 |             <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
158 |           </svg>
159 |         </motion.div>
160 |       )}
161 |     </motion.span>
162 |   )
163 | }
164 | 
165 | export default StatusBadge
```
Page 1/3FirstPrevNextLast