couchbase-mcp-server 0.5.3__py3-none-any.whl → 0.6.0__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.
- {couchbase_mcp_server-0.5.3.dist-info → couchbase_mcp_server-0.6.0.dist-info}/METADATA +217 -31
- couchbase_mcp_server-0.6.0.dist-info/RECORD +19 -0
- mcp_server.py +54 -6
- tools/__init__.py +50 -6
- tools/kv.py +64 -1
- tools/query.py +7 -2
- tools/server.py +1 -0
- utils/__init__.py +2 -0
- utils/config.py +76 -0
- utils/context.py +11 -1
- couchbase_mcp_server-0.5.3.dist-info/RECORD +0 -19
- {couchbase_mcp_server-0.5.3.dist-info → couchbase_mcp_server-0.6.0.dist-info}/WHEEL +0 -0
- {couchbase_mcp_server-0.5.3.dist-info → couchbase_mcp_server-0.6.0.dist-info}/entry_points.txt +0 -0
- {couchbase_mcp_server-0.5.3.dist-info → couchbase_mcp_server-0.6.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: couchbase-mcp-server
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Couchbase MCP Server - The Developer Data Platform for Critical Applications in Our AI World
|
|
5
5
|
Project-URL: Homepage, https://github.com/Couchbase-Ecosystem/mcp-server-couchbase
|
|
6
6
|
Project-URL: Documentation, https://github.com/Couchbase-Ecosystem/mcp-server-couchbase#readme
|
|
@@ -20,6 +20,7 @@ Requires-Dist: urllib3>=2.0.0
|
|
|
20
20
|
Provides-Extra: dev
|
|
21
21
|
Requires-Dist: pre-commit==4.2.0; extra == 'dev'
|
|
22
22
|
Requires-Dist: pytest-asyncio==0.24.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
|
|
23
24
|
Requires-Dist: pytest==8.3.3; extra == 'dev'
|
|
24
25
|
Requires-Dist: ruff==0.12.5; extra == 'dev'
|
|
25
26
|
Description-Content-Type: text/markdown
|
|
@@ -36,32 +37,49 @@ An [MCP](https://modelcontextprotocol.io/) server implementation of Couchbase th
|
|
|
36
37
|
|
|
37
38
|
<!-- mcp-name: io.github.Couchbase-Ecosystem/mcp-server-couchbase -->
|
|
38
39
|
|
|
39
|
-
## Features
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
40
|
+
## Features/Tools
|
|
41
|
+
### Cluster setup & health tools
|
|
42
|
+
| Tool Name | Description |
|
|
43
|
+
|-----------|-------------|
|
|
44
|
+
| `get_server_configuration_status` | Get the status of the MCP server |
|
|
45
|
+
| `test_cluster_connection` | Check the cluster credentials by connecting to the cluster |
|
|
46
|
+
| `get_cluster_health_and_services` | Get cluster health status and list of all running services |
|
|
47
|
+
|
|
48
|
+
### Data model & schema discovery tools
|
|
49
|
+
| Tool Name | Description |
|
|
50
|
+
|-----------|-------------|
|
|
51
|
+
| `get_buckets_in_cluster` | Get a list of all the buckets in the cluster |
|
|
52
|
+
| `get_scopes_in_bucket` | Get a list of all the scopes in the specified bucket |
|
|
53
|
+
| `get_collections_in_scope` | Get a list of all the collections in a specified scope and bucket. Note that this tool requires the cluster to have Query service. |
|
|
54
|
+
| `get_scopes_and_collections_in_bucket` | Get a list of all the scopes and collections in the specified bucket |
|
|
55
|
+
| `get_schema_for_collection` | Get the structure for a collection |
|
|
56
|
+
|
|
57
|
+
### Document KV operations tools
|
|
58
|
+
| Tool Name | Description |
|
|
59
|
+
|-----------|-------------|
|
|
60
|
+
| `get_document_by_id` | Get a document by ID from a specified scope and collection |
|
|
61
|
+
| `upsert_document_by_id` | Upsert a document by ID to a specified scope and collection. **Disabled by default when `CB_MCP_READ_ONLY_MODE=true`.** |
|
|
62
|
+
| `insert_document_by_id` | Insert a new document by ID (fails if document exists). **Disabled by default when `CB_MCP_READ_ONLY_MODE=true`.** |
|
|
63
|
+
| `replace_document_by_id` | Replace an existing document by ID (fails if document doesn't exist). **Disabled by default when `CB_MCP_READ_ONLY_MODE=true`.** |
|
|
64
|
+
| `delete_document_by_id` | Delete a document by ID from a specified scope and collection. **Disabled by default when `CB_MCP_READ_ONLY_MODE=true`.** |
|
|
65
|
+
|
|
66
|
+
### Query and indexing tools
|
|
67
|
+
| Tool Name | Description |
|
|
68
|
+
|-----------|-------------|
|
|
69
|
+
| `list_indexes` | List all indexes in the cluster with their definitions, with optional filtering by bucket, scope, collection and index name. |
|
|
70
|
+
| `get_index_advisor_recommendations` | Get index recommendations from Couchbase Index Advisor for a given SQL++ query to optimize query performance |
|
|
71
|
+
| `run_sql_plus_plus_query` | Run a [SQL++ query](https://www.couchbase.com/sqlplusplus/) on a specified scope.<br><br>Queries are automatically scoped to the specified bucket and scope, so use collection names directly (e.g., `SELECT * FROM users` instead of `SELECT * FROM bucket.scope.users`).<br><br>`CB_MCP_READ_ONLY_MODE` is `true` by default, which means that **all write operations (KV and Query)** are disabled. When enabled, KV write tools are not loaded and SQL++ queries that modify data are blocked. |
|
|
72
|
+
|
|
73
|
+
### Query performance analysis tools
|
|
74
|
+
| Tool Name | Description |
|
|
75
|
+
|-----------|-------------|
|
|
76
|
+
| `get_longest_running_queries` | Get longest running queries by average service time |
|
|
77
|
+
| `get_most_frequent_queries` | Get most frequently executed queries |
|
|
78
|
+
| `get_queries_with_largest_response_sizes` | Get queries with the largest response sizes |
|
|
79
|
+
| `get_queries_with_large_result_count` | Get queries with the largest result counts |
|
|
80
|
+
| `get_queries_using_primary_index` | Get queries that use a primary index (potential performance concern) |
|
|
81
|
+
| `get_queries_not_using_covering_index` | Get queries that don't use a covering index |
|
|
82
|
+
| `get_queries_not_selective` | Get queries that are not selective (index scans return many more documents than final result) |
|
|
65
83
|
|
|
66
84
|
## Prerequisites
|
|
67
85
|
|
|
@@ -170,21 +188,135 @@ The server can be configured using environment variables or command line argumen
|
|
|
170
188
|
| `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)** |
|
|
171
189
|
| `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)** |
|
|
172
190
|
| `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 | |
|
|
173
|
-
| `
|
|
191
|
+
| `CB_MCP_READ_ONLY_MODE` | `--read-only-mode` | Prevent all data modifications (KV and Query). When enabled, KV write tools are not loaded. | `true` |
|
|
192
|
+
| `CB_MCP_READ_ONLY_QUERY_MODE` | `--read-only-query-mode` | **[DEPRECATED]** Prevent queries that modify data. Note that data modification would still be possible via document operations tools. Use `CB_MCP_READ_ONLY_MODE` instead. | `true` |
|
|
174
193
|
| `CB_MCP_TRANSPORT` | `--transport` | Transport mode: `stdio`, `http`, `sse` | `stdio` |
|
|
175
194
|
| `CB_MCP_HOST` | `--host` | Host for HTTP/SSE transport modes | `127.0.0.1` |
|
|
176
195
|
| `CB_MCP_PORT` | `--port` | Port for HTTP/SSE transport modes | `8000` |
|
|
196
|
+
| `CB_MCP_DISABLED_TOOLS` | `--disabled-tools` | Tools to disable (see [Disabling Tools](#disabling-tools)) | None |
|
|
197
|
+
|
|
198
|
+
#### Read-Only Mode Configuration
|
|
199
|
+
|
|
200
|
+
The MCP server provides two configuration options for controlling write operations:
|
|
201
|
+
|
|
202
|
+
**`CB_MCP_READ_ONLY_MODE`** (Recommended)
|
|
203
|
+
- When `true` (default): All write operations are disabled. KV write tools (upsert, insert, replace, delete) are **not loaded** and will not be available to the LLM.
|
|
204
|
+
- When `false`: KV write tools are loaded and available.
|
|
205
|
+
|
|
206
|
+
**`CB_MCP_READ_ONLY_QUERY_MODE`** (Deprecated)
|
|
207
|
+
- This option only controls SQL++ query-based writes but does not prevent KV write operations.
|
|
208
|
+
- **Deprecated**: Use `CB_MCP_READ_ONLY_MODE` instead for comprehensive protection.
|
|
209
|
+
|
|
210
|
+
**Mode Behavior Truth Table:**
|
|
211
|
+
|
|
212
|
+
| `READ_ONLY_MODE` | `READ_ONLY_QUERY_MODE` | Result |
|
|
213
|
+
|------------------|------------------------|--------|
|
|
214
|
+
| `true` | `true` | Read-only KV and Query operations. All writes disabled. |
|
|
215
|
+
| `true` | `false` | Read-only KV and Query operations. All writes disabled. |
|
|
216
|
+
| `false` | `true` | Only Query writes disabled. KV writes allowed. |
|
|
217
|
+
| `false` | `false` | All KV and Query operations allowed. |
|
|
218
|
+
|
|
219
|
+
> **Important**: When `READ_ONLY_MODE` is `true`, it takes precedence and disables all write operations regardless of `READ_ONLY_QUERY_MODE` setting. This is the recommended safe default to prevent inadvertent data modifications by LLMs.
|
|
177
220
|
|
|
178
221
|
> 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.
|
|
179
222
|
> If both the Client Certificate & key path and the username and password are specified, the client certificates will be used for authentication.
|
|
180
223
|
|
|
224
|
+
### Disabling Tools
|
|
225
|
+
|
|
226
|
+
You can disable specific tools to prevent them from being loaded and exposed to the MCP client. Disabled tools will not appear in the tool discovery and cannot be invoked by the LLM.
|
|
227
|
+
|
|
228
|
+
#### Supported Formats
|
|
229
|
+
|
|
230
|
+
**Comma-separated list:**
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
# Environment variable
|
|
234
|
+
CB_MCP_DISABLED_TOOLS="upsert_document_by_id, delete_document_by_id"
|
|
235
|
+
|
|
236
|
+
# Command line
|
|
237
|
+
uvx couchbase-mcp-server --disabled-tools upsert_document_by_id, delete_document_by_id
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**File path (one tool name per line):**
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# Environment variable
|
|
244
|
+
CB_MCP_DISABLED_TOOLS=disabled_tools.txt
|
|
245
|
+
|
|
246
|
+
# Command line
|
|
247
|
+
uvx couchbase-mcp-server --disabled-tools disabled_tools.txt
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**File format (e.g., `disabled_tools.txt`):**
|
|
251
|
+
|
|
252
|
+
```text
|
|
253
|
+
# Write operations
|
|
254
|
+
upsert_document_by_id
|
|
255
|
+
delete_document_by_id
|
|
256
|
+
|
|
257
|
+
# Index advisor
|
|
258
|
+
get_index_advisor_recommendations
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Lines starting with `#` are treated as comments and ignored.
|
|
262
|
+
|
|
263
|
+
#### MCP Client Configuration Examples
|
|
264
|
+
|
|
265
|
+
**Using comma-separated list:**
|
|
266
|
+
|
|
267
|
+
```json
|
|
268
|
+
{
|
|
269
|
+
"mcpServers": {
|
|
270
|
+
"couchbase": {
|
|
271
|
+
"command": "uvx",
|
|
272
|
+
"args": ["couchbase-mcp-server"],
|
|
273
|
+
"env": {
|
|
274
|
+
"CB_CONNECTION_STRING": "couchbases://connection-string",
|
|
275
|
+
"CB_USERNAME": "username",
|
|
276
|
+
"CB_PASSWORD": "password",
|
|
277
|
+
"CB_MCP_DISABLED_TOOLS": "upsert_document_by_id,delete_document_by_id"
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Using file path (recommended for many tools):**
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"mcpServers": {
|
|
289
|
+
"couchbase": {
|
|
290
|
+
"command": "uvx",
|
|
291
|
+
"args": ["couchbase-mcp-server"],
|
|
292
|
+
"env": {
|
|
293
|
+
"CB_CONNECTION_STRING": "couchbases://connection-string",
|
|
294
|
+
"CB_USERNAME": "username",
|
|
295
|
+
"CB_PASSWORD": "password",
|
|
296
|
+
"CB_MCP_DISABLED_TOOLS": "/path/to/disabled_tools.txt"
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
#### Important Security Note
|
|
304
|
+
|
|
305
|
+
> **Warning:** Disabling tools alone does not guarantee that certain operations cannot be performed. The underlying database user's RBAC (Role-Based Access Control) permissions are the authoritative security control.
|
|
306
|
+
>
|
|
307
|
+
> For example, even if you disable `upsert_document_by_id` and `delete_document_by_id`, data modifications can still occur via the `run_sql_plus_plus_query` tool using SQL++ DML statements (INSERT, UPDATE, DELETE, MERGE) unless:
|
|
308
|
+
> - The `CB_MCP_READ_ONLY_MODE` is set to `true` (default), OR
|
|
309
|
+
> - The database user lacks the necessary RBAC permissions for data modification
|
|
310
|
+
>
|
|
311
|
+
> **Best Practice:** Always configure appropriate RBAC permissions on your Couchbase user credentials as the primary security measure. Use tool disabling as an additional layer to guide LLM behavior and reduce the attack surface, not as the sole security control.
|
|
312
|
+
|
|
181
313
|
You can also check the version of the server using:
|
|
182
314
|
|
|
183
315
|
```bash
|
|
184
316
|
uvx couchbase-mcp-server --version
|
|
185
317
|
```
|
|
186
318
|
|
|
187
|
-
|
|
319
|
+
### Client Specific Configuration
|
|
188
320
|
|
|
189
321
|
<details>
|
|
190
322
|
<summary>Claude Desktop</summary>
|
|
@@ -259,6 +391,60 @@ For more details about MCP integration with Windsurf Editor, refer to the offici
|
|
|
259
391
|
|
|
260
392
|
</details>
|
|
261
393
|
|
|
394
|
+
<details>
|
|
395
|
+
<summary>VS Code</summary>
|
|
396
|
+
|
|
397
|
+
Follow the steps below to use the Couchbase MCP server with [VS Code](https://code.visualstudio.com/).
|
|
398
|
+
1. Install [VS Code](https://code.visualstudio.com/)
|
|
399
|
+
2. Following are a couple of ways to configure the MCP server.
|
|
400
|
+
* For a Workspace server configuration
|
|
401
|
+
- Create a new file in workspace as .vscode/mcp.json.
|
|
402
|
+
- Add the [configuration](#configuration) and save the file.
|
|
403
|
+
* For the Global server configuration:
|
|
404
|
+
- Run **MCP: Open User Configuration** in the Command Pallete(`Ctrl+Shift+P` or `Cmd+Shift+P`)
|
|
405
|
+
- Add the [configuration](#configuration) and save the file.
|
|
406
|
+
* **Note**: VS Code uses `servers` as the top-level JSON property in mcp.json files to define MCP (Model Context Protocol) servers, while Cursor uses `mcpServers` for the equivalent configuration. Check the [VS Code client configurations](https://code.visualstudio.com/docs/copilot/customization/mcp-servers) for any further changes or details. An example VS Code configuration is provided below.
|
|
407
|
+
```json
|
|
408
|
+
{
|
|
409
|
+
"servers": {
|
|
410
|
+
"couchbase": {
|
|
411
|
+
"command": "uvx",
|
|
412
|
+
"args": ["couchbase-mcp-server"],
|
|
413
|
+
"env": {
|
|
414
|
+
"CB_CONNECTION_STRING": "couchbases://connection-string",
|
|
415
|
+
"CB_USERNAME": "username",
|
|
416
|
+
"CB_PASSWORD": "password"
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
3. Once you save the file, the server starts and a small action list appears with `Running|Stop|n Tools|More..`.
|
|
423
|
+
4. Click on the options from the option list to `Start`/`Stop`/manage the server.
|
|
424
|
+
5. You can now use the Couchbase MCP server in VS Code to query your Couchbase cluster using natural language and perform CRUD operations on documents.
|
|
425
|
+
|
|
426
|
+
Logs:
|
|
427
|
+
In the Command Palette (`Ctrl+Shift+P` or `Cmd+Shift+P`),
|
|
428
|
+
- run **MCP: List Servers** command and pick the couchbase server
|
|
429
|
+
- choose “Show Output” to see its logs in the Output tab.
|
|
430
|
+
</details>
|
|
431
|
+
|
|
432
|
+
<details>
|
|
433
|
+
<summary>JetBrains IDEs</summary>
|
|
434
|
+
|
|
435
|
+
Follow the steps below to use the Couchbase MCP server with [JetBrains IDEs](https://www.jetbrains.com/)
|
|
436
|
+
1. Install any one of the [JetBrains IDEs](https://www.jetbrains.com/)
|
|
437
|
+
2. Install any one of the JetBrains plugins - [AI Assistant](https://www.jetbrains.com/help/ai-assistant/getting-started-with-ai-assistant.html) or [Junie](https://www.jetbrains.com/help/junie/get-started-with-junie.html)
|
|
438
|
+
3. Navigate to **Settings > Tools > AI Assistant or Junie > MCP Server**
|
|
439
|
+
4. Click "+" to add the Couchbase MCP [configuration](#configuration) and click Save.
|
|
440
|
+
5. You will see the Couchbase MCP server added to the list of servers. Once you click Apply, the Couchbase MCP server starts and on-hover of status, it shows all the tools available.
|
|
441
|
+
6. You can now use the Couchbase MCP server in JetBrains IDEs to query your Couchbase cluster using natural language and perform CRUD operations on documents.
|
|
442
|
+
|
|
443
|
+
Logs:
|
|
444
|
+
The log file can be explored at **Help > Show Log in Finder (Explorer) > mcp > couchbase**
|
|
445
|
+
|
|
446
|
+
</details>
|
|
447
|
+
|
|
262
448
|
## Streamable HTTP Transport Mode
|
|
263
449
|
|
|
264
450
|
The MCP Server can be run in [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http) transport mode which allows multiple clients to connect to the same server instance via HTTP.
|
|
@@ -275,7 +461,7 @@ uvx couchbase-mcp-server \
|
|
|
275
461
|
--connection-string='<couchbase_connection_string>' \
|
|
276
462
|
--username='<database_username>' \
|
|
277
463
|
--password='<database_password>' \
|
|
278
|
-
--read-only-
|
|
464
|
+
--read-only-mode=true \
|
|
279
465
|
--transport=http
|
|
280
466
|
```
|
|
281
467
|
|
|
@@ -308,7 +494,7 @@ uvx couchbase-mcp-server \
|
|
|
308
494
|
--connection-string='<couchbase_connection_string>' \
|
|
309
495
|
--username='<database_username>' \
|
|
310
496
|
--password='<database_password>' \
|
|
311
|
-
--read-only-
|
|
497
|
+
--read-only-mode=true \
|
|
312
498
|
--transport=sse
|
|
313
499
|
```
|
|
314
500
|
|
|
@@ -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=mI5Z_d1VTIdZnFirslUJW3UQnW8Ci-0RFyD90VyHhUg,6828
|
|
4
|
+
tools/__init__.py,sha256=7HNspBZLCpz5WwQkPg7p0irPYyrD3AouDUb6H0uzhvQ,3830
|
|
5
|
+
tools/index.py,sha256=cCBr0ptFBVc-HN5SoCauQAh2DsAP_Is8NPUSa6QcLM0,6682
|
|
6
|
+
tools/kv.py,sha256=ZRb7ixq3zCqiyPwJTtt4plNl9tCC_0kRDDqlUAh_apc,4938
|
|
7
|
+
tools/query.py,sha256=sOmn45nrysKlKavBymLSu-7sbwtFHBo0GwLcV-gmbDg,11552
|
|
8
|
+
tools/server.py,sha256=c5m_6GkwTaRwEelrQE4IHcs2aKZKd_X-BjnseMjkjMo,6734
|
|
9
|
+
utils/__init__.py,sha256=lV5QqPzMlHqInev9Nw_k3ToI9ABEZDfcqvE4p7cPLbU,1415
|
|
10
|
+
utils/config.py,sha256=4jIbE0dYHGidwlZVoLALNMLz_wBQ_J8XX5hvJPpu_BM,2730
|
|
11
|
+
utils/connection.py,sha256=NtAU4pmHMZubSJcs_X_lai9o8dih5mW0RyrRdmyp1Po,2892
|
|
12
|
+
utils/constants.py,sha256=w0zvQ1zMzJBg44Yl3aQW8KfaaRPn0BgPOLEe8xLeLSE,487
|
|
13
|
+
utils/context.py,sha256=q0eCe_I72rAEPWtSnf4qBEv5BuLHnko9qqCs4KTMW6g,2788
|
|
14
|
+
utils/index_utils.py,sha256=W0rvoBXU_2aB9m-HDlLChZoMzvlIX6FUWF6RTsYGfYM,10910
|
|
15
|
+
couchbase_mcp_server-0.6.0.dist-info/METADATA,sha256=3lUXRwa_fmDiXNHDj59oZaFePfsE5SzVFOTeESeJUEA,31086
|
|
16
|
+
couchbase_mcp_server-0.6.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
17
|
+
couchbase_mcp_server-0.6.0.dist-info/entry_points.txt,sha256=iU5pF4kIMTnNhoMPHhdH-k8o1Fmxb_iM9qJHCZcL6Ak,57
|
|
18
|
+
couchbase_mcp_server-0.6.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
19
|
+
couchbase_mcp_server-0.6.0.dist-info/RECORD,,
|
mcp_server.py
CHANGED
|
@@ -10,7 +10,7 @@ import click
|
|
|
10
10
|
from mcp.server.fastmcp import FastMCP
|
|
11
11
|
|
|
12
12
|
# Import tools
|
|
13
|
-
from tools import
|
|
13
|
+
from tools import get_tools
|
|
14
14
|
|
|
15
15
|
# Import utilities
|
|
16
16
|
from utils import (
|
|
@@ -25,6 +25,7 @@ from utils import (
|
|
|
25
25
|
NETWORK_TRANSPORTS_SDK_MAPPING,
|
|
26
26
|
AppContext,
|
|
27
27
|
get_settings,
|
|
28
|
+
parse_disabled_tools,
|
|
28
29
|
)
|
|
29
30
|
|
|
30
31
|
# Configure logging
|
|
@@ -41,14 +42,20 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
|
|
|
41
42
|
"""Initialize the MCP server context without establishing database connections."""
|
|
42
43
|
# Get configuration from Click context
|
|
43
44
|
settings = get_settings()
|
|
45
|
+
read_only_mode = settings.get("read_only_mode", True)
|
|
44
46
|
read_only_query_mode = settings.get("read_only_query_mode", True)
|
|
45
47
|
|
|
46
48
|
# Note: We don't validate configuration here to allow tool discovery
|
|
47
49
|
# Configuration will be validated when tools are actually used
|
|
48
|
-
logger.info(
|
|
50
|
+
logger.info(
|
|
51
|
+
f"MCP server initialized in lazy mode for tool discovery. "
|
|
52
|
+
f"Modes: (read_only_mode={read_only_mode}, read_only_query_mode={read_only_query_mode})"
|
|
53
|
+
)
|
|
49
54
|
app_context = None
|
|
50
55
|
try:
|
|
51
|
-
app_context = AppContext(
|
|
56
|
+
app_context = AppContext(
|
|
57
|
+
read_only_mode=read_only_mode, read_only_query_mode=read_only_query_mode
|
|
58
|
+
)
|
|
52
59
|
yield app_context
|
|
53
60
|
|
|
54
61
|
except Exception as e:
|
|
@@ -95,6 +102,13 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
|
|
|
95
102
|
default=None,
|
|
96
103
|
help="Path to the client certificate key file used for mTLS authentication.",
|
|
97
104
|
)
|
|
105
|
+
@click.option(
|
|
106
|
+
"--read-only-mode",
|
|
107
|
+
envvar="CB_MCP_READ_ONLY_MODE",
|
|
108
|
+
type=bool,
|
|
109
|
+
default=DEFAULT_READ_ONLY_MODE,
|
|
110
|
+
help="Enable read-only mode. When True (default), all write operations (KV and Query) are disabled and KV write tools are not loaded. Set to False to enable write operations.",
|
|
111
|
+
)
|
|
98
112
|
@click.option(
|
|
99
113
|
"--read-only-query-mode",
|
|
100
114
|
envvar=[
|
|
@@ -102,8 +116,9 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
|
|
|
102
116
|
"READ_ONLY_QUERY_MODE", # Deprecated
|
|
103
117
|
],
|
|
104
118
|
type=bool,
|
|
119
|
+
deprecated=True,
|
|
105
120
|
default=DEFAULT_READ_ONLY_MODE,
|
|
106
|
-
help="Enable read-only query mode. Set to True (default) to allow only read-only queries. Can be set to False to allow data modification queries.",
|
|
121
|
+
help="[DEPRECATED: Use --read-only-mode instead] Enable read-only query mode. Set to True (default) to allow only read-only queries. Can be set to False to allow data modification queries.",
|
|
107
122
|
)
|
|
108
123
|
@click.option(
|
|
109
124
|
"--transport",
|
|
@@ -127,6 +142,13 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
|
|
|
127
142
|
default=DEFAULT_PORT,
|
|
128
143
|
help="Port to run the server on (default: 8000)",
|
|
129
144
|
)
|
|
145
|
+
@click.option(
|
|
146
|
+
"--disabled-tools",
|
|
147
|
+
"disabled_tools",
|
|
148
|
+
envvar="CB_MCP_DISABLED_TOOLS",
|
|
149
|
+
help="Tools to disable. Accepts comma-separated tool names (e.g., 'tool_1,tool_2') "
|
|
150
|
+
"or a file path containing one tool name per line.",
|
|
151
|
+
)
|
|
130
152
|
@click.version_option(package_name="couchbase-mcp-server")
|
|
131
153
|
@click.pass_context
|
|
132
154
|
def main(
|
|
@@ -137,10 +159,12 @@ def main(
|
|
|
137
159
|
ca_cert_path,
|
|
138
160
|
client_cert_path,
|
|
139
161
|
client_key_path,
|
|
162
|
+
read_only_mode,
|
|
140
163
|
read_only_query_mode,
|
|
141
164
|
transport,
|
|
142
165
|
host,
|
|
143
166
|
port,
|
|
167
|
+
disabled_tools,
|
|
144
168
|
):
|
|
145
169
|
"""Couchbase MCP Server"""
|
|
146
170
|
# Store configuration in context
|
|
@@ -151,12 +175,29 @@ def main(
|
|
|
151
175
|
"ca_cert_path": ca_cert_path,
|
|
152
176
|
"client_cert_path": client_cert_path,
|
|
153
177
|
"client_key_path": client_key_path,
|
|
178
|
+
"read_only_mode": read_only_mode,
|
|
154
179
|
"read_only_query_mode": read_only_query_mode,
|
|
155
180
|
"transport": transport,
|
|
156
181
|
"host": host,
|
|
157
182
|
"port": port,
|
|
158
183
|
}
|
|
159
184
|
|
|
185
|
+
# Get tools based on mode settings
|
|
186
|
+
# When read_only_mode is True, KV write tools are not loaded
|
|
187
|
+
tools = get_tools(read_only_mode=read_only_mode)
|
|
188
|
+
|
|
189
|
+
# Parse and validate disabled tools from CLI/environment variable
|
|
190
|
+
all_tool_names = {tool.__name__ for tool in tools}
|
|
191
|
+
disabled_tool_names = parse_disabled_tools(disabled_tools, all_tool_names)
|
|
192
|
+
|
|
193
|
+
if disabled_tool_names:
|
|
194
|
+
logger.info(
|
|
195
|
+
f"Disabled {len(disabled_tool_names)} tool(s): {sorted(disabled_tool_names)}"
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Filter out disabled tools
|
|
199
|
+
enabled_tools = [tool for tool in tools if tool.__name__ not in disabled_tool_names]
|
|
200
|
+
|
|
160
201
|
# Map user-friendly transport names to SDK transport names
|
|
161
202
|
sdk_transport = NETWORK_TRANSPORTS_SDK_MAPPING.get(transport, transport)
|
|
162
203
|
|
|
@@ -172,10 +213,17 @@ def main(
|
|
|
172
213
|
|
|
173
214
|
mcp = FastMCP(MCP_SERVER_NAME, lifespan=app_lifespan, **config)
|
|
174
215
|
|
|
175
|
-
|
|
176
|
-
|
|
216
|
+
logger.info(
|
|
217
|
+
f"Registering {len(enabled_tools)} tool(s) with modes (read_only_mode={read_only_mode}, "
|
|
218
|
+
f"read_only_query_mode={read_only_query_mode})"
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Register only enabled tools
|
|
222
|
+
for tool in enabled_tools:
|
|
177
223
|
mcp.add_tool(tool)
|
|
178
224
|
|
|
225
|
+
logger.info(f"Registered {len(enabled_tools)} tool(s)")
|
|
226
|
+
|
|
179
227
|
# Run the server
|
|
180
228
|
mcp.run(transport=sdk_transport) # type: ignore
|
|
181
229
|
|
tools/__init__.py
CHANGED
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
Couchbase MCP Tools
|
|
3
3
|
|
|
4
4
|
This module contains all the MCP tools for Couchbase operations.
|
|
5
|
+
|
|
6
|
+
Tool Categories:
|
|
7
|
+
- READ_ONLY_TOOLS: Tools that only read data (always available)
|
|
8
|
+
- KV_WRITE_TOOLS: KV tools that modify data (disabled when READ_ONLY_MODE=True)
|
|
5
9
|
"""
|
|
6
10
|
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
|
|
7
13
|
# Index tools
|
|
8
14
|
from .index import get_index_advisor_recommendations, list_indexes
|
|
9
15
|
|
|
@@ -11,6 +17,8 @@ from .index import get_index_advisor_recommendations, list_indexes
|
|
|
11
17
|
from .kv import (
|
|
12
18
|
delete_document_by_id,
|
|
13
19
|
get_document_by_id,
|
|
20
|
+
insert_document_by_id,
|
|
21
|
+
replace_document_by_id,
|
|
14
22
|
upsert_document_by_id,
|
|
15
23
|
)
|
|
16
24
|
|
|
@@ -38,22 +46,25 @@ from .server import (
|
|
|
38
46
|
test_cluster_connection,
|
|
39
47
|
)
|
|
40
48
|
|
|
41
|
-
#
|
|
42
|
-
|
|
49
|
+
# Read-only tools - always available regardless of mode settings
|
|
50
|
+
READ_ONLY_TOOLS = [
|
|
51
|
+
# Server/Cluster management tools
|
|
43
52
|
get_buckets_in_cluster,
|
|
44
53
|
get_server_configuration_status,
|
|
45
54
|
test_cluster_connection,
|
|
46
55
|
get_scopes_and_collections_in_bucket,
|
|
47
56
|
get_collections_in_scope,
|
|
48
57
|
get_scopes_in_bucket,
|
|
58
|
+
get_cluster_health_and_services,
|
|
59
|
+
# KV read tool
|
|
49
60
|
get_document_by_id,
|
|
50
|
-
|
|
51
|
-
delete_document_by_id,
|
|
61
|
+
# Query tools (read operations)
|
|
52
62
|
get_schema_for_collection,
|
|
53
|
-
run_sql_plus_plus_query,
|
|
63
|
+
run_sql_plus_plus_query, # Write protection handled at runtime via read_only_query_mode
|
|
64
|
+
# Index tools
|
|
54
65
|
get_index_advisor_recommendations,
|
|
55
66
|
list_indexes,
|
|
56
|
-
|
|
67
|
+
# Query performance analysis tools
|
|
57
68
|
get_queries_not_selective,
|
|
58
69
|
get_queries_not_using_covering_index,
|
|
59
70
|
get_queries_using_primary_index,
|
|
@@ -63,6 +74,33 @@ ALL_TOOLS = [
|
|
|
63
74
|
get_most_frequent_queries,
|
|
64
75
|
]
|
|
65
76
|
|
|
77
|
+
# KV write tools - disabled when READ_ONLY_MODE is True
|
|
78
|
+
KV_WRITE_TOOLS = [
|
|
79
|
+
upsert_document_by_id,
|
|
80
|
+
insert_document_by_id,
|
|
81
|
+
replace_document_by_id,
|
|
82
|
+
delete_document_by_id,
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
# List of all tools for easy registration (kept for backward compatibility)
|
|
86
|
+
ALL_TOOLS = READ_ONLY_TOOLS + KV_WRITE_TOOLS
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_tools(read_only_mode: bool = True) -> list[Callable]:
|
|
90
|
+
"""Get the list of tools based on the mode settings.
|
|
91
|
+
|
|
92
|
+
This function determines which tools should be loaded based on the
|
|
93
|
+
READ_ONLY_MODE setting. When read_only_mode is True, write tools are excluded.
|
|
94
|
+
"""
|
|
95
|
+
tools = list(READ_ONLY_TOOLS)
|
|
96
|
+
|
|
97
|
+
if not read_only_mode:
|
|
98
|
+
# KV write tools are only loaded when READ_ONLY_MODE is False
|
|
99
|
+
tools.extend(KV_WRITE_TOOLS)
|
|
100
|
+
|
|
101
|
+
return tools
|
|
102
|
+
|
|
103
|
+
|
|
66
104
|
__all__ = [
|
|
67
105
|
# Individual tools
|
|
68
106
|
"get_server_configuration_status",
|
|
@@ -73,6 +111,8 @@ __all__ = [
|
|
|
73
111
|
"get_buckets_in_cluster",
|
|
74
112
|
"get_document_by_id",
|
|
75
113
|
"upsert_document_by_id",
|
|
114
|
+
"insert_document_by_id",
|
|
115
|
+
"replace_document_by_id",
|
|
76
116
|
"delete_document_by_id",
|
|
77
117
|
"get_schema_for_collection",
|
|
78
118
|
"run_sql_plus_plus_query",
|
|
@@ -86,6 +126,10 @@ __all__ = [
|
|
|
86
126
|
"get_queries_with_largest_response_sizes",
|
|
87
127
|
"get_longest_running_queries",
|
|
88
128
|
"get_most_frequent_queries",
|
|
129
|
+
# Tool categories
|
|
130
|
+
"READ_ONLY_TOOLS",
|
|
131
|
+
"KV_WRITE_TOOLS",
|
|
89
132
|
# Convenience
|
|
90
133
|
"ALL_TOOLS",
|
|
134
|
+
"get_tools",
|
|
91
135
|
]
|
tools/kv.py
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Tools for key-value operations.
|
|
3
3
|
|
|
4
|
-
This module contains tools for
|
|
4
|
+
This module contains tools for document operations by ID:
|
|
5
|
+
- get: Retrieve a document
|
|
6
|
+
- upsert: Insert or update a document (creates if not exists, updates if exists)
|
|
7
|
+
- insert: Create a document only if it does NOT exist (fails if exists)
|
|
8
|
+
- replace: Update a document only if it exists (fails if missing)
|
|
9
|
+
- delete: Remove a document
|
|
5
10
|
"""
|
|
6
11
|
|
|
7
12
|
import logging
|
|
@@ -46,6 +51,12 @@ def upsert_document_by_id(
|
|
|
46
51
|
document_content: dict[str, Any],
|
|
47
52
|
) -> bool:
|
|
48
53
|
"""Insert or update a document by its ID.
|
|
54
|
+
|
|
55
|
+
IMPORTANT: Only use this tool when the user explicitly requests an 'upsert' operation
|
|
56
|
+
or explicitly states they want to 'insert or update' a document.
|
|
57
|
+
|
|
58
|
+
DO NOT use this as a fallback when insert_document_by_id or replace_document_by_id fails.
|
|
59
|
+
|
|
49
60
|
Returns True on success, False on failure."""
|
|
50
61
|
cluster = get_cluster_connection(ctx)
|
|
51
62
|
bucket = connect_to_bucket(cluster, bucket_name)
|
|
@@ -78,3 +89,55 @@ def delete_document_by_id(
|
|
|
78
89
|
except Exception as e:
|
|
79
90
|
logger.error(f"Error deleting document {document_id}: {e}")
|
|
80
91
|
return False
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def insert_document_by_id(
|
|
95
|
+
ctx: Context,
|
|
96
|
+
bucket_name: str,
|
|
97
|
+
scope_name: str,
|
|
98
|
+
collection_name: str,
|
|
99
|
+
document_id: str,
|
|
100
|
+
document_content: dict[str, Any],
|
|
101
|
+
) -> bool:
|
|
102
|
+
"""Insert a new document by its ID. This operation will FAIL if the document already exists.
|
|
103
|
+
|
|
104
|
+
IMPORTANT: If this operation fails, DO NOT automatically try replace or upsert.
|
|
105
|
+
Report the failure to the user. They can choose to 'replace' or 'upsert' if desired.
|
|
106
|
+
|
|
107
|
+
Returns True on success, False on failure (including if document already exists)."""
|
|
108
|
+
cluster = get_cluster_connection(ctx)
|
|
109
|
+
bucket = connect_to_bucket(cluster, bucket_name)
|
|
110
|
+
try:
|
|
111
|
+
collection = bucket.scope(scope_name).collection(collection_name)
|
|
112
|
+
collection.insert(document_id, document_content)
|
|
113
|
+
logger.info(f"Successfully inserted document {document_id}")
|
|
114
|
+
return True
|
|
115
|
+
except Exception as e:
|
|
116
|
+
logger.error(f"Error inserting document {document_id}: {e}")
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def replace_document_by_id(
|
|
121
|
+
ctx: Context,
|
|
122
|
+
bucket_name: str,
|
|
123
|
+
scope_name: str,
|
|
124
|
+
collection_name: str,
|
|
125
|
+
document_id: str,
|
|
126
|
+
document_content: dict[str, Any],
|
|
127
|
+
) -> bool:
|
|
128
|
+
"""Replace an existing document by its ID. This operation will FAIL if the document does not exist.
|
|
129
|
+
|
|
130
|
+
IMPORTANT: If this operation fails, DO NOT automatically try insert or upsert.
|
|
131
|
+
Report the failure to the user. They can choose to 'insert' or 'upsert' if desired.
|
|
132
|
+
|
|
133
|
+
Returns True on success, False on failure (including if document does not exist)."""
|
|
134
|
+
cluster = get_cluster_connection(ctx)
|
|
135
|
+
bucket = connect_to_bucket(cluster, bucket_name)
|
|
136
|
+
try:
|
|
137
|
+
collection = bucket.scope(scope_name).collection(collection_name)
|
|
138
|
+
collection.replace(document_id, document_content)
|
|
139
|
+
logger.info(f"Successfully replaced document {document_id}")
|
|
140
|
+
return True
|
|
141
|
+
except Exception as e:
|
|
142
|
+
logger.error(f"Error replacing document {document_id}: {e}")
|
|
143
|
+
return False
|
tools/query.py
CHANGED
|
@@ -53,15 +53,20 @@ def run_sql_plus_plus_query(
|
|
|
53
53
|
bucket = connect_to_bucket(cluster, bucket_name)
|
|
54
54
|
|
|
55
55
|
app_context = ctx.request_context.lifespan_context
|
|
56
|
+
read_only_mode = app_context.read_only_mode
|
|
56
57
|
read_only_query_mode = app_context.read_only_query_mode
|
|
57
|
-
|
|
58
|
+
|
|
59
|
+
# Block query writes if either read_only_mode OR read_only_query_mode is True
|
|
60
|
+
# READ_ONLY_MODE takes precedence and blocks all writes (KV and Query)
|
|
61
|
+
# READ_ONLY_QUERY_MODE (deprecated) only blocks query writes
|
|
62
|
+
block_query_writes = read_only_mode or read_only_query_mode
|
|
58
63
|
|
|
59
64
|
try:
|
|
60
65
|
scope = bucket.scope(scope_name)
|
|
61
66
|
|
|
62
67
|
results = []
|
|
63
68
|
# If read-only mode is enabled, check if the query is a data or structure modification query
|
|
64
|
-
if
|
|
69
|
+
if block_query_writes:
|
|
65
70
|
parsed_query = parse_sqlpp(query)
|
|
66
71
|
data_modification_query = modifies_data(parsed_query)
|
|
67
72
|
structure_modification_query = modifies_structure(parsed_query)
|
tools/server.py
CHANGED
|
@@ -29,6 +29,7 @@ def get_server_configuration_status(ctx: Context) -> dict[str, Any]:
|
|
|
29
29
|
configuration = {
|
|
30
30
|
"connection_string": settings.get("connection_string", "Not set"),
|
|
31
31
|
"username": settings.get("username", "Not set"),
|
|
32
|
+
"read_only_mode": settings.get("read_only_mode", True),
|
|
32
33
|
"read_only_query_mode": settings.get("read_only_query_mode", True),
|
|
33
34
|
"password_configured": bool(settings.get("password")),
|
|
34
35
|
"ca_cert_path_configured": bool(settings.get("ca_cert_path")),
|
utils/__init__.py
CHANGED
|
@@ -7,6 +7,7 @@ This module contains utility functions for configuration, connection, and contex
|
|
|
7
7
|
# Configuration utilities
|
|
8
8
|
from .config import (
|
|
9
9
|
get_settings,
|
|
10
|
+
parse_disabled_tools,
|
|
10
11
|
)
|
|
11
12
|
|
|
12
13
|
# Connection utilities
|
|
@@ -45,6 +46,7 @@ from .index_utils import (
|
|
|
45
46
|
__all__ = [
|
|
46
47
|
# Config
|
|
47
48
|
"get_settings",
|
|
49
|
+
"parse_disabled_tools",
|
|
48
50
|
# Connection
|
|
49
51
|
"connect_to_couchbase_cluster",
|
|
50
52
|
"connect_to_bucket",
|
utils/config.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from pathlib import Path
|
|
2
3
|
|
|
3
4
|
import click
|
|
4
5
|
|
|
@@ -11,3 +12,78 @@ def get_settings() -> dict:
|
|
|
11
12
|
"""Get settings from Click context."""
|
|
12
13
|
ctx = click.get_current_context()
|
|
13
14
|
return ctx.obj or {}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _parse_file(file_path: Path, valid_tool_names: set[str]) -> set[str]:
|
|
18
|
+
"""Parse tool names from a file (one tool per line)."""
|
|
19
|
+
tools: set[str] = set()
|
|
20
|
+
invalid_count = 0
|
|
21
|
+
try:
|
|
22
|
+
with open(file_path) as f:
|
|
23
|
+
for raw_line in f:
|
|
24
|
+
name = raw_line.strip()
|
|
25
|
+
if not name or name.startswith("#"):
|
|
26
|
+
continue
|
|
27
|
+
if name in valid_tool_names:
|
|
28
|
+
tools.add(name)
|
|
29
|
+
else:
|
|
30
|
+
invalid_count += 1
|
|
31
|
+
if invalid_count > 0:
|
|
32
|
+
logger.warning(
|
|
33
|
+
f"Ignored {invalid_count} invalid tool name(s) from file: {file_path}"
|
|
34
|
+
)
|
|
35
|
+
logger.debug(f"Loaded {len(tools)} disabled tools from file: {file_path}")
|
|
36
|
+
except OSError as e:
|
|
37
|
+
logger.warning(f"Failed to read disabled tools file {file_path}: {e}")
|
|
38
|
+
return tools
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _parse_comma_separated(value: str, valid_tool_names: set[str]) -> set[str]:
|
|
42
|
+
"""Parse comma-separated tool names."""
|
|
43
|
+
tools: set[str] = set()
|
|
44
|
+
invalid_count = 0
|
|
45
|
+
for part in value.split(","):
|
|
46
|
+
name = part.strip()
|
|
47
|
+
if name:
|
|
48
|
+
if name in valid_tool_names:
|
|
49
|
+
tools.add(name)
|
|
50
|
+
else:
|
|
51
|
+
invalid_count += 1
|
|
52
|
+
if invalid_count > 0:
|
|
53
|
+
logger.warning(
|
|
54
|
+
f"Ignored {invalid_count} invalid tool name(s) from comma-separated input"
|
|
55
|
+
)
|
|
56
|
+
logger.debug(f"Parsed disabled tools from comma-separated string: {tools}")
|
|
57
|
+
return tools
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def parse_disabled_tools(
|
|
61
|
+
disabled_tools_input: str | None,
|
|
62
|
+
valid_tool_names: set[str],
|
|
63
|
+
) -> set[str]:
|
|
64
|
+
"""
|
|
65
|
+
Parse disabled tools from CLI argument or environment variable.
|
|
66
|
+
|
|
67
|
+
Supported formats:
|
|
68
|
+
1. Comma-separated string: "tool_1,tool_2"
|
|
69
|
+
2. File path containing one tool name per line: "disabled_tools.txt"
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
disabled_tools_input: Comma-separated tools or file path
|
|
73
|
+
valid_tool_names: Set of valid tool names to validate against
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Set of tool names to disable
|
|
77
|
+
"""
|
|
78
|
+
if not disabled_tools_input:
|
|
79
|
+
return set()
|
|
80
|
+
|
|
81
|
+
value = disabled_tools_input.strip()
|
|
82
|
+
|
|
83
|
+
# Check if it's a file path
|
|
84
|
+
potential_path = Path(value)
|
|
85
|
+
if potential_path.exists() and potential_path.is_file():
|
|
86
|
+
return _parse_file(potential_path, valid_tool_names)
|
|
87
|
+
|
|
88
|
+
# Otherwise, treat as comma-separated
|
|
89
|
+
return _parse_comma_separated(value, valid_tool_names)
|
utils/context.py
CHANGED
|
@@ -13,9 +13,19 @@ logger = logging.getLogger(f"{MCP_SERVER_NAME}.utils.context")
|
|
|
13
13
|
|
|
14
14
|
@dataclass
|
|
15
15
|
class AppContext:
|
|
16
|
-
"""Context for the MCP server.
|
|
16
|
+
"""Context for the MCP server.
|
|
17
|
+
|
|
18
|
+
Attributes:
|
|
19
|
+
cluster: The Couchbase cluster connection (lazily initialized).
|
|
20
|
+
read_only_mode: When True, all write operations (KV and Query) are disabled
|
|
21
|
+
and KV write tools are not loaded.
|
|
22
|
+
This is the recommended mode for safety. Default is True.
|
|
23
|
+
read_only_query_mode: When True, query-based write operations are disabled.
|
|
24
|
+
DEPRECATED: Use read_only_mode instead.
|
|
25
|
+
"""
|
|
17
26
|
|
|
18
27
|
cluster: Cluster | None = None
|
|
28
|
+
read_only_mode: bool = True
|
|
19
29
|
read_only_query_mode: bool = True
|
|
20
30
|
|
|
21
31
|
|
|
@@ -1,19 +0,0 @@
|
|
|
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=72DlDEv1j_IpZTp9rL1fA5QGFXp5eburCDObGqpPuFc,2462
|
|
5
|
-
tools/index.py,sha256=cCBr0ptFBVc-HN5SoCauQAh2DsAP_Is8NPUSa6QcLM0,6682
|
|
6
|
-
tools/kv.py,sha256=NGUs43iuXElj9rYe4RCyCStqoh5y1fUgbg1oWuU4WeQ,2493
|
|
7
|
-
tools/query.py,sha256=5fYrMm6ReXuDn7uu1QdVxoCtUnaqaIFPcAWBNhiTa4Y,11303
|
|
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.3.dist-info/METADATA,sha256=-UqmmCTDyeujZ_sDWuPEsngT0ufZ4iAJaQUiPBjD3ls,22182
|
|
16
|
-
couchbase_mcp_server-0.5.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
17
|
-
couchbase_mcp_server-0.5.3.dist-info/entry_points.txt,sha256=iU5pF4kIMTnNhoMPHhdH-k8o1Fmxb_iM9qJHCZcL6Ak,57
|
|
18
|
-
couchbase_mcp_server-0.5.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
19
|
-
couchbase_mcp_server-0.5.3.dist-info/RECORD,,
|
|
File without changes
|
{couchbase_mcp_server-0.5.3.dist-info → couchbase_mcp_server-0.6.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{couchbase_mcp_server-0.5.3.dist-info → couchbase_mcp_server-0.6.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|