couchbase-mcp-server 0.5.0__tar.gz → 0.5.2__tar.gz

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.
Files changed (44) hide show
  1. couchbase_mcp_server-0.5.2/.github/workflows/alert-on-pr.yml +74 -0
  2. couchbase_mcp_server-0.5.2/.github/workflows/docker.yml +94 -0
  3. couchbase_mcp_server-0.5.2/.github/workflows/release.yml +38 -0
  4. couchbase_mcp_server-0.5.2/.github/workflows/test_release.yml +32 -0
  5. couchbase_mcp_server-0.5.2/.github/workflows/update-mcp-registry.yml +149 -0
  6. couchbase_mcp_server-0.5.2/.gitignore +12 -0
  7. couchbase_mcp_server-0.5.2/.pre-commit-config.yaml +37 -0
  8. couchbase_mcp_server-0.5.2/CONTRIBUTING.md +234 -0
  9. couchbase_mcp_server-0.5.2/DOCKER.md +78 -0
  10. couchbase_mcp_server-0.5.2/Dockerfile +61 -0
  11. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/PKG-INFO +19 -13
  12. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/README.md +6 -0
  13. couchbase_mcp_server-0.5.2/RELEASE.md +264 -0
  14. couchbase_mcp_server-0.5.2/build.sh +24 -0
  15. couchbase_mcp_server-0.5.2/glama.json +6 -0
  16. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/pyproject.toml +25 -6
  17. couchbase_mcp_server-0.5.2/scripts/lint.sh +28 -0
  18. couchbase_mcp_server-0.5.2/scripts/lint_fix.sh +26 -0
  19. couchbase_mcp_server-0.5.2/scripts/update_version.sh +79 -0
  20. couchbase_mcp_server-0.5.2/server.json +253 -0
  21. couchbase_mcp_server-0.5.2/smithery.yaml +40 -0
  22. couchbase_mcp_server-0.5.2/src/certs/__init__.py +0 -0
  23. couchbase_mcp_server-0.5.2/src/certs/capella_root_ca.pem +19 -0
  24. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/src/mcp_server.py +0 -1
  25. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/src/tools/__init__.py +10 -0
  26. couchbase_mcp_server-0.5.2/src/tools/index.py +172 -0
  27. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/src/tools/query.py +9 -1
  28. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/src/tools/server.py +41 -0
  29. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/src/utils/__init__.py +7 -0
  30. couchbase_mcp_server-0.5.2/src/utils/index_utils.py +308 -0
  31. couchbase_mcp_server-0.5.2/uv.lock +974 -0
  32. couchbase_mcp_server-0.5.0/setup.cfg +0 -4
  33. couchbase_mcp_server-0.5.0/src/couchbase_mcp_server.egg-info/PKG-INFO +0 -477
  34. couchbase_mcp_server-0.5.0/src/couchbase_mcp_server.egg-info/SOURCES.txt +0 -19
  35. couchbase_mcp_server-0.5.0/src/couchbase_mcp_server.egg-info/dependency_links.txt +0 -1
  36. couchbase_mcp_server-0.5.0/src/couchbase_mcp_server.egg-info/entry_points.txt +0 -2
  37. couchbase_mcp_server-0.5.0/src/couchbase_mcp_server.egg-info/requires.txt +0 -8
  38. couchbase_mcp_server-0.5.0/src/couchbase_mcp_server.egg-info/top_level.txt +0 -3
  39. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/LICENSE +0 -0
  40. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/src/tools/kv.py +0 -0
  41. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/src/utils/config.py +0 -0
  42. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/src/utils/connection.py +0 -0
  43. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/src/utils/constants.py +0 -0
  44. {couchbase_mcp_server-0.5.0 → couchbase_mcp_server-0.5.2}/src/utils/context.py +0 -0
