Skip to content

Commit 89a30c8

Browse files
committed
refactor: remove workspace mode
1 parent 09a520e commit 89a30c8

11 files changed

Lines changed: 79 additions & 76 deletions

File tree

src/deepset_mcp/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
# SPDX-License-Identifier: Apache-2.0
44

55
from deepset_mcp.config import DEEPSET_DOCS_DEFAULT_SHARE_URL
6-
from deepset_mcp.server import configure_mcp_server
7-
from deepset_mcp.tool_models import WorkspaceMode
8-
from deepset_mcp.tool_registry import ALL_DEEPSET_TOOLS
6+
from deepset_mcp.mcp.server import configure_mcp_server
7+
from deepset_mcp.mcp.tool_models import WorkspaceMode
8+
from deepset_mcp.mcp.tool_registry import ALL_DEEPSET_TOOLS
99

1010
__all__ = ["configure_mcp_server", "WorkspaceMode", "ALL_DEEPSET_TOOLS", "DEEPSET_DOCS_DEFAULT_SHARE_URL"]

src/deepset_mcp/main.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
from mcp.server.fastmcp import FastMCP
1212

1313
from deepset_mcp.config import DEEPSET_DOCS_DEFAULT_SHARE_URL, DOCS_SEARCH_TOOL_NAME
14-
from deepset_mcp.server import configure_mcp_server
15-
from deepset_mcp.tool_models import WorkspaceMode
16-
from deepset_mcp.tool_registry import TOOL_REGISTRY
14+
from deepset_mcp.mcp.server import configure_mcp_server
15+
from deepset_mcp.mcp.tool_models import WorkspaceMode
16+
from deepset_mcp.mcp.tool_registry import TOOL_REGISTRY
1717

1818

1919
class TransportEnum(StrEnum):

src/deepset_mcp/mcp/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# SPDX-FileCopyrightText: 2025-present deepset GmbH <info@deepset.ai>
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
from .server import configure_mcp_server
6+
from .store import initialize_or_get_initialized_store
7+
from .tool_factory import build_tool
8+
from .tool_models import ToolConfig, WorkspaceMode
9+
10+
__all__ = ["configure_mcp_server", "build_tool", "ToolConfig", "WorkspaceMode", "initialize_or_get_initialized_store"]
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010

1111
from deepset_mcp.api.client import AsyncDeepsetClient
1212
from deepset_mcp.config import DEEPSET_DOCS_DEFAULT_SHARE_URL
13-
from deepset_mcp.store import initialize_store
14-
from deepset_mcp.tool_factory import register_tools
15-
from deepset_mcp.tool_models import DeepsetDocsConfig, WorkspaceMode
16-
from deepset_mcp.tool_registry import TOOL_REGISTRY
13+
from deepset_mcp.mcp.store import initialize_or_get_initialized_store
14+
from deepset_mcp.mcp.tool_factory import register_tools
15+
from deepset_mcp.mcp.tool_models import DeepsetDocsConfig, WorkspaceMode
16+
from deepset_mcp.mcp.tool_registry import TOOL_REGISTRY
1717

1818

