Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
CB_MCP_HOSTNoHost for HTTP/SSE transport modes127.0.0.1
CB_MCP_PORTNoPort for HTTP/SSE transport modes8000
CB_PASSWORDYesPassword for authentication
CB_USERNAMEYesUsername with bucket access
CB_BUCKET_NAMEYesName of the bucket to access
CB_MCP_TRANSPORTNoTransport mode: stdio, http, ssestdio
CB_CONNECTION_STRINGYesConnection string to the Couchbase cluster
CB_MCP_READ_ONLY_QUERY_MODENoPrevent data modification queriestrue

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
extensions
{
  "io.modelcontextprotocol/ui": {}
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
get_buckets_in_clusterA

Get the names of all the accessible buckets in the cluster.

get_bucket_configA

Get a bucket's configuration and live state — or every bucket's, if bucket_name is omitted.

Answers "what is this bucket configured as, and how full is it right now?" — RAM quota, replica count, eviction policy, durability level, storage backend, conflict- resolution type, auto-compaction settings, and basic stats (item count, memory used, ops/sec, disk used). Use this to explain a bucket-level symptom that get_cluster_metrics or get_index_stats pointed at, or as a pre-flight safety check before advising a compaction/quota/durability change — this tool only ever reads; create/edit/flush/delete stay CAO-owned. get_buckets_in_cluster lists bucket names via the SDK but exposes none of this; use this tool once a specific bucket needs explaining.

bucket_name must be omitted (not passed as "") to get every bucket — an empty string is rejected rather than silently treated the same as omitting it, since a caller that meant to name a bucket should not get back every bucket's configuration instead.

Calls GET /pools/default/buckets/<bucket_name> (one bucket) or GET /pools/default/buckets (every bucket, when bucket_name is omitted). Self-managed Couchbase Server 7.6+ only (Capella is rejected without a REST call); needs the Read-Only Admin (ro_admin) role.

Reading the result — returned exactly as the endpoint sends it, nothing stripped or renamed, so every field keeps its REST API name (camelCase):

  • "autoCompactionSettings" is the bare value false, not an object, when the bucket has no per-bucket override. Read false as "uses the cluster-wide compaction settings", not "compaction disabled" — they are not the same thing, and this field alone cannot tell you which.

  • "durabilityMinLevel" and "storageBackend" are absent on server versions that predate those fields; absence means "not reported", not "none"/"couchstore".

  • "vBucketServerMap" and "nodes" are the bulk of the payload (a full server list and a per-vBucket map that grows with vbucket/replica/node count) and carry no RCA-relevant signal, but are not stripped: this tool never reshapes what the endpoint returns.

  • A node that was never joined to a cluster (or whose cluster-init failed) answers this endpoint with 200 and [] rather than an error. This is unlikely to matter for a connection_string naming hosts an operator verified are cluster members, but is a real risk when it names a DNS/SRV record backed by a rotating node set (e.g. a Kubernetes headless service), where a connection can land on a freshly provisioned, not-yet-joined node: an empty list there is not proof the cluster itself has no buckets.

Returns the endpoint's response unchanged — a dict for one bucket, a list for all buckets. Raises on failure, including a 404 for an unknown bucket name.

get_server_configuration_statusA

Get the server status and configuration without establishing connection. This tool can be used to verify if the server is running and check the configuration.

test_cluster_connectionA

Test the connection to Couchbase cluster and optionally to a bucket. This tool verifies the connection to the Couchbase cluster and bucket by establishing the connection if it is not already established. If bucket name is not provided, it will not try to connect to the bucket specified in the MCP server settings. Returns connection status and basic cluster information.

get_scopes_and_collections_in_bucketA

Get the names of all scopes and collections in the bucket. Returns a dictionary with scope names as keys and lists of collection names as values.

get_collections_in_scopeA

Get the names of all collections in the given scope and bucket.

get_scopes_in_bucketA

Get the names of all scopes in the given bucket.

get_cluster_health_and_servicesA

Check whether the cluster is reachable right now, and where it's broken.

This actively pings (see caveat below) the cluster's services and reports, per service:

  • Whether it responded and how long it took (latency)

  • Which node/endpoint answered, and any error if it didn't

Scope: cluster-level vs bucket-level ping

  • If bucket_name is omitted, this pings at the cluster level. This covers more services in one call, but whether the key-value (KV) service is included depends on the Couchbase Server version — it may be silently skipped.

  • If bucket_name is provided, this pings from the perspective of that bucket instead. This guarantees the KV service is covered for that bucket, but the result is scoped to that one bucket only — ping again per bucket_name to cover a multi-bucket cluster.

service_types optionally restricts which services get pinged. Valid values: "key_value", "query", "search", "analytics", "view", "management", "eventing". Omit to ping every service. An unrecognized value returns an error response instead of raising.

Caution — this is somewhat invasive: unlike a passive connection-state check, ping performs a live network round-trip to every targeted service. Prefer a narrow service_types filter, and avoid calling this in tight loops or high-frequency polling.

Returns:

  • Cluster health status with service-level connection details and latency measurements

get_client_connectivity_reportA

Check whether the client's connections were already broken, and for how long.

Unlike get_cluster_health_and_services (which actively pings each service right now), this reports the SDK's own cached connection state without performing any network I/O. It's cheap enough to call frequently, but it's only as fresh as the last time the SDK actually talked to each node — it won't proactively detect a service that just went down if nothing has touched it since. Use get_cluster_health_and_services instead when you need a live, right-now reachability check; there's also no way to filter this report to specific services the way that tool's ping can, since no I/O means nothing to filter.

For each known endpoint, reports which service it belongs to, its remote/local addresses, connection state, and last_activity — how long it's been since that connection last saw traffic. Also reports an overall online/degraded/offline cluster state.

This call makes no request to the server at all, so it needs no specific RBAC role beyond whatever the initial cluster connection already required — unlike an active ping, it isn't gated on KV/Query/Search or Cluster Admin privileges.

Returns:

  • Diagnostics report with per-endpoint connection state and overall cluster state

get_cluster_metricsA

Get one or more cluster statistics over a historic time window in a single call.

Use this to quantify a suspected problem (e.g. after get_cluster_health_and_services or get_client_connectivity_report) — is a metric spiking, climbing, or stable over time?

Self-managed Couchbase Server 7.6+ only — rejects Capella connections without a REST call. Calls POST /pools/default/stats/range.

metrics is passed through as the request body: a list of specs, each with a required "metric" (list of {"label", "value"} pairs, e.g. [{"label": "name", "value": "kv_ep_diskqueue_fill"}]), an optional "nodes" ("host:port" targets; omit it to cover every node, which is usually what you want), and optional "applyFunctions", "nodesAggregation", "start"/"end" (negative seconds relative to now; default -60/now), "step" (seconds, default 10), "alignTimestamps".

To find metric names, call discover_tool_input_values(tool_name="get_cluster_metrics") — it lists or searches the full Couchbase metrics reference bundled with this server, offline. Don't guess a metric name: an unknown name comes back as a per-spec error with no data.

Not bounded: any number of specs, window, step, or node count is passed straight through to the REST call, so a broad request (long window, fine step, many nodes/specs) can return a large response.

Returns {"status": "success", "data": [...]} (one entry per spec, each with "data" and any per-spec "errors") or {"status": "error", "error": "..."}.

get_cluster_tasksA

Get the cluster tasks running right now — rebalance, compaction, XDCR, index build.

Answers "what is this cluster doing?" — where stuck rebalances, hung index builds and lagging XDCR surface. One call is a single sample, so pair it with get_cluster_metrics to tell "slow but progressing" from "flatlined".

Calls GET /pools/default/tasks. Self-managed Couchbase Server 7.6+ only (Capella is rejected without a REST call); needs the Read-Only Admin (ro_admin) role.

Returns the endpoint's array unchanged, or [] if no tasks are reported. Only "type" and "status" are common to every entry; the rest are per type — rebalance: progress, perNode, detailedProgress, stageInfo, subtype; bucket_compaction: bucket, progress, changesDone, totalChanges; xdcr: changesLeft, docsChecked, docsWritten, source, target; global_indexes/indexer: bucket, index, progress, id; loadingSampleBucket: task_id, bucket, bucket_uuid.

Reading the result:

  • An idle cluster still reports a rebalance entry with status "notRunning", so check each task's "status" rather than counting entries.

  • "statusIsStale": true means the cluster cannot vouch for that status — read it as "unknown", not "stuck". Flatlined progress and a status that stopped updating look identical here but mean different things.

  • "progress" means different things per type, so do not compare it across tasks.

  • Poll no faster than "recommendedRefreshPeriod" (seconds), the server's own hint.

  • "cancelURI"/"lastReportURI" are informational UI links; this tool only ever GETs and never invokes them.

get_cluster_health_snapshotA

Get per-node service topology, membership, orchestrator and health in one call.

Use this to turn a symptom into a specific node and service: which node is in "warning", what it runs, whether it is still in the cluster, and whether it is the orchestrator — i.e. whether acting on it is disruptive. Also answers "did a topology change leave us in a good state?" after a node replacement or failover.

Self-managed Couchbase Server 7.6+ only (Capella is rejected without a REST call); needs the Read-Only Admin (ro_admin) role.

Reading the result:

  • cluster.unhealthy_nodes / inactive_nodes are the fast path: a node is in unhealthy_nodes when status is not "healthy", and in inactive_nodes when it is no longer an "active" member (e.g. "inactiveFailed" — already failed over, which is a different situation from an active node merely reporting "warning").

  • safe_to_act_on is false only for the orchestrator, where a restart or failover is disruptive in a way it is not elsewhere. When cluster.orchestrator_known is false no node could be flagged, so read safe_to_act_on as "unknown", not "yes" — the cluster reports no orchestrator while one is being elected.

  • reachable_address is the address to probe next, chosen between the node's internal and externally advertised addresses based on which one this server reached the cluster on. Probing the other form may fail for network reasons that look like a node outage; alternateAddresses keeps it as a fallback.

  • cluster.counters holds lifetime rebalance tallies: rebalance_start above rebalance_success means a rebalance began and did not finish — the signature of an interrupted topology change. Pair with get_cluster_tasks for what is running now.

  • recoveryType other than "none" means a recovery is in progress: not healthy yet, rather than broken.

Returns {"cluster": {...}, "nodes": [...]}; raises on failure.

get_cluster_system_eventsA

Get the cluster's system event log — what changed on the cluster, and when.

This is the RCA timeline: once a symptom is confirmed, it finds the config change, failover, rebalance or service restart that preceded it. Window it to the symptom's onset with since_time, then cross-check that timestamp against get_cluster_metrics.

Self-managed Couchbase Server 7.6+ only (Capella is rejected without a REST call); needs the Full Admin or Cluster Admin role. Calls GET /events.

Ordering — easy to misread:

  • Events are ALWAYS oldest-first, but which ones the server picks depends on since_time. Without it, the server takes the limit MOST RECENT events, so the last element is the newest thing on the cluster. With it, it takes the limit EARLIEST events at or after that time, so the last element is NOT the newest — more may follow it.

  • Do not re-sort or re-slice to get "the latest N": slicing keeps the oldest. Lower limit and let the server choose.

  • To page forward, pass summary.next_since_time as the next since_time. It is inclusive, so the boundary event repeats — dedupe on uuid. When it is null on a truncated result, check summary.paging_blocked: every event in the batch shares one timestamp, so sinceTime cannot move past them and a higher limit is the only way to see the rest.

A cluster's log is overwhelmingly "info", so expect routine entries in the window; move the window rather than raising limit.

Reading the result:

  • summary.by_severity / by_component say what the window holds at a glance, so a lone "error" among routine entries is visible without reading every event.

  • summary.possibly_truncated means the server filled the limit, so more events probably exist outside the window. Absence of a later event is not evidence.

  • The log is a ring buffer (10,000 entries by default), so an empty result for an old since_time can mean the events aged out, not that nothing happened.

Returns {"summary": {...}, "events": [...]}; raises on failure.

get_cluster_query_vitalsA

Get query-engine health (vitals) from every query-service node.

Distinguishes "the workload is heavy" from "the query engine itself is stressed" — get_cluster_metrics covers node hardware; this covers the N1QL service layer specifically: request rate, active/queued request counts, memory, GC, service uptime. Use it after get_cluster_metrics/ get_cluster_health_snapshot show healthy infra but queries are still slow.

Calls GET /admin/vitals. Self-managed Couchbase Server 7.6+ only (Capella is rejected without a REST call); needs at minimum the Read-Only Admin (ro_admin) role — verify against your cluster's RBAC before relying on this in production, since the N1QL Admin API's exact privilege requirements are not fully documented.

/admin/vitals answers per node, not cluster-wide — each query node only describes itself — so every query-service node is queried and the results are keyed by node ("host:port").

Returns {"status": "success", "vitals": {"host:port": {...}, ...}, "unreachable_nodes": [{"node", "error"}]} (the last key omitted when every node answered), or {"status": "error", "error": ...} if no query node could be reached at all, or the cluster is Capella.

get_active_queriesA

Get all queries executing right now, across every query-service node.

Use this to find a runaway or stuck statement: elapsed time, the statement text, the client, and current state. Pair with get_cluster_query_vitals to confirm the engine is actually under load from what this returns, and pass a result's "requestId" to delete_active_query to cancel it.

Calls GET /admin/active_requests. Self-managed Couchbase Server 7.6+ only (Capella is rejected without a REST call); needs at minimum the Read-Only Admin (ro_admin) role — verify against your cluster's RBAC before relying on this in production.

/admin/active_requests answers per node — a request only shows up when the node running it is asked — so every query-service node is queried and the lists are merged into one. Each entry already carries its own "node" field, so there is no need to tag entries by which endpoint answered.

Returns {"status": "success", "active_requests": [...merged...], "unreachable_nodes": [{"node", "error"}]} (the last key omitted when every node answered), or {"status": "error", "error": ...} if no query node could be reached at all, or the cluster is Capella.

get_document_by_idA

Get a document by its ID from the specified scope and collection. If the document is not found, it will raise an exception.

lookup_subdocumentA

Look up parts of a document without fetching the whole thing, using Couchbase sub-document operations. Use this instead of get_document_by_id when you only need a few fields, a presence check, or the size of an array/object inside a document — AND you already know the exact field path(s) to look up (e.g. from a prior get_document_by_id call on this same document, from the user explicitly naming the field, or from a known/confirmed schema for this collection).

IMPORTANT: Do NOT guess field paths. If you don't already know the document's exact field names/structure, call get_document_by_id first (or instead) — a guessed path that doesn't exist returns a per-path error here rather than the real data, and reporting "not found" for a wrong guess is worse than just fetching the whole document and reading the right field.

Provide one or more of the following. Each is a list of sub-document paths using Couchbase's dot/bracket path syntax (e.g. "address.city", "tags[0]", "tags[-1]" for the last array element):

  • get_paths: fetch the VALUE at each path.

  • exists_paths: check whether each path exists, without fetching its value (cheaper than get_paths — no payload transfer — when you only need a yes/no answer).

  • count_paths: get the number of elements in the array or object at each path (fails per-path if the path isn't an array/object).

At least one of get_paths, exists_paths, or count_paths must be provided. As a rule of thumb, keep the combined number of paths across all three to 16 or fewer — Couchbase limits subdocument operations per call, though the exact limit is server-side and may change. If the server rejects the call (too many paths, or another constraint like path length or nesting depth), the whole call fails with {"error": "..."}.

A path that doesn't exist (or otherwise fails, e.g. count on a non-array/object) does NOT fail the whole call — it is reported individually as {"error": ...} in the returned dict so the other requested paths can still be resolved.

Returns a dict with a key for each category that was requested (only requested categories are included): { "get": {"": {"value": } | {"error": "..."}}, "exists": {"": {"value": true | false} | {"error": "..."}}, "count": {"": {"value": } | {"error": "..."}}, } On a connection/lookup failure, or an invalid request (no paths / too many paths), returns {"error": ""} instead.

get_schema_for_collectionA

Get the schema for a collection in the specified scope. Returns a dictionary with the collection name and the schema returned by running INFER query on the Couchbase collection.

num_sample_values sets how many example values INFER reports per field. Leave it unset to use the server's own default (5). Pass 0 to omit sample values entirely, keeping only the structure and type information.

run_sql_plus_plus_queryA

Run a SQL++ query on a scope and return the results as a list of JSON values.

The query will be run on the specified scope in the specified bucket. The query should use collection names directly without bucket/scope prefixes, as the scope context is automatically set.

Use named_parameters to bind values to $name placeholders in the query instead of concatenating user input into the statement. This prevents SQL++ injection

Example: query = "SELECT * FROM users WHERE age > 18" # Incorrect: "SELECT * FROM bucket.scope.users WHERE age > 18"

For creating a new index (scalar or vector), prefer the create_query_index tool over a raw CREATE INDEX statement here — it defers the build by default and tells you the recommended next step. Use list_indexes to check whether an index is online before relying on it in a query plan.

For relevance-scored, fuzzy, or linguistic full-text search (scoring, highlighting, faceting, fuzzy/phrase/wildcard matching), prefer run_search over SQL++'s SEARCH() function — it keeps FTS-specific result shape (score, fragments, facets) out of general query results and gives clearer tracing of what was searched.

explain_sql_plus_plus_queryA

Generate and evaluate an EXPLAIN plan for a SQL++ query. It provides information about the execution plan for the query.

The EXPLAIN statement is run in the specified scope in the specified bucket. It returns query metadata along with an extracted plan and plan evaluation.

get_index_advisor_recommendationsB

Get index recommendations from Couchbase Index Advisor for a given SQL++ query.

The Index Advisor analyzes the query and provides recommendations for optimal indexes. This tool works with SELECT, UPDATE, DELETE, or MERGE queries. The queries will be run on the specified scope in the specified bucket.

Returns a dictionary with:

  • current_used_indexes: Array of currently used indexes (if any)

  • recommended_indexes: Array of recommended secondary indexes (if any)

  • recommended_covering_indexes: Array of recommended covering indexes (if any)

Each index object contains:

  • index: The CREATE INDEX SQL++ command

  • statements: Array of statement objects with the query and run count

Raises an error carrying the advisor's message if the advisor cannot analyse the statement (for example, a SQL++ syntax error).

list_indexesA

List indexes in the cluster with optional filtering by bucket, scope, collection, and index name.

Filters must be provided hierarchically: scope requires bucket, collection requires both, index requires all three. Set return_raw_index_stats=True to get the unprocessed source row for each index.

Each result contains: name, definition (CREATE INDEX statement), status, isPrimary, bucket, scope, collection, lastScanTime, is_vector (True for a Hyperscale or Composite Vector Index), and, only when is_vector is True, vector_type ("hyperscale" or "composite"). If a required field is missing, the entry contains warning and raw_index_stats instead.

Source depends on cluster version: v8+ queries system:indexes via the query service (RBAC-scoped — the connected user sees only indexes on keyspaces they can access); older clusters fall back to the admin-level Index Service REST API /getIndexStatus.

get_index_statsA

Get per-index statistics (size, fragmentation, scan traffic) from the Index Service.

Names which index is responsible for disk or memory pressure — use it after get_cluster_metrics shows a node's index disk climbing.

Filters are hierarchical: scope requires bucket, collection requires both, index requires all three. No filters returns every index in the cluster.

Returns nodes (keyed by node, each with an indexer block and an indexes list of bucket/scope/collection/name + stats), nodes_without_index (nodes that answered but do not hold the requested index — expected, since an index lives only where it was placed) and nodes_failed (nodes that could not be reached, so a partial answer is visible as one). indexer is None for filtered calls.

Numbers are per node. A partitioned index appears under several nodes, each reporting only its own share: sum items_count/data_size/disk_size across nodes, but not num_requests, which every hosting node counts in full.

Reading the stats: disk_size far above data_size (see frag_percent) means space reclaimable by compaction; num_requests with last_known_scan_time (Unix ns, 0 = never) identifies unused indexes; num_docs_pending is indexing lag. Counters reset when the indexer restarts, so a low count alone does not prove an index is unused.

skip_empty=True drops zero-valued fields (~two thirds on an idle cluster) — leave it False when hunting unused indexes, since it also removes num_requests: 0.

list_search_indexesA

List Search (FTS) indexes, optionally filtered by bucket and scope.

Filtering behavior:

  • No filters: lists cluster-level ("legacy") Search indexes only — the original, pre-scoped FTS index model, defined at the cluster level.

  • bucket_name only: lists scope-level (scoped) Search indexes across every scope in that bucket.

  • bucket_name and scope_name: lists scope-level Search indexes in that one scope only.

  • scope_name without bucket_name is invalid — returns an error entry explaining that bucket_name is required.

Each entry contains: name, uuid, source_name, source_type, idx_type, bucket, scope. bucket/scope are None for cluster-level (legacy) entries. This is a summary view — to get one index's full definition (mappings, analyzers, plan params), call get_search_index_definition with that entry's name and its own bucket/scope values (both, for a scoped entry; neither, when they're None). Don't reuse this call's filters: listing by bucket_name alone spans several scopes, and get_search_index_definition rejects a bucket without a scope.

get_search_index_definitionA

Get the full definition of a single Search (FTS) index.

Pass both bucket_name and scope_name together to look up a scope-level (scoped) index in that scope, or omit both to look up a cluster-level ("legacy") index. Passing only one of the two is invalid — Couchbase allows the same index name to exist in different scopes, so the location must be stated explicitly rather than guessed.

Returns {"success": True, "name", "source_type", "idx_type", "source_name", "uuid", "params" (mapping/analyzer configuration), "source_uuid", "source_params", "plan_params" (num replicas/partitions), "bucket", "scope"}. If no index with this name exists at the given location, returns {"success": False, "error": ...} — confirm the exact name and location first with list_search_indexes.

run_searchA

Run an FTS (Search) query against a Search index, or fetch its execution plan.

Use this instead of run_sql_plus_plus_query's SEARCH() function when you need relevance-scored, fuzzy, or linguistic full-text matching (scoring, highlighting, faceting, fuzzy/phrase/wildcard matching) — SQL++ can invoke FTS predicates too, but this tool gives clearer tracing of what data was searched and keeps FTS-specific result shape (score, fragments, facets) out of general query results.

query is the raw FTS query JSON body, passed through unvalidated to the Search service — this supports every non-vector FTS query type, e.g.:

  • {"match": "ale", "field": "type"}

  • {"conjuncts": [{"match": "ale"}, {"term": "beer", "field": "type"}]}

  • {"query": "type:beer +name:ale"} (query_string) Vector search is NOT supported by this tool (separate feature).

Pass both bucket_name and scope_name together to query a scope-level (scoped) index, or omit both to query a cluster-level ("legacy") index. Passing only one is invalid. Confirm the index's exact name/location first with list_search_indexes. Don't guess which fields a query body can target — if you don't already know what the index maps and how those fields are analyzed, call get_search_index_definition first; a field-scoped query against an unmapped field matches nothing rather than erroring. Note this only works for indexes with explicit static field mappings — a dynamically mapped index (dynamic: true) has no fixed field list to inspect, since it indexes whatever fields appear in each document; for those, look at actual document contents instead to know what's queryable.

explain: if True, fetches the execution plan instead of normal results. The Search service exposes the query plan per matched document, not as a separate plan-only/ dry-run call — so explain=True still executes the query (with explain enabled) and returns the explanation for each returned hit. limit defaults to 1 in this mode to keep it cheap (pass a larger limit to see the plan for more matched documents), and skip/fields/sort/facets/highlight_fields/disable_scoring/raw are ignored — they only apply when explain=False.

limit/skip/fields/sort/facets/highlight_fields/disable_scoring map to the equivalent Search options. limit defaults to 10 when explain=False (matching the other query tools in this server) and to 1 when explain=True. raw is a passthrough dict for any other SearchOptions field not exposed directly (e.g. highlight_style, consistent_with).

Returns {"success": True, "index_name", "explain", "limit" (the limit actually applied, since it defaults differently depending on explain), "total_hits", "hits", "facets", "metadata": {"errors","metrics"}} on success, or {"success": False, "error": ...} if the input is invalid or the query fails (e.g. bad query syntax, index not found). total_hits counts the hits actually returned, so it is capped by limit — for how many documents matched overall, read metadata.metrics.total_rows instead, and don't report total_hits as the size of the match set. hits entries are {"id","score","fields","fragments"} when explain=False, or {"id","score","explanation"} when explain=True (facets is empty in that case).

run_vector_queryA

Embed a query and run a vector similarity search against a GSI vector index.

Embedding: query_text is embedded using the model configured via CB_MCP_EMBEDDING_MODEL_PROVIDER/CB_MCP_EMBEDDING_MODEL/CB_MCP_EMBEDDING_MODEL_API_KEY/CB_MCP_EMBEDDING_MODEL_ENDPOINT (plus CB_MCP_EMBEDDING_MODEL_AWS_* for provider=bedrock). If no provider is configured, this tool returns {"success": False, "error": ...} explaining what to set -- it is not hidden from tool discovery when unconfigured.

Index selection: this tool queries a Couchbase 8.0+ GSI vector index (Composite Vector Index or Hyperscale Vector Index) via SQL++'s APPROX_VECTOR_DISTANCE(). Unlike Search-service vector search, GSI selects the index automatically from the vector field referenced in the query -- there is no index_name parameter, and none is needed.

distance_metric is required, deliberately with no default: it must match the similarity the index was created with (CREATE INDEX ... WITH {"similarity": ...}), or Couchbase silently falls back to not using the Composite/Hyperscale Vector Index at all (no error -- the query still returns correct results, just unindexed). There is no one value that's usually right, since it depends entirely on how the specific index was created, and this tool has no index_name to look that up automatically (see above) -- call list_indexes first and read the similarity value out of the matching index's definition field (valid values: cosine, dot, l2/euclidean, l2_squared/euclidean_squared).

num_probes/rerank/top_n_scan are Hyperscale Vector Index tuning parameters. num_probes (integer) is the number of centroids to probe -- raise it to improve poor recall. rerank (true/false) re-checks the top candidates against the full vectors; it needs num_probes. top_n_scan (integer) is how many candidates to rerank; it needs num_probes and rerank. num_probes alone, or num_probes + rerank, are both valid. A Composite Vector Index doesn't use any of them. This tool itself has no index_name to check, but list_indexes now reports each index's vector_type ("hyperscale" or "composite") -- check that first if you need to know which shape will actually serve the query.

where is an optional raw SQL++ boolean expression (e.g. "doc.status = 'active'") appended to prefilter candidates before the vector ordering -- this tool only ever emits a SELECT, so, unlike run_sql_plus_plus_query, there is no write-guard for it to bypass. If the index was created with a partial-index condition (create_query_index's condition), where must match or imply it for the planner to actually use that index -- otherwise it falls back to a full scan silently (confirmed via EXPLAIN), the same footgun documented above for a mismatched distance_metric.

select_fields limits the projected document fields; omit it to return the full document. limit defaults to 10, matching the other query/search tools in this server.

Returns {"success": True, "hits": [{"id", "distance", "document": {... selected fields, or the full document}}], "total_hits", "cluster_major_version", and a "warning" key only when the detected cluster major version is below 8 (informational -- a pre-8.0 cluster fails the query naturally with its own "unknown function" error rather than being blocked here)} or {"success": False, "error": ...}. The document is nested under "document" rather than merged into the hit directly -- a document field literally named "id" or "distance" would otherwise silently collide with (and could overwrite) this tool's own id/distance metadata.

run_vector_searchA

Run the Search service's vector search, including hybrid and prefiltered search.

Embedding: vector_query_text is embedded using the model configured via CB_MCP_EMBEDDING_MODEL_PROVIDER/CB_MCP_EMBEDDING_MODEL/CB_MCP_EMBEDDING_MODEL_API_KEY/CB_MCP_EMBEDDING_MODEL_ENDPOINT (plus CB_MCP_EMBEDDING_MODEL_AWS_* for provider=bedrock). If no provider is configured, this tool returns {"success": False, "error": ...} explaining what to set

Unlike run_vector_query's GSI-backed search, this tool always targets a named Search (FTS) index -- index_name is required. Pass both bucket_name and scope_name together to query a scope-level (scoped) index, or omit both to query a cluster-level ("legacy") index. Confirm the index's exact name/location first with list_search_indexes if unsure -- this tool does not pre-validate index_name; a wrong or non-vector index name fails naturally at the Search service with its own error.

scalar_query and prefilter are both optional and both take the same raw FTS query JSON body run_search accepts (e.g. {"match": "jacket", "field": "description"}), but they do different things -- do not confuse them:

  • scalar_query makes this a genuinely hybrid search: both the vector query and this scalar query are sent to the Search service together, and it ranks/combines their hits server-side (a document can match via either signal). is_hybrid in the response reflects whether this was set.

  • prefilter narrows which documents the vector search is even allowed to consider as nearest-neighbor candidates, evaluated before the k-nearest-neighbor search runs -- the Search-service equivalent of run_vector_query's where prefilter on a GSI Composite Vector Index. A document that doesn't match prefilter is never returned, regardless of vector similarity.

Both can be set together (prefilter narrows the candidate pool, then scalar_query's relevance signal still contributes to ranking within it). Omit both for a plain vector-only search through this tool (equivalent in intent to run_vector_query, but against a named Search index instead of a GSI vector index).

num_candidates bounds how many nearest-neighbor candidates the vector query considers; limit bounds how many hits the search as a whole returns, and both default to 10. For a vector-only search (no scalar_query), limit above num_candidates is a no-op -- there are never more than num_candidates vector hits to return. With scalar_query set, limit can meaningfully exceed num_candidates, since scalar_query's own matches aren't bounded by it. fields requests specific stored index fields per hit.

This tool does not fetch full document bodies -- a Search hit carries whatever fields the index stores (row.fields), the same as run_search, not a KV-fetched document (a hit has no reliable per-row collection name to fetch against). Follow up with get_document_by_id for any hit you need the full document for.

Returns {"success": True, "index_name", "vector_field", "num_candidates", "limit", "total_hits", "hits": [{"id", "score", "fields"}], "is_hybrid", "is_prefiltered"} or {"success": False, "error": ...}.

get_queries_not_selectiveA

Get queries that are not very selective from the system:completed_requests catalog.

Prefer this over writing a raw system:completed_requests query via run_sql_plus_plus_query.

get_queries_not_using_covering_indexA

Get queries that don't use a covering index from the system:completed_requests catalog.

Prefer this over writing a raw system:completed_requests query via run_sql_plus_plus_query.

get_queries_using_primary_indexA

Get queries that use a primary index from the system:completed_requests catalog.

Prefer this over writing a raw system:completed_requests query via run_sql_plus_plus_query.

get_queries_with_large_result_countA

Get queries with the largest result counts from the system:completed_requests catalog.

Prefer this over writing a raw system:completed_requests query via run_sql_plus_plus_query.

get_queries_with_largest_response_sizesA

Get queries with the largest response sizes from the system:completed_requests catalog.

Prefer this over writing a raw system:completed_requests query via run_sql_plus_plus_query.

get_longest_running_queriesA

Get the N longest running queries from the system:completed_requests catalog.

Prefer this over writing a raw system:completed_requests query via run_sql_plus_plus_query.

get_most_frequent_queriesA

Get the N most frequent queries from the system:completed_requests catalog.

Prefer this over writing a raw system:completed_requests query via run_sql_plus_plus_query.

discover_tool_input_valuesA

Find the exact input values a specific tool requires, from reference data bundled with this server.

Call this BEFORE calling a tool that needs an exact identifier you do not already know. Do not guess the identifier and do not browse the Couchbase documentation website for it -- a guessed value comes back from the target tool as an error with no data. The reference data ships inside this server, so this works offline and while the cluster is unreachable, which is exactly when you are most likely to be looking up a metric name.

Registered today:

  • tool_name="get_cluster_metrics" -> every Couchbase Server metric name, with its type (counter/gauge/histogram), unit, the server version it first appeared in, and a one-line description. Feed a result's "name" straight into get_cluster_metrics.

tool_name is the only required argument; everything else is optional.

Two ways to call it:

  1. Browse -- pass tool_name alone. Every registered dataset is currently treated as too large to list in full, so this returns "record_count", a small "sample_records" preview, the "chapters" block (the small set of fields you can filter on, with every legal value and a record count each), and a "next_step" pointing you at search instead of a partial list.

  2. Search -- pass tool_name and search_keywords. Returns records ranked by fuzzy relevance, best first. Matching is fuzzy over identifiers and descriptions, so partial words and near-misses still hit.

Every response includes the chapters block, so you never need a separate browse call before narrowing.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A3.7/5.0

Scored across 36 tools

Disambiguation4/5

Most tools target clearly distinct resources/actions, and the descriptions do heavy lifting to separate read-only KV, SQL++, FTS, vector, index, and cluster-ops surfaces. A few pairs are genuinely easy to confuse: run_vector_query (GSI) vs run_vector_search (FTS), get_scopes_and_collections_in_bucket vs get_scopes_in_bucket/get_collections_in_scope, and the three cluster-health tools (health_and_services, health_snapshot, client_connectivity_report). The six query-analysis tools are individually named but form a dense cluster an agent must read carefully.

Naming Consistency4/5

Names are uniformly snake_case and almost all follow verb_noun (get_, list_, run_, explain_, discover_, test_). Minor deviations: near-duplicate verbs for similar concepts (get_document_by_id vs lookup_subdocument, run_vector_query vs run_vector_search) which read consistently but blur intent. No camelCase or style mixing.

Tool Count2/5

36 tools exceeds the 25+ threshold and the surface spans many domains (KV, SQL++, FTS, vector, indexes, cluster diagnostics). Several query-analysis tools (not_selective, not_using_covering_index, using_primary_index, large_result_count, largest_response_sizes, longest_running, most_frequent) could be consolidated into a single parameterized tool. The count feels heavy relative to what an agent can reliably pick from.

Completeness3/5

The read/investigation surface is broad and strong, but there are no document write tools (no insert/upsert/replace/delete) despite the server being KV-capable. Several tools reference operations that aren't in the surface: run_sql_plus_plus_query points to create_query_index, and get_active_queries points to delete_active_query — neither exists, creating dead-end references. Read-only by design, but the stated domain (a Couchbase MCP server) implies write/lifecycle coverage that's missing.

Maintenance

ActivityActive
ResponsivenessSyncing