opensearch-mcp-server 2.0.2__py3-none-any.whl → 2.0.3__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opensearch-mcp-server
3
- Version: 2.0.2
3
+ Version: 2.0.3
4
4
  Summary: MCP Server for interacting with Elasticsearch and OpenSearch
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -211,6 +211,7 @@ Requires-Dist: fastmcp==0.4.1
211
211
  Requires-Dist: mcp==1.6.0
212
212
  Requires-Dist: opensearch-py==2.8.0
213
213
  Requires-Dist: python-dotenv==1.1.0
214
+ Requires-Dist: toml==0.10.2
214
215
  Requires-Dist: tomli-w==1.2.0
215
216
  Requires-Dist: tomli==2.2.1
216
217
  Description-Content-Type: text/markdown
@@ -231,6 +232,10 @@ https://github.com/user-attachments/assets/f7409e31-fac4-4321-9c94-b0ff2ea7ff15
231
232
 
232
233
  ## Features
233
234
 
235
+ ### General Operations
236
+
237
+ - `general_api_request`: Perform a general HTTP API request. Use this tool for any Elasticsearch/OpenSearch API that does not have a dedicated tool.
238
+
234
239
  ### Index Operations
235
240
 
236
241
  - `list_indices`: List all indices.
@@ -1,22 +1,24 @@
1
1
  src/__init__.py,sha256=aNKcThftSLh9IjOTA-UUpoRzIm4R0WwXKGAzykwecmU,211
2
- src/server.py,sha256=BtNr3oKiRK1rbnocFIKzwpukY87_AylzKh_ffwP6Zr8,2153
2
+ src/server.py,sha256=2EyBWtdAIct-L589FXhxTfQswsgo9nusC9ZORVfwXWU,2330
3
3
  src/clients/__init__.py,sha256=3UezAt9422S-7BvMiCo2Y9pmATVutorwsIQXP_g_CkA,1221
4
- src/clients/base.py,sha256=vTe4I62ruO2bEeSAag-2B5fJOWJDXllKbo8qA0h4VkM,2160
4
+ src/clients/base.py,sha256=MBAGepXyHPtdbtHhxFB8CamZ2ApWCBuOi_6-ey-MqX8,3298
5
5
  src/clients/exceptions.py,sha256=NYF3KVw-9aAgCViin5OuBI6miMEPS5QsdHx6bcis1wc,2493
6
6
  src/clients/common/__init__.py,sha256=VgvgxFpESn2wAuJmH0XM_Ej2izI7dxK7QJe9wG4fmW0,211
7
7
  src/clients/common/alias.py,sha256=rB53TSld5x2vZyDNAwyEdnh1KWUXMSD7h5fSv_ubR2Q,759
8
- src/clients/common/client.py,sha256=GD-V97Dj8c2XGUYt58vqCggkk-k8WJePPgngBDWO5aM,973
8
+ src/clients/common/client.py,sha256=khRO3osowTvoXnPscefUSuBYMrhOao2urOnRwqiUMbI,1041
9
9
  src/clients/common/cluster.py,sha256=pd5BVpqqDU6Lck3K704eEdhgFgzt9NstotWQLyG9zFM,401
10
10
  src/clients/common/document.py,sha256=ZzZiXDf_UhlN2FCmqW3drVjIZ07kGYP9yth_sgsJGPc,1623
11
+ src/clients/common/general.py,sha256=_1eS11Ha-JC1x1YoSu63zUWXKvYkwvN8RQOUM1fx39M,469
11
12
  src/clients/common/index.py,sha256=vyH5iXlJe5JLcDK6fhCCEPN-tgGm6zP5ilwGPdWCXbY,776
12
- src/tools/__init__.py,sha256=qiMRNUKlpNGnqbrkgBHGa7El1Pw_0a2qUJnuk_Q8LtY,324
13
+ src/tools/__init__.py,sha256=PGsXXpPubVnUbzXJG4keDhgjr0j6EnMNDs0aLqNIb4A,387
13
14
  src/tools/alias.py,sha256=p9TD4gXkGRGWHTYfvCg7G2hj-Uch9jwDXJNUY1hSD0Y,1376
14
15
  src/tools/cluster.py,sha256=XRAG-uxdfrieYX1ov_cBb66IYXaa8OoSWCUfXvNauy0,587
15
16
  src/tools/document.py,sha256=XZTVuk4di9VEwWMZN7jyDVnzoOiXkb4FBrXF44sVXTs,2052
