Install
$ agentstack add skill-celticht32-couchbase-skills-for-claude-ai-cb-analytics-query ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Querying Couchbase Analytics via cb-analytics-mcp
You have five SQL++ tools for talking to the Analytics service. Picking the right one matters — they have different cost profiles, rate-limit budgets, and result shapes.
| Tool | Cost | Result shape | When to reach for it | |---|---|---|---| | execute_query | high (full result) | rows, may be truncated | DDL, mutations, small SELECTs | | execute_query_readonly | high (full result), cached | rows, may be truncated, cached: bool | repeated SELECTs in an investigation loop | | execute_query_paginated | constant per page | first page + handle | SELECTs that might return many rows | | fetch_next_page | constant per page | next page for a handle | follow-up to paginated | | explain_query | tiny (no execution) | query plan | "why is this slow" |
The cardinal rule: pick the tool that matches what you'll do with the result
If you only need the first N rows to answer the user's question, use execute_query_paginated with page_size=N. Don't pull a million rows through the MCP boundary just to take the first 20.
If you need to show the user the data (and the dataset is small), execute_query_readonly is fine — but watch for truncated: true in the response.
If you need to make a decision based on aggregates (COUNT, SUM, AVG, GROUP BY), the result is small by construction. Use execute_query_readonly and benefit from the cache.
The soft cap (you will see truncated: true)
Both execute_query and execute_query_readonly enforce a server-side row cap (default 1000, configurable via MAX_QUERY_ROWS). Responses include:
truncated: trueif the cap kicked inrow_cap: the cap that was applied (ornullif disabled)full_row_count: how many rows the cluster actually had
When you see truncated: true, do not silently report incomplete data. Either:
- Tell the user the result is truncated and ask if they want all rows
(then re-issue as paginated), or
- If you only needed a sample, acknowledge it and continue ("here are the
first 1000 of 47,832 matching rows").
The user is operating an LLM-driven tool. Hidden truncation will eventually produce wrong answers.
The cache (you will see cached: true)
execute_query_readonly results are cached for ~60 seconds keyed by (cluster, statement, scan_consistency). Responses include cached: true on a cache hit, cached: false on a miss. Practical implications:
- Repeating an identical query inside an investigation loop is free; lean
into it.
- If freshness matters (e.g. you're watching an ingestion catch up), add
scan_consistency="request_plus" so the cache key differs from the default-consistency cached entry.
- If you need a definitively fresh read, use
execute_query(uncached) or
wait 60s.
Pagination, end-to-end
# 1. First page
first = execute_query_paginated(
statement="SELECT id, name, status FROM Default.Orders WHERE region = $r",
named_args={"r": "EMEA"},
page_size=100,
)
handle = first["data"]["pagination_handle"]
# Use first["data"]["results"] — that's your page 0
# 2. Walk pages until exhausted
while first["data"]["has_more"]:
nxt = fetch_next_page(pagination_handle=handle)
# Process nxt["data"]["results"]
if not nxt["data"]["has_more"]:
break
handle = nxt["data"]["pagination_handle"] # handle stays the same; this is for clarity
Important details:
page_sizemust be between 1 and 10000. Default 100.- A trailing
LIMIT/OFFSETclause in your statement gets stripped —
the server adds its own.
- Handles expire after 30 minutes of inactivity. If you get
"not found or expired", just call execute_query_paginated again to start fresh.
- When
has_moreisfalse, the handle is auto-dropped on the server.
Don't call fetch_next_page again with it.
total_seenaccumulates across pages; use it for progress reporting.
EXPLAIN — your slow-query diagnostic
plan = explain_query(statement="SELECT * FROM Default.Orders WHERE customer_id = 'C-1234'")
# plan["data"]["plan"] is the service-internal JSON plan
When to reach for explain_query:
- The user reports a slow query.
- You ran a query and
data.metrics.executionTimewas surprising. - The user asks "is this query using an index?"
- You're about to recommend adding an index — check first that the planner
isn't already using one.
You don't have to add EXPLAIN to your statement; the tool prepends it if not present.
Parameterisation rules (still apply)
Never interpolate user-controlled values into the statement string. Use named_args:
execute_query(
statement="SELECT * FROM Default.Orders o WHERE o.customer_id = $cust",
named_args={"cust": "C-1234"},
)
Identifiers (dataset names, field names) can't be parameterised by SQL++. If you must inject one, validate it first (the server already does this for infer_schema).
Note: execute_query_paginated also accepts named_args and positional_args. Parameter values are reused across pages — no need to re-pass them to fetch_next_page.
Scan consistency
not_bounded(default) — fastest, may see stale results.request_plus— wait for ingest to catch up to this point in time. Use
when correctness matters more than latency.
at_plus— wait for a specific mutation token; rarely needed outside
SDK code.
scan_consistency is part of the cache key for execute_query_readonly. Changing it gives you a fresh read without bypassing the cache for other callers.
Result shape
All five tools return {ok, data, cluster}. The data object's common fields:
| Field | executequery | readonly | paginated | fetchnext_page | explain | |---|---|---|---|---|---| | results | ✓ | ✓ | ✓ (page) | ✓ (page) | — | | plan | — | — | — | — | ✓ | | metrics | ✓ | ✓ | ✓ | ✓ | ✓ | | warnings | ✓ | ✓ | ✓ | ✓ | ✓ | | request_id, status | ✓ | ✓ | ✓ | ✓ | ✓ | | truncated, row_cap, full_row_count | ✓ | ✓ | — | — | — | | cached | — | ✓ | — | — | — | | pagination_handle, page_size, page_offset, rows_returned, has_more | — | — | ✓ | ✓ | — | | total_seen | — | — | — | ✓ | — |
Always surface data.warnings to the user — Couchbase Analytics uses warnings for things like "this query ran but ignored an index hint."
Rate limits & safety
Query tools share a single token bucket per API key, category "query", default 10 requests/sec. That means all five query tools together contribute to the same budget, not 10/sec each.
If you hit the limit:
{ "ok": false, "error": "RateLimitExceeded",
"message": "Rate limit exceeded for category 'query' (limit 10/sec). Retry in 0.41s.",
"category": "query", "rate_per_sec": 10, "retry_after_sec": 0.41 }
Honour retry_after_sec. Don't retry-storm — the bucket only refills at the rate, so hammering it just keeps failing. Better: explain to the user what happened ("hit the query rate limit, waiting half a second") and back off.
Caching helps: every cache hit on execute_query_readonly does not consume a token. So in investigative loops, the second-and-onward hits of the same query are free both for the cluster and for the rate budget.
Common patterns
Counting documents
SELECT VALUE COUNT(*) FROM Default.Users
Use execute_query_readonly. Tiny result, cacheable, almost free.
Schema discovery
Prefer the infer_schema tool (separate skill) over SELECT VALUE OBJECT_NAMES(d) FROM x d; it returns a typed summary including presence rates. Note: infer_schema runs a SELECT under the hood so it counts against the same "query" rate-limit category.
Working with multiple clusters
Always pass cluster="..." if there's any ambiguity. Use list_clusters first if you don't know what's configured.
Diagnosing slow queries
get_active_requests— see what's running now.get_completed_requests— recent history with timings.explain_query(stmt)— show the plan, look for full scans.- If the plan looks fine but the query is still slow, check
get_service_status for resource pressure.
What to avoid
- Don't run
SELECT *against multi-million-row datasets via
execute_query. Use execute_query_paginated with a reasonable page_size (100–1000) instead. The soft cap will catch you anyway, but using the right tool is cleaner.
- Don't use
request_pluson hot-path queries unless the freshness is
actually needed. It defeats both the in-memory cache and Analytics' internal optimisations.
- Don't drop or replace datasets without checking
get_active_requests
first — in-flight queries against the target will fail.
- Don't silently ignore
truncated: true. The user is operating an
LLM-driven tool; hidden truncation produces wrong answers.
- Don't keep paginating "to see if there's more" if
has_moreisfalse.
The handle is dropped server-side; the next call returns an error.
- Don't reach for
execute_query(uncached, full result) when
execute_query_readonly would do. The cache pays for itself within two identical calls.
Related skills
cb-analytics-schema— discover dataverses and infer dataset field shapes before writing queriescb-analytics-admin— monitor active/completed requests, cancel runaway queries, restart the servicecouchbase-sqlpp-tuning— SQL++ tuning principles (index design, EXPLAIN plans, anti-patterns) apply equally to Analytics; that skill has the deep reference docs
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: celticht32
- Source: celticht32/Couchbase-Skills-for-Claude.ai
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.