Skip to content

Add scope/collection management tools (create/drop scope, create/drop/update collection, get_collection_settings) - #196

Open
celticht32 wants to merge 3 commits into
couchbase:mainfrom
celticht32:feat/collections-management-tools
Open

Add scope/collection management tools (create/drop scope, create/drop/update collection, get_collection_settings)#196
celticht32 wants to merge 3 commits into
couchbase:mainfrom
celticht32:feat/collections-management-tools

Conversation

@celticht32

Copy link
Copy Markdown

⚠️ This PR stacks on top of #187 and #195. Its diff includes #187's index-management code, #195's bucket-management code, and this PR's scope/collection code because both dependencies are still under review. Once #187 and #195 merge, GitHub will auto-shrink this diff to just the 4 new/modified files:

  • src/cb_mcp/tools/collections_admin.py (new)
  • src/cb_mcp/tools/__init__.py (registration additions)
  • tests/unit/test_collections_admin.py (new)
  • tests/unit/test_read_only_mode.py (tool-count updates for the new read tool)

If you'd like to review just the scope/collection changes in isolation, view the diff at: celticht32/mcp-server-couchbase@feat/index-management-tools...feat/collections-management-tools

Phase 3 of the phased admin-tool contribution discussed in #157. Follows the same shape and safety model as #187 and #195.

What this adds

Six tools that complete the scope/collection lifecycle the server currently only reads (get_scopes_and_collections_in_bucket, get_scopes_in_bucket, get_collections_in_scope):

  • create_scope — creates a scope in a bucket via the SDK's CollectionManager.create_scope.
  • drop_scope — drops a scope and all its collections. Requires both confirm=True and confirm_name matching the target scope exactly — matches the delete_bucket pattern from Add bucket management tools (create/update/delete/flush/compact/load_sample) #195. Rejects _default scope (server would reject anyway; catching it client-side gives a clearer error).
  • create_collection — creates a collection inside a scope. Optional max_expiry_seconds (0 = no TTL; None = inherit bucket default) and history (Couchbase 7.2+ Magma per-document history retention) settings.
  • drop_collection — drops a collection and all its documents. Same confirm=True + confirm_name gate as drop_scope. Rejects the _default/_default combination (server would reject anyway).
  • update_collection — updates mutable settings on an existing collection (max_expiry_seconds and/or history). At least one of the two must be provided.
  • get_collection_settings — returns per-collection TTL and history-retention settings for a single collection (read-only; the existing get_scopes_and_collections_in_bucket doesn't surface these).

Why it's shaped this way

Follows the conventions #187 and #195 established:

  • ctx-first tool functions, dict returns, raise on error, registration via tools/__init__.py lists + TOOL_ANNOTATIONS.
  • Reuses ADMIN_WRITE_TOOLS — scope/collection lifecycle loads only when read_only_mode is false AND admin_write_mode is true. Scope/collection create/drop is namespace-level structural mutation and gates behind the same higher-privilege flag as index DDL and bucket lifecycle.
  • Same _require_write_scope() shape as index_admin.py and bucket_admin.py. When an OAuth token is present the caller must additionally hold the write scope.
  • Uses the Couchbase SDK's CollectionManager rather than direct REST — matches the style of the existing scope/collection read tools in tools/server.py, which also go through bucket.collections().get_all_scopes(). No new REST helper module needed; the SDK's CollectionSpec type handles the max_expiry (7.6+) vs. max_ttl (7.0-7.5) compatibility layer correctly.
  • max_expiry_seconds=0 maps to timedelta(seconds=0) explicitly (Couchbase semantics: "no TTL"). max_expiry_seconds=None is left unset in the CollectionSpec (semantics: "inherit bucket default" on create, "leave unchanged" on update).
  • Negative TTL values are rejected client-side with a clear error.
  • get_collection_settings is added to READ_ONLY_TOOLS (always loaded, no admin-write flag needed), which is why tests/unit/test_read_only_mode.py needs the tool-count updates (21 → 22 read-only, 25 → 26 total).

Testing

Unit tests in tests/unit/test_collections_admin.py (no cluster required): timedelta conversion (None / 0 / positive / negative), write-scope gate (present / missing / no-token), argument construction for all 5 write tools, confirmation gate coverage (drop_scope and drop_collection both require confirm=True + name-match), rejection of _default scope and _default/_default combo, correct CollectionSpec construction for TTL and history, and get_collection_settings return shape (settings present / missing max_expiry / scope not found / collection not found).

  • ruff check and ruff format --check pass against pinned ruff 0.12.5.
  • Full unit suite green — 455 tests pass (existing 425 + 30 new).
  • tests/unit/test_read_only_mode.py updated to reflect the new read-only tool count.

Open questions for maintainers

Same three from #187 and #195 apply here; happy to align with whatever you decide on those PRs:

  1. Naming. Verb-first for the write ops (create_scope, drop_scope, create_collection, drop_collection, update_collection) to match Add index management tools (create/drop/build + GSI settings) #187's and Add bucket management tools (create/update/delete/flush/compact/load_sample) #195's conventions.
  2. Admin-write flag. These load under the same --admin-write-mode / CB_MCP_ADMIN_WRITE_MODE flag Add index management tools (create/drop/build + GSI settings) #187 introduced. If you decide to collapse that into read_only_mode on Add index management tools (create/drop/build + GSI settings) #187, I'll follow suit here.
  3. Error convention. Same raised-exception shape as Add index management tools (create/drop/build + GSI settings) #187 and Add bucket management tools (create/update/delete/flush/compact/load_sample) #195. Structured ok()/err() envelope deferred to a future PR (best done uniformly at the registration layer).

Refs #157, #187, #195.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant