{
  "id": "mcp",
  "title": "Run RedisVL MCP",
  "url": "https://redis.io/docs/latest/develop/ai/redisvl/user_guide/how_to_guides/mcp/",
  "summary": "",
  "tags": [],
  "last_updated": "2026-05-06T11:49:45+02:00",
  "page_type": "content",
  "content_hash": "70cb1f1514efe07d7d63645a5b8b0dfe35a53f43102aa43b08c4a6c590a9fca6",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "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.\n\nFor the higher-level design, see [RedisVL MCP](https://redis.io/docs/latest/../../concepts/mcp)."
    },
    {
      "id": "before-you-start",
      "title": "Before You Start",
      "role": "content",
      "text": "RedisVL MCP assumes all of the following are already true:\n\n- you have Python 3.10 or newer\n- you have Redis with Search capabilities available\n- the Redis index already exists\n- you know which text field and vector field the server should use\n- you have installed the vectorizer provider dependencies your config needs\n\nInstall the MCP extra:\n\n[code example]\n\nIf your vectorizer needs a provider extra, install that too:\n\n[code example]"
    },
    {
      "id": "start-the-server",
      "title": "Start the Server",
      "role": "content",
      "text": "Run the server over stdio (default):\n\n[code example]\n\nRun it over Streamable HTTP for remote MCP clients:\n\n[code example]\n\nRun it over SSE:\n\n[code example]\n\n#### WARNING\nStreamable 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.\n\nRun it in read-only mode to expose search without upsert:\n\n[code example]"
    },
    {
      "id": "cli-flags",
      "title": "CLI Flags",
      "role": "content",
      "text": "| Flag          | Default     | Purpose                                                   |\n|---------------|-------------|-----------------------------------------------------------|\n| `--config`    | —           | Path to the MCP YAML config (required)                    |\n| `--transport` | `stdio`     | Transport protocol: `stdio`, `sse`, or `streamable-http`  |\n| `--host`      | `127.0.0.1` | Bind address (only used with `sse` and `streamable-http`) |\n| `--port`      | `8000`      | Bind port (only used with `sse` and `streamable-http`)    |\n| `--read-only` | off         | Disable the `upsert-records` tool                         |"
    },
    {
      "id": "environment-variables",
      "title": "Environment Variables",
      "role": "content",
      "text": "You can also control boot settings through environment variables:\n\n| Variable                              | Purpose                                                                                                                           |\n|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|\n| `REDISVL_MCP_CONFIG`                  | Path to the MCP YAML config                                                                                                       |\n| `REDISVL_MCP_READ_ONLY`               | Disable `upsert-records` when set to `true`                                                                                       |\n| `REDISVL_MCP_TOOL_SEARCH_DESCRIPTION` | Set the base search tool description text; RedisVL still appends schema-derived typed filter, `exists`, and `return_fields` hints |\n| `REDISVL_MCP_TOOL_UPSERT_DESCRIPTION` | Override the upsert tool description                                                                                              |"
    },
    {
      "id": "connect-a-remote-mcp-client",
      "title": "Connect a Remote MCP Client",
      "role": "content",
      "text": "When using Streamable HTTP or SSE transport, point your MCP client at the server URL:\n\n- **Streamable HTTP**: `http://<host>:<port>/mcp`\n- **SSE**: `http://<host>:<port>/sse`\n\n**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.\n\nFor example, to configure a remote MCP client to connect to a Streamable HTTP server running on `192.168.1.10:8000`:\n\n[code example]"
    },
    {
      "id": "example-config",
      "title": "Example Config",
      "role": "example",
      "text": "This example binds one logical MCP server to one existing Redis index called `knowledge`.\n\nThe 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.\n\n[code example]"
    },
    {
      "id": "what-this-config-means",
      "title": "What This Config Means",
      "role": "content",
      "text": "- `redis_name` must point to an index that already exists in Redis\n- `search.type` fixes retrieval behavior for every MCP caller\n- `runtime.text_field_name` is required for `fulltext` and `hybrid` search\n- `runtime.vector_field_name` is required for `vector` and `hybrid` search, and optional for plain full-text deployments\n- `runtime.default_embed_text_field` is only required when the server should generate embeddings during upsert\n- `vectorizer` is required for query embedding and server-side embedding, but optional for fulltext-only configs\n- `runtime.max_result_window` caps deep paging by limiting the maximum `offset + limit`\n- `schema_overrides` is only for patching incomplete field attrs discovered from Redis"
    },
    {
      "id": "fulltext-only-config",
      "title": "Fulltext-Only Config",
      "role": "content",
      "text": "For a non-vector deployment, omit vector-only settings entirely:\n\n[code example]"
    },
    {
      "id": "tool-contracts",
      "title": "Tool Contracts",
      "role": "content",
      "text": "RedisVL MCP exposes a small, implementation-owned contract."
    },
    {
      "id": "search-records",
      "title": "`search-records`",
      "role": "content",
      "text": "Arguments:\n\n- `query`\n- `limit`\n- `offset`\n- `filter`\n- `return_fields`\n\nExample request payload:\n\n[code example]\n\nExample response payload:\n\n[code example]\n\nNotes:\n\n- `search_type` is response metadata, not a request argument\n- when `return_fields` is omitted, RedisVL MCP returns all non-vector fields\n- returning the configured vector field is rejected\n- `filter` accepts either a raw string or a JSON DSL object\n- the `search-records` tool description includes schema-derived hints for typed JSON DSL filter fields, object-filter `exists` support, and valid `return_fields`\n- `offset + limit` must stay within `runtime.max_result_window`\n- startup rejects schemas that use MCP-reserved score metadata field names:\n  `id`, `__key`, `key`, `score`, `vector_distance`, `__score`, `text_score`, `vector_similarity`, `hybrid_score`"
    },
    {
      "id": "upsert-records",
      "title": "`upsert-records`",
      "role": "content",
      "text": "Arguments:\n\n- `records`\n- `id_field`\n- `skip_embedding_if_present`\n\nExample request payload:\n\n[code example]\n\nExample response payload:\n\n[code example]\n\nNotes:\n\n- this tool is not registered in read-only mode\n- when server-side embedding is configured, records that need embedding must contain `runtime.default_embed_text_field`\n- when `skip_embedding_if_present` is `true`, records that already contain the configured vector field can skip re-embedding\n- when a vector field is configured but server-side embedding is disabled, callers must supply vectors explicitly"
    },
    {
      "id": "search-examples",
      "title": "Search Examples",
      "role": "content",
      "text": ""
    },
    {
      "id": "read-only-vector-search",
      "title": "Read-Only Vector Search",
      "role": "content",
      "text": "Use read-only mode when assistants should only retrieve data:\n\n[code example]\n\nWith a `search.type` of `vector`, callers send only the query, filters, pagination, and field projection:\n\n[code example]"
    },
    {
      "id": "raw-string-filter",
      "title": "Raw String Filter",
      "role": "content",
      "text": "Pass a raw Redis filter string through unchanged:\n\n[code example]"
    },
    {
      "id": "json-dsl-filter",
      "title": "JSON DSL Filter",
      "role": "content",
      "text": "The DSL supports logical operators and type-checked field operators:\n\n[code example]"
    },
    {
      "id": "pagination-and-field-projection",
      "title": "Pagination and Field Projection",
      "role": "content",
      "text": "[code example]"
    },
    {
      "id": "hybrid-search-with-schema-overrides",
      "title": "Hybrid Search With `schema_overrides`",
      "role": "content",
      "text": "Use `schema_overrides` when Redis inspection cannot recover complete vector attrs, then keep hybrid behavior in config:\n\n[code example]\n\nThe MCP caller still sends the same request shape:\n\n[code example]"
    },
    {
      "id": "upsert-examples",
      "title": "Upsert Examples",
      "role": "content",
      "text": ""
    },
    {
      "id": "auto-embed-new-records",
      "title": "Auto-Embed New Records",
      "role": "content",
      "text": "If a record does not include the configured vector field, RedisVL MCP embeds `runtime.default_embed_text_field` and writes the result:\n\n[code example]"
    },
    {
      "id": "update-existing-records-with-id-field",
      "title": "Update Existing Records With `id_field`",
      "role": "content",
      "text": "[code example]"
    },
    {
      "id": "control-re-embedding-with-skip-embedding-if-present",
      "title": "Control Re-Embedding With `skip_embedding_if_present`",
      "role": "content",
      "text": "[code example]\n\nSet `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`."
    },
    {
      "id": "plain-writes-without-embedding",
      "title": "Plain Writes Without Embedding",
      "role": "content",
      "text": "For fulltext-only indexes, `upsert-records` can write records without any vectorizer or vector field configuration:\n\n[code example]\n\nIf 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."
    },
    {
      "id": "troubleshooting",
      "title": "Troubleshooting",
      "role": "errors",
      "text": ""
    },
    {
      "id": "missing-mcp-dependencies",
      "title": "Missing MCP Dependencies",
      "role": "content",
      "text": "If `rvl mcp` reports missing optional dependencies, install the MCP extra:\n\n[code example]\n\nIf the configured vectorizer needs a provider SDK, install that provider extra too. Fulltext-only configs can omit the vectorizer entirely."
    },
    {
      "id": "configured-redis-index-does-not-exist",
      "title": "Configured Redis Index Does Not Exist",
      "role": "configuration",
      "text": "The server only binds to an existing index. Create the index first, then point `indexes.<id>.redis_name` at that index name."
    },
    {
      "id": "missing-required-environment-variables",
      "title": "Missing Required Environment Variables",
      "role": "content",
      "text": "YAML values support `${VAR}` and `${VAR:-default}` substitution. Missing required variables fail startup before the server registers tools."
    },
    {
      "id": "vectorizer-dimension-mismatch",
      "title": "Vectorizer Dimension Mismatch",
      "role": "content",
      "text": "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."
    },
    {
      "id": "hybrid-config-requires-native-runtime-support",
      "title": "Hybrid Config Requires Native Runtime Support",
      "role": "content",
      "text": "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."
    }
  ],
  "examples": [
    {
      "id": "before-you-start-ex0",
      "language": "bash",
      "code": "pip install redisvl[mcp]",
      "section_id": "before-you-start"
    },
    {
      "id": "before-you-start-ex1",
      "language": "bash",
      "code": "pip install redisvl[mcp,openai]",
      "section_id": "before-you-start"
    },
    {
      "id": "start-the-server-ex0",
      "language": "bash",
      "code": "uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml",
      "section_id": "start-the-server"
    },
    {
      "id": "start-the-server-ex1",
      "language": "bash",
      "code": "uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --transport streamable-http --host 0.0.0.0 --port 8000",
      "section_id": "start-the-server"
    },
    {
      "id": "start-the-server-ex2",
      "language": "bash",
      "code": "uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --transport sse --host 0.0.0.0 --port 9000",
      "section_id": "start-the-server"
    },
    {
      "id": "start-the-server-ex3",
      "language": "bash",
      "code": "uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --read-only",
      "section_id": "start-the-server"
    },
    {
      "id": "connect-a-remote-mcp-client-ex0",
      "language": "json",
      "code": "{\n  \"mcpServers\": {\n    \"redisvl\": {\n      \"url\": \"http://192.168.1.10:8000/mcp\",\n      \"transport\": \"streamable-http\"\n    }\n  }\n}",
      "section_id": "connect-a-remote-mcp-client"
    },
    {
      "id": "example-config-ex0",
      "language": "yaml",
      "code": "server:\n  redis_url: ${REDIS_URL}\n\nindexes:\n  knowledge:\n    redis_name: knowledge\n\n    vectorizer:\n      class: OpenAITextVectorizer\n      model: text-embedding-3-small\n      api_config:\n        api_key: ${OPENAI_API_KEY}\n\n    schema_overrides:\n      fields:\n        - name: embedding\n          type: vector\n          attrs:\n            dims: 1536\n            datatype: float32\n\n    search:\n      type: hybrid\n      params:\n        text_scorer: BM25STD\n        stopwords: english\n        vector_search_method: KNN\n        combination_method: LINEAR\n        linear_text_weight: 0.3\n\n    runtime:\n      text_field_name: content\n      vector_field_name: embedding\n      default_embed_text_field: content\n      default_limit: 10\n      max_limit: 25\n      max_result_window: 1000\n      max_upsert_records: 64\n      skip_embedding_if_present: true\n      startup_timeout_seconds: 30\n      request_timeout_seconds: 60\n      max_concurrency: 16",
      "section_id": "example-config"
    },
    {
      "id": "fulltext-only-config-ex0",
      "language": "yaml",
      "code": "server:\n  redis_url: ${REDIS_URL}\n\nindexes:\n  knowledge:\n    redis_name: knowledge\n\n    search:\n      type: fulltext\n      params:\n        text_scorer: BM25STD\n        stopwords: english\n\n    runtime:\n      text_field_name: content\n      default_limit: 10\n      max_limit: 25\n      max_result_window: 1000\n      max_upsert_records: 64\n      skip_embedding_if_present: true\n      startup_timeout_seconds: 30\n      request_timeout_seconds: 60\n      max_concurrency: 16",
      "section_id": "fulltext-only-config"
    },
    {
      "id": "search-records-ex0",
      "language": "json",
      "code": "{\n  \"query\": \"incident response runbook\",\n  \"limit\": 2,\n  \"offset\": 0,\n  \"filter\": {\n    \"and\": [\n      { \"field\": \"category\", \"op\": \"eq\", \"value\": \"operations\" },\n      { \"field\": \"rating\", \"op\": \"gte\", \"value\": 4 }\n    ]\n  },\n  \"return_fields\": [\"title\", \"content\", \"category\", \"rating\"]\n}",
      "section_id": "search-records"
    },
    {
      "id": "search-records-ex1",
      "language": "json",
      "code": "{\n  \"search_type\": \"hybrid\",\n  \"offset\": 0,\n  \"limit\": 2,\n  \"results\": [\n    {\n      \"id\": \"knowledge:runbook:eu-failover\",\n      \"score\": 0.82,\n      \"score_type\": \"hybrid_score\",\n      \"record\": {\n        \"title\": \"EU failover runbook\",\n        \"content\": \"Restore traffic after a regional failover.\",\n        \"category\": \"operations\",\n        \"rating\": 5\n      }\n    }\n  ]\n}",
      "section_id": "search-records"
    },
    {
      "id": "upsert-records-ex0",
      "language": "json",
      "code": "{\n  \"records\": [\n    {\n      \"doc_id\": \"doc-42\",\n      \"content\": \"Updated operational guidance for failover handling.\",\n      \"category\": \"operations\",\n      \"rating\": 5\n    }\n  ],\n  \"id_field\": \"doc_id\"\n}",
      "section_id": "upsert-records"
    },
    {
      "id": "upsert-records-ex1",
      "language": "json",
      "code": "{\n  \"status\": \"success\",\n  \"keys_upserted\": 1,\n  \"keys\": [\"knowledge:doc-42\"]\n}",
      "section_id": "upsert-records"
    },
    {
      "id": "read-only-vector-search-ex0",
      "language": "bash",
      "code": "uvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --read-only",
      "section_id": "read-only-vector-search"
    },
    {
      "id": "read-only-vector-search-ex1",
      "language": "json",
      "code": "{\n  \"query\": \"cache invalidation incident\",\n  \"limit\": 3,\n  \"return_fields\": [\"title\", \"content\", \"category\"]\n}",
      "section_id": "read-only-vector-search"
    },
    {
      "id": "raw-string-filter-ex0",
      "language": "json",
      "code": "{\n  \"query\": \"science\",\n  \"filter\": \"@category:{science}\",\n  \"return_fields\": [\"content\", \"category\"]\n}",
      "section_id": "raw-string-filter"
    },
    {
      "id": "json-dsl-filter-ex0",
      "language": "json",
      "code": "{\n  \"query\": \"science\",\n  \"filter\": {\n    \"and\": [\n      { \"field\": \"category\", \"op\": \"eq\", \"value\": \"science\" },\n      { \"field\": \"rating\", \"op\": \"gte\", \"value\": 4 }\n    ]\n  },\n  \"return_fields\": [\"content\", \"category\", \"rating\"]\n}",
      "section_id": "json-dsl-filter"
    },
    {
      "id": "pagination-and-field-projection-ex0",
      "language": "json",
      "code": "{\n  \"query\": \"science\",\n  \"limit\": 1,\n  \"offset\": 1,\n  \"return_fields\": [\"content\", \"category\"]\n}",
      "section_id": "pagination-and-field-projection"
    },
    {
      "id": "hybrid-search-with-schema-overrides-ex0",
      "language": "yaml",
      "code": "schema_overrides:\n  fields:\n    - name: embedding\n      type: vector\n      attrs:\n        algorithm: flat\n        dims: 1536\n        datatype: float32\n        distance_metric: cosine\n\nsearch:\n  type: hybrid\n  params:\n    text_scorer: BM25STD\n    stopwords: english\n    vector_search_method: KNN\n    combination_method: LINEAR\n    linear_text_weight: 0.3",
      "section_id": "hybrid-search-with-schema-overrides"
    },
    {
      "id": "hybrid-search-with-schema-overrides-ex1",
      "language": "json",
      "code": "{\n  \"query\": \"legacy cache invalidation flow\",\n  \"filter\": { \"field\": \"category\", \"op\": \"eq\", \"value\": \"release-notes\" },\n  \"return_fields\": [\"title\", \"content\", \"release_version\"]\n}",
      "section_id": "hybrid-search-with-schema-overrides"
    },
    {
      "id": "auto-embed-new-records-ex0",
      "language": "json",
      "code": "{\n  \"records\": [\n    {\n      \"content\": \"First upserted document\",\n      \"category\": \"science\",\n      \"rating\": 5\n    },\n    {\n      \"content\": \"Second upserted document\",\n      \"category\": \"health\",\n      \"rating\": 4\n    }\n  ]\n}",
      "section_id": "auto-embed-new-records"
    },
    {
      "id": "update-existing-records-with-id-field-ex0",
      "language": "json",
      "code": "{\n  \"records\": [\n    {\n      \"doc_id\": \"doc-1\",\n      \"content\": \"Updated content\",\n      \"category\": \"engineering\",\n      \"rating\": 5\n    }\n  ],\n  \"id_field\": \"doc_id\"\n}",
      "section_id": "update-existing-records-with-id-field"
    },
    {
      "id": "control-re-embedding-with-skip-embedding-if-present-ex0",
      "language": "json",
      "code": "{\n  \"records\": [\n    {\n      \"doc_id\": \"doc-2\",\n      \"content\": \"Existing content\",\n      \"category\": \"science\",\n      \"rating\": 4\n    }\n  ],\n  \"id_field\": \"doc_id\",\n  \"skip_embedding_if_present\": false\n}",
      "section_id": "control-re-embedding-with-skip-embedding-if-present"
    },
    {
      "id": "plain-writes-without-embedding-ex0",
      "language": "json",
      "code": "{\n  \"records\": [\n    {\n      \"content\": \"Updated FAQ entry\",\n      \"category\": \"support\",\n      \"rating\": 5\n    }\n  ]\n}",
      "section_id": "plain-writes-without-embedding"
    },
    {
      "id": "missing-mcp-dependencies-ex0",
      "language": "bash",
      "code": "pip install redisvl[mcp]",
      "section_id": "missing-mcp-dependencies"
    }
  ]
}
