Skip to content

Commit fdb0a03

Browse files
phernandezclaude
andcommitted
feat: add optional api_url configuration for remote API connection
- Add api_url field to BasicMemoryConfig for connecting to remote Basic Memory APIs - Refactor async_client.py to conditionally create HTTP or ASGI transport based on config - Add logging for client creation (info for remote, debug for local) - Add basic test coverage for both local ASGI and remote HTTP client creation - When api_url is set, MCP tools will connect to remote API instead of local ASGI transport 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 6bfd4ae commit fdb0a03

3 files changed

Lines changed: 66 additions & 2 deletions

File tree

src/basic_memory/config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ class BasicMemoryConfig(BaseSettings):
7474
description="Whether to sync changes in real time. default (True)",
7575
)
7676

77+
# API connection configuration
78+
api_url: Optional[str] = Field(
79+
default=None,
80+
description="URL of remote Basic Memory API. If set, MCP will connect to this API instead of using local ASGI transport.",
81+
)
82+
7783
model_config = SettingsConfigDict(
7884
env_prefix="BASIC_MEMORY_",
7985
extra="ignore",
Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,29 @@
11
from httpx import ASGITransport, AsyncClient
2+
from loguru import logger
23

34
from basic_memory.api.app import app as fastapi_app
5+
from basic_memory.config import ConfigManager
46

5-
BASE_URL = "http://test"
7+
def create_client() -> AsyncClient:
8+
"""Create an HTTP client based on configuration.
9+
10+
Returns:
11+
AsyncClient configured for either local ASGI or remote HTTP transport
12+
"""
13+
config_manager = ConfigManager()
14+
config = config_manager.load_config()
15+
16+
if config.api_url:
17+
# Use HTTP transport for remote API
18+
logger.info(f"Creating HTTP client for remote Basic Memory API: {config.api_url}")
19+
return AsyncClient(base_url=config.api_url)
20+
else:
21+
# Use ASGI transport for local API
22+
logger.debug("Creating ASGI client for local Basic Memory API")
23+
return AsyncClient(
24+
transport=ASGITransport(app=fastapi_app),
25+
base_url="http://test"
26+
)
627

728
# Create shared async client
8-
client = AsyncClient(transport=ASGITransport(app=fastapi_app), base_url=BASE_URL)
29+
client = create_client()

tests/api/test_async_client.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Tests for async_client configuration."""
2+
3+
import pytest
4+
from unittest.mock import patch
5+
from httpx import AsyncClient, ASGITransport
6+
7+
from basic_memory.mcp.async_client import create_client
8+
from basic_memory.config import BasicMemoryConfig
9+
10+
11+
def test_create_client_uses_asgi_when_no_api_url():
12+
"""Test that create_client uses ASGI transport when api_url is None."""
13+
mock_config = BasicMemoryConfig(api_url=None)
14+
15+
with patch('basic_memory.mcp.async_client.ConfigManager') as mock_config_manager:
16+
mock_config_manager.return_value.load_config.return_value = mock_config
17+
18+
client = create_client()
19+
20+
assert isinstance(client, AsyncClient)
21+
assert isinstance(client._transport, ASGITransport)
22+
assert str(client.base_url) == "http://test"
23+
24+
25+
def test_create_client_uses_http_when_api_url_set():
26+
"""Test that create_client uses HTTP transport when api_url is configured."""
27+
remote_url = "https://api.basicmemory.example.com"
28+
mock_config = BasicMemoryConfig(api_url=remote_url)
29+
30+
with patch('basic_memory.mcp.async_client.ConfigManager') as mock_config_manager:
31+
mock_config_manager.return_value.load_config.return_value = mock_config
32+
33+
client = create_client()
34+
35+
assert isinstance(client, AsyncClient)
36+
assert not isinstance(client._transport, ASGITransport)
37+
assert str(client.base_url) == remote_url

0 commit comments

Comments
 (0)