You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(mcp): document multi-index server contract (RAAE-1608)
Update the MCP concept doc, how-to guide, and README MCP section to reflect
formal multi-index support. Replace single-index-only language ("one server
binds to exactly one index") with the compatibility story: a single configured
index remains the simplest deployment and behaves unchanged, while multiple
indexes are formally supported behind discovery and explicit routing.
Document the list-indexes discovery tool and recommend clients call it first on
a multi-index server, then pass the chosen logical id as the index argument to
search-records and upsert-records. Explain that both tools echo the resolved
index, that an omitted index is valid only on single-index servers, and that
unknown ids fail with invalid_request.
Explain the two-level write policy: global --read-only disables writes across
every binding, while per-index read_only disables a single binding; upsert is
exposed only when at least one binding is writable, and writes to a read-only
binding are rejected with invalid_request. Clarify that list-indexes shares the
filterable fields discovered from each index, omits the vector and embed-source
fields, surfaces only explicitly configured runtime limits, and never exposes
redis_name.
- Add a two-binding config example (writable vector index + read-only fulltext
index) and a list-indexes response example.
- Add index-parameterized search-records and upsert-records request/response
examples and a discovery-first multi-index flow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: README.md
+9-7Lines changed: 9 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -35,7 +35,7 @@ Perfect for building **RAG pipelines** with real-time retrieval, **AI agents** w
35
35
|**[Vector Search](#retrieval)**<br/>*Similarity search with metadata filters*|**[LLM Memory](#llm-memory)**<br/>*Agentic AI context management*|**Async Support**<br/>*Async indexing and search for improved performance*|
|**[Hybrid Search](#retrieval)**<br/>*Combine semantic & full-text signals*|**[Embedding Caching](#embedding-caching)**<br/>*Cache embeddings for efficiency*|**[Rerankers](#rerankers)**<br/>*Improve search result relevancy*|
38
-
|||**[MCP Server](#mcp-server)**<br/>*Expose an existing Redis index to MCP clients*|
38
+
|||**[MCP Server](#mcp-server)**<br/>*Expose one or more existing Redis indexes to MCP clients*|
39
39
40
40
</div>
41
41
@@ -51,7 +51,7 @@ Install `redisvl` into your Python (>=3.10) environment using `pip`:
51
51
pip install redisvl
52
52
```
53
53
54
-
Install the MCP server extra when you want to expose an existing Redis index through MCP:
54
+
Install the MCP server extra when you want to expose one or more existing Redis indexes through MCP:
55
55
56
56
```bash
57
57
pip install redisvl[mcp]
@@ -572,16 +572,18 @@ Use `--read-only` to expose search without upsert.
572
572
573
573
### MCP Server
574
574
575
-
RedisVL includes an MCP server that lets MCP-compatible clients search or upsert data in an existing Redis index through a small, stable tool contract.
575
+
RedisVL includes an MCP server that lets MCP-compatible clients search or upsert data in one or more existing Redis indexes through a small, stable tool contract.
576
576
577
577
The server:
578
578
579
-
- connects to one existing Redis Search index
580
-
- reconstructs the schema from Redis at startup
581
-
- uses the configured vectorizer for query embedding and optional upsert embedding
582
-
- exposes `search-records` and, unless read-only mode is enabled, `upsert-records`
579
+
- connects to one or more existing Redis Search indexes, each addressed by a logical id
580
+
- reconstructs each index's schema from Redis at startup
581
+
- uses each index's configured vectorizer for query embedding and optional upsert embedding
582
+
- exposes `list-indexes` for discovery, `search-records`, and (unless every index is read-only) `upsert-records`
583
583
- supports stdio (default), Streamable HTTP, and SSE transports
584
584
585
+
A single configured index is the simplest case and works exactly as before — callers omit the index selector. With multiple indexes, clients call `list-indexes` first and pass the chosen `index` to `search-records` and `upsert-records`.
Copy file name to clipboardExpand all lines: docs/concepts/mcp.md
+58-23Lines changed: 58 additions & 23 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,28 +7,30 @@ myst:
7
7
8
8
# RedisVL MCP
9
9
10
-
RedisVL includes an MCP server that exposes a Redis-backed retrieval surface through a small, deterministic tool contract. It is designed for AI applications that want to search or maintain data in an existing Redis index without each client reimplementing Redis query logic.
10
+
RedisVL includes an MCP server that exposes a Redis-backed retrieval surface through a small, deterministic tool contract. It is designed for AI applications that want to search or maintain data in one or more existing Redis indexes without each client reimplementing Redis query logic.
11
11
12
12
## What RedisVL MCP Does
13
13
14
14
The RedisVL MCP server sits between an MCP client and Redis:
15
15
16
-
1. It connects to an existing Redis Search index.
17
-
2. It inspects that index at startup and reconstructs its schema.
16
+
1. It connects to one or more existing Redis Search indexes.
17
+
2. It inspects each index at startup and reconstructs its schema.
18
18
3. It initializes vector capabilities only when the configured search or upsert behavior needs them.
19
-
4. It exposes stable MCP tools for search, and optionally upsert.
19
+
4. It exposes stable MCP tools for discovery, search, and optionally upsert.
20
20
21
-
This keeps the Redis index as the source of truth for search behavior while giving MCP clients a predictable interface.
21
+
This keeps each Redis index as the source of truth for its search behavior while giving MCP clients a predictable interface.
22
22
23
23
## How RedisVL MCP Runs
24
24
25
25
RedisVL MCP works with a focused model:
26
26
27
-
- One server process binds to exactly one existing Redis index.
27
+
- One server process binds to one *or several*existing Redis indexes, each addressed by a logical id.
28
28
- The server supports stdio (default), Streamable HTTP, and SSE transports.
29
-
- Search behavior is owned by configuration, not by MCP callers.
30
-
- Vector search and server-side embedding are optional capabilities configured explicitly.
31
-
- Upsert is optional and can be disabled with read-only mode.
29
+
- Search behavior is owned by per-index configuration, not by MCP callers.
30
+
- Vector search and server-side embedding are optional capabilities configured explicitly per index.
31
+
- Upsert is optional and can be disabled globally with read-only mode or per index with a `read_only` flag.
32
+
33
+
A single-index server remains the simplest deployment: when exactly one index is configured, callers can omit the index selector entirely and every tool call targets that index. Multi-index support is fully formal — it adds discovery and explicit routing without changing the single-index contract.
32
34
33
35
## Config-Owned Search Behavior
34
36
@@ -44,17 +46,30 @@ These request-time controls are still bounded by runtime config. In particular,
44
46
deep paging is limited by a configured maximum result window, enforced as
45
47
`offset + limit`.
46
48
47
-
MCP callers do not choose:
49
+
On a multi-index server, callers also choose **which index to target** through an optional `index` argument (see [Index Selection](#index-selection-and-discovery)). Callers do not choose:
48
50
49
-
- which index to target
50
51
- whether retrieval is `vector`, `fulltext`, or `hybrid`
51
52
- query tuning parameters such as hybrid fusion or vector runtime settings
52
53
53
-
That behavior lives in the server config under `indexes.<id>.search`. The response includes `search_type` as informational metadata, but it is not a request parameter.
54
+
That behavior lives in the per-index server config under `indexes.<id>.search`. The response includes `search_type` as informational metadata, but it is not a request parameter.
55
+
56
+
## Single and Multiple Index Bindings
57
+
58
+
The YAML config uses an `indexes` mapping. Each entry is a logical binding keyed by an id (for example `knowledge` or `tickets`) that points to an existing Redis index through `redis_name`. The mapping may contain one entry or several; each binding is inspected, validated, and given its own search config, runtime limits, and optional vectorizer independently at startup. Startup is all-or-nothing — if any binding fails to initialize, the server does not start.
59
+
60
+
A single-binding config is the simplest case and behaves exactly as before: the lone binding is the implicit target of every call. With multiple bindings the server stays a single process and endpoint, but callers select a binding per call.
61
+
62
+
## Index Selection and Discovery
63
+
64
+
On a multi-index server, every tool call must say which logical index it targets:
54
65
55
-
## Single Index Binding
66
+
-`search-records` and `upsert-records` accept an optional `index` argument naming the logical id.
67
+
- When exactly one index is configured, `index` may be omitted and resolves to that sole binding (backward compatible).
68
+
- When multiple indexes are configured, omitting `index` is an `invalid_request`; the caller must name one.
69
+
- An unknown logical id is an `invalid_request`.
70
+
- Both tools echo the resolved `index` in their response so clients can confirm routing.
56
71
57
-
The YAML config uses an `indexes`mapping with one configured entry. That binding points to an existing Redis index through `redis_name`, and every tool call targets that configured index.
72
+
Because a client cannot guess the configured logical ids, multi-index servers expose a `list-indexes`discovery tool. **Clients should call `list-indexes` first**to enumerate the available indexes and their filterable fields, then pass the chosen id as `index` on subsequent calls.
58
73
59
74
## Schema Inspection and Overrides
60
75
@@ -71,14 +86,16 @@ MCP-reserved score metadata field names for the configured search mode.
71
86
72
87
## Read-Only and Read-Write Modes
73
88
74
-
RedisVL MCP always registers `search-records`.
89
+
RedisVL MCP always registers `search-records` and `list-indexes`.
75
90
76
-
`upsert-records` is only registered when the server is not in read-only mode. Read-only mode is controlled by:
91
+
Write availability is enforced at two levels:
77
92
78
-
- the CLI flag `--read-only`
79
-
-or the environment variable `REDISVL_MCP_READ_ONLY=true`
93
+
-**Global read-only mode** disables writes across every binding. It is controlled by the CLI flag `--read-only` or the environment variable `REDISVL_MCP_READ_ONLY=true`.
94
+
-**Per-index read-only** disables writes for a single binding via `indexes.<id>.read_only: true`, while other bindings stay writable.
80
95
81
-
Use read-only mode when Redis is serving approved content to assistants and another system owns ingestion.
96
+
These combine into each binding's *effective* write availability: a binding is read-only if global read-only is on **or** that binding sets `read_only: true`. The `upsert-records` tool is registered only when at least one binding is writable, so a fully read-only server does not advertise it at all. When the tool is registered, a write to a read-only binding is rejected with `invalid_request` before any data is changed. `list-indexes` reports each binding's effective write availability as `upsert_available`.
97
+
98
+
Use read-only mode when Redis is serving approved content to assistants and another system owns ingestion — globally when no binding should accept writes, or per index when only some indexes are writable.
82
99
83
100
## Authentication and Authorization
84
101
@@ -88,18 +105,36 @@ For configuration and the gateway boundary, see {doc}`/user_guide/how_to_guides/
88
105
89
106
## Tool Surface
90
107
91
-
RedisVL MCP exposes two tools:
108
+
RedisVL MCP exposes up to three tools:
92
109
93
-
-`search-records` searches the configured index using the server-owned search mode
94
-
-`upsert-records` validates and upserts records, embedding them only when that capability is configured
110
+
-`list-indexes` enumerates the configured logical indexes for discovery (always available)
111
+
-`search-records` searches a selected index using that index's server-owned search mode
112
+
-`upsert-records` validates and upserts records into a selected writable index, embedding them only when that capability is configured
95
113
96
114
These tools follow a stable contract:
97
115
98
116
- request validation happens before query or write execution
117
+
- the resolved logical `index` is echoed in every `search-records` and `upsert-records` response
99
118
- filters support either raw strings or a RedisVL-backed JSON DSL
100
-
-`search-records` describes the inspected schema by advertising typed JSON DSL filter fields, object-filter `exists` support, and valid `return_fields`
119
+
-on a single-index server, `search-records` describes the inspected schema by advertising typed JSON DSL filter fields, object-filter `exists` support, and valid `return_fields`; on a multi-index server those hints are ambiguous, so the description instead directs clients to call `list-indexes` and pass `index`
101
120
- error codes are mapped into a stable set of MCP-facing categories
102
121
122
+
### `list-indexes`
123
+
124
+
`list-indexes` returns one entry per configured binding so clients can route subsequent calls. Each entry reports:
125
+
126
+
- the logical `id`
127
+
- an optional `description` (only when configured)
128
+
-`upsert_available`, reflecting the binding's effective write availability
129
+
-`fields`, the filterable fields discovered from the index
130
+
-`limits`, only the runtime limits that were explicitly configured
131
+
132
+
The discovery payload is deliberately minimal:
133
+
134
+
- the underlying Redis index name (`redis_name`) is **never** exposed
135
+
- the vector field and the configured embed-source text field are **omitted** from `fields`, since they are implementation inputs rather than fields a client filters on
136
+
-`limits` shows only explicitly set values (such as `max_limit` or `max_upsert_records`); defaults are not echoed
137
+
103
138
## Why Use MCP Instead of Direct RedisVL Calls
104
139
105
140
Use RedisVL MCP when you want a standard tool boundary for agent frameworks or assistants that already speak MCP.
0 commit comments