Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ef28ac0
RAAE-1396: Create MCP framework for RedisVL
vishal-bala Mar 12, 2026
e267c8f
Ensure server shutdown disconnects
vishal-bala Mar 12, 2026
91709b2
Exclude MCP module from import sanity-check
vishal-bala Mar 12, 2026
41eb2fb
Ensure startup failures clean up server resources
vishal-bala Mar 12, 2026
24fec66
Clear index state after MCP server shutdown
vishal-bala Mar 12, 2026
f197652
Fix MCP vectorizer cleanup on shutdown failure
vishal-bala Mar 13, 2026
3040ef6
Merge branch 'main' into feat/RAAE-1396/mcp-framework
vishal-bala Mar 24, 2026
1242d7a
Update implementation based on plan
vishal-bala Mar 25, 2026
cb3c543
Add filter type-hints; allow float values in `Num`
vishal-bala Mar 25, 2026
7529d61
Implement MCP search-records tool
vishal-bala Mar 25, 2026
9bdbee3
Add Codex config files to .gitignore
vishal-bala Mar 25, 2026
708d284
Merge branch 'feat/RAAE-1395-redisvl-mcp' into feat/RAAE-1397/search-…
vishal-bala Mar 25, 2026
473614a
Adapt type-hints for Python 3.9
vishal-bala Mar 25, 2026
9db4c13
Configure search in config, tool just takes query
vishal-bala Mar 25, 2026
aa93dd2
Python 3.9 compat
vishal-bala Mar 25, 2026
d8f5e3d
Merge branch 'feat/RAAE-1396/mcp-framework' into feat/RAAE-1397/searc…
vishal-bala Mar 25, 2026
08ca214
Merge branch 'feat/RAAE-1395-redisvl-mcp' into feat/RAAE-1396/mcp-fra…
vishal-bala Mar 25, 2026
ac3cc90
Cache hybrid support checks and validate fallback search params
vishal-bala Mar 25, 2026
32f4a07
Classify malformed search results as internal errors
vishal-bala Mar 25, 2026
c7b2154
Fix native hybrid linear defaults for RRF
vishal-bala Mar 26, 2026
d29d307
feat(mcp): gate requests on server lifecycle
vishal-bala Apr 2, 2026
b16f33c
Merge remote-tracking branch 'origin/feat/RAAE-1396/mcp-framework' in…
vishal-bala Apr 2, 2026
2170d84
Merge branch 'feat/RAAE-1395-redisvl-mcp' into feat/RAAE-1397/search-…
vishal-bala Apr 8, 2026
078b779
fix(mcp): allow implicit linear hybrid weight
vishal-bala Apr 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ dmypy.json
# Cython debug symbols
cython_debug/

# Codex
.codex/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
Expand Down
1 change: 1 addition & 0 deletions docs/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ reranker
cache
message_history
router
cli
```

4 changes: 3 additions & 1 deletion docs/user_guide/cli.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"\n",
"Before running this notebook, be sure to\n",
"1. Have installed ``redisvl`` and have that environment active for this notebook.\n",
"2. Have a running Redis instance with Redis Search enabled"
"2. Have a running Redis instance with Redis Search enabled\n",
"\n",
"For complete command syntax and options, see the [CLI Reference](../api/cli.rst)."
]
},
{
Expand Down
6 changes: 6 additions & 0 deletions docs/user_guide/how_to_guides/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ How-to guides are **task-oriented** recipes that help you accomplish specific go
- [Choose a Storage Type](../05_hash_vs_json.ipynb) -- Hash vs JSON formats and nested data
:::

:::{grid-item-card} 💻 CLI Operations

- [Manage Indices with the CLI](../cli.ipynb) -- create, inspect, and delete indices from your terminal
:::

::::

## Quick Reference
Expand All @@ -53,6 +58,7 @@ How-to guides are **task-oriented** recipes that help you accomplish specific go
| Improve search accuracy | [Rerank Search Results](../06_rerankers.ipynb) |
| Optimize index performance | [Optimize Indexes with SVS-VAMANA](../09_svs_vamana.ipynb) |
| Decide on storage format | [Choose a Storage Type](../05_hash_vs_json.ipynb) |
| Manage indices from terminal | [Manage Indices with the CLI](../cli.ipynb) |

```{toctree}
:hidden:
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ dependencies = [
]

[project.optional-dependencies]
mcp = [
"fastmcp>=2.0.0 ; python_version >= '3.10'",
"pydantic-settings>=2.0",
]
mistralai = ["mistralai>=1.0.0"]
openai = ["openai>=1.1.0"]
nltk = ["nltk>=3.8.1,<4"]
Expand Down
7 changes: 0 additions & 7 deletions redisvl/cli/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,6 @@ def __init__(self):
parser = argparse.ArgumentParser(usage=self.usage)

parser.add_argument("command", help="Subcommand to run")
parser.add_argument(
"-f",
"--format",
help="Output format for info command",
type=str,
default="rounded_outline",
)
parser = add_index_parsing_options(parser)

