couchbase-mcp-server 0.5.1__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 (37) hide show
  1. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/.github/workflows/docker.yml +26 -3
  2. couchbase_mcp_server-0.5.2/.github/workflows/update-mcp-registry.yml +149 -0
  3. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/PKG-INFO +4 -1
  4. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/README.md +3 -0
  5. couchbase_mcp_server-0.5.2/RELEASE.md +264 -0
  6. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/pyproject.toml +1 -1
  7. couchbase_mcp_server-0.5.2/scripts/update_version.sh +79 -0
  8. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/server.json +3 -3
  9. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/tools/query.py +9 -1
  10. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/uv.lock +1 -1
  11. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/.github/workflows/alert-on-pr.yml +0 -0
  12. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/.github/workflows/release.yml +0 -0
  13. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/.github/workflows/test_release.yml +0 -0
  14. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/.gitignore +0 -0
  15. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/.pre-commit-config.yaml +0 -0
  16. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/CONTRIBUTING.md +0 -0
  17. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/DOCKER.md +0 -0
  18. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/Dockerfile +0 -0
  19. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/LICENSE +0 -0
  20. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/build.sh +0 -0
  21. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/glama.json +0 -0
  22. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/scripts/lint.sh +0 -0
  23. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/scripts/lint_fix.sh +0 -0
  24. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/smithery.yaml +0 -0
  25. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/certs/__init__.py +0 -0
  26. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/certs/capella_root_ca.pem +0 -0
  27. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/mcp_server.py +0 -0
  28. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/tools/__init__.py +0 -0
  29. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/tools/index.py +0 -0
  30. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/tools/kv.py +0 -0
  31. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/tools/server.py +0 -0
  32. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/utils/__init__.py +0 -0
  33. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/utils/config.py +0 -0
  34. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/utils/connection.py +0 -0
  35. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/utils/constants.py +0 -0
  36. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/utils/context.py +0 -0
  37. {couchbase_mcp_server-0.5.1 → couchbase_mcp_server-0.5.2}/src/utils/index_utils.py +0 -0
@@ -32,16 +32,39 @@ jobs:
32
32
  username: ${{ secrets.DOCKERHUB_USERNAME }}
33
33
  password: ${{ secrets.DOCKERHUB_TOKEN }}
34
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
+
35
51
  - name: Extract metadata
36
52
  id: meta
37
53
  uses: docker/metadata-action@v5
38
54
  with:
39
55
  images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
56
+ flavor: |
57
+ # Disable automatic 'latest' tag to have explicit control
58
+ latest=false
40
59
  tags: |
60
+ # For PRs: tag as pr-<number>
41
61
  type=ref,event=pr
42
- type=semver,pattern={{version}}
43
- type=semver,pattern={{major}}.{{minor}}
44
- type=raw,value=latest
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' }}
45
68
 
46
69
  - name: Set build timestamp
47
70
  id: timestamp