17
+ src/tools/general.py,sha256=whj1spjIb8SS75h843X6c3RTsrZcSm-66KVLlY7OEh0,817
16
18
  src/tools/index.py,sha256=7KNPtElTFelkjRSvdMqPBx9nx_9Uk01OnTMeVo7YeCs,1345
17
19
  src/tools/register.py,sha256=wrG2P6-YPW77bTg1j_ELp8omWRYsJjFeOHUy_unHe6Y,1344
18
- opensearch_mcp_server-2.0.2.dist-info/METADATA,sha256=G1phXdISE1LdPqcw9087IDXr4YXLYuEsXuF2OHr8S-o,18514
19
- opensearch_mcp_server-2.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
20
- opensearch_mcp_server-2.0.2.dist-info/entry_points.txt,sha256=ImfJnUwMpQUBmu-1MeBG_P0dwamfXKQh82mBKW7tWNY,138
21
- opensearch_mcp_server-2.0.2.dist-info/licenses/LICENSE,sha256=DBsjuP5FR51d9kaUdXlVBuBv3cQ_I_adq9gefYQ9FcY,11339
22
- opensearch_mcp_server-2.0.2.dist-info/RECORD,,
20
+ opensearch_mcp_server-2.0.3.dist-info/METADATA,sha256=OFMMCH1mufu1PkUACANPjp0fzWu3NSTtH6gVccB67r4,18716
21
+ opensearch_mcp_server-2.0.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
22
+ opensearch_mcp_server-2.0.3.dist-info/entry_points.txt,sha256=ImfJnUwMpQUBmu-1MeBG_P0dwamfXKQh82mBKW7tWNY,138
23
+ opensearch_mcp_server-2.0.3.dist-info/licenses/LICENSE,sha256=DBsjuP5FR51d9kaUdXlVBuBv3cQ_I_adq9gefYQ9FcY,11339
24
+ opensearch_mcp_server-2.0.3.dist-info/RECORD,,
src/clients/base.py CHANGED
@@ -3,6 +3,10 @@ import logging
3
3
  import warnings
4
4
  from typing import Dict
5
5
 
6
+ from elasticsearch import Elasticsearch
7
+ import httpx
8
+ from opensearchpy import OpenSearch
9
+
6
10
  class SearchClientBase(ABC):
7
11
  def __init__(self, config: Dict, engine_type: str):
8
12
  """
@@ -35,7 +39,6 @@ class SearchClientBase(ABC):
35
39
 
36
40
  # Initialize client based on engine type
37
41
  if engine_type == "elasticsearch":
38
- from elasticsearch import Elasticsearch
39
42
  self.client = Elasticsearch(
40
43
  hosts=hosts,
41
44
  basic_auth=(username, password) if username and password else None,
@@ -43,7 +46,6 @@ class SearchClientBase(ABC):
43
46
  )
44
47
  self.logger.info(f"Elasticsearch client initialized with hosts: {hosts}")
45
48
  elif engine_type == "opensearch":
46
- from opensearchpy import OpenSearch
47
49
  self.client = OpenSearch(
48
50
  hosts=hosts,
49
51
  http_auth=(username, password) if username and password else None,
@@ -52,3 +54,34 @@ class SearchClientBase(ABC):
52
54
  self.logger.info(f"OpenSearch client initialized with hosts: {hosts}")
53
55
  else:
54
56
  raise ValueError(f"Unsupported engine type: {engine_type}")
57
+
58
+ # General REST client
59
+ base_url = hosts[0] if isinstance(hosts, list) else hosts
60
+ self.general_client = GeneralRestClient(
61
+ base_url=base_url,
62
+ username=username,
63
+ password=password,
64
+ verify_certs=verify_certs,
65
+ )
66
+
67
+ class GeneralRestClient:
68
+ def __init__(self, base_url: str, username: str, password: str, verify_certs: bool):
69
+ self.base_url = base_url.rstrip("/")
70
+ self.auth = (username, password) if username and password else None
71
+ self.verify_certs = verify_certs
72
+
73
+ def request(self, method, path, params=None, body=None):
74
+ url = f"{self.base_url}/{path.lstrip('/')}"
75
+ with httpx.Client(verify=self.verify_certs) as client:
76
+ resp = client.request(
77
+ method=method.upper(),
78
+ url=url,
79
+ params=params,
80
+ json=body,
81
+ auth=self.auth
82
+ )
83
+ resp.raise_for_status()
84
+ ct = resp.headers.get("content-type", "")
85
+ if ct.startswith("application/json"):
86
+ return resp.json()
87
+ return resp.text
@@ -3,9 +3,10 @@ from typing import Dict
3
3
  from src.clients.common.alias import AliasClient
4
4
  from src.clients.common.cluster import ClusterClient
5
5
  from src.clients.common.document import DocumentClient
6
+ from src.clients.common.general import GeneralClient
6
7
  from src.clients.common.index import IndexClient
7
8
 
8
- class SearchClient(IndexClient, DocumentClient, ClusterClient, AliasClient):
9
+ class SearchClient(IndexClient, DocumentClient, ClusterClient, AliasClient, GeneralClient):
9
10
  """
