Skip to content

Commit 2e2f3f3

Browse files
authored
release/0.1.2 (#6)
1 parent 05d52ce commit 2e2f3f3

File tree

14 files changed

+1250
-514
lines changed

14 files changed

+1250
-514
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@ __pycache__*
22
*.py[cod]
33
*$py.class
44
.venv
5+
.env
6+
.coverage
7+
coverage.xml
8+
report.xml
59
out

README.md

Lines changed: 121 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ The server leverages a combination of curated resources, intelligent prompts, an
1414
- [Features](#features)
1515
- [KDB-X Setup](#kdb-x-setup)
1616
- [MCP Server Installation](#mcp-server-installation)
17+
- [Security Considerations](#security-considerations)
1718
- [Transport Options](#transport-options)
18-
- [Command line Parameters](#command-line-parameters)
19+
- [Command Line Tool](#command-line-tool)
1920
- [Configure Embeddings](#configure-embeddings)
2021
- [Usage with Claude Desktop](#usage-with-claude-desktop)
2122
- [Prompts/Resources/Tools](#promptsresourcestools)
@@ -76,17 +77,18 @@ To demonstrate basic usage of the KDB-X MCP Server, using an empty KDB-X databas
7677
7778
1. Open a KDB-X service listening on a port.
7879

79-
By default the KDB-X MCP server will connect to KDB-X service on port 5000 - [but this can be changed](#command-line-parameters) via command line flags or environment variables.
80+
By default the KDB-X MCP server will connect to KDB-X service on port 5000 - [but this can be changed](#command-line-tool) via command line flags or environment variables.
8081

8182
> Note: KDB-X is currently not supported on Windows - if you are using Windows we recommend running KDB-X on WSL as outlined in the [prerequisites steps](#prerequisites)
8283
8384
```bash
8485
q -p 5000
8586
```
8687

87-
2. Load the sql interface.
88+
2. Load the ai and sql interfaces.
8889

8990
```q
91+
\l ai-libs/init.q
9092
.s.init[]
9193
```
9294

@@ -198,56 +200,131 @@ For more info on the supported transports see official documentation
198200

199201
> Note: We don't support [sse](https://modelcontextprotocol.io/docs/concepts/transports#server-sent-events-sse-deprecated) transport (server-sent events) as it has been deprecated since protocol version 2024-11-05.
200202
201-
## Command line Parameters
203+
## Security Considerations
204+
205+
To simplify getting started, we recommend running your MCP Client, KDB-X MCP server, and your KDB-X database on the same internal network.
206+
207+
### Encrypting Database Connections
208+
209+
If you require an encrypted connection between your KDB-X MCP server and your KDB-X database, you can enable enable TLS with `--db.tls=true`
210+
211+
This requires setting up your KDB-X database with TLS as a prerequisite:
212+
213+
- You can follow the [kdb+ SSL/TLS guide](https://code.kx.com/q/kb/ssl/) to setup TLS with your KDB-X database
214+
- If you are using self signed certificates:
215+
- You will need to specify the location of your self signed CA cert
216+
- Set the `KX_SSL_CA_CERT_FILE` environment variable to point to the CA cert file that your KDB-X database is using
217+
- Alternatively, you can bypass certificate verification by setting `KX_SSL_VERIFY_SERVER=NO` for development and testing
218+
219+
### Encrypting MCP Client Connections
220+
221+
If you require an encrypted connection between your MCP Client and your KDB-X MCP server:
222+
223+
- The KDB-X MCP server uses streamable-http transport by default and starts a localhost server at 127.0.0.1:8000. We do not recommend exposing this externally.
224+
- You can optionally setup an HTTPS proxy in front of your KDB-X MCP server such as [envoy](https://www.envoyproxy.io/) or [nginx](https://nginx.org/) for HTTPS termination
225+
- When using stdio transport, this is not required as communication is through standard input/output streams on the same host
226+
227+
> Note: FastMCP v2 was evaluated for it's authentication features, but the KDB-X MCP Server will remain temporarily on v1 to preserve broad model compatibility until clients/models catch up, at which point we will transition.
228+
229+
## Command Line Tool
202230

203231
```bash
204232
uv run mcp-server -h
205-
usage: mcp-server [-h] [--streamable-http | --stdio] [--kdbx-mcp-port KDBX_MCP_PORT]
206-
[--kdbx-host KDBX_HOST] [--kdbx-port KDBX_PORT]
207-
[--kdbx-timeout KDBX_TIMEOUT] [--kdbx-retry KDBX_RETRY]
233+
usage: mcp-server [-h] [--mcp.server-name str] [--mcp.log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
234+
[--mcp.transport {stdio,streamable-http}] [--mcp.port int] [--mcp.host str] [--db.host str]
235+
[--db.port int] [--db.username str] [--db.password SecretStr] [--db.tls bool] [--db.timeout int]
236+
[--db.retry int] [--db.embedding-csv-path str] [--db.metric str] [--db.k int]
208237

209-
KDB-X MCP Server
238+
KDB-X MCP Server that enables interaction with KDB-X using natural language
210239

211240
options:
212241
-h, --help show this help message and exit
213-
--streamable-http Start the KDB-X MCP server with streamable HTTP transport (default)
214-
--stdio Start the KDB-X MCP server with stdio transport
215-
--kdbx-mcp-port KDBX_MCP_PORT
216-
Port number the KDB-X MCP server will listen on when using streamable-http
217-
transport (default 8000)
218-
--kdbx-host KDBX_HOST
219-
KDB-X host that the MCP server will connect to (default: localhost)
220-
--kdbx-port KDBX_PORT
221-
KDB-X port that the MCP server will connect to (default: 5000)
222-
--kdbx-timeout KDBX_TIMEOUT
223-
KDB-X connection timeout in seconds (default: 1)
224-
--kdbx-retry KDBX_RETRY
225-
KDB-X connection retry attempts (default: 2)
242+
243+
mcp options:
244+
MCP server configuration and transport settings
245+
246+
--mcp.server-name str
247+
Name identifier for the MCP server instance [env: KDBX_MCP_SERVER_NAME] (default:
248+
KDBX_MCP_Server)
249+
--mcp.log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}
250+
Logging verbosity level [env: KDBX_MCP_LOG_LEVEL] (default: INFO)
251+
--mcp.transport {stdio,streamable-http}
252+
Communication protocol: 'stdio' (pipes) or 'streamable-http' (HTTP server) [env:
253+
KDBX_MCP_TRANSPORT] (default: streamable-http)
254+
--mcp.port int HTTP server port - ignored when using stdio transport [env: KDBX_MCP_PORT] (default: 8000)
255+
--mcp.host str HTTP server bind address - ignored when using stdio transport [env: KDBX_MCP_HOST] (default:
256+
127.0.0.1)
257+
258+
db options:
259+
KDB-X database connection settings
260+
261+
--db.host str KDB-X server hostname or IP address [env: KDBX_DB_HOST] (default: 127.0.0.1)
262+
--db.port int KDB-X server port number [env: KDBX_DB_PORT] (default: 5000)
263+
--db.username str Username for KDB-X authentication [env: KDBX_DB_USERNAME] (default: )
264+
--db.password SecretStr
265+
Password for KDB-X authentication [env: KDBX_DB_PASSWORD] (default: )
266+
--db.tls bool Enable TLS for KDB-X connections. When using TLS you will need to set the environment variable
267+
`KX_SSL_CA_CERT_FILE` that points to the certificate on your local filesystem that your KDB-X
268+
server is using. For local development and testing you can set `KX_SSL_VERIFY_SERVER=NO` to
269+
bypass this requirement [env: KDBX_DB_TLS] (default: False)
270+
--db.timeout int Timeout in seconds for KDB-X connection attempts [env: KDBX_DB_TIMEOUT] (default: 1)
271+
--db.retry int Number of connection retry attempts on failure [env: KDBX_DB_RETRY] (default: 2)
272+
--db.embedding-csv-path str
273+
Path to embeddings csv [env: KDBX_DB_EMBEDDING_CSV_PATH] (default:
274+
src/mcp_server/utils/embeddings.csv)
275+
--db.metric str Distance metric used for vector similarity search (e.g., CS, L2, IP) [env: KDBX_DB_METRIC]
276+
(default: CS)
277+
--db.k int Default number of results to return from vector searches [env: KDBX_DB_K] (default: 5)
226278
```
227279

228-
> Note: `kdbx-*` command line flags can be used when pointing to a KDB+ Service
280+
### CLI Configuration Options
281+
282+
The command line options are organized into two main categories:
283+
284+
- MCP Options - Configures the MCP server behavior and transport settings
285+
- Database Options - Configures the KDB-X database connection settings
229286

230-
**Environment Variables:**
287+
For details on each option, refer to the [help text](#command-line-tool)
231288

232-
- `KDBX_MCP_TRANSPORT`: Set transport mode (streamable-http, stdio)
233-
- `KDBX_MCP_PORT`: Set port number (default: 8000)
234-
- `KDBX_MCP_HOST`: Set host address (default: 127.0.0.1)
235-
- `KDBX_MCP_SERVER_NAME`: Set server name (default: KDB-X_Demo)
236-
- `KDBX_LOG_LEVEL`: Set logging level (default: INFO)
237-
- `KDBX_RETRY`: KDB-X server connection retry count (default: 2)
238-
- `KDBX_TIMEOUT`: KDB-X server connection timeout in seconds (default: 2)
239-
- `KDBX_HOST`: KDB-X server hostname (default: localhost)
240-
- `KDBX_PORT`: KDB-X server port (default: 5000)
241-
- `KDBX_USERNAME`: KDB-X username (optional)
242-
- `KDBX_PASSWORD`: KDB-X password (optional)
289+
### Configuration Methods
243290

244-
> Note: `KDBX_*` environment variables can be used when pointing to a KDB+ Service
291+
Configuration values are resolved in the following priority order:
245292

246-
**Configuration Priority:**
293+
1. **Command Line Arguments** - Highest priority
294+
2. **Environment Variables** - Second priority
295+
3. **.env File** - Third priority
296+
4. **Default Values** - Default values defined in `settings.py`
247297

248-
1. **CLI flags** (highest precedence) - `--streamable-http`, `--kdbx-port 8000`, `--kdbx-host myhost`
249-
2. **Environment variables** (middle precedence) - `KDBX_MCP_TRANSPORT=streamable-http`, `KDBX_HOST=myhost`
250-
3. **Default values** (lowest precedence)
298+
### Environment Variables
299+
300+
Every command line option has a corresponding environment variable. For example:
301+
302+
- `--mcp.port 7001``KDBX_MCP_PORT=7001`
303+
- `--db.host localhost``KDBX_DB_HOST=localhost`
304+
305+
> Note: `KDBX_DB_*` environment variables can be used when pointing to a KDB+ Service
306+
307+
### Example Usage
308+
309+
```bash
310+
# Using defaults
311+
uv run mcp-server
312+
313+
# Using a .env file
314+
echo "KDBX_MCP_PORT=7001" >> .env
315+
echo "KDBX_DB_RETRY=4" >> .env
316+
uv run mcp-server
317+
318+
# Using environment variables
319+
export KDBX_MCP_PORT=7001
320+
export KDBX_DB_RETRY=4
321+
uv run mcp-server
322+
323+
# Using command line arguments
324+
uv run mcp-server \
325+
--mcp.port 7001 \
326+
--db.retry 4
327+
```
251328

252329
## Configure Embeddings
253330

@@ -322,7 +399,8 @@ If you have pre-existing MCP servers see [example config with multiple mcp-serve
322399
"/path/to/this/repo/",
323400
"run",
324401
"mcp-server",
325-
"--stdio"
402+
"--mcp.transport",
403+
"stdio"
326404
]
327405
}
328406
}
@@ -331,7 +409,7 @@ If you have pre-existing MCP servers see [example config with multiple mcp-serve
331409

332410
**Note**
333411

334-
- Update your `<user>` to point to the absolute path of the uv executable - only required if `uv` is not on your path
412+
- Update your `<user>` to point to the [absolute path of the uv executable](#uv-default-paths) - only required if `uv` is not on your path
335413
- Update the `--directory` path to the absolute path of this repo
336414
- Currently `KDB-X` does not support Windows, meaning `stdio` is not an option for Windows users
337415
- Claude Desktop is responsible for starting/stopping the MCP server when using `stdio`
@@ -407,6 +485,7 @@ To enable Developer mode:
407485
|-------------------|------------------------------------------|-------------------------------------------------|------------------------------------------------|
408486
| kdbx_run_sql_query | Execute SQL SELECT against KDB-X database | `query`: SQL SELECT query string to execute | JSON object with query results (max 1000 rows) |
409487
| kdbx_similarity_search | Perform vector similarity search on a KDB-X table | `table_name`: Name of the table to search <br> `query`: Text query to convert to vector and search <br> `n` (optional): Number of results to return | Dictionary containing search result |
488+
| kdbx_hybrid_search | Perform hybrid search combining vector similarity and sparse text search on a KDB-X table | table_name: Name of the table to search <br> query: Text query to convert to dense and sparse vectors for search <br> n (optional): Number of results to return | Dictionary containing search result |
410489

411490
## Development
412491

@@ -448,7 +527,7 @@ KDB-X public preview has recently been extended. If you have installed KDB-X pri
448527

449528
Ensure that your KDB-X database is online and accessible on the specified kdb host and port.
450529

451-
The default KDB-X endpoint is `localhost:5000`, but you can update as needed via section [Command line Parameters](#command-line-parameters).
530+
The default KDB-X endpoint is `localhost:5000`, but you can update as needed via section [Command line Tool](#command-line-tool).
452531

453532
#### KDB-X SQL interface error
454533

pyproject.toml

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,49 @@ dependencies = [
1414
# "tiktoken",
1515
]
1616

17-
[project.optional-dependencies]
17+
[dependency-groups]
1818
dev = [
1919
"ruff>=0.1.0",
20+
"pytest>=7.3.2,<8",
21+
"pytest-cov>=4.0.0,<5",
22+
"pytest-mock",
23+
"coverage>=7.8.0",
24+
"mypy",
25+
"trio",
2026
]
2127

2228
[project.scripts]
2329
mcp-server = "mcp_server:main"
2430

25-
2631
[build-system]
2732
requires = ["hatchling"]
2833
build-backend = "hatchling.build"
34+
35+
[tool.coverage.run]
36+
command_line = "-m pytest tests --junitxml=report.xml"
37+
branch = true
38+
dynamic_context = "test_function"
39+
source_pkgs = ["mcp_server"]
40+
relative_files = true
41+
omit = [
42+
"*/_template.py",
43+
"main.py"
44+
]
45+
46+
[tool.coverage.paths]
47+
source = [
48+
"mcp_server",
49+
]
50+
51+
[tool.coverage.report]
52+
# Regexes for lines to exclude from consideration
53+
skip_empty = true
54+
skip_covered = false
55+
precision = 2
56+
57+
[tool.coverage.html]
58+
directory = "htmlcov/coverage"
59+
show_contexts = true
60+
61+
[tool.coverage.xml]
62+
output = "coverage.xml"

src/mcp_server/resources/kdbx_database_tables.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
21
import logging
32
from typing import List
43
from mcp.types import TextContent
54
from mcp_server.utils.kdbx import get_kdb_connection
5+
from mcp_server.utils.format_utils import format_data_for_display
66
from mcp_server.utils.embeddings_helpers import get_embedding_config
7-
from mcp_server.server import config
87

98
logger = logging.getLogger(__name__)
109

@@ -34,7 +33,7 @@ async def kdbx_describe_table_impl(table: str) -> List[TextContent]:
3433

3534
output_lines.extend([
3635
f"\n Schema Information:",
37-
_format_data(schema_data)
36+
format_data_for_display(schema_data, table)
3837
])
3938

4039
if total_records > 0:
@@ -46,7 +45,7 @@ async def kdbx_describe_table_impl(table: str) -> List[TextContent]:
4645

4746
output_lines.extend([
4847
f"\n Data Preview ({preview_size} records):",
49-
_format_data(preview_data, table)
48+
format_data_for_display(preview_data, table)
5049
])
5150
else:
5251
output_lines.append("\n Table is empty - no data to preview")
@@ -66,6 +65,12 @@ async def kdbx_describe_tables_impl() -> List[TextContent]:
6665
conn = get_kdb_connection()
6766

6867
available_tables = conn.tables(None).py()
68+
69+
# Filter out internal AI library index tables (*document, *stats, *token)
70+
available_tables = [
71+
table for table in available_tables
72+
if not (table.endswith('document') or table.endswith('stats') or table.endswith('token'))
73+
]
6974

7075
if not available_tables:
7176
return [TextContent(
@@ -84,7 +89,7 @@ async def kdbx_describe_tables_impl() -> List[TextContent]:
8489
overview_parts.append(table_analysis[0].text)
8590

8691
complete_overview = "\n".join(overview_parts)
87-
logger.info(complete_overview)
92+
logger.debug(complete_overview)
8893
return [TextContent(type="text", text=complete_overview)]
8994

9095
except Exception as error:
@@ -95,16 +100,6 @@ async def kdbx_describe_tables_impl() -> List[TextContent]:
95100
)]
96101

97102

98-
def _format_data(data, table=None) -> str:
99-
if table:
100-
embeddings_column, _, _, _, _ = get_embedding_config(table)
101-
if embeddings_column and hasattr(data, "pop"):
102-
data.pop(embeddings_column, None)
103-
# data = data.drop(embeddings_column, axis=1, errors="ignore")
104-
if hasattr(data, 'to_string'):
105-
return data.to_string()
106-
return str(data)
107-
108103

109104
def register_resources(mcp_server):
110105
@mcp_server.resource("kdbx://tables")

0 commit comments

Comments
 (0)