Skip to content

Commit 5e498ed

Browse files
nithishrrajagp
andauthored
Add support for mTLS & certificates (#51)
* Add support for mTLS & certificates - Added support for Basic Authentication and mTLS in the README.md, detailing the required environment variables and configuration examples. - Updated the `mcp_server.py` to include new command-line options for CA certificate and client certificate paths. - Modified connection logic in `connection.py` to support mTLS authentication using client certificates, with appropriate error handling for missing files. - Updated context management in `context.py` to include new certificate paths in the connection setup. - Enhanced server status reporting in `server.py` to reflect the new authentication configurations. * Add support for key in CLI arguments - Revised README.md to add updated environment variable descriptions for mTLS authentication, including the addition of `CB_CLIENT_KEY_PATH`. - Enhanced `mcp_server.py` to include a new command-line option for the client key path. - Updated connection logic in `connection.py` to support both client certificate and key paths for mTLS authentication, with improved error handling for missing files. - Modified context management in `context.py` to incorporate the new client key path in the connection setup. - Improved server status reporting in `server.py` to reflect the new authentication configurations. * Update README.md (#52) * Update README.md Removed CA_SERVER_CERT from the config examples as it is optional. Also updated "uv" example to indicate path to uv binary * Update README.md to clarify configuration and troubleshooting instructions - Simplified the command path for the `uv` binary in the configuration example. - Corrected the wording in the environment variable table for `CB_CLIENT_KEY_PATH` to clarify its requirement for mTLS. - Enhanced troubleshooting tips to specify the need for valid database credentials and permissions for at least one bucket. * Clarify README.md environment variable requirements for mTLS authentication - Updated the description for `CB_CLIENT_KEY_PATH` in the environment variable table to emphasize the requirement for mTLS authentication, ensuring consistency in the documentation. --------- Co-authored-by: Nithish Raghunandanan <12782505+nithishr@users.noreply.github.com> --------- Co-authored-by: Priya Rajagopal <rajagp@users.noreply.github.com>
1 parent 37fe8e1 commit 5e498ed

File tree

5 files changed

+109
-17
lines changed

5 files changed

+109
-17
lines changed

README.md

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,16 @@ An [MCP](https://modelcontextprotocol.io/) server implementation of Couchbase th
3232

3333
## Configuration
3434

35-
The MCP server can be run either from the pre built PyPI package or the source using uv.
35+
The MCP server can be run either from the prebuilt PyPI package or the source using uv.
3636

3737
### Running from PyPI
3838

3939
We publish a pre built [PyPI package](https://pypi.org/project/couchbase-mcp-server/) for the MCP server.
4040

4141
#### Server Configuration using Pre built Package for MCP Clients
4242

43+
#### Basic Authentication
44+
4345
```json
4446
{
4547
"mcpServers": {
@@ -56,6 +58,26 @@ We publish a pre built [PyPI package](https://pypi.org/project/couchbase-mcp-ser
5658
}
5759
```
5860

61+
or
62+
63+
#### mTLS
64+
65+
```json
66+
{
67+
"mcpServers": {
68+
"couchbase": {
69+
"command": "uvx",
70+
"args": ["couchbase-mcp-server"],
71+
"env": {
72+
"CB_CONNECTION_STRING": "couchbases://connection-string",
73+
"CB_CLIENT_CERT_PATH": "/path/to/client-certificate.pem",
74+
"CB_CLIENT_KEY_PATH": "/path/to/client.key"
75+
}
76+
}
77+
}
78+
}
79+
```
80+
5981
> Note: If you have other MCP servers in use in the client, you can add it to the existing `mcpServers` object.
6082
6183
### Running from Source
@@ -100,16 +122,21 @@ This is the common configuration for the MCP clients such as Claude Desktop, Cur
100122
### Additional Configuration for MCP Server
101123

102124
The server can be configured using environment variables or command line arguments:
103-
104-
| Environment Variable | CLI Argument | Description | Default |
105-
| ----------------------------- | ------------------------ | ------------------------------------------ | ------------ |
106-
| `CB_CONNECTION_STRING` | `--connection-string` | Connection string to the Couchbase cluster | **Required** |
107-
| `CB_USERNAME` | `--username` | Username with access to required buckets | **Required** |
108-
| `CB_PASSWORD` | `--password` | Password for authentication | **Required** |
109-
| `CB_MCP_READ_ONLY_QUERY_MODE` | `--read-only-query-mode` | Prevent data modification queries | `true` |
110-
| `CB_MCP_TRANSPORT` | `--transport` | Transport mode: `stdio`, `http`, `sse` | `stdio` |
111-
| `CB_MCP_HOST` | `--host` | Host for HTTP/SSE transport modes | `127.0.0.1` |
112-
| `CB_MCP_PORT` | `--port` | Port for HTTP/SSE transport modes | `8000` |
125+
| Environment Variable | CLI Argument | Description | Default |
126+
|--------------------------------|--------------------------|---------------------------------------------------------------------------------------------|------------------------------------------|
127+
| `CB_CONNECTION_STRING` | `--connection-string` | Connection string to the Couchbase cluster | **Required** |
128+
| `CB_USERNAME` | `--username` | Username with access to required buckets for basic authentication | **Required (or Client Certificate and Key needed for mTLS)** |
129+
| `CB_PASSWORD` | `--password` | Password for basic authentication | **Required (or Client Certificate and Key needed for mTLS)** |
130+
| `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)** |
131+
| `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)** |
132+
| `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 | |
133+
| `CB_MCP_READ_ONLY_QUERY_MODE` | `--read-only-query-mode` | Prevent data modification queries | `true` |
134+
| `CB_MCP_TRANSPORT` | `--transport` | Transport mode: `stdio`, `http`, `sse` | `stdio` |
135+
| `CB_MCP_HOST` | `--host` | Host for HTTP/SSE transport modes | `127.0.0.1` |
136+
| `CB_MCP_PORT` | `--port` | Port for HTTP/SSE transport modes | `8000` |
137+
138+
> 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.
139+
> If both the Client Certificate & key path and the username and password are specified, the client certificates will be used for authentication.
113140
114141
You can also check the version of the server using:
115142

@@ -370,9 +397,9 @@ The Couchbase MCP server can also be used as a managed server in your agentic ap
370397
## Troubleshooting Tips
371398

372399
- Ensure the path to your MCP server repository is correct in the configuration if running from source.
373-
- Verify that your Couchbase connection string, database username, password are correct.
400+
- Verify that your Couchbase connection string, database username, password or the path to the certificates are correct.
374401
- 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.
375-
- Check that the database user has proper permissions to access the specified bucket.
402+
- Check that the database user has proper permissions to access at least one bucket.
376403
- 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.
377404
- 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.
378405
- 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).

src/mcp_server.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,24 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
7777
envvar="CB_PASSWORD",
7878
help="Couchbase database password (required for operations)",
7979
)
80+
@click.option(
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.",
97+
)
8098
@click.option(
8199
"--read-only-query-mode",
82100
envvar=[
@@ -116,6 +134,9 @@ def main(
116134
connection_string,
117135
username,
118136
password,
137+
ca_cert_path,
138+
client_cert_path,
139+
client_key_path,
119140
read_only_query_mode,
120141
transport,
121142
host,
@@ -127,6 +148,9 @@ def main(
127148
"connection_string": connection_string,
128149
"username": username,
129150
"password": password,
151+
"ca_cert_path": ca_cert_path,
152+
"client_cert_path": client_cert_path,
153+
"client_key_path": client_key_path,
130154
"read_only_query_mode": read_only_query_mode,
131155
"transport": transport,
132156
"host": host,

src/tools/server.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ def get_server_configuration_status(ctx: Context) -> dict[str, Any]:
3030
"username": settings.get("username", "Not set"),
3131
"read_only_query_mode": settings.get("read_only_query_mode", True),
3232
"password_configured": bool(settings.get("password")),
33+
"ca_cert_path_configured": bool(settings.get("ca_cert_path")),
34+
"client_cert_path_configured": bool(settings.get("client_cert_path")),
35+
"client_key_path_configured": bool(settings.get("client_key_path")),
3336
}
3437

3538
app_context = ctx.request_context.lifespan_context

src/utils/connection.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import logging
2+
import os
23
from datetime import timedelta
34

4-
from couchbase.auth import PasswordAuthenticator
5+
from couchbase.auth import CertificateAuthenticator, PasswordAuthenticator
56
from couchbase.cluster import Bucket, Cluster
67
from couchbase.options import ClusterOptions
78

@@ -11,15 +12,40 @@
1112

1213

1314
def connect_to_couchbase_cluster(
14-
connection_string: str, username: str, password: str
15+
connection_string: str,
16+
username: str,
17+
password: str,
18+
ca_cert_path: str | None = None,
19+
client_cert_path: str | None = None,
20+
client_key_path: str | None = None,
1521
) -> Cluster:
1622
"""Connect to Couchbase cluster and return the cluster object if successful.
23+
The connection can be established using the client certificate and key or the username and password. Optionally, the CA root certificate path can also be provided.
24+
Either of the path to the client certificate and key or the username and password should be provided.
25+
If the client certificate and key are provided, the username and password are not used.
26+
If both the client certificate and key and the username and password are provided, the client certificate is used for authentication.
1727
If the connection fails, it will raise an exception.
1828
"""
1929

2030
try:
2131
logger.info("Connecting to Couchbase cluster...")
22-
auth = PasswordAuthenticator(username, password)
32+
if client_cert_path and client_key_path:
33+
logger.info("Connecting to Couchbase cluster with client certificate...")
34+
if not os.path.exists(client_cert_path) or not os.path.exists(
35+
client_key_path
36+
):
37+
raise FileNotFoundError(
38+
f"Client certificate files not found at {os.path.basename(client_cert_path)} or {os.path.basename(client_key_path)}."
39+
)
40+
41+
auth = CertificateAuthenticator(
42+
cert_path=client_cert_path,
43+
key_path=client_key_path,
44+
trust_store_path=ca_cert_path,
45+
)
46+
else:
47+
logger.info("Connecting to Couchbase cluster with password...")
48+
auth = PasswordAuthenticator(username, password, cert_path=ca_cert_path)
2349
options = ClusterOptions(auth)
2450
options.apply_profile("wan_development")
2551

src/utils/context.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,27 @@ def _set_cluster_in_lifespan_context(ctx: Context) -> None:
2929
connection_string = settings.get("connection_string")
3030
username = settings.get("username")
3131
password = settings.get("password")
32+
ca_cert_path = settings.get("ca_cert_path")
33+
client_cert_path = settings.get("client_cert_path")
34+
client_key_path = settings.get("client_key_path")
35+
3236
cluster = connect_to_couchbase_cluster(
3337
connection_string, # type: ignore
3438
username, # type: ignore
3539
password, # type: ignore
40+
ca_cert_path,
41+
client_cert_path,
42+
client_key_path,
3643
)
3744
ctx.request_context.lifespan_context.cluster = cluster
3845
except Exception as e:
3946
logger.error(
40-
f"Failed to connect to Couchbase: {e} \n Please check your connection string, username and password"
47+
"Failed to connect to Couchbase: %s\n"
48+
"Verify connection string, and either:\n"
49+
"- Username/password are correct, or\n"
50+
"- Client certificate and key exist and match server mapping.\n"
51+
"If using self-signed or custom CA, set CB_CA_CERT_PATH to the CA file.",
52+
e,
4153
)
4254
raise
4355

0 commit comments

Comments
 (0)