10
11
  Unified search client that combines all search functionality.
11
12
 
@@ -0,0 +1,10 @@
1
+ from typing import Dict, Optional
2
+
3
+ from src.clients.base import SearchClientBase
4
+
5
+ class GeneralClient(SearchClientBase):
6
+ def general_api_request(self, method: str, path: str, params: Optional[Dict] = None, body: Optional[Dict] = None):
7
+ """Perform a general HTTP API request.
8
+ Use this tool for any Elasticsearch/OpenSearch API that does not have a dedicated tool.
9
+ """
10
+ return self.general_client.request(method, path, params, body)
src/server.py CHANGED
@@ -2,11 +2,13 @@ import logging
2
2
  import sys
3
3
 
4
4
  from fastmcp import FastMCP
5
+ import toml
5
6
 
6
7
  from src.clients import create_search_client
7
8
  from src.tools.alias import AliasTools
8
9
  from src.tools.cluster import ClusterTools
9
10
  from src.tools.document import DocumentTools
11
+ from src.tools.general import GeneralTools
10
12
  from src.tools.index import IndexTools
11
13
  from src.tools.register import ToolsRegister
12
14
 
@@ -17,7 +19,8 @@ class SearchMCPServer:
17
19
  self.name = f"{self.engine_type}_mcp_server"
18
20
  self.mcp = FastMCP(self.name)
19
21
  self.logger = logging.getLogger()
20
- self.logger.info(f"Initializing {self.name}...")
22
+ self.version = toml.load("pyproject.toml")["project"]["version"]
23
+ self.logger.info(f"Initializing {self.name}, Version: {self.version}")
21
24
 
22
25
  # Create the corresponding search client
23
26
  self.search_client = create_search_client(self.engine_type)
@@ -35,7 +38,8 @@ class SearchMCPServer:
35
38
  IndexTools,
36
39
  DocumentTools,
37
40
  ClusterTools,
38
- AliasTools
41
+ AliasTools,
42
+ GeneralTools,
39
43
  ]
40
44
  # Register all tools
41
45
  register.register_all_tools(tool_classes)
src/tools/__init__.py CHANGED
@@ -1,13 +1,15 @@
1
- from src.tools.index import IndexTools
2
- from src.tools.document import DocumentTools
3
- from src.tools.cluster import ClusterTools
4
1
  from src.tools.alias import AliasTools
2
+ from src.tools.cluster import ClusterTools
3
+ from src.tools.document import DocumentTools
4
+ from src.tools.general import GeneralTools
5
+ from src.tools.index import IndexTools
5
6
  from src.tools.register import ToolsRegister
6
7
 
7
8
  __all__ = [
8
- 'IndexTools',
9
- 'DocumentTools',
10
- 'ClusterTools',
11
9
  'AliasTools',
10
+ 'ClusterTools',
11
+ 'DocumentTools',
12
+ 'GeneralTools',
13
+ 'IndexTools',
12
14
  'ToolsRegister',
13
15
  ]
src/tools/general.py ADDED
@@ -0,0 +1,20 @@
1
+ from typing import Dict, Optional
2
+
3
+ from fastmcp import FastMCP
4
+
5
+ class GeneralTools:
6
+ def __init__(self, search_client):
7
+ self.search_client = search_client
8
+ def register_tools(self, mcp: FastMCP):
9
+ @mcp.tool()
10
+ def general_api_request(method: str, path: str, params: Optional[Dict] = None, body: Optional[Dict] = None):
11
+ """Perform a general HTTP API request.
12
+ Use this tool for any Elasticsearch/OpenSearch API that does not have a dedicated tool.
13
+
14
+ Args:
15
+ method: HTTP method (GET, POST, PUT, DELETE, etc.)
16
+ path: API endpoint path
17
+ params: Query parameters
18
+ body: Request body
19
+ """
20
+ return self.search_client.general_api_request(method, path, params, body)