Run RedisVL MCP
This guide shows how to run the RedisVL MCP server against an existing Redis index, configure its behavior, and use the MCP tools it exposes.
For the higher-level design, see RedisVL MCP.
Before You Start
RedisVL MCP assumes all of the following are already true:
- you have Python 3.10 or newer
- you have Redis with Search capabilities available
- the Redis index already exists
- you know which text field and vector field the server should use
- you have installed the vectorizer provider dependencies your config needs
Install the MCP extra:
pip install redisvl[mcp]
If your vectorizer needs a provider extra, install that too:
pip install redisvl[mcp,openai]
Start the Server
Run the server over stdio (default):
uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml
Run it over Streamable HTTP for remote MCP clients:
uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --transport streamable-http --host 0.0.0.0 --port 8000
Run it over SSE:
uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --transport sse --host 0.0.0.0 --port 9000
WARNING
Streamable HTTP and SSE endpoints are unauthenticated by default. Only bind to public interfaces (--host 0.0.0.0) on trusted networks or behind an authenticating reverse proxy. When not using --read-only, the upsert-records tool is also exposed to any client that can reach the server.
Run it in read-only mode to expose search without upsert:
uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --read-only
CLI Flags
| Flag | Default | Purpose |
|---|---|---|
--config |
— | Path to the MCP YAML config (required) |
--transport |
stdio |
Transport protocol: stdio, sse, or streamable-http |
--host |
127.0.0.1 |
Bind address (only used with sse and streamable-http) |
--port |
8000 |
Bind port (only used with sse and streamable-http) |
--read-only |
off | Disable the upsert-records tool |
Environment Variables
You can also control boot settings through environment variables:
| Variable | Purpose |
|---|---|
REDISVL_MCP_CONFIG |
Path to the MCP YAML config |
REDISVL_MCP_READ_ONLY |
Disable upsert-records when set to true |
REDISVL_MCP_TOOL_SEARCH_DESCRIPTION |
Set the base search tool description text; RedisVL still appends schema-derived typed filter, exists, and return_fields hints |
REDISVL_MCP_TOOL_UPSERT_DESCRIPTION |
Override the upsert tool description |
Connect a Remote MCP Client
When using Streamable HTTP or SSE transport, point your MCP client at the server URL:
- Streamable HTTP:
http://<host>:<port>/mcp - SSE:
http://<host>:<port>/sse
Note: <host> here is the bind address the server was started with. The default 127.0.0.1 only accepts connections from the same machine. To allow connections from other machines, start the server with --host 0.0.0.0 and use the machine’s actual IP or hostname in the client URL.
For example, to configure a remote MCP client to connect to a Streamable HTTP server running on 192.168.1.10:8000:
{
"mcpServers": {
"redisvl": {
"url": "http://192.168.1.10:8000/mcp",
"transport": "streamable-http"
}
}
}
Example Config
This example binds one logical MCP server to one existing Redis index called knowledge.
The config uses ${REDIS_URL} and ${OPENAI_API_KEY} as environment-variable placeholders. These values are resolved when the server starts. You can also use ${VAR:-default} to provide a fallback value.
server:
redis_url: ${REDIS_URL}
indexes:
knowledge:
redis_name: knowledge
vectorizer:
class: OpenAITextVectorizer
model: text-embedding-3-small
api_config:
api_key: ${OPENAI_API_KEY}
schema_overrides:
fields:
- name: embedding
type: vector
attrs:
dims: 1536
datatype: float32
search:
type: hybrid
params:
text_scorer: BM25STD
stopwords: english
vector_search_method: KNN
combination_method: LINEAR
linear_text_weight: 0.3
runtime:
text_field_name: content
vector_field_name: embedding
default_embed_text_field: content
default_limit: 10
max_limit: 25
max_result_window: 1000
max_upsert_records: 64
skip_embedding_if_present: true
startup_timeout_seconds: 30
request_timeout_seconds: 60
max_concurrency: 16
What This Config Means
redis_namemust point to an index that already exists in Redissearch.typefixes retrieval behavior for every MCP callerruntime.text_field_nameis required forfulltextandhybridsearchruntime.vector_field_nameis required forvectorandhybridsearch, and optional for plain full-text deploymentsruntime.default_embed_text_fieldis only required when the server should generate embeddings during upsertvectorizeris required for query embedding and server-side embedding, but optional for fulltext-only configsruntime.max_result_windowcaps deep paging by limiting the maximumoffset + limitschema_overridesis only for patching incomplete field attrs discovered from Redis
Fulltext-Only Config
For a non-vector deployment, omit vector-only settings entirely:
server:
redis_url: ${REDIS_URL}
indexes:
knowledge:
redis_name: knowledge
search:
type: fulltext
params:
text_scorer: BM25STD
stopwords: english
runtime:
text_field_name: content
default_limit: 10
max_limit: 25
max_result_window: 1000
max_upsert_records: 64
skip_embedding_if_present: true
startup_timeout_seconds: 30
request_timeout_seconds: 60
max_concurrency: 16
Tool Contracts
RedisVL MCP exposes a small, implementation-owned contract.
search-records
Arguments:
querylimitoffsetfilterreturn_fields
Example request payload:
{
"query": "incident response runbook",
"limit": 2,
"offset": 0,
"filter": {
"and": [
{ "field": "category", "op": "eq", "value": "operations" },
{ "field": "rating", "op": "gte", "value": 4 }
]
},
"return_fields": ["title", "content", "category", "rating"]
}
Example response payload:
{
"search_type": "hybrid",
"offset": 0,
"limit": 2,
"results": [
{
"id": "knowledge:runbook:eu-failover",
"score": 0.82,
"score_type": "hybrid_score",
"record": {
"title": "EU failover runbook",
"content": "Restore traffic after a regional failover.",
"category": "operations",
"rating": 5
}
}
]
}
Notes:
search_typeis response metadata, not a request argument- when
return_fieldsis omitted, RedisVL MCP returns all non-vector fields - returning the configured vector field is rejected
filteraccepts either a raw string or a JSON DSL object- the
search-recordstool description includes schema-derived hints for typed JSON DSL filter fields, object-filterexistssupport, and validreturn_fields offset + limitmust stay withinruntime.max_result_window- startup rejects schemas that use MCP-reserved score metadata field names:
id,__key,key,score,vector_distance,__score,text_score,vector_similarity,hybrid_score
upsert-records
Arguments:
recordsid_fieldskip_embedding_if_present
Example request payload:
{
"records": [
{
"doc_id": "doc-42",
"content": "Updated operational guidance for failover handling.",
"category": "operations",
"rating": 5
}
],
"id_field": "doc_id"
}
Example response payload:
{
"status": "success",
"keys_upserted": 1,
"keys": ["knowledge:doc-42"]
}
Notes:
- this tool is not registered in read-only mode
- when server-side embedding is configured, records that need embedding must contain
runtime.default_embed_text_field - when
skip_embedding_if_presentistrue, records that already contain the configured vector field can skip re-embedding - when a vector field is configured but server-side embedding is disabled, callers must supply vectors explicitly
Search Examples
Read-Only Vector Search
Use read-only mode when assistants should only retrieve data:
uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --read-only
With a search.type of vector, callers send only the query, filters, pagination, and field projection:
{
"query": "cache invalidation incident",
"limit": 3,
"return_fields": ["title", "content", "category"]
}
Raw String Filter
Pass a raw Redis filter string through unchanged:
{
"query": "science",
"filter": "@category:{science}",
"return_fields": ["content", "category"]
}
JSON DSL Filter
The DSL supports logical operators and type-checked field operators:
{
"query": "science",
"filter": {
"and": [
{ "field": "category", "op": "eq", "value": "science" },
{ "field": "rating", "op": "gte", "value": 4 }
]
},
"return_fields": ["content", "category", "rating"]
}
Pagination and Field Projection
{
"query": "science",
"limit": 1,
"offset": 1,
"return_fields": ["content", "category"]
}
Hybrid Search With schema_overrides
Use schema_overrides when Redis inspection cannot recover complete vector attrs, then keep hybrid behavior in config:
schema_overrides:
fields:
- name: embedding
type: vector
attrs:
algorithm: flat
dims: 1536
datatype: float32
distance_metric: cosine
search:
type: hybrid
params:
text_scorer: BM25STD
stopwords: english
vector_search_method: KNN
combination_method: LINEAR
linear_text_weight: 0.3
The MCP caller still sends the same request shape:
{
"query": "legacy cache invalidation flow",
"filter": { "field": "category", "op": "eq", "value": "release-notes" },
"return_fields": ["title", "content", "release_version"]
}
Upsert Examples
Auto-Embed New Records
If a record does not include the configured vector field, RedisVL MCP embeds runtime.default_embed_text_field and writes the result:
{
"records": [
{
"content": "First upserted document",
"category": "science",
"rating": 5
},
{
"content": "Second upserted document",
"category": "health",
"rating": 4
}
]
}
Update Existing Records With id_field
{
"records": [
{
"doc_id": "doc-1",
"content": "Updated content",
"category": "engineering",
"rating": 5
}
],
"id_field": "doc_id"
}
Control Re-Embedding With skip_embedding_if_present
{
"records": [
{
"doc_id": "doc-2",
"content": "Existing content",
"category": "science",
"rating": 4
}
],
"id_field": "doc_id",
"skip_embedding_if_present": false
}
Set skip_embedding_if_present to false when you want the server to regenerate embeddings during upsert. In most cases, the caller should omit the vector field and let the server manage embeddings from runtime.default_embed_text_field.
Plain Writes Without Embedding
For fulltext-only indexes, upsert-records can write records without any vectorizer or vector field configuration:
{
"records": [
{
"content": "Updated FAQ entry",
"category": "support",
"rating": 5
}
]
}
If you configure a vector field but omit server-side embedding support, the caller must send vectors in each record instead of relying on the server to generate them.
Troubleshooting
Missing MCP Dependencies
If rvl mcp reports missing optional dependencies, install the MCP extra:
pip install redisvl[mcp]
If the configured vectorizer needs a provider SDK, install that provider extra too. Fulltext-only configs can omit the vectorizer entirely.
Configured Redis Index Does Not Exist
The server only binds to an existing index. Create the index first, then point indexes.<id>.redis_name at that index name.
Missing Required Environment Variables
YAML values support ${VAR} and ${VAR:-default} substitution. Missing required variables fail startup before the server registers tools.
Vectorizer Dimension Mismatch
If the vectorizer dims do not match the configured vector field dims, startup fails. Make sure the embedding model and the effective vector field dimensions are aligned.
Hybrid Config Requires Native Runtime Support
Some hybrid params depend on native hybrid support in Redis and redis-py. If your environment does not support that path, remove native-only params such as knn_ef_runtime or upgrade Redis and redis-py.