@@ -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"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: couchbase-mcp-server
3
- Version: 0.5.1
3
+ Version: 0.5.2
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
@@ -32,6 +32,8 @@ An [MCP](https://modelcontextprotocol.io/) server implementation of Couchbase th
32
32
  <img width="380" height="200" src="https://glama.ai/mcp/servers/@Couchbase-Ecosystem/mcp-server-couchbase/badge" alt="Couchbase Server MCP server" />
33
33
  </a>
34
34
 
35
+ <!-- mcp-name: io.github.Couchbase-Ecosystem/mcp-server-couchbase -->
36
+
35
37
  ## Features
36
38
 
37
39
  - Get a list of all the buckets in the cluster
@@ -43,6 +45,7 @@ An [MCP](https://modelcontextprotocol.io/) server implementation of Couchbase th
43
45
  - Upsert a document by ID to a specified scope and collection
44
46
  - Delete a document by ID from a specified scope and collection
45
47
  - Run a [SQL++ query](https://www.couchbase.com/sqlplusplus/) on a specified scope
48
+ - Queries are automatically scoped to the specified bucket and scope, so use collection names directly (e.g., use `SELECT * FROM users` instead of `SELECT * FROM bucket.scope.users`)
46
49
  - 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.
47
50
  - Get the status of the MCP server
48
51
  - Check the cluster credentials by connecting to the cluster
@@ -8,6 +8,8 @@ An [MCP](https://modelcontextprotocol.io/) server implementation of Couchbase th
8
8
  <img width="380" height="200" src="https://glama.ai/mcp/servers/@Couchbase-Ecosystem/mcp-server-couchbase/badge" alt="Couchbase Server MCP server" />
9
9
  </a>
10
10
 
11
+ <!-- mcp-name: io.github.Couchbase-Ecosystem/mcp-server-couchbase -->
12
+
11
13
  ## Features
12
14
 
13
15
  - Get a list of all the buckets in the cluster
@@ -19,6 +21,7 @@ An [MCP](https://modelcontextprotocol.io/) server implementation of Couchbase th
19
21
  - Upsert a document by ID to a specified scope and collection
20
22
  - Delete a document by ID from a specified scope and collection
21
23
  - Run a [SQL++ query](https://www.couchbase.com/sqlplusplus/) on a specified scope
24
+ - Queries are automatically scoped to the specified bucket and scope, so use collection names directly (e.g., use `SELECT * FROM users` instead of `SELECT * FROM bucket.scope.users`)
22
25
  - 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.
23
26
  - Get the status of the MCP server
24
27
  - Check the cluster credentials by connecting to the cluster
@@ -0,0 +1,264 @@
1
+ # Release Process
2
+
3
+ This document describes how to create a new release of `mcp-server-couchbase`.
4
+
5
+ ## Release Process
6
+
7
+ ### Update Version Numbers
8
+
9
+ **Option A: Use the helper script (Recommended):**
10
+
11
+ ```bash
12
+ ./scripts/update_version.sh 0.5.2
13
+ ```
14
+
15
+ This automatically updates:
16
+
17
+ - `pyproject.toml` version
18
+ - `server.json` root version
19
+ - `server.json` all package versions
20
+ - `server.json` Docker image tags (OCI identifiers)
21
+ - `uv.lock`
22
+
23
+ **Option B: Manual update:**
24
+
25
+ Update the version in all locations:
26
+
27
+ 1. **`pyproject.toml`:**
28
+
29
+ ```toml
30
+ version = "0.5.2"
31
+ ```
32
+
33
+ 2. **`server.json`** (root version):
34
+
35
+ ```json
36
+ {
37
+ "version": "0.5.2",
38
+ ...
39
+ }
40
+ ```
41
+
42
+ 3. **`server.json`** (each package version):
43
+
44
+ ```json
45
+ {
46
+ "packages": [
47
+ {
48
+ "version": "0.5.2",
49
+ ...
50
+ }
51
+ ]
52
+ }
53
+ ```
54
+
55
+ 4. **`server.json`** (Docker image tags in OCI packages):
56
+
57
+ ```json
58
+ {
59
+ "packages": [
60
+ {
61
+ "registryType": "oci",
62
+ "identifier": "docker.io/couchbaseecosystem/mcp-server-couchbase:0.5.2",
63
+ ...
64
+ }
65
+ ]
66
+ }
67
+ ```
68
+
69
+ 5. Update lock file:
70
+ ```bash
71
+ uv lock
72
+ ```
73
+
74
+ > **Important:** All versions and Docker image tags must match the root version. The CI/CD pipeline validates this and will fail if versions are inconsistent.
75
+
76
+ ### 2. Validate Versions
77
+
78
+ Before pushing, verify all versions match:
79
+
80
+ ```bash
81
+ # Check versions
82
+ echo "Checking version consistency..."
83
+ echo "pyproject.toml: $(grep '^version = ' pyproject.toml)"
84
+ echo "server.json root: $(jq -r '.version' server.json)"
85
+ echo "server.json packages:"
86
+ jq -r '.packages[] |
87
+ if .registryType == "oci" then
88
+ " - \(.registryType):\(.identifier) (tag: \(.identifier | split(":")[1]))"
89
+ else
90
+ " - \(.registryType):\(.identifier) (version: \(.version))"
91
+ end' server.json
92
+ ```
93
+
94
+ **Expected output:**
95
+
96
+ - All versions should be `0.5.2`
97
+ - Docker image tag should be `:0.5.2`
98
+
99
+ If versions don't match, run `./scripts/update_version.sh 0.5.2` again.
100
+
101
+ ### 3. Commit and Tag
102
+
103
+ ```bash
104
+ git add pyproject.toml server.json uv.lock
105
+ git commit -m "Bump version to 0.5.2"
106
+ git tag v0.5.2
107
+ git push origin main
108
+ git push origin v0.5.2
109
+ ```
110
+
111
+ > **Important:** Once you push the tag, **all workflows start immediately** and PyPI publishes within ~3 minutes. PyPI versions are **immutable** - if anything fails later, you'll need a new version number. There's no going back!
112
+
113
+ ### 4. Automated Pipeline
114
+
115
+ Once the tag is pushed, three GitHub Actions workflows run **in parallel/sequence**:
116
+
117
+ 1. **PyPI Release**
118
+
119
+ - Builds Python package
120
+ - Publishes to PyPI as `couchbase-mcp-server`
121
+ - Creates GitHub Release with changelog
122
+
123
+ 2. **Docker Build**
124
+
125
+ - Builds multi-architecture images (amd64, arm64)
126
+ - Pushes to Docker Hub as `couchbaseecosystem/mcp-server-couchbase`
127
+ - Updates Docker Hub description
128
+
129
+ 3. **MCP Registry Update** (runs after Docker completes)
130
+ - Waits for both PyPI and Docker to complete
131
+ - Validates version consistency
132
+ - Publishes to MCP Registry
133
+
134
+ > **Note:** Version validation happens in the MCP Registry workflow, which runs **after** PyPI and Docker have already published. This is why local validation (step 2) is critical!
135
+
136
+ ### 5. Verify Release
137
+
138
+ Check that all three workflows succeeded:
139
+
140
+ - https://github.com/Couchbase-Ecosystem/mcp-server-couchbase/actions
141
+
142
+ Verify the release is available:
143
+
144
+ - PyPI: https://pypi.org/project/couchbase-mcp-server/
145
+ - Docker Hub: https://hub.docker.com/r/couchbaseecosystem/mcp-server-couchbase
146
+ - MCP Registry
147
+
148
+ ## Release Candidates
149
+
150
+ **Recommended for first-time releases or major changes.**
151
+
152
+ Release candidates let you test the full release pipeline without committing to a final version number. If something fails, you can fix it and release the final version without version conflicts.
153
+
154
+ **Create an RC release:**
155
+
156
+ ```bash
157
+ # Update version to RC
158
+ ./scripts/update_version.sh 0.5.2rc1
159
+
160
+ # Or manually update pyproject.toml and server.json (root + all packages)
161
+
162
+ # Commit and tag
163
+ git add pyproject.toml server.json uv.lock
164
+ git commit -m "Bump version to 0.5.2rc1"
165
+ git tag v0.5.2rc1
166
+ git push origin main
167
+ git push origin v0.5.2rc1
168
+ ```
169
+
170
+ **What gets published:**
171
+
172
+ - PyPI: `couchbase-mcp-server==0.5.2rc1`
173
+ - Docker Hub: `couchbaseecosystem/mcp-server-couchbase:0.5.2rc1`
174
+ - MCP Registry: version `0.5.2rc1`
175
+
176
+ **If RC succeeds, release the final version:**
177
+
178
+ ```bash
179
+ ./scripts/update_version.sh 0.5.2
180
+ git add pyproject.toml server.json uv.lock
181
+ git commit -m "Bump version to 0.5.2"
182
+ git tag v0.5.2
183
+ git push origin main
184
+ git push origin v0.5.2
185
+ ```
186
+
187
+ **If RC fails:**
188
+
189
+ - Fix the issues
190
+ - Create `0.5.2rc2` and test again
191
+ - No version conflicts since the final `0.5.2` wasn't published yet!
192
+
193
+ ## Troubleshooting
194
+
195
+ ### Release Failed
196
+
197
+ **IMPORTANT:** Once PyPI publishes a version, it **cannot be reused**. PyPI versions are immutable.
198
+
199
+ If a release fails after PyPI has published (e.g., Docker build fails, MCP Registry update fails):
200
+
201
+ **Skip to next patch version:**
202
+
203
+ ```bash
204
+ # If v0.5.2 was published but release incomplete
205
+ ./scripts/update_version.sh 0.5.3
206
+
207
+ git add pyproject.toml server.json uv.lock
208
+ git commit -m "Bump version to 0.5.3"
209
+ git tag v0.5.3
210
+ git push origin main
211
+ git push origin v0.5.3
212
+ ```
213
+
214
+ **Why this happens:**
215
+
216
+ - PyPI, Docker, and MCP Registry workflows all start when you push the tag
217
+ - Version validation only happens in the MCP Registry workflow (which runs last)
218
+ - By that time, PyPI and Docker have already published
219
+ - If validation or MCP Registry publish fails, you can't reuse the version number
220
+
221
+ **Prevention:**
222
+
223
+ - **Always test with RC releases first** (e.g., `0.5.2rc1`)
224
+ - **Use the helper script** (`./scripts/update_version.sh`) to ensure all versions match
225
+ - **Review changes carefully** before pushing the tag (`git diff`)
226
+ - Verify all workflows succeeded before announcing release
227
+
228
+ ## How Versioning Works
229
+
230
+ ### Version Files
231
+
232
+ All version numbers must be **manually synchronized** across:
233
+
234
+ - **`pyproject.toml`**: Python package version
235
+ - **`server.json` root `version`**: MCP Registry metadata version
236
+ - **`server.json` package `version`**: Must match root version
237
+ - **`server.json` OCI identifiers**: Docker image tags must match root version
238
+ - **Git tag**: Must match all versions
239
+
240
+ ### Why All Versions Must Match
241
+
242
+ The CI/CD pipeline validates version consistency and will **fail the build** if:
243
+
244
+ - Package versions in `server.json` don't match the root version
245
+ - Docker image tags in OCI identifiers don't match the root version
246
+ - Root version in `server.json` doesn't match the git tag
247
+ - (Warning only) `pyproject.toml` doesn't match the git tag
248
+
249
+ This ensures:
250
+
251
+ - No accidental version mismatches
252
+ - Consistent versioning across PyPI, Docker, and MCP Registry
253
+ - Valid JSON files that can be tested locally
254
+ - Clear version history in git
255
+
256
+ ### Helper Script
257
+
258
+ The `scripts/update_version.sh` script keeps all versions synchronized automatically:
259
+
260
+ ```bash
261
+ ./scripts/update_version.sh 0.5.2
262
+ ```
263
+
264
+ This updates all three locations and runs `uv lock` in one command.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "couchbase-mcp-server"
3
- version = "0.5.1"
3
+ version = "0.5.2"
4
4
  description = "Couchbase MCP Server - The Developer Data Platform for Critical Applications in Our AI World"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10,<3.14"
@@ -0,0 +1,79 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ # Simple script to update version in all necessary files
5
+ # Usage: ./scripts/update_version.sh 0.5.2
6
+
7
+ if [ -z "$1" ]; then
8
+ echo "Usage: $0 <new_version>"
9
+ echo "Example: $0 0.5.2"
10
+ echo "Example: $0 0.5.2rc1"
11
+ exit 1
12
+ fi
13
+
14
+ NEW_VERSION="$1"
15
+
16
+ echo "Updating version to $NEW_VERSION"
17
+ echo ""
18
+
19
+ # Update pyproject.toml
20
+ echo "Updating pyproject.toml..."
21
+ if [[ "$OSTYPE" == "darwin"* ]]; then
22
+ # macOS
23
+ sed -i '' "s/^version = \".*\"/version = \"$NEW_VERSION\"/" pyproject.toml
24
+ else
25
+ # Linux
26
+ sed -i "s/^version = \".*\"/version = \"$NEW_VERSION\"/" pyproject.toml
27
+ fi
28
+
29
+ # Update server.json (root version, package versions, and Docker image tags)
30
+ echo "Updating server.json..."
31
+ if command -v jq &> /dev/null; then
32
+ # Use jq for safer JSON manipulation
33
+ jq --arg ver "$NEW_VERSION" '
34
+ .version = $ver |
35
+ .packages = [
36
+ .packages[] |
37
+ if .registryType == "oci" then
38
+ # Update Docker image tag (everything after last :)
39
+ # OCI packages should NOT have a separate version field
40
+ .identifier = (.identifier | sub(":[^:]*$"; ":" + $ver))
41
+ else
42
+ # Update version field for non-OCI packages (e.g., PyPI)
43
+ .version = $ver
44
+ end
45
+ ]
46
+ ' server.json > server.json.tmp
47
+ mv server.json.tmp server.json
48
+ else
49
+ echo "Error: jq is required but not installed"
50
+ echo "Install with: brew install jq (macOS) or apt install jq (Linux)"
51
+ exit 1
52
+ fi
53
+
54
+ # Update lock file
55
+ echo "Updating uv.lock"
56
+ uv lock
57
+
58
+ echo ""
59
+ echo "Version updated to $NEW_VERSION in:"
60
+ echo " - pyproject.toml"
61
+ echo " - server.json (root, packages, and Docker image tags)"
62
+ echo " - uv.lock"
63
+ echo ""
64
+ echo "Verification:"
65
+ echo " pyproject.toml: $(grep '^version = ' pyproject.toml)"
66
+ echo " server.json root: $(jq -r '.version' server.json)"
67
+ echo " server.json packages:"
68
+ jq -r '.packages[] |
69
+ if .registryType == "oci" then
70
+ " - \(.registryType):\(.identifier) (tag: \(.identifier | split(":")[1]))"
71
+ else
72
+ " - \(.registryType):\(.identifier) (version: \(.version))"
73
+ end' server.json
74
+ echo ""
75
+ echo "Next steps:"
76
+ echo " 1. Review changes: git diff"
77
+ echo " 2. Commit: git add pyproject.toml server.json uv.lock && git commit -m 'Bump version to $NEW_VERSION'"
78
+ echo " 3. Tag: git tag v$NEW_VERSION"
79
+ echo " 4. Push: git push origin main && git push origin v$NEW_VERSION"
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/Couchbase-Ecosystem/mcp-server-couchbase",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.5.1",
9
+ "version": "0.5.2",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "pypi",
13
13
  "identifier": "couchbase-mcp-server",
14
- "version": "0.5.1",
14
+ "version": "0.5.2",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },
@@ -172,7 +172,7 @@
172
172
  },
173
173
  {
174
174
  "registryType": "oci",
175
- "identifier": "docker.io/couchbaseecosystem/mcp-server-couchbase:0.5.1",
175
+ "identifier": "docker.io/couchbaseecosystem/mcp-server-couchbase:0.5.2",
176
176
  "transport": {
177
177
  "type": "stdio"
178
178
  },
@@ -39,7 +39,15 @@ def get_schema_for_collection(
39
39
  def run_sql_plus_plus_query(
40
40
  ctx: Context, bucket_name: str, scope_name: str, query: str
41
41
  ) -> list[dict[str, Any]]:
42
- """Run a SQL++ query on a scope and return the results as a list of JSON objects."""
42
+ """Run a SQL++ query on a scope and return the results as a list of JSON objects.
43
+
44
+ The query will be run on the specified scope in the specified bucket.
45
+ The query should use collection names directly without bucket/scope prefixes, as the scope context is automatically set.
46
+
47
+ Example:
48
+ query = "SELECT * FROM users WHERE age > 18"
49
+ # Incorrect: "SELECT * FROM bucket.scope.users WHERE age > 18"
50
+ """
43
51
  cluster = get_cluster_connection(ctx)
44
52
 
45
53
  bucket = connect_to_bucket(cluster, bucket_name)
@@ -168,7 +168,7 @@ wheels = [
168
168
 
169
169
  [[package]]
170
170
  name = "couchbase-mcp-server"
171
- version = "0.5.1"
171
+ version = "0.5.2"
172
172
  source = { editable = "." }
173
173
  dependencies = [
174
174
  { name = "click" },