mcp-hydrolix 0.1.4__py3-none-any.whl → 0.1.5__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.
- mcp_hydrolix/auth/__init__.py +29 -0
- mcp_hydrolix/auth/credentials.py +63 -0
- mcp_hydrolix/auth/mcp_providers.py +137 -0
- mcp_hydrolix/log/__init__.py +6 -0
- mcp_hydrolix/log/log.py +60 -0
- mcp_hydrolix/log/log.yaml +40 -0
- mcp_hydrolix/log/utils.py +56 -0
- mcp_hydrolix/main.py +58 -2
- mcp_hydrolix/mcp_env.py +142 -52
- mcp_hydrolix/mcp_server.py +169 -111
- mcp_hydrolix/utils.py +70 -0
- {mcp_hydrolix-0.1.4.dist-info → mcp_hydrolix-0.1.5.dist-info}/METADATA +70 -7
- mcp_hydrolix-0.1.5.dist-info/RECORD +17 -0
- {mcp_hydrolix-0.1.4.dist-info → mcp_hydrolix-0.1.5.dist-info}/WHEEL +1 -1
- mcp_hydrolix-0.1.4.dist-info/RECORD +0 -9
- {mcp_hydrolix-0.1.4.dist-info → mcp_hydrolix-0.1.5.dist-info}/entry_points.txt +0 -0
- {mcp_hydrolix-0.1.4.dist-info → mcp_hydrolix-0.1.5.dist-info}/licenses/LICENSE +0 -0
mcp_hydrolix/utils.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import ipaddress
|
|
3
|
+
import json
|
|
4
|
+
from datetime import datetime, time
|
|
5
|
+
from decimal import Decimal
|
|
6
|
+
from functools import wraps
|
|
7
|
+
|
|
8
|
+
import fastmcp.utilities.types
|
|
9
|
+
from fastmcp.tools.tool import ToolResult
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ExtendedEncoder(json.JSONEncoder):
|
|
13
|
+
"""Extends JSONEncoder to apply custom serialization of CH data types."""
|
|
14
|
+
|
|
15
|
+
def default(self, obj):
|
|
16
|
+
if isinstance(obj, ipaddress.IPv4Address):
|
|
17
|
+
return str(obj)
|
|
18
|
+
if isinstance(obj, datetime):
|
|
19
|
+
return obj.time()
|
|
20
|
+
if isinstance(obj, time):
|
|
21
|
+
return obj.hour * 3600 + obj.minute * 60 + obj.second + obj.microsecond / 1_000_000
|
|
22
|
+
if isinstance(obj, bytes):
|
|
23
|
+
return obj.decode()
|
|
24
|
+
if isinstance(obj, Decimal):
|
|
25
|
+
return str(obj)
|
|
26
|
+
return super().default(obj)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def with_serializer(fn):
|
|
30
|
+
"""
|
|
31
|
+
Decorator to apply custom serialization to CH query tool result.
|
|
32
|
+
Should be applied as a first decorator of the tool function.
|
|
33
|
+
|
|
34
|
+
:returns: sync/async wrapper of mcp tool function
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
@wraps(fn)
|
|
38
|
+
def wrapper(*args, **kwargs):
|
|
39
|
+
"""
|
|
40
|
+
Sync wrapper of mcpt tool `fn` function.
|
|
41
|
+
Function should return a dict or None.
|
|
42
|
+
|
|
43
|
+
:returns: ToolResult object with text-serialized and structured content.
|
|
44
|
+
"""
|
|
45
|
+
result = fn(*args, **kwargs)
|
|
46
|
+
if not isinstance(result, dict):
|
|
47
|
+
result = {"result": result}
|
|
48
|
+
enc = json.dumps(result, cls=ExtendedEncoder)
|
|
49
|
+
return ToolResult(content=enc, structured_content=json.loads(enc))
|
|
50
|
+
|
|
51
|
+
@wraps(fn)
|
|
52
|
+
async def async_wrapper(*args, **kwargs):
|
|
53
|
+
"""
|
|
54
|
+
Async wrapper of mcp tool `fn` function.
|
|
55
|
+
Function should return a dict or None.
|
|
56
|
+
|
|
57
|
+
:returns: ToolResult object with text-serialized and structured content.
|
|
58
|
+
"""
|
|
59
|
+
result = await fn(*args, **kwargs)
|
|
60
|
+
if not isinstance(result, dict):
|
|
61
|
+
result = {"result": result}
|
|
62
|
+
enc = json.dumps(result, cls=ExtendedEncoder)
|
|
63
|
+
return ToolResult(content=enc, structured_content=json.loads(enc))
|
|
64
|
+
|
|
65
|
+
# TODO: remove next signature fix code when a new fastmcp released (https://github.com/jlowin/fastmcp/issues/2524)
|
|
66
|
+
new_fn = fastmcp.utilities.types.create_function_without_params(fn, ["ctx"])
|
|
67
|
+
sig = inspect.signature(new_fn)
|
|
68
|
+
async_wrapper.__signature__ = sig
|
|
69
|
+
wrapper.__signature__ = sig
|
|
70
|
+
return async_wrapper if inspect.iscoroutinefunction(fn) else wrapper
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-hydrolix
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: An MCP server for Hydrolix.
|
|
5
5
|
Project-URL: Home, https://github.com/hydrolix/mcp-hydrolix
|
|
6
6
|
License-Expression: Apache-2.0
|
|
7
7
|
License-File: LICENSE
|
|
8
8
|
Requires-Python: >=3.13
|
|
9
|
-
Requires-Dist: clickhouse-connect>=0.
|
|
10
|
-
Requires-Dist: fastmcp>=2.
|
|
9
|
+
Requires-Dist: clickhouse-connect>=0.10.0
|
|
10
|
+
Requires-Dist: fastmcp>=2.13.3
|
|
11
|
+
Requires-Dist: gunicorn>=23.0.0
|
|
11
12
|
Requires-Dist: pip-system-certs>=4.0
|
|
13
|
+
Requires-Dist: pyjwt>=2.10.1
|
|
12
14
|
Requires-Dist: python-dotenv>=1.0.1
|
|
13
15
|
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: fastapi>=0.124.0; extra == 'dev'
|
|
17
|
+
Requires-Dist: mcp-clickhouse>=0.1.12; extra == 'dev'
|
|
14
18
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
15
19
|
Requires-Dist: pytest; extra == 'dev'
|
|
16
20
|
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
21
|
+
Requires-Dist: pytest-repeat; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest-xdist; extra == 'dev'
|
|
17
23
|
Requires-Dist: ruff; extra == 'dev'
|
|
18
24
|
Description-Content-Type: text/markdown
|
|
19
25
|
|
|
@@ -64,6 +70,18 @@ The Hydrolix MCP server is configured using a standard MCP server entry. Consult
|
|
|
64
70
|
|
|
65
71
|
The recommended way to launch the Hydrolix MCP server is via the [`uv` project manager](https://github.com/astral-sh/uv), which will manage installing all other dependencies in an isolated environment.
|
|
66
72
|
|
|
73
|
+
### Authentication
|
|
74
|
+
|
|
75
|
+
The server supports multiple authentication methods with the following precedence (highest to lowest):
|
|
76
|
+
|
|
77
|
+
1. **Per-request Bearer token**: Service account token provided via `Authorization: Bearer <token>` header
|
|
78
|
+
2. **Per-request GET parameter**: Service account token provided via `?token=<token>` query parameter
|
|
79
|
+
3. **Environment-based credentials**: Credentials configured via environment variables
|
|
80
|
+
- Service account token (`HYDROLIX_TOKEN`), or
|
|
81
|
+
- Username and password (`HYDROLIX_USER` and `HYDROLIX_PASSWORD`)
|
|
82
|
+
|
|
83
|
+
When multiple authentication methods are configured, the server will use the first available method in the precedence order above. Per-request authentication is only available when using HTTP or SSE transport modes.
|
|
84
|
+
|
|
67
85
|
MCP Server definition using username and password (JSON):
|
|
68
86
|
|
|
69
87
|
```json
|
|
@@ -199,17 +217,37 @@ To leverage service account use the following config block:
|
|
|
199
217
|
|
|
200
218
|
5. Restart Claude Desktop to apply the changes. If you are using Windows, ensure Claude is stopped completely by closing the client using the system tray icon.
|
|
201
219
|
|
|
220
|
+
### Configuration Example (Claude Code)
|
|
221
|
+
|
|
222
|
+
To configure the Hydrolix MCP server for Claude Code, run the following command:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
claude mcp add --transport stdio hydrolix \
|
|
226
|
+
--env HYDROLIX_USER=<hydrolix-user> \
|
|
227
|
+
--env HYDROLIX_PASSWORD=<hydrolix-password> \
|
|
228
|
+
--env HYDROLIX_HOST=<hydrolix-host> \
|
|
229
|
+
--env HYDROLIX_MCP_SERVER_TRANSPORT=stdio \
|
|
230
|
+
-- uv run --with mcp-hydrolix --python 3.13 mcp-hydrolix
|
|
231
|
+
```
|
|
232
|
+
|
|
202
233
|
### Environment Variables
|
|
203
234
|
|
|
204
235
|
The following variables are used to configure the Hydrolix connection. These variables may be provided via the MCP config block (as shown above), a `.env` file, or traditional environment variables.
|
|
205
236
|
|
|
206
237
|
#### Required Variables
|
|
207
238
|
* `HYDROLIX_HOST`: The hostname of your Hydrolix server
|
|
208
|
-
* `HYDROLIX_TOKEN`: The Hydrolix service account token (omit if using username/password)
|
|
209
|
-
* `HYDROLIX_USER`: The username for authentication (omit if using service account)
|
|
210
|
-
* `HYDROLIX_PASSWORD`: The password for authentication (omit if using service account)
|
|
211
239
|
|
|
212
|
-
|
|
240
|
+
#### Authentication Variables
|
|
241
|
+
At least one authentication method must be configured when using the stdio transport:
|
|
242
|
+
|
|
243
|
+
* `HYDROLIX_TOKEN`: Service account token for environment-based authentication
|
|
244
|
+
* `HYDROLIX_USER` and `HYDROLIX_PASSWORD`: Username and password for environment-based authentication (both must be provided together)
|
|
245
|
+
|
|
246
|
+
In summary:
|
|
247
|
+
- For stdio, you MUST use HYDROLIX_TOKEN or HYDROLIX_USER+HYDROLIX_PASS (environmental credentials)
|
|
248
|
+
- For http/sse, you MAY use HYDROLIX_TOKEN or HYDROLIX_USER+HYDROLIX_PASS (environmental credentials), but you may instead use per-request credentials.
|
|
249
|
+
|
|
250
|
+
If no credentials are provided via the environment or the request, the request will fail.
|
|
213
251
|
|
|
214
252
|
#### Optional Variables
|
|
215
253
|
* `HYDROLIX_PORT`: The port number of your Hydrolix server
|
|
@@ -248,4 +286,29 @@ When using HTTP transport, the server will run on the configured port (default 8
|
|
|
248
286
|
- MCP endpoint: `http://localhost:4200/mcp`
|
|
249
287
|
- Health check: `http://localhost:4200/health`
|
|
250
288
|
|
|
289
|
+
#### Using Per-Request Authentication with HTTP Transport
|
|
290
|
+
|
|
291
|
+
When using HTTP or SSE transport, you can omit environment-based credentials and instead provide authentication per-request. This is useful for multi-user scenarios or with clients that don't support running MCP servers locally.
|
|
292
|
+
|
|
293
|
+
Example `mcpServers` configuration connecting to a remote HTTP server with per-request authentication:
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"mcpServers": {
|
|
298
|
+
"mcp-hydrolix-remote": {
|
|
299
|
+
"url": "http://my-hydrolix-mcp.example.com:8000/mcp?token=<service-account-token>"
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Example minimal `.env` configuration for running your own HTTP server without environment credentials:
|
|
306
|
+
|
|
307
|
+
```env
|
|
308
|
+
HYDROLIX_HOST=my-cluster.hydrolix.net
|
|
309
|
+
HYDROLIX_MCP_SERVER_TRANSPORT=http
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Though not part of the MCP specification, many MCP clients allow adding headers to MCP-issued requests. When this is possible, we recommend configuring the MCP client to pass a service account token via the `Authorization: Bearer <sa-token-here>` header instead of as a query parameter for greater security.
|
|
313
|
+
|
|
251
314
|
Note: The bind host and port settings are only used when transport is set to "http" or "sse".
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
mcp_hydrolix/__init__.py,sha256=DnAQkvoFf_QhrDNFLOmn-nHlldPUgtdN33k3xJWthgc,225
|
|
2
|
+
mcp_hydrolix/main.py,sha256=Q58yz9ykx0bilptGALXW_Lli0pR7wDNOPib34l1z8Sg,2760
|
|
3
|
+
mcp_hydrolix/mcp_env.py,sha256=CM8LG1ce1-LyM_CUm3Fg8hCoVi3ef5Lv-kLUVji7Jj0,11521
|
|
4
|
+
mcp_hydrolix/mcp_server.py,sha256=CyOozGeu0MYX3m2UdaFAECyXA7Zk2fM_5pwh6mxI-Ng,12475
|
|
5
|
+
mcp_hydrolix/utils.py,sha256=fMGCsRa2DqlS2PMfIpD5VaHTbaxUkW7mvgArgVViXbs,2433
|
|
6
|
+
mcp_hydrolix/auth/__init__.py,sha256=uWF8v7ooLEcgBctxgyf4E4gtM_-PQM3xYTljA-Pbgnk,622
|
|
7
|
+
mcp_hydrolix/auth/credentials.py,sha256=IK8w6TjNxS1K0LCKBt3xXOOI-0ogWCVAkiJuOzEJuJY,1915
|
|
8
|
+
mcp_hydrolix/auth/mcp_providers.py,sha256=LSijw3RxC_BB9NnWXUSfWOSBjHwAk-vK41zYVM4CbFU,5177
|
|
9
|
+
mcp_hydrolix/log/__init__.py,sha256=n7S4B06C1B6ZrOyz_15BbQ72D3lmmVNfOcc2qYiKans,103
|
|
10
|
+
mcp_hydrolix/log/log.py,sha256=6KX0oSz-BbCWUoPxbJED4sZBmbgCHa3KDrc5nYtdks4,1838
|
|
11
|
+
mcp_hydrolix/log/log.yaml,sha256=ldw66lGkQjqyJ92gJqOtdP63T_3MSD_ndKU1p8Xegvs,978
|
|
12
|
+
mcp_hydrolix/log/utils.py,sha256=iwiFB331RzlWndhL8fbzPUmNlWS0e4qCV8n6W2Hpi5s,2088
|
|
13
|
+
mcp_hydrolix-0.1.5.dist-info/METADATA,sha256=UVLw_p_jxkng-iKuDe-UffCWIcP7ci2OIAJ1UWlQ-VE,11074
|
|
14
|
+
mcp_hydrolix-0.1.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
15
|
+
mcp_hydrolix-0.1.5.dist-info/entry_points.txt,sha256=vHa7F2rOCVu8lpsqR8BYbE1w8ugJSOYwX95w802Y5qE,56
|
|
16
|
+
mcp_hydrolix-0.1.5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
17
|
+
mcp_hydrolix-0.1.5.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
mcp_hydrolix/__init__.py,sha256=DnAQkvoFf_QhrDNFLOmn-nHlldPUgtdN33k3xJWthgc,225
|
|
2
|
-
mcp_hydrolix/main.py,sha256=9cNwIVNE0fCbPuwde-VjcwyZwNb07i9zFRxzEE1yLus,703
|
|
3
|
-
mcp_hydrolix/mcp_env.py,sha256=3NyjHiMyhodB9D7QpPxtFtXFzHbw-FzrqlsmGPElqwc,7651
|
|
4
|
-
mcp_hydrolix/mcp_server.py,sha256=i0qPwXv-s6-kxMh1FeuPNAItk5u17sSjY8GGu1SiyB8,10537
|
|
5
|
-
mcp_hydrolix-0.1.4.dist-info/METADATA,sha256=13PY5b6HeuurxPMYOysJ29FwJ8wc2xPnKUNvGSWuqxA,8376
|
|
6
|
-
mcp_hydrolix-0.1.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
-
mcp_hydrolix-0.1.4.dist-info/entry_points.txt,sha256=vHa7F2rOCVu8lpsqR8BYbE1w8ugJSOYwX95w802Y5qE,56
|
|
8
|
-
mcp_hydrolix-0.1.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
9
|
-
mcp_hydrolix-0.1.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|