args = parser.parse_args(sys.argv[2:])
Expand Down
9 changes: 2 additions & 7 deletions redisvl/cli/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from redisvl.index import SearchIndex
from redisvl.schema.schema import IndexSchema
from redisvl.utils.log import get_logger
from redisvl.utils.utils import lazy_import

logger = get_logger("[RedisVL]")

Expand Down Expand Up @@ -42,10 +41,6 @@ class Stats:

def __init__(self):
parser = argparse.ArgumentParser(usage=self.usage)

parser.add_argument(
"-f", "--format", help="Output format", type=str, default="rounded_outline"
)
parser = add_index_parsing_options(parser)
args = parser.parse_args(sys.argv[2:])
try:
Expand All @@ -61,7 +56,7 @@ def stats(self, args: Namespace):
rvl stats -i <index_name> | -s <schema_path>
"""
index = self._connect_to_index(args)
_display_stats(index.info(), output_format=args.format)
_display_stats(index.info())

def _connect_to_index(self, args: Namespace) -> SearchIndex:
# connect to redis
Expand All @@ -85,7 +80,7 @@ def _connect_to_index(self, args: Namespace) -> SearchIndex:
return index


def _display_stats(index_info, output_format="rounded_outline"):
def _display_stats(index_info):
# Extracting the statistics
stats_data = [(key, str(index_info.get(key))) for key in STATS_KEYS]

Expand Down
4 changes: 2 additions & 2 deletions redisvl/extensions/cache/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
"""

from collections.abc import Mapping
from typing import Any, Dict, Optional, Union
from typing import Any, Dict, Optional

from redis import Redis # For backwards compatibility in type checking
from redis.cluster import RedisCluster

from redisvl.redis.connection import RedisConnectionFactory
from redisvl.types import AsyncRedisClient, SyncRedisClient, SyncRedisCluster
from redisvl.types import AsyncRedisClient, SyncRedisClient


class BaseCache:
Expand Down
2 changes: 1 addition & 1 deletion redisvl/extensions/router/semantic.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pathlib import Path
from typing import Any, Dict, List, Mapping, Optional, Type, Union
from typing import Any, Dict, List, Optional, Type, Union

import redis.commands.search.reducers as reducers
import yaml
Expand Down
18 changes: 11 additions & 7 deletions redisvl/index/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,13 @@ def _validate_query(self, query: BaseQuery) -> None:
def _validate_hybrid_query(self, query: Any) -> None:
"""Validate that a hybrid query can be executed."""
try:
from redis.commands.search.hybrid_result import HybridResult
from redis.commands.search.hybrid_result import ( # noqa: F401
HybridResult as _HybridResult,
)

from redisvl.query.hybrid import HybridQuery

del _HybridResult # Only imported to check availability
except (ImportError, ModuleNotFoundError):
raise ImportError(_HYBRID_SEARCH_ERROR_MESSAGE)

Expand Down Expand Up @@ -894,14 +898,14 @@ def load(
batch_size=batch_size,
validate=self._validate_on_load,
)
except SchemaValidationError as e:
except SchemaValidationError:
# Log the detailed validation error with actionable information
logger.error("Data validation failed during load operation")
raise
except Exception as e:
except Exception as exc:
# Wrap other errors as general RedisVL errors
logger.exception("Error while loading data to Redis")
raise RedisVLError(f"Failed to load data: {str(e)}") from e
raise RedisVLError(f"Failed to load data: {str(exc)}") from exc

def fetch(self, id: str) -> Optional[Dict[str, Any]]:
"""Fetch an object from Redis by id.
Expand Down Expand Up @@ -1840,14 +1844,14 @@ def add_field(d):
batch_size=batch_size,
validate=self._validate_on_load,
)
except SchemaValidationError as e:
except SchemaValidationError:
# Log the detailed validation error with actionable information
logger.error("Data validation failed during load operation")
raise
except Exception as e:
except Exception as exc:
# Wrap other errors as general RedisVL errors
logger.exception("Error while loading data to Redis")
raise RedisVLError(f"Failed to load data: {str(e)}") from e
raise RedisVLError(f"Failed to load data: {str(exc)}") from exc

async def fetch(self, id: str) -> Optional[Dict[str, Any]]:
"""Asynchronously etch an object from Redis by id. The id is typically
Expand Down
13 changes: 1 addition & 12 deletions redisvl/index/storage.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
from collections.abc import Collection
from typing import (
Any,
Awaitable,
Callable,
Dict,
Iterable,
List,
Optional,
Tuple,
Union,
cast,
)
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union

from pydantic import BaseModel, ValidationError
from redis import __version__ as redis_version
Expand Down
14 changes: 14 additions & 0 deletions redisvl/mcp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from redisvl.mcp.config import MCPConfig, load_mcp_config
from redisvl.mcp.errors import MCPErrorCode, RedisVLMCPError, map_exception
from redisvl.mcp.server import RedisVLMCPServer
from redisvl.mcp.settings import MCPSettings

__all__ = [
"MCPConfig",
"MCPErrorCode",
"MCPSettings",
"RedisVLMCPError",
"RedisVLMCPServer",
"load_mcp_config",
"map_exception",
]
Loading
Loading