feat(mcp): add index routing to search-records (RAAE-1606)#631
Open
vishal-bala wants to merge 5 commits into
Open
feat(mcp): add index routing to search-records (RAAE-1606)#631vishal-bala wants to merge 5 commits into
vishal-bala wants to merge 5 commits into
Conversation
🛡️ Jit Security Scan Results✅ No security findings were detected in this PR
Security scan by Jit
|
This was referenced Jun 16, 2026
e8d750c to
14bbdbf
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ 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 80a6a78. Configure here.
Add an always-registered, read-only `list-indexes` MCP tool so clients can enumerate the logical indexes a multi-index server exposes and choose the right one before calling search-records or upsert-records. For each configured binding the tool returns the logical id, an optional description, whether upsert is available (reflecting both the global --read-only flag and the per-index read_only policy), the shared filterable fields, and any explicitly configured runtime limits. Fields are derived from the binding's already-inspected effective schema rather than user-declared metadata; the vector field and the configured default embed-source text field are omitted because they are implementation inputs, not things a client filters on. The Redis index name (redis_name) is never exposed. Limits are surfaced only when explicitly set in config (detected via the runtime model's model_fields_set), so the output reflects deliberate overrides rather than defaults. - New redisvl/mcp/tools/list_indexes.py with list_indexes() + register_list_indexes_tool(). - Registered unconditionally in the server's tool registration, alongside search/upsert. - Output is deterministic and ordered by configured binding. - TDD: unit coverage for field omission, description/limits inclusion rules, redis_name secrecy, read-only reflection, and registration; integration test verifying fields are derived from the inspected schema across a vector and a fulltext binding. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the opaque `rt: Any` parameters in list_indexes.py with the concrete `BindingRuntime` type and the clearer name `binding_runtime`, and type the `server` parameters as `RedisVLMCPServer` (via a TYPE_CHECKING import to avoid the server<->tools import cycle). No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ead (RAAE-1605) Address review on list_indexes.py: - Remove the `tool_list_indexes_description` override: that setting does not exist on MCPSettings (only tool_search/upsert_description do), so the getattr branch was always None and never fired. Pass the default description constant directly. - Read the read scope as `auth_config.read_scope` (a typed field on MCPAuthConfig) instead of a silent `getattr(..., "read_scope", None)`. The old form would fail open — silently yielding None and skipping auth enforcement — if the field were ever renamed; direct access fails loud. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
14bbdbf to
2276985
Compare
80a6a78 to
3d41055
Compare
…605)
list_indexes registered the tool instance-level, so it can still be called
before startup or after shutdown when _bindings is empty. Returning
{"indexes": []} there is misleading — a client reads it as "no indexes
configured" rather than "server not ready". Guard with the same
"MCP server has not been started" RuntimeError that resolve_binding raises.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an optional `index` argument to the search-records tool so a single multi-binding MCP server can target a specific logical index. The argument is optional when exactly one binding is configured (preserving single-index behavior) and resolves through the same resolve_binding routing used elsewhere, so an omitted index on a multi-binding server and unknown ids both surface as invalid_request. The resolved logical id is echoed back as the `index` field in the response. - Expose `index` on the FastMCP wrapper param list. - Append a routing note to the tool description when the schema is ambiguous (multiple bindings) directing clients to call list-indexes first. - Add unit + integration coverage for routing, omitted-index rejection, unknown ids, and single-binding backward compatibility. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3d41055 to
c2f30d5
Compare
Base automatically changed from
feature/raae-1605-list-indexes
to
feature/raae-1603-mcp-multi-index
July 1, 2026 09:41
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Motivation
With a single MCP server now able to expose multiple logical index bindings (RAAE-1604) and advertise them via
list-indexes(RAAE-1605), thesearch-recordstool still implicitly resolved the sole binding. On a multi-binding server it had no way to say which index a query should run against. This change (RAAE-1606) makes that routing explicit while keeping the public contract backwards-safe for existing single-index callers.The design goal is that v1 clients see no behavioral change: when exactly one binding is configured and the caller omits
index, the request resolves to that binding exactly as before. Routing only becomes mandatory once ambiguity exists. Query construction, validation, pagination, filtering, and the configured search mode all remain owned by the selected binding — this ticket adds only the selection and a confirmation echo, not new query behavior.Implemented changes
search-recordsgains an optionalindexargument naming the logical binding to query. Resolution flows through the sharedresolve_bindingrouting introduced in RAAE-1604, so the three cases fall out consistently: an omittedindexwith one binding resolves to that binding; an omittedindexwith multiple bindings returnsinvalid_request; and an unknown id returnsinvalid_request. The resolved logical id is echoed back as theindexfield of the response payload so multi-index clients can confirm where a query actually ran. All downstream work (limits, schema, vectorizer, search config) continues to read from the resolved binding's runtime.When multiple bindings are configured the tool description is ambiguous about fields, so instead of emitting per-field filter hints it now appends a short routing note directing the client to call
list-indexesfirst and pass the chosen id asindex. Single-binding servers keep their full schema-derived description unchanged.Minor additional changes:
indexas a tool parameter so MCP clients can supply it.Verification
make format(isort + black) and mypy clean on changed files.Stacking
This PR targets
feature/raae-1605-list-indexesso its diff stays scoped to search routing. Review/merge bottom-up: #629 → #630 → this PR.🤖 Generated with Claude Code
Note
Low Risk
Backward-compatible for single-index callers; changes are limited to MCP search routing and an additive response field, with validation delegated to existing
resolve_binding.Overview
The MCP
search-recordstool now accepts an optionalindexargument so clients can target a specific logical binding on multi-index servers. Resolution goes throughresolve_binding: omittingindexstill works when only one binding exists; with multiple bindings,indexis required and unknown ids returninvalid_request.Successful responses include a new
indexfield with the resolved binding id so callers can confirm routing. The FastMCP wrapper exposesindexas a tool parameter.When the server has multiple indexes, the tool description skips per-schema filter/return-field hints and instead tells clients to call
list-indexesand pass the chosen id asindex. Single-index servers keep the full schema-derived description.Unit and integration tests cover named routing, omitted-index errors on multi-binding setups, unknown-index rejection, single-binding echo behavior, and the ambiguous-schema description.
Reviewed by Cursor Bugbot for commit c2f30d5. Bugbot is set up for automated code reviews on this repo. Configure here.