es-mcp-server 1.0.0

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 (4) hide show
  1. package/README.md +182 -0
  2. package/bin/cli.js +10 -0
  3. package/index.js +435 -0
  4. package/package.json +32 -0
package/README.md ADDED
@@ -0,0 +1,182 @@
1
+ # Elasticsearch MCP Server
2
+
3
+ 这是一个为 Elasticsearch 设计的 MCP (Model Context Protocol) 服务器,允许通过 Claude Code 直接管理和查询 Elasticsearch 集群。
4
+
5
+ ## 功能特性
6
+
7
+ - ✅ 集群健康检查
8
+ - ✅ 索引管理(创建、删除、查看)
9
+ - ✅ 文档操作(增删改查)
10
+ - ✅ 搜索和查询
11
+ - ✅ 集群信息获取
12
+ - ✅ 支持认证(用户名/密码 或 API Key)
13
+
14
+ ## 安装
15
+
16
+ ### 方式一:npm 全局安装(推荐)
17
+
18
+ ```bash
19
+ npm install -g es-mcp-server
20
+ ```
21
+
22
+ ### 方式二:从本地安装
23
+
24
+ ```bash
25
+ cd <path-to-es-mcp-server>
26
+ npm install -g .
27
+ ```
28
+
29
+ ### 方式三:开发模式
30
+
31
+ ```bash
32
+ cd <path-to-es-mcp-server>
33
+ npm install
34
+ npm start
35
+ ```
36
+
37
+ ## 配置
38
+
39
+ ### 环境变量(可选)
40
+
41
+ ```bash
42
+ export ES_HOST="localhost:9200"
43
+ export ES_USERNAME="your_username" # 如果需要认证
44
+ export ES_PASSWORD="your_password" # 如果需要认证
45
+ export ES_API_KEY="your_api_key" # 如果使用 API Key 认证
46
+ ```
47
+
48
+ ## 使用方法
49
+
50
+ ### 集成到 Claude Code
51
+
52
+ 将以下配置添加到你的 Claude Code MCP 配置中:
53
+
54
+ **使用 npm 全局安装的命令:**
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "elasticsearch": {
60
+ "command": "es-mcp-server",
61
+ "env": {
62
+ "ES_HOST": "localhost:9200"
63
+ }
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ **开发模式(从源码运行):**
70
+
71
+ ```json
72
+ {
73
+ "mcpServers": {
74
+ "elasticsearch": {
75
+ "command": "node",
76
+ "args": ["<path-to-es-mcp-server>/index.js"],
77
+ "env": {
78
+ "ES_HOST": "localhost:9200"
79
+ }
80
+ }
81
+ }
82
+ }
83
+ ```
84
+
85
+ ## 可用工具
86
+
87
+ | 工具名称 | 描述 | 参数 |
88
+ |---------|------|------|
89
+ | `es_health_check` | 检查集群健康状态 | 无 |
90
+ | `es_list_indices` | 列出所有索引 | `pattern` (可选) - 索引模式 |
91
+ | `es_create_index` | 创建新索引 | `index` (必需) - 索引名<br>`mappings` (可选) - 映射<br>`settings` (可选) - 设置 |
92
+ | `es_delete_index` | 删除索引 | `index` (必需) - 索引名 |
93
+ | `es_index_document` | 索引文档 | `index` (必需) - 索引名<br>`document` (必需) - 文档内容<br>`id` (可选) - 文档ID |
94
+ | `es_get_document` | 获取文档 | `index` (必需) - 索引名<br>`id` (必需) - 文档ID |
95
+ | `es_search` | 搜索文档 | `index` (必需) - 索引名<br>`query` (可选) - 查询DSL<br>`size` (可选) - 返回数量<br>`from` (可选) - 偏移量 |
96
+ | `es_update_document` | 更新文档 | `index` (必需) - 索引名<br>`id` (必需) - 文档ID<br>`document` (必需) - 更新内容 |
97
+ | `es_delete_document` | 删除文档 | `index` (必需) - 索引名<br>`id` (必需) - 文档ID |
98
+ | `es_cluster_info` | 获取集群信息 | 无 |
99
+
100
+ ## 使用示例
101
+
102
+ ### 检查集群健康
103
+ ```javascript
104
+ // 使用 MCP 工具
105
+ await mcpCall("es_health_check", {});
106
+ ```
107
+
108
+ ### 创建索引
109
+ ```javascript
110
+ await mcpCall("es_create_index", {
111
+ index: "products",
112
+ mappings: {
113
+ properties: {
114
+ name: { type: "text" },
115
+ price: { type: "float" },
116
+ category: { type: "keyword" }
117
+ }
118
+ }
119
+ });
120
+ ```
121
+
122
+ ### 索引文档
123
+ ```javascript
124
+ await mcpCall("es_index_document", {
125
+ index: "products",
126
+ document: {
127
+ name: "iPhone 15",
128
+ price: 999.99,
129
+ category: "Electronics"
130
+ }
131
+ });
132
+ ```
133
+
134
+ ### 搜索文档
135
+ ```javascript
136
+ await mcpCall("es_search", {
137
+ index: "products",
138
+ query: {
139
+ query: {
140
+ match: {
141
+ name: "iPhone"
142
+ }
143
+ }
144
+ },
145
+ size: 10
146
+ });
147
+ ```
148
+
149
+ ## 认证配置
150
+
151
+ ### 用户名/密码认证
152
+ ```bash
153
+ export ES_USERNAME="elastic"
154
+ export ES_PASSWORD="your_password"
155
+ ```
156
+
157
+ ### API Key 认证
158
+ ```bash
159
+ export ES_API_KEY="your_base64_encoded_api_key"
160
+ ```
161
+
162
+ ## 故障排除
163
+
164
+ 1. **连接失败**:确保 Elasticsearch 服务正在运行且可访问
165
+ 2. **认证错误**:检查用户名/密码或 API Key 是否正确
166
+ 3. **权限错误**:确保用户有足够的权限执行请求的操作
167
+
168
+ ## 开发
169
+
170
+ ### 开发模式运行
171
+ ```bash
172
+ npm run dev
173
+ ```
174
+
175
+ ### 添加新工具
176
+ 1. 在 `index.js` 的 `ListToolsRequestSchema` 处理程序中添加工具定义
177
+ 2. 在 `CallToolRequestSchema` 处理程序中添加相应的 case
178
+ 3. 测试新功能
179
+
180
+ ## 许可证
181
+
182
+ MIT License
package/bin/cli.js ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname, join } from 'path';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ // Import and run the main server
10
+ import(join(__dirname, '../index.js'));
package/index.js ADDED
@@ -0,0 +1,435 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import {
6
+ CallToolRequestSchema,
7
+ ListToolsRequestSchema,
8
+ } from "@modelcontextprotocol/sdk/types.js";
9
+ import { Client } from "@elastic/elasticsearch";
10
+
11
+ // Elasticsearch client
12
+ let esClient;
13
+
14
+ // MCP Server
15
+ const server = new Server(
16
+ {
17
+ name: "elasticsearch-mcp",
18
+ version: "1.0.0",
19
+ },
20
+ {
21
+ capabilities: {
22
+ tools: {},
23
+ },
24
+ }
25
+ );
26
+
27
+ // Initialize Elasticsearch client
28
+ function initESClient() {
29
+ const esHost = process.env.ES_HOST || "localhost:9200";
30
+ const esUsername = process.env.ES_USERNAME;
31
+ const esPassword = process.env.ES_PASSWORD;
32
+ const esApiKey = process.env.ES_API_KEY;
33
+
34
+ const clientConfig = {
35
+ node: `http://${esHost}`,
36
+ requestTimeout: 30000,
37
+ sniffOnStart: true,
38
+ };
39
+
40
+ if (esApiKey) {
41
+ clientConfig.auth = {
42
+ apiKey: esApiKey,
43
+ };
44
+ } else if (esUsername && esPassword) {
45
+ clientConfig.auth = {
46
+ username: esUsername,
47
+ password: esPassword,
48
+ };
49
+ }
50
+
51
+ esClient = new Client(clientConfig);
52
+ }
53
+
54
+ // List available tools
55
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
56
+ return {
57
+ tools: [
58
+ {
59
+ name: "es_health_check",
60
+ description: "Check Elasticsearch cluster health",
61
+ inputSchema: {
62
+ type: "object",
63
+ properties: {},
64
+ },
65
+ },
66
+ {
67
+ name: "es_list_indices",
68
+ description: "List all indices in the cluster",
69
+ inputSchema: {
70
+ type: "object",
71
+ properties: {
72
+ pattern: {
73
+ type: "string",
74
+ description: "Index pattern (default: '*')",
75
+ },
76
+ },
77
+ },
78
+ },
79
+ {
80
+ name: "es_create_index",
81
+ description: "Create a new index",
82
+ inputSchema: {
83
+ type: "object",
84
+ properties: {
85
+ index: {
86
+ type: "string",
87
+ description: "Index name",
88
+ },
89
+ mappings: {
90
+ type: "object",
91
+ description: "Index mappings (optional)",
92
+ },
93
+ settings: {
94
+ type: "object",
95
+ description: "Index settings (optional)",
96
+ },
97
+ },
98
+ required: ["index"],
99
+ },
100
+ },
101
+ {
102
+ name: "es_delete_index",
103
+ description: "Delete an index",
104
+ inputSchema: {
105
+ type: "object",
106
+ properties: {
107
+ index: {
108
+ type: "string",
109
+ description: "Index name",
110
+ },
111
+ },
112
+ required: ["index"],
113
+ },
114
+ },
115
+ {
116
+ name: "es_index_document",
117
+ description: "Index a document",
118
+ inputSchema: {
119
+ type: "object",
120
+ properties: {
121
+ index: {
122
+ type: "string",
123
+ description: "Index name",
124
+ },
125
+ id: {
126
+ type: "string",
127
+ description: "Document ID (optional, will be auto-generated if not provided)",
128
+ },
129
+ document: {
130
+ type: "object",
131
+ description: "Document content",
132
+ },
133
+ },
134
+ required: ["index", "document"],
135
+ },
136
+ },
137
+ {
138
+ name: "es_get_document",
139
+ description: "Get a document by ID",
140
+ inputSchema: {
141
+ type: "object",
142
+ properties: {
143
+ index: {
144
+ type: "string",
145
+ description: "Index name",
146
+ },
147
+ id: {
148
+ type: "string",
149
+ description: "Document ID",
150
+ },
151
+ },
152
+ required: ["index", "id"],
153
+ },
154
+ },
155
+ {
156
+ name: "es_search",
157
+ description: "Search documents",
158
+ inputSchema: {
159
+ type: "object",
160
+ properties: {
161
+ index: {
162
+ type: "string",
163
+ description: "Index name or pattern",
164
+ },
165
+ query: {
166
+ type: "object",
167
+ description: "Search query DSL",
168
+ },
169
+ size: {
170
+ type: "number",
171
+ description: "Number of results to return (default: 10)",
172
+ },
173
+ from: {
174
+ type: "number",
175
+ description: "Starting offset (default: 0)",
176
+ },
177
+ },
178
+ required: ["index"],
179
+ },
180
+ },
181
+ {
182
+ name: "es_update_document",
183
+ description: "Update a document",
184
+ inputSchema: {
185
+ type: "object",
186
+ properties: {
187
+ index: {
188
+ type: "string",
189
+ description: "Index name",
190
+ },
191
+ id: {
192
+ type: "string",
193
+ description: "Document ID",
194
+ },
195
+ document: {
196
+ type: "object",
197
+ description: "Partial document to update",
198
+ },
199
+ },
200
+ required: ["index", "id", "document"],
201
+ },
202
+ },
203
+ {
204
+ name: "es_delete_document",
205
+ description: "Delete a document",
206
+ inputSchema: {
207
+ type: "object",
208
+ properties: {
209
+ index: {
210
+ type: "string",
211
+ description: "Index name",
212
+ },
213
+ id: {
214
+ type: "string",
215
+ description: "Document ID",
216
+ },
217
+ },
218
+ required: ["index", "id"],
219
+ },
220
+ },
221
+ {
222
+ name: "es_cluster_info",
223
+ description: "Get cluster information",
224
+ inputSchema: {
225
+ type: "object",
226
+ properties: {},
227
+ },
228
+ },
229
+ ],
230
+ };
231
+ });
232
+
233
+ // Handle tool calls
234
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
235
+ const { name, arguments: args } = request.params;
236
+
237
+ try {
238
+ if (!esClient) {
239
+ initESClient();
240
+ }
241
+
242
+ switch (name) {
243
+ case "es_health_check":
244
+ const health = await esClient.cluster.health();
245
+ return {
246
+ content: [
247
+ {
248
+ type: "text",
249
+ text: JSON.stringify(health, null, 2),
250
+ },
251
+ ],
252
+ };
253
+
254
+ case "es_list_indices":
255
+ const indices = await esClient.cat.indices({
256
+ format: "json",
257
+ index: args.pattern || "*",
258
+ });
259
+ return {
260
+ content: [
261
+ {
262
+ type: "text",
263
+ text: JSON.stringify(indices, null, 2),
264
+ },
265
+ ],
266
+ };
267
+
268
+ case "es_create_index":
269
+ const createParams = {
270
+ index: args.index,
271
+ };
272
+ if (args.mappings) {
273
+ createParams.mappings = args.mappings;
274
+ }
275
+ if (args.settings) {
276
+ createParams.settings = args.settings;
277
+ }
278
+ const createResult = await esClient.indices.create(createParams);
279
+ return {
280
+ content: [
281
+ {
282
+ type: "text",
283
+ text: JSON.stringify(createResult, null, 2),
284
+ },
285
+ ],
286
+ };
287
+
288
+ case "es_delete_index":
289
+ const deleteResult = await esClient.indices.delete({
290
+ index: args.index,
291
+ });
292
+ return {
293
+ content: [
294
+ {
295
+ type: "text",
296
+ text: JSON.stringify(deleteResult, null, 2),
297
+ },
298
+ ],
299
+ };
300
+
301
+ case "es_index_document":
302
+ const indexParams = {
303
+ index: args.index,
304
+ body: args.document,
305
+ };
306
+ if (args.id) {
307
+ indexParams.id = args.id;
308
+ }
309
+ const indexResult = await esClient.index(indexParams);
310
+ return {
311
+ content: [
312
+ {
313
+ type: "text",
314
+ text: JSON.stringify(indexResult, null, 2),
315
+ },
316
+ ],
317
+ };
318
+
319
+ case "es_get_document":
320
+ const doc = await esClient.get({
321
+ index: args.index,
322
+ id: args.id,
323
+ });
324
+ return {
325
+ content: [
326
+ {
327
+ type: "text",
328
+ text: JSON.stringify(doc, null, 2),
329
+ },
330
+ ],
331
+ };
332
+
333
+ case "es_search":
334
+ const searchParams = {
335
+ index: args.index,
336
+ body: args.query || { query: { match_all: {} } },
337
+ };
338
+ if (args.size) {
339
+ searchParams.size = args.size;
340
+ }
341
+ if (args.from) {
342
+ searchParams.from = args.from;
343
+ }
344
+ const searchResult = await esClient.search(searchParams);
345
+ return {
346
+ content: [
347
+ {
348
+ type: "text",
349
+ text: JSON.stringify(searchResult, null, 2),
350
+ },
351
+ ],
352
+ };
353
+
354
+ case "es_update_document":
355
+ const updateResult = await esClient.update({
356
+ index: args.index,
357
+ id: args.id,
358
+ body: { doc: args.document },
359
+ });
360
+ return {
361
+ content: [
362
+ {
363
+ type: "text",
364
+ text: JSON.stringify(updateResult, null, 2),
365
+ },
366
+ ],
367
+ };
368
+
369
+ case "es_delete_document":
370
+ const deleteDocResult = await esClient.delete({
371
+ index: args.index,
372
+ id: args.id,
373
+ });
374
+ return {
375
+ content: [
376
+ {
377
+ type: "text",
378
+ text: JSON.stringify(deleteDocResult, null, 2),
379
+ },
380
+ ],
381
+ };
382
+
383
+ case "es_cluster_info":
384
+ const info = await esClient.info();
385
+ const nodes = await esClient.nodes.stats();
386
+ return {
387
+ content: [
388
+ {
389
+ type: "text",
390
+ text: JSON.stringify(
391
+ {
392
+ cluster_info: info,
393
+ nodes_stats: nodes,
394
+ },
395
+ null,
396
+ 2
397
+ ),
398
+ },
399
+ ],
400
+ };
401
+
402
+ default:
403
+ throw new Error(`Unknown tool: ${name}`);
404
+ }
405
+ } catch (error) {
406
+ return {
407
+ content: [
408
+ {
409
+ type: "text",
410
+ text: JSON.stringify(
411
+ {
412
+ error: error.message,
413
+ details: error.meta?.body || error.stack,
414
+ },
415
+ null,
416
+ 2
417
+ ),
418
+ },
419
+ ],
420
+ isError: true,
421
+ };
422
+ }
423
+ });
424
+
425
+ // Start the server
426
+ async function main() {
427
+ const transport = new StdioServerTransport();
428
+ await server.connect(transport);
429
+ console.error("Elasticsearch MCP Server running on stdio");
430
+ }
431
+
432
+ main().catch((error) => {
433
+ console.error("Server error:", error);
434
+ process.exit(1);
435
+ });
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "es-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "Elasticsearch MCP Server for Claude Code",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "es-mcp-server": "bin/cli.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node index.js",
12
+ "dev": "node --watch index.js"
13
+ },
14
+ "keywords": [
15
+ "mcp",
16
+ "elasticsearch",
17
+ "claude-code"
18
+ ],
19
+ "author": "",
20
+ "license": "MIT",
21
+ "dependencies": {
22
+ "@modelcontextprotocol/sdk": "^0.6.0",
23
+ "@elastic/elasticsearch": "^8.12.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^20.0.0"
27
+ },
28
+ "files": [
29
+ "index.js",
30
+ "bin/"
31
+ ]
32
+ }