elasticsearch-mcp-vsee-stage 0.5.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +304 -0
  3. package/build/config.d.ts +76 -0
  4. package/build/config.d.ts.map +1 -0
  5. package/build/config.js +63 -0
  6. package/build/config.js.map +1 -0
  7. package/build/elasticsearch/client.d.ts +26 -0
  8. package/build/elasticsearch/client.d.ts.map +1 -0
  9. package/build/elasticsearch/client.js +131 -0
  10. package/build/elasticsearch/client.js.map +1 -0
  11. package/build/errors/handlers.d.ts +44 -0
  12. package/build/errors/handlers.d.ts.map +1 -0
  13. package/build/errors/handlers.js +231 -0
  14. package/build/errors/handlers.js.map +1 -0
  15. package/build/index.d.ts +9 -0
  16. package/build/index.d.ts.map +1 -0
  17. package/build/index.js +28 -0
  18. package/build/index.js.map +1 -0
  19. package/build/logger.d.ts +31 -0
  20. package/build/logger.d.ts.map +1 -0
  21. package/build/logger.js +81 -0
  22. package/build/logger.js.map +1 -0
  23. package/build/server.d.ts +23 -0
  24. package/build/server.d.ts.map +1 -0
  25. package/build/server.js +571 -0
  26. package/build/server.js.map +1 -0
  27. package/build/tools/find-entities-by-metric.d.ts +51 -0
  28. package/build/tools/find-entities-by-metric.d.ts.map +1 -0
  29. package/build/tools/find-entities-by-metric.js +375 -0
  30. package/build/tools/find-entities-by-metric.js.map +1 -0
  31. package/build/tools/get-index-fields.d.ts +26 -0
  32. package/build/tools/get-index-fields.d.ts.map +1 -0
  33. package/build/tools/get-index-fields.js +94 -0
  34. package/build/tools/get-index-fields.js.map +1 -0
  35. package/build/tools/get-platform-breakdown.d.ts +42 -0
  36. package/build/tools/get-platform-breakdown.d.ts.map +1 -0
  37. package/build/tools/get-platform-breakdown.js +305 -0
  38. package/build/tools/get-platform-breakdown.js.map +1 -0
  39. package/build/tools/get-rating-distribution.d.ts +48 -0
  40. package/build/tools/get-rating-distribution.d.ts.map +1 -0
  41. package/build/tools/get-rating-distribution.js +283 -0
  42. package/build/tools/get-rating-distribution.js.map +1 -0
  43. package/build/tools/get-subscription-breakdown.d.ts +34 -0
  44. package/build/tools/get-subscription-breakdown.d.ts.map +1 -0
  45. package/build/tools/get-subscription-breakdown.js +179 -0
  46. package/build/tools/get-subscription-breakdown.js.map +1 -0
  47. package/build/tools/get-usage-leaderboard.d.ts +38 -0
  48. package/build/tools/get-usage-leaderboard.d.ts.map +1 -0
  49. package/build/tools/get-usage-leaderboard.js +177 -0
  50. package/build/tools/get-usage-leaderboard.js.map +1 -0
  51. package/build/tools/get-usage-profile.d.ts +52 -0
  52. package/build/tools/get-usage-profile.d.ts.map +1 -0
  53. package/build/tools/get-usage-profile.js +273 -0
  54. package/build/tools/get-usage-profile.js.map +1 -0
  55. package/build/tools/get-visit-trends.d.ts +37 -0
  56. package/build/tools/get-visit-trends.d.ts.map +1 -0
  57. package/build/tools/get-visit-trends.js +289 -0
  58. package/build/tools/get-visit-trends.js.map +1 -0
  59. package/build/tools/index.d.ts +19 -0
  60. package/build/tools/index.d.ts.map +1 -0
  61. package/build/tools/index.js +22 -0
  62. package/build/tools/index.js.map +1 -0
  63. package/build/tools/top-change.d.ts +34 -0
  64. package/build/tools/top-change.d.ts.map +1 -0
  65. package/build/tools/top-change.js +262 -0
  66. package/build/tools/top-change.js.map +1 -0
  67. package/build/utils/aggregation-limits.d.ts +23 -0
  68. package/build/utils/aggregation-limits.d.ts.map +1 -0
  69. package/build/utils/aggregation-limits.js +32 -0
  70. package/build/utils/aggregation-limits.js.map +1 -0
  71. package/build/utils/date-math.d.ts +31 -0
  72. package/build/utils/date-math.d.ts.map +1 -0
  73. package/build/utils/date-math.js +116 -0
  74. package/build/utils/date-math.js.map +1 -0
  75. package/build/utils/field-constants.d.ts +23 -0
  76. package/build/utils/field-constants.d.ts.map +1 -0
  77. package/build/utils/field-constants.js +26 -0
  78. package/build/utils/field-constants.js.map +1 -0
  79. package/build/validation/schemas.d.ts +243 -0
  80. package/build/validation/schemas.d.ts.map +1 -0
  81. package/build/validation/schemas.js +151 -0
  82. package/build/validation/schemas.js.map +1 -0
  83. package/package.json +65 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 elastic-mcp
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,304 @@
1
+ # Elasticsearch MCP (VSee Fork)
2
+
3
+ > **Modified MCP server with hardcoded schemas matching VSee's Elasticsearch indexes. Specialized analytics tools optimized for stats-* indices.**
4
+
5
+ [![npm version](https://badge.fury.io/js/elasticsearch-mcp-vsee.svg)](https://www.npmjs.com/package/elasticsearch-mcp-vsee)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
7
+ [![Elasticsearch](https://img.shields.io/badge/Elasticsearch-005571?logo=elasticsearch&logoColor=white)](https://www.elastic.co/)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ **elasticsearch-mcp-vsee** is a modified Model Context Protocol (MCP) server that provides specialized analytics tools for Elasticsearch clusters, optimized for VSee's stats-* indices. This fork features hardcoded schemas and field names that match VSee's specific Elasticsearch index structure, enabling specialized tools for account/group analytics, visit trends, platform breakdowns, and rating distributions. Built with TypeScript and optimized for Elastic Cloud environments, it offers comprehensive analytics capabilities with enterprise-grade security features.
11
+
12
+ ## 🚀 Features
13
+
14
+ - **🔐 Secure by Design**: Input validation, script sanitization, injection prevention
15
+ - **☁️ Elastic Cloud Ready**: Native support for cloud ID and API key authentication
16
+ - **⚡ High Performance**: Connection pooling, optimized query execution, efficient aggregations
17
+ - **🛠️ Comprehensive Tools**: 11 specialized tools for analytics, summaries, and data exploration
18
+ - **📊 Advanced Querying**: Full Elasticsearch DSL support with aggregations and highlighting
19
+ - **🔍 Smart Validation**: Zod-based schemas with security-first validation
20
+ - **📝 Full TypeScript**: Complete type safety with strict null checks
21
+
22
+ ## 🎯 Purpose
23
+
24
+ This MCP server is designed for **VSee's Open WebUI deployment** to provide specialized analytics tools for querying VSee's Elasticsearch `stats-*` indices. It integrates with VSee's Open WebUI infrastructure via MCPO (MCP OpenAPI bridge) to expose Elasticsearch analytics capabilities to LLMs.
25
+
26
+ ## 📦 Usage with VSee's Open WebUI Deployment
27
+
28
+ This MCP server is automatically loaded by VSee's Open WebUI deployment through the MCP configuration. It connects to VSee's Elasticsearch deployment to provide analytics on visit statistics, account/group metrics, platform breakdowns, and more.
29
+
30
+ ### Configuration
31
+
32
+ The MCP server is configured in `vsee/mcp/config.json`:
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "elasticsearch": {
38
+ "command": "npx",
39
+ "args": ["-y", "elasticsearch-mcp-vsee"],
40
+ "env": {
41
+ "ELASTIC_NODE": "https://omtm.es.us-east-1.aws.found.io",
42
+ "ELASTIC_USERNAME": "your-username",
43
+ "ELASTIC_PASSWORD": "your-password",
44
+ "NODE_TLS_REJECT_UNAUTHORIZED": "0"
45
+ }
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ The Open WebUI deployment automatically loads this configuration and starts the MCP server via MCPO, making all 11 tools available to the LLM for querying Elasticsearch data.
52
+
53
+ ## 🔄 Updating and Publishing
54
+
55
+ ### Making Changes
56
+
57
+ 1. **Develop locally**: Make changes to the code in `elasticsearch-mcp/`
58
+ 2. **Test your changes**: Use `npm run test:tools` to test against your Elasticsearch instance
59
+ 3. **Build**: Run `npm run build` to compile TypeScript
60
+ 4. **Publish**: Publish to npm with `npm publish --access public`
61
+ - Make sure to increment the version in `package.json` first
62
+
63
+ ### Updating VSee's Deployment
64
+
65
+ After publishing a new version to npm:
66
+
67
+ 1. **Update `vsee/mcp/config.json`**: Change the package version in the `args` array:
68
+ ```json
69
+ {
70
+ "mcpServers": {
71
+ "elasticsearch": {
72
+ "command": "npx",
73
+ "args": ["-y", "elasticsearch-mcp-vsee@0.5.0"], // Update version here
74
+ "env": {
75
+ ...
76
+ }
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
82
+ 2. **Restart the MCPO service**: The MCPO container will automatically download and use the new version on restart:
83
+ ```bash
84
+ docker compose -f docker-compose.vsee.yaml restart mcpo
85
+ ```
86
+
87
+ 3. **Verify**: Check that the new version is loaded by examining the MCPO logs or testing the tools in Open WebUI.
88
+
89
+ **Note**: You can also use `@latest` to always pull the latest version, but specifying a version number is recommended for production stability.
90
+
91
+ ## 🛠️ Available Tools
92
+
93
+ | Tool | Description | Use Cases |
94
+ |------|-------------|-----------|
95
+ | `get_index_fields` | Discover index fields and types | Schema exploration, field discovery |
96
+ | `top_change` | Find top accounts or groups with highest visit increase/decrease | Trend analysis, account/group monitoring |
97
+ | `get_subscription_breakdown` | Compare subscription tiers with metrics per tier | Subscription-tier analysis and comparisons |
98
+ | `get_platform_breakdown` | Platform or platform version breakdown (provider/patient, platform/version) | Platform adoption, device preferences, version analysis |
99
+ | `get_rating_distribution` | Rating histograms with statistics | Satisfaction analysis |
100
+ | `get_visit_trends` | Time series visit trends (daily/weekly/monthly) | Trend visualization |
101
+ | `get_usage_summary` | Comprehensive metrics summary with flexible filtering and grouping | Multi-dimensional analysis and comparisons |
102
+
103
+ ## 📋 Tool Examples
104
+
105
+ ### Get Account Summary
106
+
107
+ ```json
108
+ {
109
+ "tool": "get_account_summary",
110
+ "arguments": {
111
+ "account": "example-customer",
112
+ "startDate": "now-1y",
113
+ "endDate": "now"
114
+ }
115
+ }
116
+ ```
117
+
118
+ ### Get Top Accounts by Growth
119
+
120
+ ```json
121
+ {
122
+ "tool": "top_change",
123
+ "arguments": {
124
+ "groupBy": "account",
125
+ "direction": "increase",
126
+ "topN": 10,
127
+ "currentPeriodDays": 30,
128
+ "previousPeriodDays": 30
129
+ }
130
+ }
131
+ ```
132
+
133
+ ### Get Platform Breakdown
134
+
135
+ ```json
136
+ {
137
+ "tool": "get_platform_breakdown",
138
+ "arguments": {
139
+ "role": "provider",
140
+ "breakdownType": "version",
141
+ "topN": 10,
142
+ "startDate": "now-30d",
143
+ "endDate": "now"
144
+ }
145
+ }
146
+ ```
147
+
148
+ ### Get Visit Trends
149
+
150
+ ```json
151
+ {
152
+ "tool": "get_visit_trends",
153
+ "arguments": {
154
+ "interval": "daily",
155
+ "startDate": "now-30d",
156
+ "endDate": "now",
157
+ "groupBy": "subscription"
158
+ }
159
+ }
160
+ ```
161
+
162
+ ## ⚙️ Configuration
163
+
164
+ ### Environment Variables
165
+
166
+ The MCP server reads configuration from environment variables. These are set in `vsee/mcp/config.json` under the `env` section:
167
+
168
+ | Variable | Description | Required | Example |
169
+ |----------|-------------|----------|---------|
170
+ | `ELASTIC_NODE` | Elasticsearch URL | Yes | `https://omtm.es.us-east-1.aws.found.io` |
171
+ | `ELASTIC_USERNAME` | Basic auth username | Yes | `your-username` |
172
+ | `ELASTIC_PASSWORD` | Basic auth password | Yes | `your-password` |
173
+ | `NODE_TLS_REJECT_UNAUTHORIZED` | Disable TLS verification (for self-signed certs) | No | `"0"` |
174
+
175
+ ### Alternative: Elastic Cloud Authentication
176
+
177
+ If using Elastic Cloud with cloud ID and API key:
178
+
179
+ | Variable | Description | Required |
180
+ |----------|-------------|----------|
181
+ | `ELASTIC_CLOUD_ID` | Elastic Cloud deployment ID | Yes* |
182
+ | `ELASTIC_API_KEY` | Elasticsearch API key | Yes* |
183
+
184
+ *Either `ELASTIC_CLOUD_ID` + `ELASTIC_API_KEY` OR `ELASTIC_NODE` + `ELASTIC_USERNAME` + `ELASTIC_PASSWORD` is required
185
+
186
+ ## 🔒 Security Features
187
+
188
+ ### Input Validation
189
+ - **Zod Schemas**: Strict type validation for all inputs
190
+ - **Field Name Validation**: Prevents reserved field usage
191
+ - **Size Limits**: Document size, array length, string length limits
192
+ - **Depth Validation**: Prevents deeply nested objects/queries
193
+
194
+ ### Script Security
195
+ - **Script Sanitization**: Blocks dangerous script patterns
196
+ - **Parameter Validation**: Validates script parameters
197
+ - **Execution Limits**: Prevents resource exhaustion
198
+
199
+ ### Query Security
200
+ - **Injection Prevention**: Sanitizes and validates all queries
201
+ - **Script Query Blocking**: Prevents script-based queries in sensitive operations
202
+ - **Rate Limiting**: Protects against abuse
203
+
204
+ ### Data Protection
205
+ - **Credential Masking**: Never logs sensitive information
206
+ - **Secure Connections**: TLS/SSL support
207
+ - **Access Control**: Validates permissions before operations
208
+
209
+ ## 🏗️ Architecture
210
+
211
+ ```
212
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
213
+ │ MCP Client │◄──►│Elasticsearch MCP│◄──►│ Elasticsearch │
214
+ │ (Claude, etc.) │ │ Server │ │ Cluster │
215
+ └─────────────────┘ └─────────────────┘ └─────────────────┘
216
+
217
+ ┌─────────────┐
218
+ │ Tools │
219
+ │ │
220
+ │ • search │
221
+ │ • fields │
222
+ │ • summaries │
223
+ │ • trends │
224
+ │ • analytics │
225
+ └─────────────┘
226
+ ```
227
+
228
+ ## 📊 Performance
229
+
230
+ ### Benchmarks
231
+ - **Search**: <500ms average response time
232
+ - **Aggregations**: Optimized for large-scale analytics
233
+ - **Memory Usage**: <100MB for typical operations
234
+ - **Concurrent Requests**: Up to 10 simultaneous operations
235
+
236
+ ### Optimization Features
237
+ - **Connection Pooling**: Reuses Elasticsearch connections
238
+ - **Optimized Queries**: Efficient aggregation pipelines
239
+ - **Smart Caching**: Reduced redundant queries
240
+ - **Health Monitoring**: Automatic reconnection on failures
241
+
242
+ ## 🔧 Development
243
+
244
+ ### Setup Development Environment
245
+
246
+ ```bash
247
+ # Install dependencies
248
+ npm install
249
+
250
+ # Set up environment variables
251
+ export ELASTIC_NODE="https://your-elasticsearch-url"
252
+ export ELASTIC_USERNAME="your-username"
253
+ export ELASTIC_PASSWORD="your-password"
254
+ export NODE_TLS_REJECT_UNAUTHORIZED="0" # If needed for self-signed certs
255
+
256
+ # Run in development mode
257
+ npm run dev
258
+
259
+ # Test tools against live Elasticsearch
260
+ npm run test:tools
261
+
262
+ # Build for production
263
+ npm run build
264
+
265
+ # Publish new version (after incrementing version in package.json)
266
+ npm publish --access public
267
+ ```
268
+
269
+ ### Project Structure
270
+
271
+ ```
272
+ elasticsearch-mcp/
273
+ ├── src/
274
+ │ ├── tools/ # MCP tool implementations
275
+ │ ├── elasticsearch/ # ES client and connection management
276
+ │ ├── validation/ # Input validation schemas
277
+ │ ├── errors/ # Error handling utilities
278
+ │ ├── config.ts # Configuration management
279
+ │ ├── logger.ts # Structured logging
280
+ │ └── server.ts # Main MCP server
281
+ ├── tests/ # Test suite
282
+ └── build/ # Compiled output
283
+ ```
284
+
285
+ ## 📄 License
286
+
287
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
288
+
289
+ ## 🏷️ Version History
290
+
291
+ - **v0.5.0** - Added `find_entities_by_metric` tool with multi-metric filtering support, updated default limits
292
+ - **v0.4.0** - Tool consolidation: merged 14 tools into 11 specialized analytics tools
293
+ - **v0.3.0** - Specialized analytics tools for stats-* indices
294
+ - Full changelog: [CHANGELOG.md](CHANGELOG.md)
295
+
296
+ ## 🔗 Links
297
+
298
+ - [npm Package](https://www.npmjs.com/package/elasticsearch-mcp-vsee)
299
+ - [Elasticsearch Documentation](https://www.elastic.co/guide/)
300
+ - [Model Context Protocol](https://modelcontextprotocol.io/)
301
+
302
+ ---
303
+
304
+ **Built for VSee by VSee**
@@ -0,0 +1,76 @@
1
+ import { z } from 'zod';
2
+ export declare const ElasticConfigSchema: z.ZodObject<{
3
+ cloudId: z.ZodOptional<z.ZodString>;
4
+ apiKey: z.ZodOptional<z.ZodString>;
5
+ node: z.ZodOptional<z.ZodString>;
6
+ auth: z.ZodOptional<z.ZodObject<{
7
+ username: z.ZodString;
8
+ password: z.ZodString;
9
+ }, "strip", z.ZodTypeAny, {
10
+ username: string;
11
+ password: string;
12
+ }, {
13
+ username: string;
14
+ password: string;
15
+ }>>;
16
+ maxRetries: z.ZodDefault<z.ZodNumber>;
17
+ requestTimeout: z.ZodDefault<z.ZodNumber>;
18
+ pingTimeout: z.ZodDefault<z.ZodNumber>;
19
+ sniffOnStart: z.ZodDefault<z.ZodBoolean>;
20
+ sniffInterval: z.ZodOptional<z.ZodNumber>;
21
+ ssl: z.ZodOptional<z.ZodObject<{
22
+ rejectUnauthorized: z.ZodDefault<z.ZodBoolean>;
23
+ }, "strip", z.ZodTypeAny, {
24
+ rejectUnauthorized: boolean;
25
+ }, {
26
+ rejectUnauthorized?: boolean | undefined;
27
+ }>>;
28
+ }, "strip", z.ZodTypeAny, {
29
+ maxRetries: number;
30
+ requestTimeout: number;
31
+ pingTimeout: number;
32
+ sniffOnStart: boolean;
33
+ cloudId?: string | undefined;
34
+ apiKey?: string | undefined;
35
+ node?: string | undefined;
36
+ auth?: {
37
+ username: string;
38
+ password: string;
39
+ } | undefined;
40
+ sniffInterval?: number | undefined;
41
+ ssl?: {
42
+ rejectUnauthorized: boolean;
43
+ } | undefined;
44
+ }, {
45
+ cloudId?: string | undefined;
46
+ apiKey?: string | undefined;
47
+ node?: string | undefined;
48
+ auth?: {
49
+ username: string;
50
+ password: string;
51
+ } | undefined;
52
+ maxRetries?: number | undefined;
53
+ requestTimeout?: number | undefined;
54
+ pingTimeout?: number | undefined;
55
+ sniffOnStart?: boolean | undefined;
56
+ sniffInterval?: number | undefined;
57
+ ssl?: {
58
+ rejectUnauthorized?: boolean | undefined;
59
+ } | undefined;
60
+ }>;
61
+ export type ElasticConfig = z.infer<typeof ElasticConfigSchema>;
62
+ export interface ServerConfig {
63
+ name: string;
64
+ version: string;
65
+ elasticsearch: ElasticConfig;
66
+ logging: {
67
+ level: 'error' | 'warn' | 'info' | 'debug';
68
+ format: 'json' | 'text';
69
+ };
70
+ server: {
71
+ maxConcurrentRequests: number;
72
+ requestTimeoutMs: number;
73
+ };
74
+ }
75
+ export declare function loadConfig(): ServerConfig;
76
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgB9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,EAAE;QACP,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;QAC3C,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;KACzB,CAAC;IACF,MAAM,EAAE;QACN,qBAAqB,EAAE,MAAM,CAAC;QAC9B,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,wBAAgB,UAAU,IAAI,YAAY,CA4BzC"}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ElasticConfigSchema = void 0;
4
+ exports.loadConfig = loadConfig;
5
+ const zod_1 = require("zod");
6
+ exports.ElasticConfigSchema = zod_1.z.object({
7
+ cloudId: zod_1.z.string().optional(),
8
+ apiKey: zod_1.z.string().optional(),
9
+ node: zod_1.z.string().optional(),
10
+ auth: zod_1.z.object({
11
+ username: zod_1.z.string(),
12
+ password: zod_1.z.string(),
13
+ }).optional(),
14
+ maxRetries: zod_1.z.number().min(0).max(10).default(3),
15
+ requestTimeout: zod_1.z.number().min(1000).max(300000).default(30000),
16
+ pingTimeout: zod_1.z.number().min(1000).max(30000).default(3000),
17
+ sniffOnStart: zod_1.z.boolean().default(false),
18
+ sniffInterval: zod_1.z.number().positive().optional(),
19
+ ssl: zod_1.z.object({
20
+ rejectUnauthorized: zod_1.z.boolean().default(true),
21
+ }).optional(),
22
+ });
23
+ function loadConfig() {
24
+ const config = {
25
+ name: 'elasticsearch-mcp',
26
+ version: '0.1.3',
27
+ elasticsearch: exports.ElasticConfigSchema.parse({
28
+ cloudId: process.env.ELASTIC_CLOUD_ID,
29
+ apiKey: process.env.ELASTIC_API_KEY,
30
+ node: process.env.ELASTIC_NODE,
31
+ auth: process.env.ELASTIC_USERNAME && process.env.ELASTIC_PASSWORD ? {
32
+ username: process.env.ELASTIC_USERNAME,
33
+ password: process.env.ELASTIC_PASSWORD,
34
+ } : undefined,
35
+ maxRetries: process.env.ELASTIC_MAX_RETRIES ? parseInt(process.env.ELASTIC_MAX_RETRIES, 10) : 3,
36
+ requestTimeout: process.env.ELASTIC_REQUEST_TIMEOUT ? parseInt(process.env.ELASTIC_REQUEST_TIMEOUT, 10) : 30000,
37
+ pingTimeout: process.env.ELASTIC_PING_TIMEOUT ? parseInt(process.env.ELASTIC_PING_TIMEOUT, 10) : 3000,
38
+ }),
39
+ logging: {
40
+ level: process.env.LOG_LEVEL || 'info',
41
+ format: process.env.LOG_FORMAT || 'text',
42
+ },
43
+ server: {
44
+ maxConcurrentRequests: process.env.MAX_CONCURRENT_REQUESTS ? parseInt(process.env.MAX_CONCURRENT_REQUESTS, 10) : 10,
45
+ requestTimeoutMs: process.env.REQUEST_TIMEOUT_MS ? parseInt(process.env.REQUEST_TIMEOUT_MS, 10) : 30000,
46
+ },
47
+ };
48
+ validateConfig(config);
49
+ return config;
50
+ }
51
+ function validateConfig(config) {
52
+ const { elasticsearch } = config;
53
+ if (!elasticsearch.cloudId && !elasticsearch.node) {
54
+ throw new Error('Either ELASTIC_CLOUD_ID or ELASTIC_NODE must be provided');
55
+ }
56
+ if (elasticsearch.cloudId && !elasticsearch.apiKey) {
57
+ throw new Error('ELASTIC_API_KEY is required when using Elastic Cloud');
58
+ }
59
+ if (elasticsearch.node && !elasticsearch.auth && !elasticsearch.apiKey) {
60
+ throw new Error('Authentication (username/password or API key) is required');
61
+ }
62
+ }
63
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { Client } from '@elastic/elasticsearch';
2
+ import { ElasticConfig } from '../config.js';
3
+ import { Logger } from '../logger.js';
4
+ export interface ConnectionInfo {
5
+ isConnected: boolean;
6
+ clusterName?: string;
7
+ version?: string;
8
+ lastHealthCheck: Date;
9
+ error?: string;
10
+ }
11
+ export declare class ElasticsearchManager {
12
+ private client;
13
+ private config;
14
+ private logger;
15
+ private connectionInfo;
16
+ private healthCheckInterval;
17
+ constructor(config: ElasticConfig, logger: Logger);
18
+ initialize(): Promise<void>;
19
+ healthCheck(): Promise<boolean>;
20
+ reconnect(): Promise<void>;
21
+ getClient(): Client;
22
+ getConnectionInfo(): ConnectionInfo;
23
+ private startHealthMonitoring;
24
+ shutdown(): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/elasticsearch/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,mBAAmB,CAA+B;gBAE9C,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM;IAS3C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA2D3B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAiB/B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAUhC,SAAS,IAAI,MAAM;IAUnB,iBAAiB,IAAI,cAAc;IAInC,OAAO,CAAC,qBAAqB;IAOvB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAmBhC"}
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ElasticsearchManager = void 0;
4
+ const elasticsearch_1 = require("@elastic/elasticsearch");
5
+ class ElasticsearchManager {
6
+ client = null;
7
+ config;
8
+ logger;
9
+ connectionInfo;
10
+ healthCheckInterval = null;
11
+ constructor(config, logger) {
12
+ this.config = config;
13
+ this.logger = logger.child({ component: 'elasticsearch' });
14
+ this.connectionInfo = {
15
+ isConnected: false,
16
+ lastHealthCheck: new Date(),
17
+ };
18
+ }
19
+ async initialize() {
20
+ try {
21
+ this.logger.info('Initializing Elasticsearch client', {
22
+ cloudId: this.config.cloudId ? '***' : undefined,
23
+ node: this.config.node,
24
+ hasApiKey: !!this.config.apiKey,
25
+ hasAuth: !!this.config.auth,
26
+ });
27
+ const clientOptions = {
28
+ maxRetries: this.config.maxRetries,
29
+ requestTimeout: this.config.requestTimeout,
30
+ pingTimeout: this.config.pingTimeout,
31
+ sniffOnStart: this.config.sniffOnStart,
32
+ ...(this.config.sniffInterval && { sniffInterval: this.config.sniffInterval }),
33
+ };
34
+ if (this.config.cloudId) {
35
+ clientOptions.cloud = { id: this.config.cloudId };
36
+ if (this.config.apiKey) {
37
+ clientOptions.auth = { apiKey: this.config.apiKey };
38
+ }
39
+ }
40
+ else if (this.config.node) {
41
+ clientOptions.node = this.config.node;
42
+ if (this.config.apiKey) {
43
+ clientOptions.auth = { apiKey: this.config.apiKey };
44
+ }
45
+ else if (this.config.auth) {
46
+ clientOptions.auth = {
47
+ username: this.config.auth.username,
48
+ password: this.config.auth.password,
49
+ };
50
+ }
51
+ }
52
+ if (this.config.ssl) {
53
+ clientOptions.tls = {
54
+ rejectUnauthorized: this.config.ssl.rejectUnauthorized,
55
+ };
56
+ }
57
+ this.client = new elasticsearch_1.Client(clientOptions);
58
+ // Mark as connected immediately - actual API calls will handle connection errors
59
+ // Health checks with limited permissions often fail, so we skip them
60
+ this.connectionInfo = {
61
+ isConnected: true,
62
+ lastHealthCheck: new Date(),
63
+ };
64
+ // Start health monitoring (non-blocking, won't cause failures)
65
+ this.startHealthMonitoring();
66
+ this.logger.info('Elasticsearch client initialized successfully');
67
+ }
68
+ catch (error) {
69
+ this.logger.error('Failed to initialize Elasticsearch client', {}, error);
70
+ throw error;
71
+ }
72
+ }
73
+ async healthCheck() {
74
+ if (!this.client) {
75
+ this.connectionInfo = {
76
+ isConnected: false,
77
+ lastHealthCheck: new Date(),
78
+ error: 'Client not initialized',
79
+ };
80
+ return false;
81
+ }
82
+ // For users with limited permissions, we skip health checks
83
+ // The client is marked as connected, and actual API calls will handle errors gracefully
84
+ // Health checks requiring cluster privileges often fail unnecessarily
85
+ this.connectionInfo.lastHealthCheck = new Date();
86
+ return this.connectionInfo.isConnected;
87
+ }
88
+ async reconnect() {
89
+ this.logger.info('Attempting to reconnect to Elasticsearch');
90
+ if (this.client) {
91
+ await this.client.close();
92
+ }
93
+ await this.initialize();
94
+ }
95
+ getClient() {
96
+ if (!this.client) {
97
+ throw new Error('Elasticsearch client not initialized');
98
+ }
99
+ // Don't check isConnected - let the actual API calls handle connection errors
100
+ // This allows tools to work even if health checks fail due to permissions
101
+ return this.client;
102
+ }
103
+ getConnectionInfo() {
104
+ return { ...this.connectionInfo };
105
+ }
106
+ startHealthMonitoring() {
107
+ // Disabled health monitoring for users with limited permissions
108
+ // Periodic health checks often fail unnecessarily and cause reconnections
109
+ // Actual API calls will handle connection errors gracefully
110
+ this.logger.debug('Health monitoring disabled (limited permissions mode)');
111
+ }
112
+ async shutdown() {
113
+ this.logger.info('Shutting down Elasticsearch manager');
114
+ if (this.healthCheckInterval) {
115
+ clearInterval(this.healthCheckInterval);
116
+ this.healthCheckInterval = null;
117
+ }
118
+ if (this.client) {
119
+ try {
120
+ await this.client.close();
121
+ this.logger.info('Elasticsearch client closed');
122
+ }
123
+ catch (error) {
124
+ this.logger.warn('Error closing Elasticsearch client', { error: error.message });
125
+ }
126
+ }
127
+ this.connectionInfo.isConnected = false;
128
+ }
129
+ }
130
+ exports.ElasticsearchManager = ElasticsearchManager;
131
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/elasticsearch/client.ts"],"names":[],"mappings":"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"}