@@ -0,0 +1,74 @@
1
+ name: Alert on PR Changes
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, reopened]
6
+ pull_request_target:
7
+ types: [opened, synchronize, reopened]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ alert:
14
+ # Only run this job if:
15
+ # - The event is 'pull_request' and the PR is from the same repository (not a fork), OR
16
+ # - The event is 'pull_request_target' and the PR is from a forked repository.
17
+ # This ensures that PRs from forks are handled with 'pull_request_target' (for security),
18
+ # while PRs from the same repo are handled with 'pull_request'.
19
+ if: >-
20
+ (
21
+ github.event_name == 'pull_request' &&
22
+ github.event.pull_request.head.repo.full_name == github.repository
23
+ ) ||
24
+ (
25
+ github.event_name == 'pull_request_target' &&
26
+ github.event.pull_request.head.repo.full_name != github.repository
27
+ )
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - name: Set up Python
31
+ uses: actions/setup-python@v5
32
+ with:
33
+ python-version: "3.11"
34
+
35
+ - name: Install requests
36
+ run: |
37
+ python -m pip install --upgrade pip
38
+ pip install requests
39
+
40
+ - name: Send Slack alert on PR changes
41
+ env:
42
+ SLACK_WEBHOOK: ${{ secrets.DEVEX_ALERTS_SECRET }}
43
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44
+ PR_NUMBER: ${{ github.event.pull_request.number }}
45
+ REPO: ${{ github.repository }}
46
+ shell: python
47
+ run: |
48
+ import os, requests
49
+ repo = os.environ['REPO']
50
+ pr_number = os.environ['PR_NUMBER']
51
+ token = os.environ['GITHUB_TOKEN']
52
+ api_url = f"https://api.github.com/repos/{repo}/pulls/{pr_number}"
53
+ headers = {'Authorization': f'token {token}', 'Accept': 'application/vnd.github.v3+json'}
54
+ pr_resp = requests.get(api_url, headers=headers, timeout=15)
55
+ if pr_resp.ok:
56
+ pr = pr_resp.json()
57
+ branch_name = pr.get('head', {}).get('ref') or os.environ.get('GITHUB_HEAD_REF', '')
58
+ pr_title = pr.get('title', '')
59
+ pr_body = pr.get('body', '')
60
+ pr_user = pr.get('user', {}).get('login', '')
61
+ pr_url = pr.get('html_url', '')
62
+ prefix = "PR Alert from Forked Repo!" if pr.get('head', {}).get('repo', {}).get('fork') else "PR Alert!"
63
+ message = f"{prefix}\nTitle: {pr_title}\nBranch: {branch_name}\nAuthor: {pr_user}\nURL: {pr_url}\nDescription: {pr_body}"
64
+ else:
65
+ message = f"PR Alert!\nUnable to fetch PR details.\nStatus Code: {pr_resp.status_code}\nResponse: {pr_resp.text}"
66
+ webhook = os.environ.get('SLACK_WEBHOOK', '').strip()
67
+ if webhook and webhook.startswith(("http://", "https://")):
68
+ try:
69
+ resp = requests.post(webhook, json={"text": message}, timeout=15)
70
+ resp.raise_for_status()
71
+ except Exception as e:
72
+ print(f"Slack notification failed: {e}")
73
+ else:
74
+ print("SLACK_WEBHOOK missing or invalid; skipping Slack notification.")
@@ -0,0 +1,94 @@
1
+ name: Build and Push Docker Image
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ env:
10
+ REGISTRY: docker.io
11
+ IMAGE_NAME: couchbaseecosystem/mcp-server-couchbase
12
+
13
+ jobs:
14
+ docker:
15
+ runs-on: ubuntu-latest
16
+
17
+ steps:
18
+ - name: Checkout
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Set up QEMU
22
+ uses: docker/setup-qemu-action@v3
23
+
24
+ - name: Set up Docker Buildx
25
+ uses: docker/setup-buildx-action@v3
26
+
27
+ - name: Log in to Docker Hub
28
+ if: github.event_name != 'pull_request'
29
+ uses: docker/login-action@v3
30
+ with:
31
+ registry: ${{ env.REGISTRY }}
32
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
33
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
34
+
35
+ - name: Check if stable release
36
+ id: check-stable
37
+ if: startsWith(github.ref, 'refs/tags/')
38
+ run: |
39
+ TAG_NAME="${GITHUB_REF#refs/tags/}"
40
+ echo "Checking tag: $TAG_NAME"
41
+
42
+ # Only match vX.Y.Z format (no suffixes like rc, alpha, beta)
43
+ if [[ "$TAG_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
44
+ echo "is_stable=true" >> $GITHUB_OUTPUT
45
+ echo "This is a STABLE release: $TAG_NAME"
46
+ else
47
+ echo "is_stable=false" >> $GITHUB_OUTPUT
48
+ echo "This is a PRE-RELEASE: $TAG_NAME (will not update 'latest' or major.minor tags)"
49
+ fi
50
+
51
+ - name: Extract metadata
52
+ id: meta
53
+ uses: docker/metadata-action@v5
54
+ with:
55
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
56
+ flavor: |
57
+ # Disable automatic 'latest' tag to have explicit control
58
+ latest=false
59
+ tags: |
60
+ # For PRs: tag as pr-<number>
61
+ type=ref,event=pr
62
+ # For all tags: extract full version without 'v' prefix (e.g., 0.5.2 or 0.5.2rc3)
63
+ type=match,pattern=v(.*),group=1
64
+ # For stable releases only: extract major.minor (e.g., 0.5 from v0.5.2)
65
+ type=match,pattern=v(\d+\.\d+),group=1,enable=${{ steps.check-stable.outputs.is_stable == 'true' }}
66
+ # For stable releases only: tag as 'latest'
67
+ type=raw,value=latest,enable=${{ steps.check-stable.outputs.is_stable == 'true' }}
68
+
69
+ - name: Set build timestamp
70
+ id: timestamp
71
+ run: echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
72
+
73
+ - name: Build and push Docker image
74
+ uses: docker/build-push-action@v6
75
+ with:
76
+ context: .
77
+ platforms: linux/amd64,linux/arm64
78
+ push: ${{ github.event_name != 'pull_request' }}
79
+ tags: ${{ steps.meta.outputs.tags }}
80
+ labels: ${{ steps.meta.outputs.labels }}
81
+ build-args: |
82
+ GIT_COMMIT_HASH=${{ github.sha }}
83
+ BUILD_DATE=${{ steps.timestamp.outputs.BUILD_DATE }}
84
+ cache-from: type=gha
85
+ cache-to: type=gha,mode=max
86
+
87
+ - name: Update Docker Hub description
88
+ if: github.ref_type == 'tag'
89
+ uses: peter-evans/dockerhub-description@v3
90
+ with:
91
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
92
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
93
+ repository: ${{ env.IMAGE_NAME }}
94
+ readme-filepath: ./DOCKER.md
@@ -0,0 +1,38 @@
1
+ name: PyPI Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v[0-9]+.[0-9]+.[0-9]+*" # Match tags like v0.1.0, v1.2.3, v1.2.3-alpha.1
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ pypi-publish:
11
+ name: Build and publish Python distributions to PyPI
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ id-token: write # Required for trusted publishing
15
+ contents: write # Required for creating releases
16
+
17
+ steps:
18
+ - name: Checkout repository
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Install uv with python 3.11
22
+ uses: astral-sh/setup-uv@v6
23
+ with:
24
+ version: latest
25
+ python-version: 3.11
26
+
27
+ - name: Build package
28
+ run: uv build
29
+
30
+ - name: Publish package to PyPI
31
+ uses: pypa/gh-action-pypi-publish@release/v1
32
+
33
+ - name: Generate changelog and create release
34
+ uses: softprops/action-gh-release@v2
35
+ with:
36
+ generate_release_notes: true
37
+ prerelease: false
38
+ files: dist/*
@@ -0,0 +1,32 @@
1
+ name: Test PyPI Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v[0-9]+.[0-9]+.[0-9]+*" # Match tags like v0.1.0, v1.2.3, v1.2.3-alpha.1
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ test-pypi-publish:
11
+ name: Build and publish Python distributions to Test PyPI
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ id-token: write # Required for trusted publishing
15
+
16
+ steps:
17
+ - name: Checkout repository
18
+ uses: actions/checkout@v4
19
+
20
+ - name: Install uv with python 3.11
21
+ uses: astral-sh/setup-uv@v6
22
+ with:
23
+ version: latest
24
+ python-version: 3.11
25
+
26
+ - name: Build package
27
+ run: uv build
28
+
29
+ - name: Publish package to TestPyPI
30
+ uses: pypa/gh-action-pypi-publish@release/v1
31
+ with:
32
+ repository-url: https://test.pypi.org/legacy/
@@ -0,0 +1,149 @@
1
+ name: Update MCP Registry
2
+
3
+ on:
4
+ workflow_run:
5
+ workflows: ["Build and Push Docker Image"]
6
+ types:
7
+ - completed
8
+
9
+ jobs:
10
+ check-and-update-registry:
11
+ # Only run on tag pushes and if the docker workflow succeeded
12
+ if: |
13
+ github.event.workflow_run.conclusion == 'success' &&
14
+ github.event.workflow_run.event == 'push' &&
15
+ startsWith(github.event.workflow_run.head_branch, 'v')
16
+
17
+ runs-on: ubuntu-latest
18
+ permissions:
19
+ id-token: write # Required for GitHub OIDC authentication with MCP Registry
20
+ contents: read
21
+
22
+ steps:
23
+ - name: Checkout repository
24
+ uses: actions/checkout@v4
25
+ with:
26
+ ref: ${{ github.event.workflow_run.head_branch }}
27
+
28
+ - name: Wait for PyPI release to complete
29
+ uses: fountainhead/action-wait-for-check@v1.2.0
30
+ id: wait-for-pypi
31
+ with:
32
+ token: ${{ secrets.GITHUB_TOKEN }}
33
+ checkName: "Build and publish Python distributions to PyPI"
34
+ ref: ${{ github.event.workflow_run.head_sha }}
35
+ timeoutSeconds: 600
36
+ intervalSeconds: 10
37
+
38
+ - name: Check PyPI release status
39
+ if: steps.wait-for-pypi.outputs.conclusion != 'success'
40
+ run: |
41
+ echo "PyPI release did not succeed. Status: ${{ steps.wait-for-pypi.outputs.conclusion }}"
42
+ exit 1
43
+
44
+ - name: Validate version consistency
45
+ id: version
46
+ env:
47
+ HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
48
+ run: |
49
+ # Read versions from files
50
+ ROOT_VERSION=$(jq -r '.version' server.json)
51
+ # Only get versions from packages that have a version field (exclude null/empty)
52
+ PACKAGE_VERSIONS=$(jq -r '.packages[] | select(.version != null) | .version' server.json | sort -u)
53
+ PYPROJECT_VERSION=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/')
54
+ # Get tag from the triggering workflow (Docker), not current workflow
55
+ # Use environment variable to prevent code injection
56
+ TAG_VERSION=${HEAD_BRANCH#v}
57
+
58
+ echo "Version Check:"
59
+ echo " server.json root: $ROOT_VERSION"
60
+ echo " server.json packages:"
61
+ jq -r '.packages[] |
62
+ if .version != null then
63
+ " - \(.registryType):\(.identifier) = \(.version)"
64
+ else
65
+ " - \(.registryType):\(.identifier) (no version field)"
66
+ end' server.json
67
+ echo " pyproject.toml: $PYPROJECT_VERSION"
68
+ echo " Git tag: $TAG_VERSION"
69
+ echo ""
70
+
71
+ # Check if all package versions match root version (only for packages with version field)
72
+ MISMATCH=false
73
+ if [ -n "$PACKAGE_VERSIONS" ]; then
74
+ while IFS= read -r pkg_ver; do
75
+ if [ "$pkg_ver" != "$ROOT_VERSION" ]; then
76
+ echo "ERROR: Package version ($pkg_ver) doesn't match root version ($ROOT_VERSION)"
77
+ MISMATCH=true
78
+ fi
79
+ done <<< "$PACKAGE_VERSIONS"
80
+ fi
81
+
82
+ if [ "$MISMATCH" = true ]; then
83
+ echo ""
84
+ echo "Fix: Update server.json so all package versions match the root version"
85
+ exit 1
86
+ fi
87
+
88
+ # Check if root version matches tag
89
+ if [ "$ROOT_VERSION" != "$TAG_VERSION" ]; then
90
+ echo "ERROR: server.json version ($ROOT_VERSION) doesn't match tag ($TAG_VERSION)"
91
+ echo "Fix: Update server.json root version to match the tag"
92
+ exit 1
93
+ fi
94
+
95
+ # Warn if pyproject.toml doesn't match
96
+ if [ "$PYPROJECT_VERSION" != "$TAG_VERSION" ]; then
97
+ echo "WARNING: pyproject.toml version ($PYPROJECT_VERSION) doesn't match tag ($TAG_VERSION)"
98
+ echo "This may cause PyPI issues"
99
+ fi
100
+
101
+ # Check Docker image tags in OCI identifiers
102
+ echo ""
103
+ echo "Checking Docker image tags..."
104
+ OCI_PACKAGES=$(jq -r '.packages[] | select(.registryType == "oci") | .identifier' server.json)
105
+ if [ -n "$OCI_PACKAGES" ]; then
106
+ OCI_TAG_MISMATCH=false
107
+ while IFS= read -r oci_id; do
108
+ # Extract tag from identifier (everything after last :)
109
+ IMAGE_TAG="${oci_id##*:}"
110
+ echo " - Image: $oci_id"
111
+ echo " Tag: $IMAGE_TAG"
112
+
113
+ if [ "$IMAGE_TAG" != "$ROOT_VERSION" ]; then
114
+ echo " ERROR: Docker image tag ($IMAGE_TAG) doesn't match version ($ROOT_VERSION)"
115
+ OCI_TAG_MISMATCH=true
116
+ else
117
+ echo " Tag matches"
118
+ fi
119
+ done <<< "$OCI_PACKAGES"
120
+
121
+ if [ "$OCI_TAG_MISMATCH" = true ]; then
122
+ echo ""
123
+ echo "Fix: Update Docker image tags in server.json to match the version"
124
+ exit 1
125
+ fi
126
+ fi
127
+
128
+ echo ""
129
+ echo "All version checks passed!"
130
+ echo "version=$ROOT_VERSION" >> $GITHUB_OUTPUT
131
+
132
+ - name: Install MCP Publisher
133
+ run: |
134
+ curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
135
+
136
+ - name: Login to MCP Registry
137
+ run: ./mcp-publisher login github-oidc
138
+
139
+ - name: Publish to MCP Registry
140
+ run: ./mcp-publisher publish
141
+
142
+ - name: Notify completion
143
+ if: success()
144
+ env:
145
+ VERSION: ${{ steps.version.outputs.version }}
146
+ run: |
147
+ echo "MCP Registry updated successfully for version $VERSION"
148
+ echo "Docker image: docker.io/couchbaseecosystem/mcp-server-couchbase:$VERSION"
149
+ echo "PyPI package: couchbase-mcp-server==$VERSION"
@@ -0,0 +1,12 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+ # Environment variables
12
+ .env
@@ -0,0 +1,37 @@
1
+ # Pre-commit hooks configuration
2
+ # See https://pre-commit.com for more information
3
+
4
+ repos:
5
+ # Ruff linter and formatter
6
+ - repo: https://github.com/astral-sh/ruff-pre-commit
7
+ rev: v0.12.0
8
+ hooks:
9
+ # Run the linter
10
+ - id: ruff
11
+ name: ruff-lint
12
+ args: [--fix]
13
+ types_or: [python, pyi, jupyter]
14
+ # Run the formatter
15
+ - id: ruff-format
16
+ name: ruff-format
17
+ types_or: [python, pyi, jupyter]
18
+
19
+ # Additional useful hooks
20
+ - repo: https://github.com/pre-commit/pre-commit-hooks
21
+ rev: v4.6.0
22
+ hooks:
23
+ - id: trailing-whitespace
24
+ - id: end-of-file-fixer
25
+ - id: check-yaml
26
+ - id: check-toml
27
+ - id: check-merge-conflict
28
+ - id: check-added-large-files
29
+ - id: check-case-conflict
30
+ - id: debug-statements
31
+
32
+ # Check for Python syntax errors
33
+ - repo: https://github.com/pre-commit/pygrep-hooks
34
+ rev: v1.10.0
35
+ hooks:
36
+ - id: python-check-blanket-noqa
37
+ - id: python-no-log-warn
@@ -0,0 +1,234 @@
1
+ # Contributing to Couchbase MCP Server
2
+
3
+ Thank you for your interest in contributing to the Couchbase MCP Server! This guide will help you set up your development environment and understand our development workflow.
4
+
5
+ ## 🚀 Development Setup
6
+
7
+ ### Prerequisites
8
+
9
+ - **Python 3.10+**: Required for the project
10
+ - **[uv](https://docs.astral.sh/uv/)**: Fast Python package installer and dependency manager
11
+ - **Git**: For version control
12
+ - **VS Code** (recommended): With Python extension for the best development experience
13
+
14
+ ### Clone and Setup
15
+
16
+ ```bash
17
+ # Clone the repository
18
+ git clone https://github.com/Couchbase-Ecosystem/mcp-server-couchbase.git
19
+ cd mcp-server-couchbase
20
+
21
+ # Install dependencies (including development tools)
22
+ uv sync --extra dev
23
+ ```
24
+
25
+ ### Install Development Tools
26
+
27
+ ```bash
28
+ # Install pre-commit hooks (runs linting on every commit)
29
+ uv run pre-commit install
30
+
31
+ # Verify installation
32
+ uv run pre-commit run --all-files
33
+ ```
34
+
35
+ ## 🧹 Code Quality & Linting
36
+
37
+ We use **[Ruff](https://docs.astral.sh/ruff/)** for fast linting and code formatting to maintain consistent code quality.
38
+
39
+ ### Manual Linting
40
+
41
+ ```bash
42
+ # Check code quality (no changes made)
43
+ ./scripts/lint.sh
44
+ # or: uv run ruff check src/
45
+
46
+ # Auto-fix issues
47
+ ./scripts/fix_lint.sh
48
+ # or: uv run ruff check src/ --fix && uv run ruff format src/
49
+ ```
50
+
51
+ ### Automatic Linting
52
+
53
+ - **Pre-commit hooks**: Ruff runs automatically on every `git commit`
54
+ - **VS Code**: Auto-format on save using [Ruff extension](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff)
55
+
56
+ ### Linting Rules
57
+
58
+ Our Ruff configuration includes:
59
+
60
+ - **Code style**: PEP 8 compliance with 88-character line limit
61
+ - **Import organization**: Automatic import sorting and cleanup
62
+ - **Code quality**: Detection of unused variables, simplification opportunities
63
+ - **Modern Python**: Encourages modern Python patterns with `pyupgrade`
64
+
65
+ ## 🏗️ Project Structure
66
+
67
+ ```
68
+ mcp-server-couchbase/
69
+ ├── src/
70
+ │ ├── mcp_server.py # MCP server entry point
71
+ │ ├── certs/ # SSL/TLS certificates
72
+ │ │ ├── __init__.py # Package marker
73
+ │ │ └── capella_root_ca.pem # Capella root CA certificate (for Capella connections)
74
+ │ ├── tools/ # MCP tool implementations
75
+ │ │ ├── __init__.py # Tool exports and ALL_TOOLS list
76
+ │ │ ├── server.py # Server status and connection tools
77
+ │ │ ├── kv.py # Key-value operations (CRUD)
78
+ │ │ ├── query.py # SQL++ query operations
79
+ │ │ └── index.py # Index operations and recommendations
80
+ │ └── utils/ # Utility modules
81
+ │ ├── __init__.py # Utility exports
82
+ │ ├── constants.py # Project constants
83
+ │ ├── config.py # Configuration management
84
+ │ ├── connection.py # Couchbase connection handling
85
+ │ ├── context.py # Application context management
86
+ │ └── index_utils.py # Index-related helper functions
87
+ ├── scripts/ # Development scripts
88
+ │ ├── lint.sh # Manual linting script
89
+ │ └── lint_fix.sh # Auto-fix linting issues
90
+ ├── .pre-commit-config.yaml # Pre-commit hook configuration
91
+ ├── pyproject.toml # Project dependencies and Ruff config
92
+ ├── CONTRIBUTING.md # Contribution Guide
93
+ └── README.md # Usage
94
+ ```
95
+
96
+ ## 🛠️ Development Workflow
97
+
98
+ ### Making Changes
99
+
100
+ 1. **Create a branch** for your feature/fix:
101
+
102
+ ```bash
103
+ git checkout -b feature/your-feature-name
104
+ ```
105
+
106
+ 2. **Make your changes** following the existing patterns
107
+
108
+ 3. **Test your changes**:
109
+
110
+ ```bash
111
+ # Run linting
112
+ ./scripts/lint.sh
113
+
114
+ # Test the MCP server
115
+ uv run src/mcp_server.py --help
116
+ ```
117
+
118
+ 4. **Commit your changes**:
119
+
120
+ ```bash
121
+ git add .
122
+ git commit -m "feat: add your feature description"
123
+ ```
124
+
125
+ The pre-commit hooks will automatically run and fix any formatting issues.
126
+
127
+ ### Adding New Tools
128
+
129
+ When adding new MCP tools:
130
+
131
+ 1. **Create the tool function** in the appropriate module (in `tools` directory)
132
+ 2. **Export the tool** in `tools/__init__.py`
133
+ 3. **Add to ALL_TOOLS** list in `tools/__init__.py`
134
+ 4. **Test the tool** with an MCP client
135
+
136
+ ### Code Style Guidelines
137
+
138
+ - **Line length**: 88 characters (enforced by Ruff)
139
+ - **Import organization**: Use isort-style grouping (standard library, third-party, local)
140
+ - **Type hints**: Use modern Python type hints where helpful
141
+ - **Docstrings**: Add docstrings for public functions and classes
142
+ - **Error handling**: Include appropriate exception handling with logging
143
+
144
+ ## 🧪 Testing
145
+
146
+ ### Manual Testing
147
+
148
+ Currently, testing is done manually with MCP clients:
149
+
150
+ 1. **Set up environment variables** for your Couchbase cluster
151
+ 2. **Run the server** with an MCP client like Claude Desktop
152
+ 3. **Test tool functionality** through the client interface
153
+
154
+ ### Future Testing Plans
155
+
156
+ We plan to add:
157
+
158
+ - Unit tests for utility functions
159
+ - Integration tests
160
+ - Automated testing in CI/CD
161
+
162
+ ## 📋 Adding New Features
163
+
164
+ ### Before You Start
165
+
166
+ 1. **Check existing issues** to see if someone is already working on it
167
+ 2. **Open an issue** to discuss larger changes
168
+ 3. **Review the codebase** to understand existing patterns
169
+
170
+ ### Implementation Guidelines
171
+
172
+ 1. **Follow existing patterns**: Look at similar tools for guidance
173
+ 2. **Use the utility modules**: Leverage existing connection and context management
174
+ 3. **Add proper logging**: Use the hierarchical logging system
175
+ 4. **Handle errors gracefully**: Provide helpful error messages
176
+ 5. **Update documentation**: Update README.md if adding user-facing features
177
+
178
+ ## 🤝 Submitting Changes
179
+
180
+ 1. **Run final checks**:
181
+
182
+ ```bash
183
+ # Ensure all linting passes
184
+ ./scripts/lint.sh
185
+
186
+ # Test with pre-commit
187
+ uv run pre-commit run --all-files
188
+ ```
189
+
190
+ 2. **Push your branch** and create a pull request
191
+
192
+ 3. **Describe your changes** in the PR description:
193
+ - What does this change do?
194
+ - Why is this change needed?
195
+ - How have you tested it?
196
+
197
+ ## 💡 Tips for Contributors
198
+
199
+ ### Common Development Tasks
200
+
201
+ ```bash
202
+ # Install new dependencies
203
+ uv add package-name
204
+
205
+ # Install new dev dependencies
206
+ uv add --dev package-name
207
+
208
+ # Update dependencies
209
+ uv sync
210
+
211
+ # Run the server for testing
212
+ uv run src/mcp_server.py --connection-string "..." --username "..." --password "..." --bucket-name "..."
213
+ ```
214
+
215
+ ### Debugging
216
+
217
+ - **Use logging**: The project uses hierarchical logging with the pattern `logger = logging.getLogger(f"{MCP_SERVER_NAME}.module.name")`
218
+ - **Check connection**: Ensure your Couchbase cluster is accessible
219
+ - **Validate configuration**: Make sure all required environment variables are set
220
+
221
+ ## 📖 Additional Resources
222
+
223
+ - **[Model Context Protocol Documentation](https://modelcontextprotocol.io/)**
224
+ - **[Couchbase Python SDK Documentation](https://docs.couchbase.com/python-sdk/current/hello-world/start-using-sdk.html)**
225
+ - **[SQL++ Query Language](https://www.couchbase.com/sqlplusplus/)**
226
+ - **[Ruff Documentation](https://docs.astral.sh/ruff/)**
227
+
228
+ ## 🆘 Getting Help
229
+
230
+ - **Open an issue** for bugs or feature requests
231
+ - **Check existing issues** for similar problems
232
+ - **Review the code** for examples and patterns
233
+
234
+ Thank you for contributing to the Couchbase MCP Server! 🚀