1919
def configure_mcp_server(
@@ -73,7 +73,9 @@ def configure_mcp_server(
7373
docs_config = DeepsetDocsConfig(api_key=api_key_docs, workspace_name=workspace_name, pipeline_name=pipeline_name)
7474

7575
# Initialize the store before registering tools
76-
store = initialize_store(backend=object_store_backend, redis_url=object_store_redis_url, ttl=object_store_ttl)
76+
store = initialize_or_get_initialized_store(
77+
backend=object_store_backend, redis_url=object_store_redis_url, ttl=object_store_ttl
78+
)
7779

7880
register_tools(
7981
mcp_server_instance=mcp_server_instance,
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ def create_redis_backend(url: str) -> ObjectStoreBackend:
3030

3131

3232
@functools.lru_cache(maxsize=1)
33-
def initialize_store(
33+
def initialize_or_get_initialized_store(
3434
backend: str = "memory",
3535
redis_url: str | None = None,
3636
ttl: int = 600,
3737
) -> ObjectStore:
38-
"""Initialize the object store.
38+
"""Initializes the object store or gets an existing object store instance if it was initialized before.
3939
4040
:param backend: Backend type ('memory' or 'redis')
4141
:param redis_url: Redis connection URL (required if backend='redis')
Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@
1414

1515
from deepset_mcp.api.client import AsyncDeepsetClient
1616
from deepset_mcp.config import DEFAULT_CLIENT_HEADER, DOCS_SEARCH_TOOL_NAME
17+
from deepset_mcp.mcp.tool_models import DeepsetDocsConfig, MemoryType, ToolConfig, WorkspaceMode
18+
from deepset_mcp.mcp.tool_registry import TOOL_REGISTRY
1719
from deepset_mcp.tokonomics import (
1820
ObjectStore,
1921
RichExplorer,
2022
explorable,
2123
explorable_and_referenceable,
2224
referenceable,
2325
)
24-
from deepset_mcp.tool_models import DeepsetDocsConfig, MemoryType, ToolConfig, WorkspaceMode
25-
from deepset_mcp.tool_registry import TOOL_REGISTRY
2626

2727

2828
def apply_custom_args(base_func: Callable[..., Any], config: ToolConfig) -> Callable[..., Any]:
@@ -78,41 +78,35 @@ def remove_params_from_docstring(docstring: str | None, params_to_remove: set[st
7878

7979

8080
def apply_workspace(
81-
base_func: Callable[..., Any], config: ToolConfig, workspace_mode: WorkspaceMode, workspace: str | None = None
81+
base_func: Callable[..., Any], config: ToolConfig, workspace: str | None = None
8282
) -> Callable[..., Any]:
8383
"""
84-
Applies a deepset workspace to the function depending on the workspace mode and the ToolConfig.
84+
Applies a deepset workspace to the function depending on the ToolConfig.
8585
8686
Removes the workspace argument from the function's signature and docstring if applied.
8787
8888
:param base_func: The function to apply workspace to.
8989
:param config: The ToolConfig for the function.
90-
:param workspace_mode: The WorkspaceMode for the function.
91-
:param workspace: The workspace to use for static mode.
90+
:param workspace: The workspace to use.
9291
:returns: Function with workspace handling applied and updated signature/docstring.
9392
:raises ValueError: If workspace is required but not available.
9493
"""
95-
if not config.needs_workspace:
94+
if not config.needs_workspace or not workspace:
9695
return base_func
9796

98-
if workspace_mode == WorkspaceMode.STATIC:
99-
100-
@functools.wraps(base_func)
101-
async def workspace_wrapper(*args: Any, **kwargs: Any) -> Any:
102-
return await base_func(*args, workspace=workspace, **kwargs)
97+
@functools.wraps(base_func)
98+
async def workspace_wrapper(*args: Any, **kwargs: Any) -> Any:
99+
return await base_func(*args, workspace=workspace, **kwargs)
103100

104-
# Remove workspace from signature
105-
original_sig = inspect.signature(base_func)
106-
new_params = [p for name, p in original_sig.parameters.items() if name != "workspace"]
107-
workspace_wrapper.__signature__ = original_sig.replace(parameters=new_params) # type: ignore
101+
# Remove workspace from signature
102+
original_sig = inspect.signature(base_func)
103+
new_params = [p for name, p in original_sig.parameters.items() if name != "workspace"]
104+
workspace_wrapper.__signature__ = original_sig.replace(parameters=new_params) # type: ignore
108105

109-
# Remove workspace from docstring
110-
workspace_wrapper.__doc__ = remove_params_from_docstring(base_func.__doc__, {"workspace"})
106+
# Remove workspace from docstring
107+
workspace_wrapper.__doc__ = remove_params_from_docstring(base_func.__doc__, {"workspace"})
111108

112-
return workspace_wrapper
113-
else:
114-
# For dynamic mode, workspace is passed as parameter
115-
return base_func
109+
return workspace_wrapper
116110

117111

118112
def apply_memory(
@@ -226,7 +220,6 @@ async def client_wrapper_without_context(*args: Any, **kwargs: Any) -> Any:
226220
def build_tool(
227221
base_func: Callable[..., Any],
228222
config: ToolConfig,
229-
workspace_mode: WorkspaceMode,
230223
api_key: str | None = None,
231224
workspace: str | None = None,
232225
use_request_context: bool = True,
@@ -240,7 +233,6 @@ def build_tool(
240233
241234
:param base_func: The base tool function.
242235
:param config: Tool configuration specifying dependencies and custom arguments.
243-
:param workspace_mode: How the workspace should be handled.
244236
:param api_key: The deepset API key to use.
245237
:param workspace: The workspace to use when using a static workspace.
246238
:param use_request_context: Whether to collect the API key from the request context.
@@ -257,7 +249,7 @@ def build_tool(
257249
enhanced_func = apply_memory(enhanced_func, config, object_store)
258250

259251
# Apply workspace handling
260-
enhanced_func = apply_workspace(enhanced_func, config, workspace_mode, workspace)
252+
enhanced_func = apply_workspace(base_func=enhanced_func, config=config, workspace=workspace)
261253

262254
# Apply client injection (adds ctx parameter if needed)
263255
enhanced_func = apply_client(
@@ -360,7 +352,6 @@ def register_tools(
360352
enhanced_tool = build_tool(
361353
base_func=base_func,
362354
config=config,
363-
workspace_mode=workspace_mode,
364355
workspace=workspace,
365356
use_request_context=get_api_key_from_authorization_header,
366357
base_url=base_url,
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from deepset_mcp.api.client import AsyncDeepsetClient
99
from deepset_mcp.config import DEFAULT_CLIENT_HEADER, DOCS_SEARCH_TOOL_NAME
1010
from deepset_mcp.initialize_embedding_model import get_initialized_model
11-
from deepset_mcp.tool_models import DeepsetDocsConfig, MemoryType, ToolConfig
11+
from deepset_mcp.mcp.tool_models import DeepsetDocsConfig, MemoryType, ToolConfig
1212
from deepset_mcp.tools.custom_components import (
1313
get_latest_custom_component_installation_logs as get_latest_custom_component_installation_logs_tool,
1414
list_custom_component_installations as list_custom_component_installations_tool,

test/unit/test_server_base_url.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77
from unittest.mock import MagicMock, patch
88

9-
from deepset_mcp.server import configure_mcp_server
10-
from deepset_mcp.tool_models import WorkspaceMode
9+
from deepset_mcp.mcp.server import configure_mcp_server
10+
from deepset_mcp.mcp.tool_models import WorkspaceMode
1111

1212

1313
class TestConfigureMcpServerBaseUrl:
1414
"""Test the configure_mcp_server function with base_url parameter."""
1515

16-
@patch("deepset_mcp.server.register_tools")
16+
@patch("deepset_mcp.mcp.server.register_tools")
1717
def test_configure_mcp_server_passes_base_url(self, mock_register_tools: MagicMock) -> None:
1818
"""Test that configure_mcp_server passes base_url to register_tools."""
1919
mock_server = MagicMock()
@@ -33,7 +33,7 @@ def test_configure_mcp_server_passes_base_url(self, mock_register_tools: MagicMo
3333
call_args = mock_register_tools.call_args
3434
assert call_args[1]["base_url"] == custom_url
3535

36-
@patch("deepset_mcp.server.register_tools")
36+
@patch("deepset_mcp.mcp.server.register_tools")
3737
def test_configure_mcp_server_without_base_url(self, mock_register_tools: MagicMock) -> None:
3838
"""Test that configure_mcp_server works without base_url."""
3939
mock_server = MagicMock()

test/unit/test_store.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import pytest
88

9-
from deepset_mcp.store import create_redis_backend, initialize_store
9+
from deepset_mcp.mcp.store import create_redis_backend, initialize_or_get_initialized_store
1010
from deepset_mcp.tokonomics import InMemoryBackend, ObjectStore
1111

1212

@@ -15,15 +15,15 @@ class TestStoreInitialization:
1515

1616
def test_initialize_store_memory_backend(self) -> None:
1717
"""Test initializing store with memory backend."""
18-
store = initialize_store(backend="memory", ttl=1800)
18+
store = initialize_or_get_initialized_store(backend="memory", ttl=1800)
1919

2020
assert isinstance(store, ObjectStore)
2121
assert isinstance(store._backend, InMemoryBackend)
2222
assert store._ttl == 1800
2323

2424
def test_initialize_store_default_backend(self) -> None:
2525
"""Test initializing store with default backend."""
26-
store = initialize_store()
26+
store = initialize_or_get_initialized_store()
2727

2828
assert isinstance(store, ObjectStore)
2929
assert isinstance(store._backend, InMemoryBackend)
@@ -35,7 +35,7 @@ def test_initialize_store_redis_backend_success(self) -> None:
3535
mock_redis_client.ping.return_value = True
3636

3737
with patch("redis.from_url", return_value=mock_redis_client):
38-
store = initialize_store(backend="redis", redis_url="redis://localhost:6379", ttl=7200)
38+
store = initialize_or_get_initialized_store(backend="redis", redis_url="redis://localhost:6379", ttl=7200)
3939

4040
assert isinstance(store, ObjectStore)
4141
assert store._ttl == 7200
@@ -44,7 +44,7 @@ def test_initialize_store_redis_backend_success(self) -> None:
4444
def test_initialize_store_redis_backend_no_url(self) -> None:
4545
"""Test initializing store with Redis backend but no URL."""
4646
with pytest.raises(ValueError, match="redis_url.*is None"):
47-
initialize_store(backend="redis", redis_url=None)
47+
initialize_or_get_initialized_store(backend="redis", redis_url=None)
4848

4949
def test_initialize_store_redis_backend_connection_failure(self) -> None:
5050
"""Test initializing store with Redis backend connection failure."""
@@ -53,7 +53,7 @@ def test_initialize_store_redis_backend_connection_failure(self) -> None:
5353

5454
with patch("redis.from_url", return_value=mock_redis_client):
5555
with pytest.raises(Exception, match="Connection failed"):
56-
initialize_store(backend="redis", redis_url="redis://localhost:6379")
56+
initialize_or_get_initialized_store(backend="redis", redis_url="redis://localhost:6379")
5757

5858
def test_create_redis_backend_success(self) -> None:
5959
"""Test creating Redis backend successfully."""
@@ -85,21 +85,21 @@ def test_create_redis_backend_connection_failure(self) -> None:
8585
def test_initialize_store_caching(self) -> None:
8686
"""Test that initialize_store uses caching."""
8787
# Clear any existing cache
88-
initialize_store.cache_clear()
88+
initialize_or_get_initialized_store.cache_clear()
8989

90-
store1 = initialize_store(backend="memory", ttl=1800)
91-
store2 = initialize_store(backend="memory", ttl=1800)
90+
store1 = initialize_or_get_initialized_store(backend="memory", ttl=1800)
91+
store2 = initialize_or_get_initialized_store(backend="memory", ttl=1800)
9292

9393
# Should return the same instance due to caching
9494
assert store1 is store2
9595

9696
def test_initialize_store_different_params_different_instances(self) -> None:
9797
"""Test that different parameters create different instances."""
9898
# Clear any existing cache
99-
initialize_store.cache_clear()
99+
initialize_or_get_initialized_store.cache_clear()
100100

101-
store1 = initialize_store(backend="memory", ttl=1800)
102-
store2 = initialize_store(backend="memory", ttl=3600)
101+
store1 = initialize_or_get_initialized_store(backend="memory", ttl=1800)
102+
store2 = initialize_or_get_initialized_store(backend="memory", ttl=3600)
103103

104104
# Should return different instances due to different parameters
105105
assert store1 is not store2
@@ -108,7 +108,7 @@ def test_initialize_store_different_params_different_instances(self) -> None:
108108

109109
def test_initialize_store_unknown_backend(self) -> None:
110110
"""Test initializing store with unknown backend defaults to memory."""
111-
store = initialize_store(backend="unknown", ttl=1800)
111+
store = initialize_or_get_initialized_store(backend="unknown", ttl=1800)
112112

113113
assert isinstance(store, ObjectStore)
114114
assert isinstance(store._backend, InMemoryBackend)

0 commit comments

Comments
 (0)