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/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.4
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.8.16
10
- Requires-Dist: fastmcp>=2.0.0
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
- **Authentication precedence:** If both `HYDROLIX_TOKEN` and `HYDROLIX_USER`/`HYDROLIX_PASSWORD` are provided, the service account token takes precedence and username/password authentication will be ignored.
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,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -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,,