couchbase-mcp-server 0.4.0rc1__py3-none-any.whl → 0.5.1__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.
- certs/__init__.py +0 -0
- certs/capella_root_ca.pem +19 -0
- {couchbase_mcp_server-0.4.0rc1.dist-info → couchbase_mcp_server-0.5.1.dist-info}/METADATA +76 -39
- couchbase_mcp_server-0.5.1.dist-info/RECORD +19 -0
- {couchbase_mcp_server-0.4.0rc1.dist-info → couchbase_mcp_server-0.5.1.dist-info}/WHEEL +1 -2
- mcp_server.py +22 -6
- tools/__init__.py +19 -0
- tools/index.py +172 -0
- tools/kv.py +20 -6
- tools/query.py +27 -6
- tools/server.py +105 -16
- utils/__init__.py +9 -6
- utils/config.py +0 -25
- utils/connection.py +29 -4
- utils/context.py +21 -37
- utils/index_utils.py +308 -0
- couchbase_mcp_server-0.4.0rc1.dist-info/RECORD +0 -16
- couchbase_mcp_server-0.4.0rc1.dist-info/top_level.txt +0 -3
- {couchbase_mcp_server-0.4.0rc1.dist-info → couchbase_mcp_server-0.5.1.dist-info}/entry_points.txt +0 -0
- {couchbase_mcp_server-0.4.0rc1.dist-info → couchbase_mcp_server-0.5.1.dist-info}/licenses/LICENSE +0 -0
certs/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDFTCCAf2gAwIBAgIRANLVkgOvtaXiQJi0V6qeNtswDQYJKoZIhvcNAQELBQAw
|
|
3
|
+
JDESMBAGA1UECgwJQ291Y2hiYXNlMQ4wDAYDVQQLDAVDbG91ZDAeFw0xOTEyMDYy
|
|
4
|
+
MjEyNTlaFw0yOTEyMDYyMzEyNTlaMCQxEjAQBgNVBAoMCUNvdWNoYmFzZTEOMAwG
|
|
5
|
+
A1UECwwFQ2xvdWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfvOIi
|
|
6
|
+
enG4Dp+hJu9asdxEMRmH70hDyMXv5ZjBhbo39a42QwR59y/rC/sahLLQuNwqif85
|
|
7
|
+
Fod1DkqgO6Ng3vecSAwyYVkj5NKdycQu5tzsZkghlpSDAyI0xlIPSQjoORA/pCOU
|
|
8
|
+
WOpymA9dOjC1bo6rDyw0yWP2nFAI/KA4Z806XeqLREuB7292UnSsgFs4/5lqeil6
|
|
9
|
+
rL3ooAw/i0uxr/TQSaxi1l8t4iMt4/gU+W52+8Yol0JbXBTFX6itg62ppb/Eugmn
|
|
10
|
+
mQRMgL67ccZs7cJ9/A0wlXencX2ohZQOR3mtknfol3FH4+glQFn27Q4xBCzVkY9j
|
|
11
|
+
KQ20T1LgmGSngBInAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
|
|
12
|
+
FJQOBPvrkU2In1Sjoxt97Xy8+cKNMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0B
|
|
13
|
+
AQsFAAOCAQEARgM6XwcXPLSpFdSf0w8PtpNGehmdWijPM3wHb7WZiS47iNen3oq8
|
|
14
|
+
m2mm6V3Z57wbboPpfI+VEzbhiDcFfVnK1CXMC0tkF3fnOG1BDDvwt4jU95vBiNjY
|
|
15
|
+
xdzlTP/Z+qr0cnVbGBSZ+fbXstSiRaaAVcqQyv3BRvBadKBkCyPwo+7svQnScQ5P
|
|
16
|
+
Js7HEHKVms5tZTgKIw1fbmgR2XHleah1AcANB+MAPBCcTgqurqr5G7W2aPSBLLGA
|
|
17
|
+
fRIiVzm7VFLc7kWbp7ENH39HVG6TZzKnfl9zJYeiklo5vQQhGSMhzBsO70z4RRzi
|
|
18
|
+
DPFAN/4qZAgD5q3AFNIq2WWADFQGSwVJhg==
|
|
19
|
+
-----END CERTIFICATE-----
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: couchbase-mcp-server
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Couchbase MCP Server - The Developer Data Platform for Critical Applications in Our AI World
|
|
5
|
-
Author-email: Nithish Raghunandanan <devadvocates@couchbase.com>
|
|
6
|
-
License-Expression: Apache-2.0
|
|
7
5
|
Project-URL: Homepage, https://github.com/Couchbase-Ecosystem/mcp-server-couchbase
|
|
8
6
|
Project-URL: Documentation, https://github.com/Couchbase-Ecosystem/mcp-server-couchbase#readme
|
|
9
7
|
Project-URL: Issues, https://github.com/Couchbase-Ecosystem/mcp-server-couchbase/issues
|
|
8
|
+
Author-email: Nithish Raghunandanan <devadvocates@couchbase.com>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
10
11
|
Classifier: Development Status :: 4 - Beta
|
|
11
12
|
Classifier: Programming Language :: Python :: 3
|
|
12
13
|
Classifier: Topic :: Database
|
|
13
|
-
Requires-Python:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Requires-Dist:
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist:
|
|
19
|
-
Requires-Dist: mcp[cli]==1.12.0
|
|
14
|
+
Requires-Python: <3.14,>=3.10
|
|
15
|
+
Requires-Dist: click<9.0.0,>=8.2.1
|
|
16
|
+
Requires-Dist: couchbase<5.0.0,>=4.4.0
|
|
17
|
+
Requires-Dist: lark-sqlpp>=0.0.1
|
|
18
|
+
Requires-Dist: mcp[cli]<2.0.0,>=1.20.0
|
|
19
|
+
Requires-Dist: urllib3>=2.0.0
|
|
20
20
|
Provides-Extra: dev
|
|
21
|
-
Requires-Dist:
|
|
22
|
-
Requires-Dist:
|
|
23
|
-
|
|
21
|
+
Requires-Dist: pre-commit==4.2.0; extra == 'dev'
|
|
22
|
+
Requires-Dist: ruff==0.12.5; extra == 'dev'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
24
|
|
|
25
25
|
# Couchbase MCP Server
|
|
26
26
|
|
|
27
27
|
An [MCP](https://modelcontextprotocol.io/) server implementation of Couchbase that allows LLMs to directly interact with Couchbase clusters.
|
|
28
28
|
|
|
29
|
-
[](https://opensource.org/licenses/Apache-2.0) [](https://www.python.org/downloads/) [](https://pypi.org/project/couchbase-mcp-server/) [](https://mseep.ai/app/13fce476-0e74-4b1e-ab82-1df2a3204809)
|
|
29
|
+
[](https://opensource.org/licenses/Apache-2.0) [](https://www.python.org/downloads/) [](https://pypi.org/project/couchbase-mcp-server/) [](https://mseep.ai/app/13fce476-0e74-4b1e-ab82-1df2a3204809) [](https://archestra.ai/mcp-catalog/couchbase-ecosystem__mcp-server-couchbase)
|
|
30
30
|
|
|
31
31
|
<a href="https://glama.ai/mcp/servers/@Couchbase-Ecosystem/mcp-server-couchbase">
|
|
32
32
|
<img width="380" height="200" src="https://glama.ai/mcp/servers/@Couchbase-Ecosystem/mcp-server-couchbase/badge" alt="Couchbase Server MCP server" />
|
|
@@ -34,7 +34,10 @@ An [MCP](https://modelcontextprotocol.io/) server implementation of Couchbase th
|
|
|
34
34
|
|
|
35
35
|
## Features
|
|
36
36
|
|
|
37
|
+
- Get a list of all the buckets in the cluster
|
|
37
38
|
- Get a list of all the scopes and collections in the specified bucket
|
|
39
|
+
- Get a list of all the scopes in the specified bucket
|
|
40
|
+
- Get a list of all the collections in a specified scope and bucket. Note that this tool requires the cluster to have Query service.
|
|
38
41
|
- Get the structure for a collection
|
|
39
42
|
- Get a document by ID from a specified scope and collection
|
|
40
43
|
- Upsert a document by ID to a specified scope and collection
|
|
@@ -43,6 +46,9 @@ An [MCP](https://modelcontextprotocol.io/) server implementation of Couchbase th
|
|
|
43
46
|
- There is an option in the MCP server, `CB_MCP_READ_ONLY_QUERY_MODE` that is set to true by default to disable running SQL++ queries that change the data or the underlying collection structure. Note that the documents can still be updated by ID.
|
|
44
47
|
- Get the status of the MCP server
|
|
45
48
|
- Check the cluster credentials by connecting to the cluster
|
|
49
|
+
- List all indexes in the cluster with their definitions, with optional filtering by bucket, scope, collection and index name.
|
|
50
|
+
- Get index recommendations from Couchbase Index Advisor for a given SQL++ query to optimize query performance
|
|
51
|
+
- Get cluster health status and list of all running services
|
|
46
52
|
|
|
47
53
|
## Prerequisites
|
|
48
54
|
|
|
@@ -53,7 +59,7 @@ An [MCP](https://modelcontextprotocol.io/) server implementation of Couchbase th
|
|
|
53
59
|
|
|
54
60
|
## Configuration
|
|
55
61
|
|
|
56
|
-
The MCP server can be run either from the
|
|
62
|
+
The MCP server can be run either from the prebuilt PyPI package or the source using uv.
|
|
57
63
|
|
|
58
64
|
### Running from PyPI
|
|
59
65
|
|
|
@@ -61,6 +67,8 @@ We publish a pre built [PyPI package](https://pypi.org/project/couchbase-mcp-ser
|
|
|
61
67
|
|
|
62
68
|
#### Server Configuration using Pre built Package for MCP Clients
|
|
63
69
|
|
|
70
|
+
#### Basic Authentication
|
|
71
|
+
|
|
64
72
|
```json
|
|
65
73
|
{
|
|
66
74
|
"mcpServers": {
|
|
@@ -70,8 +78,27 @@ We publish a pre built [PyPI package](https://pypi.org/project/couchbase-mcp-ser
|
|
|
70
78
|
"env": {
|
|
71
79
|
"CB_CONNECTION_STRING": "couchbases://connection-string",
|
|
72
80
|
"CB_USERNAME": "username",
|
|
73
|
-
"CB_PASSWORD": "password"
|
|
74
|
-
|
|
81
|
+
"CB_PASSWORD": "password"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
or
|
|
89
|
+
|
|
90
|
+
#### mTLS
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"mcpServers": {
|
|
95
|
+
"couchbase": {
|
|
96
|
+
"command": "uvx",
|
|
97
|
+
"args": ["couchbase-mcp-server"],
|
|
98
|
+
"env": {
|
|
99
|
+
"CB_CONNECTION_STRING": "couchbases://connection-string",
|
|
100
|
+
"CB_CLIENT_CERT_PATH": "/path/to/client-certificate.pem",
|
|
101
|
+
"CB_CLIENT_KEY_PATH": "/path/to/client.key"
|
|
75
102
|
}
|
|
76
103
|
}
|
|
77
104
|
}
|
|
@@ -108,8 +135,7 @@ This is the common configuration for the MCP clients such as Claude Desktop, Cur
|
|
|
108
135
|
"env": {
|
|
109
136
|
"CB_CONNECTION_STRING": "couchbases://connection-string",
|
|
110
137
|
"CB_USERNAME": "username",
|
|
111
|
-
"CB_PASSWORD": "password"
|
|
112
|
-
"CB_BUCKET_NAME": "bucket_name"
|
|
138
|
+
"CB_PASSWORD": "password"
|
|
113
139
|
}
|
|
114
140
|
}
|
|
115
141
|
}
|
|
@@ -123,17 +149,21 @@ This is the common configuration for the MCP clients such as Claude Desktop, Cur
|
|
|
123
149
|
### Additional Configuration for MCP Server
|
|
124
150
|
|
|
125
151
|
The server can be configured using environment variables or command line arguments:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
152
|
+
| Environment Variable | CLI Argument | Description | Default |
|
|
153
|
+
|--------------------------------|--------------------------|---------------------------------------------------------------------------------------------|------------------------------------------|
|
|
154
|
+
| `CB_CONNECTION_STRING` | `--connection-string` | Connection string to the Couchbase cluster | **Required** |
|
|
155
|
+
| `CB_USERNAME` | `--username` | Username with access to required buckets for basic authentication | **Required (or Client Certificate and Key needed for mTLS)** |
|
|
156
|
+
| `CB_PASSWORD` | `--password` | Password for basic authentication | **Required (or Client Certificate and Key needed for mTLS)** |
|
|
157
|
+
| `CB_CLIENT_CERT_PATH` | `--client-cert-path` | Path to the client certificate file for mTLS authentication| **Required if using mTLS (or Username and Password required)** |
|
|
158
|
+
| `CB_CLIENT_KEY_PATH` | `--client-key-path` | Path to the client key file for mTLS authentication| **Required if using mTLS (or Username and Password required)** |
|
|
159
|
+
| `CB_CA_CERT_PATH` | `--ca-cert-path` | Path to server root certificate for TLS if server is configured with a self-signed/untrusted certificate. This will not be required if you are connecting to Capella | |
|
|
160
|
+
| `CB_MCP_READ_ONLY_QUERY_MODE` | `--read-only-query-mode` | Prevent data modification queries | `true` |
|
|
161
|
+
| `CB_MCP_TRANSPORT` | `--transport` | Transport mode: `stdio`, `http`, `sse` | `stdio` |
|
|
162
|
+
| `CB_MCP_HOST` | `--host` | Host for HTTP/SSE transport modes | `127.0.0.1` |
|
|
163
|
+
| `CB_MCP_PORT` | `--port` | Port for HTTP/SSE transport modes | `8000` |
|
|
164
|
+
|
|
165
|
+
> Note: For authentication, you need either the Username and Password or the Client Certificate and key paths. Optionally, you can specify the CA root certificate path that will be used to validate the server certificates.
|
|
166
|
+
> If both the Client Certificate & key path and the username and password are specified, the client certificates will be used for authentication.
|
|
137
167
|
|
|
138
168
|
You can also check the version of the server using:
|
|
139
169
|
|
|
@@ -228,7 +258,12 @@ Check if your [MCP client](https://modelcontextprotocol.io/clients) supports str
|
|
|
228
258
|
By default, the MCP server will run on port 8000 but this can be configured using the `--port` or `CB_MCP_PORT` environment variable.
|
|
229
259
|
|
|
230
260
|
```bash
|
|
231
|
-
uvx couchbase-mcp-server
|
|
261
|
+
uvx couchbase-mcp-server \
|
|
262
|
+
--connection-string='<couchbase_connection_string>' \
|
|
263
|
+
--username='<database_username>' \
|
|
264
|
+
--password='<database_password>' \
|
|
265
|
+
--read-only-query-mode=true \
|
|
266
|
+
--transport=http
|
|
232
267
|
```
|
|
233
268
|
|
|
234
269
|
The server will be available on http://localhost:8000/mcp. This can be used in MCP clients supporting streamable http transport mode such as Cursor.
|
|
@@ -256,7 +291,12 @@ There is an option to run the MCP server in [Server-Sent Events (SSE)](https://m
|
|
|
256
291
|
By default, the MCP server will run on port 8000 but this can be configured using the `--port` or `CB_MCP_PORT` environment variable.
|
|
257
292
|
|
|
258
293
|
```bash
|
|
259
|
-
|
|
294
|
+
uvx couchbase-mcp-server \
|
|
295
|
+
--connection-string='<couchbase_connection_string>' \
|
|
296
|
+
--username='<database_username>' \
|
|
297
|
+
--password='<database_password>' \
|
|
298
|
+
--read-only-query-mode=true \
|
|
299
|
+
--transport=sse
|
|
260
300
|
```
|
|
261
301
|
|
|
262
302
|
The server will be available on http://localhost:8000/sse. This can be used in MCP clients supporting SSE transport mode such as Cursor.
|
|
@@ -331,7 +371,6 @@ docker run --rm -i \
|
|
|
331
371
|
-e CB_CONNECTION_STRING='<couchbase_connection_string>' \
|
|
332
372
|
-e CB_USERNAME='<database_user>' \
|
|
333
373
|
-e CB_PASSWORD='<database_password>' \
|
|
334
|
-
-e CB_BUCKET_NAME='<bucket_name>' \
|
|
335
374
|
-e CB_MCP_TRANSPORT='<http|sse|stdio>' \
|
|
336
375
|
-e CB_MCP_READ_ONLY_QUERY_MODE='<true|false>' \
|
|
337
376
|
-e CB_MCP_PORT=9001 \
|
|
@@ -360,8 +399,6 @@ The Docker image can be used in `stdio` transport mode with the following config
|
|
|
360
399
|
"CB_USERNAME=<database_user>",
|
|
361
400
|
"-e",
|
|
362
401
|
"CB_PASSWORD=<database_password>",
|
|
363
|
-
"-e",
|
|
364
|
-
"CB_BUCKET_NAME=<bucket_name>",
|
|
365
402
|
"mcp/couchbase"
|
|
366
403
|
]
|
|
367
404
|
}
|
|
@@ -387,11 +424,11 @@ The Couchbase MCP server can also be used as a managed server in your agentic ap
|
|
|
387
424
|
## Troubleshooting Tips
|
|
388
425
|
|
|
389
426
|
- Ensure the path to your MCP server repository is correct in the configuration if running from source.
|
|
390
|
-
- Verify that your Couchbase connection string, database username, password
|
|
427
|
+
- Verify that your Couchbase connection string, database username, password or the path to the certificates are correct.
|
|
391
428
|
- If using Couchbase Capella, ensure that the cluster is [accessible](https://docs.couchbase.com/cloud/clusters/allow-ip-address.html) from the machine where the MCP server is running.
|
|
392
|
-
- Check that the database user has proper permissions to access
|
|
393
|
-
- Confirm that the uv package manager is properly installed and accessible. You may need to provide absolute path to uv
|
|
394
|
-
- Check the logs for any errors or warnings that may indicate issues with the MCP server. The
|
|
429
|
+
- Check that the database user has proper permissions to access at least one bucket.
|
|
430
|
+
- Confirm that the `uv` package manager is properly installed and accessible. You may need to provide absolute path to `uv`/`uvx` in the `command` field in the configuration.
|
|
431
|
+
- Check the logs for any errors or warnings that may indicate issues with the MCP server. The location of the logs depend on your MCP client.
|
|
395
432
|
- If you are observing issues running your MCP server from source after updating your local MCP server repository, try running `uv sync` to update the [dependencies](https://docs.astral.sh/uv/concepts/projects/sync/#syncing-the-environment).
|
|
396
433
|
|
|
397
434
|
---
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
certs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
certs/capella_root_ca.pem,sha256=SuSjgKclcQQg0kheTRd3dg6B0FUsUy717T5n3xcAU_E,1131
|
|
3
|
+
mcp_server.py,sha256=dvHQR-55JhuXX_bj2hLU0ek411qPp0qHEKqAmPdwjKU,4991
|
|
4
|
+
tools/__init__.py,sha256=otQd8IiEILtl1jgorEO1E9KqL_2xBBlqwnVHejoCPE0,1668
|
|
5
|
+
tools/index.py,sha256=cCBr0ptFBVc-HN5SoCauQAh2DsAP_Is8NPUSa6QcLM0,6682
|
|
6
|
+
tools/kv.py,sha256=NGUs43iuXElj9rYe4RCyCStqoh5y1fUgbg1oWuU4WeQ,2493
|
|
7
|
+
tools/query.py,sha256=fSSG7XuxnND1lHwI-r8y_M3h6f82vCXxCwB_A2wHN-M,3598
|
|
8
|
+
tools/server.py,sha256=4krPjBoQmUHUmOE03T0CcCGFJtoaeHVS91oOrYj8JsA,6670
|
|
9
|
+
utils/__init__.py,sha256=Fcbp-VIK0Gwwy7hl1AjV9NBKZsscmOV2vYdTBam5M3A,1361
|
|
10
|
+
utils/config.py,sha256=B6H_JYDn6uxtu9juM924zdvNQgSaHh_u6rYME3_0_xQ,268
|
|
11
|
+
utils/connection.py,sha256=NtAU4pmHMZubSJcs_X_lai9o8dih5mW0RyrRdmyp1Po,2892
|
|
12
|
+
utils/constants.py,sha256=w0zvQ1zMzJBg44Yl3aQW8KfaaRPn0BgPOLEe8xLeLSE,487
|
|
13
|
+
utils/context.py,sha256=XZL4M70BMdFBptJ9sT0zxhEey-EvvoSKZJrP_sb7q-A,2286
|
|
14
|
+
utils/index_utils.py,sha256=W0rvoBXU_2aB9m-HDlLChZoMzvlIX6FUWF6RTsYGfYM,10910
|
|
15
|
+
couchbase_mcp_server-0.5.1.dist-info/METADATA,sha256=ufeqvKJPZcWL_b0uki8UqGMuU34c2R2--aNnP1211MY,20964
|
|
16
|
+
couchbase_mcp_server-0.5.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
17
|
+
couchbase_mcp_server-0.5.1.dist-info/entry_points.txt,sha256=iU5pF4kIMTnNhoMPHhdH-k8o1Fmxb_iM9qJHCZcL6Ak,57
|
|
18
|
+
couchbase_mcp_server-0.5.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
19
|
+
couchbase_mcp_server-0.5.1.dist-info/RECORD,,
|
mcp_server.py
CHANGED
|
@@ -78,9 +78,22 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
|
|
|
78
78
|
help="Couchbase database password (required for operations)",
|
|
79
79
|
)
|
|
80
80
|
@click.option(
|
|
81
|
-
"--
|
|
82
|
-
envvar="
|
|
83
|
-
|
|
81
|
+
"--ca-cert-path",
|
|
82
|
+
envvar="CB_CA_CERT_PATH",
|
|
83
|
+
default=None,
|
|
84
|
+
help="Path to the server trust store (CA certificate) file. The certificate at this path is used to verify the server certificate during the authentication process.",
|
|
85
|
+
)
|
|
86
|
+
@click.option(
|
|
87
|
+
"--client-cert-path",
|
|
88
|
+
envvar="CB_CLIENT_CERT_PATH",
|
|
89
|
+
default=None,
|
|
90
|
+
help="Path to the client certificate file used for mTLS authentication.",
|
|
91
|
+
)
|
|
92
|
+
@click.option(
|
|
93
|
+
"--client-key-path",
|
|
94
|
+
envvar="CB_CLIENT_KEY_PATH",
|
|
95
|
+
default=None,
|
|
96
|
+
help="Path to the client certificate key file used for mTLS authentication.",
|
|
84
97
|
)
|
|
85
98
|
@click.option(
|
|
86
99
|
"--read-only-query-mode",
|
|
@@ -121,7 +134,9 @@ def main(
|
|
|
121
134
|
connection_string,
|
|
122
135
|
username,
|
|
123
136
|
password,
|
|
124
|
-
|
|
137
|
+
ca_cert_path,
|
|
138
|
+
client_cert_path,
|
|
139
|
+
client_key_path,
|
|
125
140
|
read_only_query_mode,
|
|
126
141
|
transport,
|
|
127
142
|
host,
|
|
@@ -133,7 +148,9 @@ def main(
|
|
|
133
148
|
"connection_string": connection_string,
|
|
134
149
|
"username": username,
|
|
135
150
|
"password": password,
|
|
136
|
-
"
|
|
151
|
+
"ca_cert_path": ca_cert_path,
|
|
152
|
+
"client_cert_path": client_cert_path,
|
|
153
|
+
"client_key_path": client_key_path,
|
|
137
154
|
"read_only_query_mode": read_only_query_mode,
|
|
138
155
|
"transport": transport,
|
|
139
156
|
"host": host,
|
|
@@ -148,7 +165,6 @@ def main(
|
|
|
148
165
|
{
|
|
149
166
|
"host": host,
|
|
150
167
|
"port": port,
|
|
151
|
-
"transport": sdk_transport,
|
|
152
168
|
}
|
|
153
169
|
if transport in NETWORK_TRANSPORTS
|
|
154
170
|
else {}
|
tools/__init__.py
CHANGED
|
@@ -4,6 +4,9 @@ Couchbase MCP Tools
|
|
|
4
4
|
This module contains all the MCP tools for Couchbase operations.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
# Index tools
|
|
8
|
+
from .index import get_index_advisor_recommendations, list_indexes
|
|
9
|
+
|
|
7
10
|
# Key-Value tools
|
|
8
11
|
from .kv import (
|
|
9
12
|
delete_document_by_id,
|
|
@@ -19,21 +22,31 @@ from .query import (
|
|
|
19
22
|
|
|
20
23
|
# Server tools
|
|
21
24
|
from .server import (
|
|
25
|
+
get_buckets_in_cluster,
|
|
26
|
+
get_cluster_health_and_services,
|
|
27
|
+
get_collections_in_scope,
|
|
22
28
|
get_scopes_and_collections_in_bucket,
|
|
29
|
+
get_scopes_in_bucket,
|
|
23
30
|
get_server_configuration_status,
|
|
24
31
|
test_cluster_connection,
|
|
25
32
|
)
|
|
26
33
|
|
|
27
34
|
# List of all tools for easy registration
|
|
28
35
|
ALL_TOOLS = [
|
|
36
|
+
get_buckets_in_cluster,
|
|
29
37
|
get_server_configuration_status,
|
|
30
38
|
test_cluster_connection,
|
|
31
39
|
get_scopes_and_collections_in_bucket,
|
|
40
|
+
get_collections_in_scope,
|
|
41
|
+
get_scopes_in_bucket,
|
|
32
42
|
get_document_by_id,
|
|
33
43
|
upsert_document_by_id,
|
|
34
44
|
delete_document_by_id,
|
|
35
45
|
get_schema_for_collection,
|
|
36
46
|
run_sql_plus_plus_query,
|
|
47
|
+
get_index_advisor_recommendations,
|
|
48
|
+
list_indexes,
|
|
49
|
+
get_cluster_health_and_services,
|
|
37
50
|
]
|
|
38
51
|
|
|
39
52
|
__all__ = [
|
|
@@ -41,11 +54,17 @@ __all__ = [
|
|
|
41
54
|
"get_server_configuration_status",
|
|
42
55
|
"test_cluster_connection",
|
|
43
56
|
"get_scopes_and_collections_in_bucket",
|
|
57
|
+
"get_collections_in_scope",
|
|
58
|
+
"get_scopes_in_bucket",
|
|
59
|
+
"get_buckets_in_cluster",
|
|
44
60
|
"get_document_by_id",
|
|
45
61
|
"upsert_document_by_id",
|
|
46
62
|
"delete_document_by_id",
|
|
47
63
|
"get_schema_for_collection",
|
|
48
64
|
"run_sql_plus_plus_query",
|
|
65
|
+
"get_index_advisor_recommendations",
|
|
66
|
+
"list_indexes",
|
|
67
|
+
"get_cluster_health_and_services",
|
|
49
68
|
# Convenience
|
|
50
69
|
"ALL_TOOLS",
|
|
51
70
|
]
|
tools/index.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tools for index operations.
|
|
3
|
+
|
|
4
|
+
This module contains tools for listing and managing indexes in the Couchbase cluster and getting index recommendations using the Couchbase Index Advisor.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from mcp.server.fastmcp import Context
|
|
11
|
+
|
|
12
|
+
from tools.query import run_sql_plus_plus_query
|
|
13
|
+
from utils.config import get_settings
|
|
14
|
+
from utils.constants import MCP_SERVER_NAME
|
|
15
|
+
from utils.index_utils import (
|
|
16
|
+
fetch_indexes_from_rest_api,
|
|
17
|
+
process_index_data,
|
|
18
|
+
validate_connection_settings,
|
|
19
|
+
validate_filter_params,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(f"{MCP_SERVER_NAME}.tools.index")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_index_advisor_recommendations(
|
|
26
|
+
ctx: Context, bucket_name: str, scope_name: str, query: str
|
|
27
|
+
) -> dict[str, Any]:
|
|
28
|
+
"""Get index recommendations from Couchbase Index Advisor for a given SQL++ query.
|
|
29
|
+
|
|
30
|
+
The Index Advisor analyzes the query and provides recommendations for optimal indexes.
|
|
31
|
+
This tool works with SELECT, UPDATE, DELETE, or MERGE queries.
|
|
32
|
+
The queries will be run on the specified scope in the specified bucket.
|
|
33
|
+
|
|
34
|
+
Returns a dictionary with:
|
|
35
|
+
- current_used_indexes: Array of currently used indexes (if any)
|
|
36
|
+
- recommended_indexes: Array of recommended secondary indexes (if any)
|
|
37
|
+
- recommended_covering_indexes: Array of recommended covering indexes (if any)
|
|
38
|
+
|
|
39
|
+
Each index object contains:
|
|
40
|
+
- index: The CREATE INDEX SQL++ command
|
|
41
|
+
- statements: Array of statement objects with the query and run count
|
|
42
|
+
"""
|
|
43
|
+
try:
|
|
44
|
+
# Build the ADVISOR query
|
|
45
|
+
advisor_query = f"SELECT ADVISOR('{query}') AS advisor_result"
|
|
46
|
+
|
|
47
|
+
logger.info("Running Index Advisor for the provided query")
|
|
48
|
+
|
|
49
|
+
# Execute the ADVISOR function at cluster level using run_sql_plus_plus_query
|
|
50
|
+
advisor_results = run_sql_plus_plus_query(
|
|
51
|
+
ctx, bucket_name, scope_name, advisor_query
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if not advisor_results:
|
|
55
|
+
return {
|
|
56
|
+
"message": "No recommendations available",
|
|
57
|
+
"current_used_indexes": [],
|
|
58
|
+
"recommended_indexes": [],
|
|
59
|
+
"recommended_covering_indexes": [],
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# The result is wrapped in advisor_result key
|
|
63
|
+
advisor_data = advisor_results[0].get("advisor_result", {})
|
|
64
|
+
|
|
65
|
+
# Extract the relevant fields with defaults
|
|
66
|
+
response = {
|
|
67
|
+
"current_used_indexes": advisor_data.get("current_used_indexes", []),
|
|
68
|
+
"recommended_indexes": advisor_data.get("recommended_indexes", []),
|
|
69
|
+
"recommended_covering_indexes": advisor_data.get(
|
|
70
|
+
"recommended_covering_indexes", []
|
|
71
|
+
),
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Add summary information for better user experience
|
|
75
|
+
response["summary"] = {
|
|
76
|
+
"current_indexes_count": len(response["current_used_indexes"]),
|
|
77
|
+
"recommended_indexes_count": len(response["recommended_indexes"]),
|
|
78
|
+
"recommended_covering_indexes_count": len(
|
|
79
|
+
response["recommended_covering_indexes"]
|
|
80
|
+
),
|
|
81
|
+
"has_recommendations": bool(
|
|
82
|
+
response["recommended_indexes"]
|
|
83
|
+
or response["recommended_covering_indexes"]
|
|
84
|
+
),
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
logger.info(
|
|
88
|
+
f"Index Advisor completed. Found {response['summary']['recommended_indexes_count']} recommended indexes"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
return response
|
|
92
|
+
|
|
93
|
+
except Exception as e:
|
|
94
|
+
logger.error(f"Error running Index Advisor: {e!s}", exc_info=True)
|
|
95
|
+
raise
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def list_indexes(
|
|
99
|
+
ctx: Context,
|
|
100
|
+
bucket_name: str | None = None,
|
|
101
|
+
scope_name: str | None = None,
|
|
102
|
+
collection_name: str | None = None,
|
|
103
|
+
index_name: str | None = None,
|
|
104
|
+
include_raw_index_stats: bool = False,
|
|
105
|
+
) -> list[dict[str, Any]]:
|
|
106
|
+
"""List all indexes in the cluster with optional filtering by bucket, scope, collection, and index name.
|
|
107
|
+
Returns a list of indexes with their names and CREATE INDEX definitions.
|
|
108
|
+
Uses the Index Service REST API (/getIndexStatus) to retrieve index information directly.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
ctx: MCP context for cluster connection
|
|
112
|
+
bucket_name: Optional bucket name to filter indexes
|
|
113
|
+
scope_name: Optional scope name to filter indexes (requires bucket_name)
|
|
114
|
+
collection_name: Optional collection name to filter indexes (requires bucket_name and scope_name)
|
|
115
|
+
index_name: Optional index name to filter indexes (requires bucket_name, scope_name, and collection_name)
|
|
116
|
+
include_raw_index_stats: If True, include raw index stats (as-is from API) in addition
|
|
117
|
+
to cleaned-up version. Default is False.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
List of dictionaries with keys:
|
|
121
|
+
- name (str): Index name
|
|
122
|
+
- definition (str): Cleaned-up CREATE INDEX statement
|
|
123
|
+
- status (str): Current status of the index (e.g., "Ready", "Building", "Deferred")
|
|
124
|
+
- isPrimary (bool): Whether this is a primary index
|
|
125
|
+
- bucket (str): Bucket name where the index exists
|
|
126
|
+
- scope (str): Scope name where the index exists
|
|
127
|
+
- collection (str): Collection name where the index exists
|
|
128
|
+
- raw_index_stats (dict, optional): Complete raw index status object from API including metadata,
|
|
129
|
+
state, keyspace info, etc. (only if include_raw_index_stats=True)
|
|
130
|
+
"""
|
|
131
|
+
try:
|
|
132
|
+
# Validate parameters
|
|
133
|
+
validate_filter_params(bucket_name, scope_name, collection_name, index_name)
|
|
134
|
+
|
|
135
|
+
# Get and validate connection settings
|
|
136
|
+
settings = get_settings()
|
|
137
|
+
validate_connection_settings(settings)
|
|
138
|
+
|
|
139
|
+
# Fetch indexes from REST API
|
|
140
|
+
logger.info(
|
|
141
|
+
f"Fetching indexes from REST API for bucket={bucket_name}, "
|
|
142
|
+
f"scope={scope_name}, collection={collection_name}, index={index_name}"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
raw_indexes = fetch_indexes_from_rest_api(
|
|
146
|
+
settings["connection_string"],
|
|
147
|
+
settings["username"],
|
|
148
|
+
settings["password"],
|
|
149
|
+
bucket_name=bucket_name,
|
|
150
|
+
scope_name=scope_name,
|
|
151
|
+
collection_name=collection_name,
|
|
152
|
+
index_name=index_name,
|
|
153
|
+
ca_cert_path=settings.get("ca_cert_path"),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Process and format the results
|
|
157
|
+
indexes = [
|
|
158
|
+
processed
|
|
159
|
+
for idx in raw_indexes
|
|
160
|
+
if (processed := process_index_data(idx, include_raw_index_stats))
|
|
161
|
+
is not None
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
logger.info(
|
|
165
|
+
f"Found {len(indexes)} indexes from REST API "
|
|
166
|
+
f"(include_raw_index_stats={include_raw_index_stats})"
|
|
167
|
+
)
|
|
168
|
+
return indexes
|
|
169
|
+
|
|
170
|
+
except Exception as e:
|
|
171
|
+
logger.error(f"Error listing indexes: {e}", exc_info=True)
|
|
172
|
+
raise
|
tools/kv.py
CHANGED
|
@@ -9,18 +9,25 @@ from typing import Any
|
|
|
9
9
|
|
|
10
10
|
from mcp.server.fastmcp import Context
|
|
11
11
|
|
|
12
|
+
from utils.connection import connect_to_bucket
|
|
12
13
|
from utils.constants import MCP_SERVER_NAME
|
|
13
|
-
from utils.context import
|
|
14
|
+
from utils.context import get_cluster_connection
|
|
14
15
|
|
|
15
16
|
logger = logging.getLogger(f"{MCP_SERVER_NAME}.tools.kv")
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
def get_document_by_id(
|
|
19
|
-
ctx: Context,
|
|
20
|
+
ctx: Context,
|
|
21
|
+
bucket_name: str,
|
|
22
|
+
scope_name: str,
|
|
23
|
+
collection_name: str,
|
|
24
|
+
document_id: str,
|
|
20
25
|
) -> dict[str, Any]:
|
|
21
26
|
"""Get a document by its ID from the specified scope and collection.
|
|
22
27
|
If the document is not found, it will raise an exception."""
|
|
23
|
-
|
|
28
|
+
|
|
29
|
+
cluster = get_cluster_connection(ctx)
|
|
30
|
+
bucket = connect_to_bucket(cluster, bucket_name)
|
|
24
31
|
try:
|
|
25
32
|
collection = bucket.scope(scope_name).collection(collection_name)
|
|
26
33
|
result = collection.get(document_id)
|
|
@@ -32,6 +39,7 @@ def get_document_by_id(
|
|
|
32
39
|
|
|
33
40
|
def upsert_document_by_id(
|
|
34
41
|
ctx: Context,
|
|
42
|
+
bucket_name: str,
|
|
35
43
|
scope_name: str,
|
|
36
44
|
collection_name: str,
|
|
37
45
|
document_id: str,
|
|
@@ -39,7 +47,8 @@ def upsert_document_by_id(
|
|
|
39
47
|
) -> bool:
|
|
40
48
|
"""Insert or update a document by its ID.
|
|
41
49
|
Returns True on success, False on failure."""
|
|
42
|
-
|
|
50
|
+
cluster = get_cluster_connection(ctx)
|
|
51
|
+
bucket = connect_to_bucket(cluster, bucket_name)
|
|
43
52
|
try:
|
|
44
53
|
collection = bucket.scope(scope_name).collection(collection_name)
|
|
45
54
|
collection.upsert(document_id, document_content)
|
|
@@ -51,11 +60,16 @@ def upsert_document_by_id(
|
|
|
51
60
|
|
|
52
61
|
|
|
53
62
|
def delete_document_by_id(
|
|
54
|
-
ctx: Context,
|
|
63
|
+
ctx: Context,
|
|
64
|
+
bucket_name: str,
|
|
65
|
+
scope_name: str,
|
|
66
|
+
collection_name: str,
|
|
67
|
+
document_id: str,
|
|
55
68
|
) -> bool:
|
|
56
69
|
"""Delete a document by its ID.
|
|
57
70
|
Returns True on success, False on failure."""
|
|
58
|
-
|
|
71
|
+
cluster = get_cluster_connection(ctx)
|
|
72
|
+
bucket = connect_to_bucket(cluster, bucket_name)
|
|
59
73
|
try:
|
|
60
74
|
collection = bucket.scope(scope_name).collection(collection_name)
|
|
61
75
|
collection.remove(document_id)
|