feat(mcp): add index routing + per-index write policy to upsert-records (RAAE-1607)#632
Draft
vishal-bala wants to merge 1 commit into
Draft
Conversation
…ords (RAAE-1607) Add an optional `index` argument to the upsert-records tool so a multi-binding MCP server can target a specific logical index for writes. As with search, the argument is optional on single-binding servers and required when multiple bindings exist; resolution flows through the shared resolve_binding routing 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, and the selected binding's embedding, runtime limits, and schema validation are used throughout. Write availability is now enforced at two levels. The upsert tool is registered only when at least one binding is writable, so an all-read-only server (whether from global read-only mode or every binding's own read_only policy) does not advertise the tool at all. When the tool is registered, a per-call check rejects writes to any individual read-only binding with invalid_request before any embedding or backend write occurs, so a writable server can still protect specific indexes. - Expose `index` on the FastMCP wrapper param list. - Refine the registration gate from "global read-only off" to "any binding writable" using effective_read_only, which folds in both global and per-index read-only. - Add unit + integration coverage for routing, omitted-index rejection, unknown ids, read-only rejection, the registration gate, and single-binding backward compatibility. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🛡️ Jit Security Scan Results✅ No security findings were detected in this PR
Security scan by Jit
|
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
This completes the multi-index tool surface for the RedisVL MCP server. After RAAE-1606 taught
search-recordsto route by logical index,upsert-records(RAAE-1607) needs the same explicit routing — but writes also carry a policy dimension that reads do not. A single server can now host a mix of writable and read-only bindings, and the tool must respect both the global--read-onlyoverride and each binding's ownread_onlyflag while staying backwards-safe for existing single-index clients.The design keeps single-index behavior identical: when one binding is configured and
indexis omitted, the write resolves to that binding exactly as before. Routing becomes mandatory only once multiple bindings exist. Write enforcement happens at two complementary levels so the contract is unambiguous: a server with no writable bindings should not advertise the tool at all, while a server with some writable bindings still needs to protect the read-only ones on a per-call basis.Implemented changes
upsert-recordsgains an optionalindexargument naming the logical binding to write to, resolved through the sharedresolve_bindingrouting introduced in RAAE-1604. 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, and the selected binding's embedding, runtime limits, and schema validation drive the rest of the write unchanged.Write availability is enforced at two levels. The tool registration gate is refined from "global read-only is off" to "at least one binding is writable" — expressed via
effective_read_only, which already folds in both global read-only mode and a binding's ownread_onlypolicy — so an all-read-only server does not exposeupsert-recordsat all. When the tool is registered, a per-call guard rejects writes to any individual read-only binding withinvalid_requestbefore any embedding or backend write occurs, so a writable server can still protect specific indexes.Minor additional changes:
indexas a tool parameter.Verification
make format(isort + black) and mypy clean on changed files.Stacking
This PR targets
feature/raae-1606-search-routingso its diff stays scoped to upsert routing + write policy. Review/merge bottom-up: #629 → #630 → #631 → this PR.🤖 Generated with Claude Code