Skip to content

feat(mcp): let operators disable individual built-in tools - #668

Open
vishal-bala wants to merge 1 commit into
mainfrom
feat/mcp-builtin-tool-toggle
Open

feat(mcp): let operators disable individual built-in tools#668
vishal-bala wants to merge 1 commit into
mainfrom
feat/mcp-builtin-tool-toggle

Conversation

@vishal-bala

@vishal-bala vishal-bala commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

list-indexes, search-records, and upsert-records all registered unconditionally, so an operator who wanted a narrower tool surface had no way to get one. A deployment that should never advertise writes still published upsert-records whenever any binding was writable, and a single-purpose server still published discovery.

The config

server:
  builtin_tools:
    upsert-records: disabled

Omitted names stay enabled, so existing configs are unaffected. Only the three real names are accepted: search_records with underscores fails at startup rather than silently disabling nothing while reading as though it had.

Two unusable-but-valid tool surfaces now warn

Both shapes are legal config that presents to a client as a server that simply does not work, and both were previously silent:

  • Everything disabled leaves a server that connects and offers nothing. The warning deliberately does not name a cause, since upsert-records can also be absent because every binding is read-only.
  • Discovery disabled on a multi-index server leaves search-records demanding a logical index id that clients have no way to learn — its own description tells them to call list-indexes first.

Neither is fatal, because an operator may be mid-rollout.

The multi-index discovery case had no coverage anywhere, so this adds it, along with the negative case: with a sole binding the index argument defaults, so disabling discovery there is legitimate and stays quiet. I verified by mutation that the new test fails when the warning condition is neutered.

Verification

  • MCP unit tests: 237 passing
  • make check-types: clean
  • Pre-commit: passing

Note on sequencing

This is independently useful and mergeable on its own. It is also a prerequisite for the custom tool profiles work that follows, since a profile name must be checked against the built-in names this PR introduces.


Note

Low Risk
Config-only surface change with defaults preserving current behavior; write paths remain gated by existing read-only rules.

Overview
Operators can narrow the MCP tool surface via server.builtin_tools, setting any of list-indexes, search-records, or upsert-records to disabled while omitted names stay enabled (existing configs unchanged). Unknown keys fail at startup with a clear error instead of being ignored.

_register_tools now gates each built-in through MCPServerConfig.builtin_tool_enabled; upsert-records still also requires a writable binding. Startup logs warnings when the resulting surface is empty or when multi-index search-records is exposed without list-indexes.

Docs describe the YAML knob and the three built-ins; config and server unit tests cover defaults, validation, YAML load, per-tool gating, and warning behavior.

Reviewed by Cursor Bugbot for commit 04fbfad. Bugbot is set up for automated code reviews on this repo. Configure here.

@vishal-bala vishal-bala added the auto:minor Increment the minor version when merged label Aug 6, 2026
@vishal-bala
vishal-bala force-pushed the feat/mcp-builtin-tool-toggle branch from 264f13e to 20dc663 Compare August 6, 2026 13:42
@vishal-bala
vishal-bala marked this pull request as ready for review August 7, 2026 15:36
`list-indexes`, `search-records`, and `upsert-records` all registered
unconditionally, so an operator who wanted a narrower tool surface had no
way to get one -- a deployment that should never advertise writes still
published `upsert-records` whenever any binding was writable, and a
single-purpose server still published discovery.

`server.builtin_tools` maps a built-in name to enabled/disabled. Omitted
names stay enabled, so existing configs are unaffected. Only the three
real names are accepted: `search_records` with underscores fails at
startup rather than silently disabling nothing while reading as though it
had.

Two tool-set shapes are valid config but unusable in practice, and both
would otherwise be silent. Disabling everything leaves a server that
connects and offers nothing. Disabling discovery on a multi-index server
leaves `search-records` demanding a logical index id that clients have no
way to learn, since its own description tells them to call `list-indexes`
first. Both now log a warning at startup; neither is fatal, because an
operator may be mid-rollout. The empty-surface warning deliberately does
not name a cause, since `upsert-records` can also be absent because every
binding is read-only.

The multi-index discovery case had no coverage, so this adds it along
with the negative case: a sole binding makes the index argument default,
so disabling discovery there is legitimate and stays quiet.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 20dc663. Configure here.

Comment thread redisvl/mcp/server.py
Comment thread redisvl/mcp/tools/list_indexes.py
Comment thread redisvl/mcp/server.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto:minor Increment the minor version when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant