{
  "id": "mcp",
  "title": "Run RedisVL MCP",
  "url": "https://redis.io/docs/latest/develop/ai/redisvl/0.17.1/user_guide/how_to_guides/mcp/",
  "summary": "",
  "content": "\n\nThis 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).\n\n## Before You Start\n\nRedisVL 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```bash\npip install redisvl[mcp]\n```\n\nIf your vectorizer needs a provider extra, install that too:\n\n```bash\npip install redisvl[mcp,openai]\n```\n\n## Start the Server\n\nRun the server over stdio (default):\n\n```bash\nuvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml\n```\n\nRun it over Streamable HTTP for remote MCP clients:\n\n```bash\nuvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --transport streamable-http --host 0.0.0.0 --port 8000\n```\n\nRun it over SSE:\n\n```bash\nuvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --transport sse --host 0.0.0.0 --port 9000\n```\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```bash\nuvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --read-only\n```\n\n### CLI Flags\n\n| 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                         |\n\n### Environment Variables\n\nYou 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` | Override the search tool description        |\n| `REDISVL_MCP_TOOL_UPSERT_DESCRIPTION` | Override the upsert tool description        |\n\n## Connect a Remote MCP Client\n\nWhen using Streamable HTTP or SSE transport, point your MCP client at the server URL:\n\n- **Streamable HTTP**: `http://\u003chost\u003e:\u003cport\u003e/mcp`\n- **SSE**: `http://\u003chost\u003e:\u003cport\u003e/sse`\n\n**Note:** `\u003chost\u003e` 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```json\n{\n  \"mcpServers\": {\n    \"redisvl\": {\n      \"url\": \"http://192.168.1.10:8000/mcp\",\n      \"transport\": \"streamable-http\"\n    }\n  }\n}\n```\n\n## Example Config\n\nThis 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```yaml\nserver:\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\n```\n\n### What This Config Means\n\n- `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` tells full-text and hybrid search which field to search\n- `runtime.vector_field_name` tells the server which vector field to use\n- `runtime.default_embed_text_field` tells upsert which text field to embed when a record needs embedding\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\n\n## Tool Contracts\n\nRedisVL MCP exposes a small, implementation-owned contract.\n\n### `search-records`\n\nArguments:\n\n- `query`\n- `limit`\n- `offset`\n- `filter`\n- `return_fields`\n\nExample request payload:\n\n```json\n{\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}\n```\n\nExample response payload:\n\n```json\n{\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}\n```\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- `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`\n\n### `upsert-records`\n\nArguments:\n\n- `records`\n- `id_field`\n- `skip_embedding_if_present`\n\nExample request payload:\n\n```json\n{\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}\n```\n\nExample response payload:\n\n```json\n{\n  \"status\": \"success\",\n  \"keys_upserted\": 1,\n  \"keys\": [\"knowledge:doc-42\"]\n}\n```\n\nNotes:\n\n- this tool is not registered in read-only mode\n- records that need embedding must contain `runtime.default_embed_text_field`\n- when `skip_embedding_if_present` is `true`, records that already contain the vector field can skip re-embedding\n\n## Search Examples\n\n### Read-Only Vector Search\n\nUse read-only mode when assistants should only retrieve data:\n\n```bash\nuvx --from redisvl[mcp] rvl mcp --config /path/to/mcp.yaml --read-only\n```\n\nWith a `search.type` of `vector`, callers send only the query, filters, pagination, and field projection:\n\n```json\n{\n  \"query\": \"cache invalidation incident\",\n  \"limit\": 3,\n  \"return_fields\": [\"title\", \"content\", \"category\"]\n}\n```\n\n### Raw String Filter\n\nPass a raw Redis filter string through unchanged:\n\n```json\n{\n  \"query\": \"science\",\n  \"filter\": \"@category:{science}\",\n  \"return_fields\": [\"content\", \"category\"]\n}\n```\n\n### JSON DSL Filter\n\nThe DSL supports logical operators and type-checked field operators:\n\n```json\n{\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}\n```\n\n### Pagination and Field Projection\n\n```json\n{\n  \"query\": \"science\",\n  \"limit\": 1,\n  \"offset\": 1,\n  \"return_fields\": [\"content\", \"category\"]\n}\n```\n\n### Hybrid Search With `schema_overrides`\n\nUse `schema_overrides` when Redis inspection cannot recover complete vector attrs, then keep hybrid behavior in config:\n\n```yaml\nschema_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\n```\n\nThe MCP caller still sends the same request shape:\n\n```json\n{\n  \"query\": \"legacy cache invalidation flow\",\n  \"filter\": { \"field\": \"category\", \"op\": \"eq\", \"value\": \"release-notes\" },\n  \"return_fields\": [\"title\", \"content\", \"release_version\"]\n}\n```\n\n## Upsert Examples\n\n### Auto-Embed New Records\n\nIf a record does not include the configured vector field, RedisVL MCP embeds `runtime.default_embed_text_field` and writes the result:\n\n```json\n{\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}\n```\n\n### Update Existing Records With `id_field`\n\n```json\n{\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}\n```\n\n### Control Re-Embedding With `skip_embedding_if_present`\n\n```json\n{\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}\n```\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`.\n\n## Troubleshooting\n\n### Missing MCP Dependencies\n\nIf `rvl mcp` reports missing optional dependencies, install the MCP extra:\n\n```bash\npip install redisvl[mcp]\n```\n\nIf the configured vectorizer needs a provider SDK, install that provider extra too.\n\n### Unsupported Python Runtime\n\nRedisVL MCP requires Python 3.10 or newer even though the core package supports Python 3.9. Use a newer interpreter for the MCP server process.\n\n### Configured Redis Index Does Not Exist\n\nThe server only binds to an existing index. Create the index first, then point `indexes.\u003cid\u003e.redis_name` at that index name.\n\n### Missing Required Environment Variables\n\nYAML values support `${VAR}` and `${VAR:-default}` substitution. Missing required variables fail startup before the server registers tools.\n\n### Vectorizer Dimension Mismatch\n\nIf 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.\n\n### Hybrid Config Requires Native Runtime Support\n\nSome 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.\n",
  "tags": [],
  "last_updated": "2026-05-06T11:49:45+02:00"
}
