fix(mcp): add back bank list and create_bank tools (#123)

* fix(mcp): add back bank list and create_bank tools

* fix tests

* fix tests
This commit is contained in:
Nicolò Boschi 2026-01-08 14:02:28 +01:00 committed by GitHub
parent c65c6a9dc0
commit 9fd567984c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 105 additions and 24 deletions

View file

@ -187,6 +187,60 @@ def create_mcp_server(memory: MemoryEngine) -> FastMCP:
logger.error(f"Error reflecting: {e}", exc_info=True)
return f'{{"error": "{e}", "text": ""}}'
@mcp.tool()
async def list_banks() -> str:
"""
List all available memory banks.
Use this tool to discover what memory banks exist in the system.
Each bank is an isolated memory store (like a separate "brain").
Returns:
JSON list of banks with their IDs, names, dispositions, and backgrounds.
"""
try:
banks = await memory.list_banks(request_context=RequestContext())
return json.dumps({"banks": banks}, indent=2)
except Exception as e:
logger.error(f"Error listing banks: {e}", exc_info=True)
return f'{{"error": "{e}", "banks": []}}'
@mcp.tool()
async def create_bank(bank_id: str, name: str | None = None, background: str | None = None) -> str:
"""
Create a new memory bank or get an existing one.
Memory banks are isolated stores - each one is like a separate "brain" for a user/agent.
Banks are auto-created with default settings if they don't exist.
Args:
bank_id: Unique identifier for the bank (e.g., 'user-123', 'agent-alpha')
name: Optional human-friendly name for the bank
background: Optional background context about the bank's owner/purpose
"""
try:
# get_bank_profile auto-creates bank if it doesn't exist
profile = await memory.get_bank_profile(bank_id, request_context=RequestContext())
# Update name/background if provided
if name is not None or background is not None:
await memory.update_bank(
bank_id,
name=name,
background=background,
request_context=RequestContext(),
)
# Fetch updated profile
profile = await memory.get_bank_profile(bank_id, request_context=RequestContext())
# Serialize disposition if it's a Pydantic model
if "disposition" in profile and hasattr(profile["disposition"], "model_dump"):
profile["disposition"] = profile["disposition"].model_dump()
return json.dumps(profile, indent=2)
except Exception as e:
logger.error(f"Error creating bank: {e}", exc_info=True)
return f'{{"error": "{e}"}}'
return mcp

View file

@ -9,6 +9,7 @@ def mock_memory():
"""Create a mock MemoryEngine."""
memory = MagicMock()
memory.retain_batch_async = AsyncMock()
memory.submit_async_retain = AsyncMock(return_value={"operation_id": "test-op-123"})
memory.recall_async = AsyncMock(return_value=MagicMock(results=[]))
return memory
@ -44,11 +45,11 @@ async def test_mcp_tools_use_context_bank_id(mock_memory):
assert "retain" in tools
assert "recall" in tools
# Test retain with bank_id from context
# Test retain with bank_id from context (use async_processing=False for synchronous test)
token = _current_bank_id.set("context-bank-id")
try:
retain_tool = tools["retain"]
result = await retain_tool.fn(content="test content", context="test_context")
result = await retain_tool.fn(content="test content", context="test_context", async_processing=False)
assert "successfully" in result.lower()
# Verify the memory was called with the context bank_id

View file

@ -137,42 +137,68 @@ hindsight.retain(
## Supported Languages
Hindsight supports any language that your configured LLM can understand. This typically includes:
**Hindsight's multilingual support depends entirely on your LLM's language capabilities.** Hindsight instructs the LLM to detect the input language and respond in that same language. If your LLM supports a language, Hindsight will work with it.
| Language | Script | Example |
|----------|--------|---------|
| Chinese (Simplified) | 简体中文 | 张伟是软件工程师 |
| Chinese (Traditional) | 繁體中文 | 張偉是軟體工程師 |
| Japanese | 日本語 | 田中さんはエンジニアです |
| Korean | 한국어 | 김철수는 개발자입니다 |
| Arabic | العربية | أحمد مهندس برمجيات |
| Russian | Русский | Иван - разработчик |
| Spanish | Español | María es ingeniera |
| French | Français | Pierre est développeur |
| German | Deutsch | Hans ist Entwickler |
| And many more... | | |
Most modern LLMs (GPT-4, Claude, Gemini, Llama 3, etc.) support dozens of languages including:
The actual language support depends on your LLM provider's capabilities.
- **East Asian**: Chinese (Simplified/Traditional), Japanese, Korean
- **European**: Spanish, French, German, Italian, Portuguese, Dutch, Polish, Russian
- **Middle Eastern**: Arabic, Hebrew, Turkish
- **South Asian**: Hindi, Bengali, Tamil
- **Southeast Asian**: Thai, Vietnamese, Indonesian
**To verify support for your target language**, test your LLM directly with content in that language. If the LLM can understand and generate text in the language, Hindsight will preserve it correctly.
---
## Best Practices
## Configuring for Multilingual Use
### 1. Keep Content in One Language Per Retain Call
While mixed content works, keeping each `retain` call in a single language produces more consistent results.
For optimal multilingual performance, you should configure all three components of the pipeline:
### 2. Query in the Same Language as Your Content
For best results, query using the same language as your stored content. Cross-language queries (e.g., English query for Chinese content) may work but results can vary.
### 1. LLM (Required)
Your LLM must support the target languages. Most modern LLMs do, but verify with your specific model.
### 3. Consider Embedding Model Language Support
The default embedding model (`BAAI/bge-small-en-v1.5`) is English-optimized. For better multilingual semantic search, consider using a multilingual embedding model:
### 2. Embedding Model (Recommended)
The default embedding model (`BAAI/bge-small-en-v1.5`) is **English-only**. For multilingual content, use a multilingual embedding model:
```bash
# In your .env file
HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-m3
```
The `bge-m3` model supports 100+ languages with better cross-lingual retrieval.
**Recommended multilingual embedding models:**
| Model | Languages | Notes |
|-------|-----------|-------|
| `BAAI/bge-m3` | 100+ | Best overall multilingual performance |
| `intfloat/multilingual-e5-large` | 100+ | Good alternative |
| `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2` | 50+ | Lighter weight |
### 3. Reranker Model (Recommended)
The default reranker (`cross-encoder/ms-marco-MiniLM-L-6-v2`) is **English-only**. For multilingual content, use a multilingual reranker:
```bash
# In your .env file
HINDSIGHT_API_RERANKER_LOCAL_MODEL=BAAI/bge-reranker-v2-m3
```
**Recommended multilingual reranker models:**
| Model | Languages | Notes |
|-------|-----------|-------|
| `BAAI/bge-reranker-v2-m3` | 100+ | Best multilingual reranking |
| `cross-encoder/mmarco-mMiniLMv2-L12-H384-v1` | 14 | Lighter alternative |
---
## Best Practices
### 1. Use Multilingual Models for Non-English Content
If you primarily work with non-English content, configure multilingual embedding and reranker models. English-only models will still store your content correctly, but semantic search quality will be degraded.
### 2. Keep Content in One Language Per Retain Call
While mixed content works, keeping each `retain` call in a single language produces more consistent results.
### 3. Query in the Same Language as Your Content
For best results, query using the same language as your stored content. Cross-language queries (e.g., English query for Chinese content) may work but results can vary depending on your embedding model.
---