deepset-mcp 0.0.4__py3-none-any.whl → 0.0.5rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- deepset_mcp/__init__.py +5 -5
- deepset_mcp/api/transport.py +5 -2
- deepset_mcp/config.py +9 -1
- deepset_mcp/main.py +186 -169
- deepset_mcp/py.typed +0 -0
- deepset_mcp/server.py +154 -0
- deepset_mcp/store.py +51 -2
- deepset_mcp/tool_factory.py +301 -428
- deepset_mcp/tool_models.py +42 -0
- deepset_mcp/tool_registry.py +208 -0
- deepset_mcp/tools/object_store.py +49 -0
- deepset_mcp/tools/tokonomics/__init__.py +2 -61
- deepset_mcp/tools/tokonomics/decorators.py +60 -87
- deepset_mcp/tools/tokonomics/explorer.py +32 -17
- deepset_mcp/tools/tokonomics/object_store.py +116 -139
- {deepset_mcp-0.0.4.dist-info → deepset_mcp-0.0.5rc1.dist-info}/METADATA +59 -13
- {deepset_mcp-0.0.4.dist-info → deepset_mcp-0.0.5rc1.dist-info}/RECORD +20 -15
- deepset_mcp-0.0.5rc1.dist-info/entry_points.txt +2 -0
- deepset_mcp-0.0.4.dist-info/entry_points.txt +0 -2
- {deepset_mcp-0.0.4.dist-info → deepset_mcp-0.0.5rc1.dist-info}/WHEEL +0 -0
- {deepset_mcp-0.0.4.dist-info → deepset_mcp-0.0.5rc1.dist-info}/licenses/LICENSE +0 -0
|
@@ -18,7 +18,7 @@ from glom import GlomError, Path, T, glom
|
|
|
18
18
|
from rich.console import Console
|
|
19
19
|
from rich.pretty import Pretty
|
|
20
20
|
|
|
21
|
-
from .object_store import
|
|
21
|
+
from deepset_mcp.tools.tokonomics.object_store import ObjectStore
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class RichExplorer:
|
|
@@ -58,11 +58,26 @@ class RichExplorer:
|
|
|
58
58
|
# Validation pattern for allowed attributes
|
|
59
59
|
self.allowed_attr_regex = re.compile(r"[A-Za-z][A-Za-z0-9_]*\Z")
|
|
60
60
|
|
|
61
|
+
def parse_reference(self, ref_str: str) -> tuple[str, str]:
|
|
62
|
+
"""Parse @obj_id.path into (obj_id, path).
|
|
63
|
+
|
|
64
|
+
:param ref_str: Reference string like @obj_id.path or obj_id
|
|
65
|
+
:return: Tuple of (obj_id, path)
|
|
66
|
+
"""
|
|
67
|
+
if not ref_str.startswith("@"):
|
|
68
|
+
return ref_str, "" # Not a reference, return as-is
|
|
69
|
+
|
|
70
|
+
ref_str = ref_str[1:] # Remove @
|
|
71
|
+
if "." in ref_str:
|
|
72
|
+
obj_id, path = ref_str.split(".", 1)
|
|
73
|
+
return obj_id, path
|
|
74
|
+
return ref_str, ""
|
|
75
|
+
|
|
61
76
|
def explore(self, obj_id: str, path: str = "") -> str:
|
|
62
77
|
"""Return a string preview of the requested object.
|
|
63
78
|
|
|
64
79
|
:param obj_id: Identifier obtained from the store.
|
|
65
|
-
:param path: Navigation path using ``.`` or ``[...]`` notation (e.g. ``@
|
|
80
|
+
:param path: Navigation path using ``.`` or ``[...]`` notation (e.g. ``@obj_id.path.to.attribute``).
|
|
66
81
|
:return: String representation of the object.
|
|
67
82
|
"""
|
|
68
83
|
obj = self._get_object_at_path(obj_id, path)
|
|
@@ -76,7 +91,7 @@ class RichExplorer:
|
|
|
76
91
|
else:
|
|
77
92
|
body = self._get_pretty_repr(obj)
|
|
78
93
|
|
|
79
|
-
return f"{header}\n\n
|
|
94
|
+
return f"{header}\n\n" + body
|
|
80
95
|
|
|
81
96
|
def search(self, obj_id: str, pattern: str, path: str = "", case_sensitive: bool = False) -> str:
|
|
82
97
|
"""Search for a pattern within a string object.
|
|
@@ -147,21 +162,21 @@ class RichExplorer:
|
|
|
147
162
|
|
|
148
163
|
# Handle string slicing
|
|
149
164
|
if isinstance(obj, str):
|
|
150
|
-
|
|
165
|
+
sliced_str: str = obj[start:end]
|
|
151
166
|
actual_end = end if end is not None else len(obj)
|
|
152
|
-
body = f"String slice [{start}:{actual_end}] of length {len(
|
|
153
|
-
return f"{header}\n\n
|
|
167
|
+
body = f"String slice [{start}:{actual_end}] of length {len(sliced_str)}:\n\n{sliced_str}"
|
|
168
|
+
return f"{header}\n\n" + body
|
|
154
169
|
|
|
155
170
|
# Handle list/tuple slicing
|
|
156
171
|
elif isinstance(obj, list | tuple):
|
|
157
|
-
|
|
172
|
+
sliced_list = obj[start:end]
|
|
158
173
|
actual_end = end if end is not None else len(obj)
|
|
159
174
|
|
|
160
175
|
# Use Pretty to render the sliced list with current settings
|
|
161
176
|
with self.console.capture() as cap:
|
|
162
177
|
self.console.print(
|
|
163
178
|
Pretty(
|
|
164
|
-
|
|
179
|
+
sliced_list,
|
|
165
180
|
max_depth=self.max_depth,
|
|
166
181
|
max_length=None, # Show all items in the slice
|
|
167
182
|
max_string=self.max_string_length,
|
|
@@ -172,10 +187,10 @@ class RichExplorer:
|
|
|
172
187
|
type_name = type(obj).__name__
|
|
173
188
|
body = (
|
|
174
189
|
f"{type_name.capitalize()} slice [{start}:{actual_end}] "
|
|
175
|
-
f"(showing {len(
|
|
190
|
+
f"(showing {len(sliced_list)} of {len(obj)} items):\n\n"
|
|
176
191
|
f"{cap.get().rstrip()}"
|
|
177
192
|
)
|
|
178
|
-
return f"{header}\n\n
|
|
193
|
+
return f"{header}\n\n" + body
|
|
179
194
|
|
|
180
195
|
else:
|
|
181
196
|
return f"{header}\n\nObject of type {type(obj).__name__} does not support slicing"
|
|
@@ -187,12 +202,11 @@ class RichExplorer:
|
|
|
187
202
|
:param path: Navigation path (optional).
|
|
188
203
|
:return: Object at path or error string.
|
|
189
204
|
"""
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
resolved_obj_id = ref.obj_id
|
|
205
|
+
resolved_obj_id, ref_path = self.parse_reference(obj_id)
|
|
206
|
+
|
|
207
|
+
# If there's a path from the reference, combine it with the provided path
|
|
208
|
+
if ref_path:
|
|
209
|
+
path = f"{ref_path}.{path}" if path else ref_path
|
|
196
210
|
|
|
197
211
|
obj = self.store.get(resolved_obj_id)
|
|
198
212
|
if obj is None:
|
|
@@ -274,7 +288,8 @@ class RichExplorer:
|
|
|
274
288
|
if hasattr(obj, "__module__") and obj.__module__ not in ("builtins", "__main__"):
|
|
275
289
|
type_name = f"{obj.__module__}.{type_name}"
|
|
276
290
|
|
|
277
|
-
location =
|
|
291
|
+
location = "@" if not obj_id.startswith("@") else ""
|
|
292
|
+
location += obj_id + (f".{path}" if path else "")
|
|
278
293
|
|
|
279
294
|
# Add size info for sized objects
|
|
280
295
|
size_info = ""
|
|
@@ -2,180 +2,157 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
-
"""
|
|
6
|
-
Tokonomics: Explorable and Referenceable Tools.
|
|
7
|
-
|
|
8
|
-
===============================================
|
|
9
|
-
|
|
10
|
-
A library that equips LLM‑agents with:
|
|
11
|
-
|
|
12
|
-
* TTL‑based object storage
|
|
13
|
-
* Rich object exploration & reference passing
|
|
14
|
-
* Smart decorators for explorable outputs and referenceable inputs
|
|
15
|
-
* Strict typing / signature preservation (incl. *async* callables)
|
|
16
|
-
* ReST‑style docstring enhancement
|
|
17
|
-
* Configurable preview truncation (`max_bytes`) and a user‑supplied
|
|
18
|
-
`preview_callback` for custom renderings (e.g. pandas.DataFrame)
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
5
|
from __future__ import annotations
|
|
22
6
|
|
|
23
|
-
import
|
|
7
|
+
import logging
|
|
24
8
|
import time
|
|
9
|
+
import uuid
|
|
25
10
|
from typing import (
|
|
26
11
|
Any,
|
|
27
|
-
|
|
28
|
-
TypeVar,
|
|
12
|
+
Protocol,
|
|
29
13
|
)
|
|
30
14
|
|
|
31
|
-
|
|
32
|
-
# 1 · Generic return‑value wrapper
|
|
33
|
-
# =============================================================================
|
|
15
|
+
import orjson
|
|
34
16
|
|
|
35
|
-
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
36
18
|
|
|
37
19
|
|
|
38
|
-
class
|
|
39
|
-
"""
|
|
40
|
-
Wrapper returned by ``@explorable`` decorated tools.
|
|
20
|
+
class ObjectStoreBackend(Protocol):
|
|
21
|
+
"""Backend protocol with ID generation."""
|
|
41
22
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
The internal identifier of the stored object.
|
|
46
|
-
value :
|
|
47
|
-
The original, *unmodified* object returned by the wrapped tool.
|
|
48
|
-
preview :
|
|
49
|
-
Rich‑rendered string generated by the explorer.
|
|
50
|
-
"""
|
|
23
|
+
def generate_id(self) -> str:
|
|
24
|
+
"""Generate a unique ID for this backend."""
|
|
25
|
+
...
|
|
51
26
|
|
|
52
|
-
|
|
27
|
+
def set(self, key: str, value: bytes, ttl_seconds: int | None) -> None:
|
|
28
|
+
"""Store bytes value with optional TTL."""
|
|
29
|
+
...
|
|
53
30
|
|
|
54
|
-
def
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
self.value: _T = value
|
|
58
|
-
self._preview = preview
|
|
31
|
+
def get(self, key: str) -> bytes | None:
|
|
32
|
+
"""Retrieve bytes value or None if not found/expired."""
|
|
33
|
+
...
|
|
59
34
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
35
|
+
def delete(self, key: str) -> bool:
|
|
36
|
+
"""Delete and return True if existed."""
|
|
37
|
+
...
|
|
63
38
|
|
|
64
|
-
def __str__(self) -> str:
|
|
65
|
-
"""Return the preview string representation."""
|
|
66
|
-
return self._preview
|
|
67
39
|
|
|
68
|
-
|
|
40
|
+
class InMemoryBackend:
|
|
41
|
+
"""In-memory backend with counter-based IDs."""
|
|
69
42
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
43
|
+
def __init__(self) -> None:
|
|
44
|
+
"""Initialize an instance of InMemoryBackend."""
|
|
45
|
+
self._data: dict[str, tuple[bytes, float | None]] = {}
|
|
46
|
+
self._counter = 0
|
|
73
47
|
|
|
74
|
-
|
|
48
|
+
def generate_id(self) -> str:
|
|
49
|
+
"""Generate sequential ID."""
|
|
50
|
+
self._counter += 1
|
|
51
|
+
return f"obj_{self._counter:03d}"
|
|
75
52
|
|
|
53
|
+
def set(self, key: str, value: bytes, ttl_seconds: int | None) -> None:
|
|
54
|
+
"""Set a value at key."""
|
|
55
|
+
expiry = None if ttl_seconds is None else time.time() + ttl_seconds
|
|
56
|
+
self._data[key] = (value, expiry)
|
|
76
57
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
58
|
+
def get(self, key: str) -> bytes | None:
|
|
59
|
+
"""Get a value at key."""
|
|
60
|
+
entry = self._data.get(key)
|
|
61
|
+
if entry is None:
|
|
62
|
+
return None
|
|
63
|
+
value, expiry = entry
|
|
64
|
+
if expiry and time.time() > expiry:
|
|
65
|
+
self.delete(key)
|
|
66
|
+
return None
|
|
67
|
+
return value
|
|
80
68
|
|
|
69
|
+
def delete(self, key: str) -> bool:
|
|
70
|
+
"""Delete a value at key."""
|
|
71
|
+
return self._data.pop(key, None) is not None
|
|
81
72
|
|
|
82
|
-
class ObjectStore:
|
|
83
|
-
"""
|
|
84
|
-
Very small in‑memory store with TTL‑based eviction.
|
|
85
|
-
|
|
86
|
-
Parameters
|
|
87
|
-
----------
|
|
88
|
-
ttl :
|
|
89
|
-
Default time‑to‑live in **seconds** for every stored entry. The TTL is
|
|
90
|
-
evaluated lazily on every ``get`` / ``put``. A value of ``0`` disables
|
|
91
|
-
expiry (mainly for tests).
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
def __init__(self, ttl: float = 3_600.0) -> None:
|
|
95
|
-
"""Initialize ObjectStore with TTL in seconds."""
|
|
96
|
-
self._ttl: float = float(ttl)
|
|
97
|
-
self._objects: dict[str, tuple[Any, float]] = {}
|
|
98
|
-
self._counter: int = 0
|
|
99
|
-
|
|
100
|
-
# ––––––––––––––––––––––––––––––––––––––––––––––––––––––
|
|
101
|
-
# Internal helpers
|
|
102
|
-
# ––––––––––––––––––––––––––––––––––––––––––––––––––––––
|
|
103
|
-
|
|
104
|
-
def _now(self) -> float:
|
|
105
|
-
return time.time()
|
|
106
|
-
|
|
107
|
-
def _evict_expired(self) -> None:
|
|
108
|
-
if self._ttl == 0:
|
|
109
|
-
return
|
|
110
|
-
expiry_threshold = self._now() - self._ttl
|
|
111
|
-
expired = [k for k, (_, ts) in self._objects.items() if ts < expiry_threshold]
|
|
112
|
-
for k in expired:
|
|
113
|
-
del self._objects[k]
|
|
114
|
-
|
|
115
|
-
# ––––––––––––––––––––––––––––––––––––––––––––––––––––––
|
|
116
|
-
# Public API
|
|
117
|
-
# ––––––––––––––––––––––––––––––––––––––––––––––––––––––
|
|
118
73
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
self._evict_expired()
|
|
122
|
-
self._counter += 1
|
|
123
|
-
obj_id = f"obj_{self._counter:03d}"
|
|
124
|
-
self._objects[obj_id] = (obj, self._now())
|
|
125
|
-
return obj_id
|
|
74
|
+
class RedisBackend:
|
|
75
|
+
"""Redis backend with UUID-based IDs."""
|
|
126
76
|
|
|
127
|
-
def
|
|
128
|
-
"""
|
|
77
|
+
def __init__(self, redis_url: str) -> None:
|
|
78
|
+
"""Initialize the redis backend."""
|
|
79
|
+
try:
|
|
80
|
+
import redis
|
|
81
|
+
except ImportError as e:
|
|
82
|
+
logger.error(
|
|
83
|
+
"Redis package not installed. Install with: pip install deepset-mcp[redis] to use the RedisBackend."
|
|
84
|
+
)
|
|
85
|
+
raise ImportError(
|
|
86
|
+
"Redis package not installed. Install with: pip install deepset-mcp[redis] to use the RedisBackend."
|
|
87
|
+
) from e
|
|
129
88
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
self.
|
|
133
|
-
entry = self._objects.get(obj_id)
|
|
134
|
-
return None if entry is None else entry[0]
|
|
89
|
+
self._client = redis.from_url(redis_url, decode_responses=False) # type: ignore[no-untyped-call]
|
|
90
|
+
# Test connection immediately
|
|
91
|
+
self._client.ping()
|
|
135
92
|
|
|
136
|
-
def
|
|
137
|
-
"""
|
|
93
|
+
def generate_id(self) -> str:
|
|
94
|
+
"""Generate UUID."""
|
|
95
|
+
# Using UUID4 for Redis to ensure uniqueness across instances
|
|
96
|
+
return f"obj_{uuid.uuid4()}"
|
|
138
97
|
|
|
139
|
-
|
|
140
|
-
"""
|
|
141
|
-
|
|
142
|
-
|
|
98
|
+
def set(self, key: str, value: bytes, ttl_seconds: int | None) -> None:
|
|
99
|
+
"""Set a value at key."""
|
|
100
|
+
if ttl_seconds:
|
|
101
|
+
self._client.setex(key, ttl_seconds, value)
|
|
102
|
+
else:
|
|
103
|
+
self._client.set(key, value)
|
|
143
104
|
|
|
105
|
+
def get(self, key: str) -> bytes | None:
|
|
106
|
+
"""Get a value at key."""
|
|
107
|
+
return self._client.get(key) # type: ignore[no-any-return]
|
|
144
108
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
109
|
+
def delete(self, key: str) -> bool:
|
|
110
|
+
"""Delete a value at key."""
|
|
111
|
+
return bool(self._client.delete(key))
|
|
148
112
|
|
|
149
113
|
|
|
150
|
-
class
|
|
151
|
-
"""
|
|
114
|
+
class ObjectStore:
|
|
115
|
+
"""JSON-based object store with pluggable backends."""
|
|
152
116
|
|
|
153
|
-
|
|
117
|
+
def __init__(self, backend: ObjectStoreBackend, ttl: int = 600) -> None:
|
|
118
|
+
"""Initialize ObjectStore with backend and TTL.
|
|
154
119
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
120
|
+
Parameters
|
|
121
|
+
----------
|
|
122
|
+
backend :
|
|
123
|
+
Backend implementation for storage
|
|
124
|
+
ttl :
|
|
125
|
+
Time-to-live in seconds for stored objects. The TTL is managed by the backend.
|
|
126
|
+
"""
|
|
127
|
+
self._backend = backend
|
|
128
|
+
self._ttl = ttl
|
|
158
129
|
|
|
159
|
-
|
|
130
|
+
def put(self, obj: Any) -> str:
|
|
131
|
+
"""Store any object as JSON using backend-generated ID."""
|
|
132
|
+
obj_id = self._backend.generate_id()
|
|
160
133
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
134
|
+
def default(obj: Any) -> Any:
|
|
135
|
+
if isinstance(obj, set | tuple):
|
|
136
|
+
return list(obj)
|
|
137
|
+
# Check if it's a Pydantic model
|
|
138
|
+
if hasattr(obj, "model_dump"):
|
|
139
|
+
return obj.model_dump(mode="json")
|
|
140
|
+
raise TypeError
|
|
165
141
|
|
|
166
|
-
|
|
167
|
-
# Factory
|
|
168
|
-
# --------------------------------------------------------------------- #
|
|
142
|
+
json_bytes = orjson.dumps(obj, default=default)
|
|
169
143
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
144
|
+
ttl_seconds = self._ttl if self._ttl > 0 else None
|
|
145
|
+
self._backend.set(obj_id, json_bytes, ttl_seconds)
|
|
146
|
+
return obj_id
|
|
147
|
+
|
|
148
|
+
def get(self, obj_id: str) -> Any | None:
|
|
149
|
+
"""Get object as JSON-decoded data."""
|
|
150
|
+
json_bytes = self._backend.get(obj_id)
|
|
151
|
+
if json_bytes is None:
|
|
177
152
|
return None
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
153
|
+
|
|
154
|
+
return orjson.loads(json_bytes)
|
|
155
|
+
|
|
156
|
+
def delete(self, obj_id: str) -> bool:
|
|
157
|
+
"""Delete object."""
|
|
158
|
+
return self._backend.delete(obj_id)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepset-mcp
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5rc1
|
|
4
4
|
Summary: Collection of MCP tools and Agents to work with the deepset AI platform. Create, debug or learn about pipelines on the platform. Useable from the CLI, Cursor, Claude Code, or other MCP clients.
|
|
5
5
|
Project-URL: Homepage, https://deepset.ai
|
|
6
6
|
Author-email: Mathis Lucka <mathis.lucka@deepset.ai>, Tanay Soni <tanay.soni@deepset.ai>
|
|
@@ -25,10 +25,14 @@ Requires-Dist: httpx
|
|
|
25
25
|
Requires-Dist: mcp>=1.10.1
|
|
26
26
|
Requires-Dist: model2vec
|
|
27
27
|
Requires-Dist: numpy
|
|
28
|
+
Requires-Dist: orjson
|
|
28
29
|
Requires-Dist: pydantic>=2.0.0
|
|
29
30
|
Requires-Dist: pyjwt[crypto]
|
|
30
31
|
Requires-Dist: pyyaml
|
|
31
32
|
Requires-Dist: rich
|
|
33
|
+
Requires-Dist: typer
|
|
34
|
+
Provides-Extra: redis
|
|
35
|
+
Requires-Dist: redis>=4.0.0; extra == 'redis'
|
|
32
36
|
Description-Content-Type: text/markdown
|
|
33
37
|
|
|
34
38
|
# MCP Server for the deepset AI platform
|
|
@@ -53,6 +57,7 @@ Using the server, you benefit from faster creation of pipelines or indexes and s
|
|
|
53
57
|
- [2.2 Manage Tools](#manage-tools)
|
|
54
58
|
- [2.3 Reduce Tool Count](#reduce-tool-count)
|
|
55
59
|
- [2.4 Prompts](#prompts)
|
|
60
|
+
- [2.5 Providing a Remote MCP Server](#providing-a-remote-mcp-server)
|
|
56
61
|
- [3. Use Cases](#use-cases)
|
|
57
62
|
- [3.1. Creating Pipelines](#creating-pipelines)
|
|
58
63
|
- [3.2. Debugging Pipelines](#debugging-pipelines)
|
|
@@ -249,7 +254,6 @@ For example:
|
|
|
249
254
|
"env": {
|
|
250
255
|
"DEEPSET_API_KEY":"<DEEPSET_API_KEY>"
|
|
251
256
|
}
|
|
252
|
-
|
|
253
257
|
}
|
|
254
258
|
}
|
|
255
259
|
}
|
|
@@ -353,8 +357,6 @@ All tools exposed through the MCP server have minimal prompts. Any Agent interac
|
|
|
353
357
|
|
|
354
358
|
View the **recommended prompt** [here](src/deepset_mcp/prompts/deepset_debugging_agent.md).
|
|
355
359
|
|
|
356
|
-
This prompt is also exposed as the `deepset_recommended_prompt` on the MCP server.
|
|
357
|
-
|
|
358
360
|
In Cursor, add the prompt to `.cursorrules`.
|
|
359
361
|
|
|
360
362
|
In Claude Desktop, create a "Project" and add the prompt as system instructions.
|
|
@@ -362,6 +364,48 @@ In Claude Desktop, create a "Project" and add the prompt as system instructions.
|
|
|
362
364
|
You may find that customizing the prompt for your specific needs yields best results.
|
|
363
365
|
|
|
364
366
|
|
|
367
|
+
### Providing a Remote MCP Server
|
|
368
|
+
|
|
369
|
+
The `deepset-mcp` package can be configured to run as a remote MCP server, allowing you to provide deepset platform access to multiple users through a centralized service. This is particularly useful for organizations that want to deploy the MCP server as a shared service or integrate it into existing infrastructure.
|
|
370
|
+
|
|
371
|
+
**Key Requirements**
|
|
372
|
+
|
|
373
|
+
When running as a remote MCP server, you must configure the following:
|
|
374
|
+
|
|
375
|
+
1. **Transport Protocol**: Use `streamable-http` instead of the default `stdio` transport
|
|
376
|
+
2. **Authentication**: Implement OAuth or similar authentication flow to securely handle user credentials
|
|
377
|
+
3. **Authorization Headers**: Ensure client requests include proper `Authorization` headers with Bearer token for deepset access
|
|
378
|
+
4. **Dynamic Workspace Mode**: Use `workspace_mode='dynamic'` to support multiple users with different workspaces
|
|
379
|
+
5. **API Key Management**: Enable `get_api_key_from_auth_header` to extract deepset API keys from request headers
|
|
380
|
+
|
|
381
|
+
**Implementation Example**
|
|
382
|
+
|
|
383
|
+
Here's a complete example of how to set up a remote MCP server:
|
|
384
|
+
|
|
385
|
+
```python
|
|
386
|
+
from mcp.server.fastmcp import FastMCP
|
|
387
|
+
from deepset_mcp import configure_mcp_server, WorkspaceMode, ALL_DEEPSET_TOOLS, DEEPSET_DOCS_DEFAULT_SHARE_URL
|
|
388
|
+
|
|
389
|
+
# Create FastMCP instance
|
|
390
|
+
mcp = FastMCP("Deepset Remote MCP Server")
|
|
391
|
+
|
|
392
|
+
# Add authentication middleware
|
|
393
|
+
|
|
394
|
+
# Configure the deepset MCP server
|
|
395
|
+
configure_mcp_server(
|
|
396
|
+
mcp_server_instance=mcp,
|
|
397
|
+
workspace_mode=WorkspaceMode.DYNAMIC,
|
|
398
|
+
tools_to_register=ALL_DEEPSET_TOOLS,
|
|
399
|
+
deepset_docs_shareable_prototype_url=DEEPSET_DOCS_DEFAULT_SHARE_URL,
|
|
400
|
+
get_api_key_from_authorization_header=True
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
# Run the server
|
|
404
|
+
if __name__ == "__main__":
|
|
405
|
+
mcp.run(transport="streamable-http")
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
|
|
365
409
|
## Use Cases
|
|
366
410
|
|
|
367
411
|
The primary way to use the deepset MCP server is through an LLM that interacts with the deepset MCP tools in an agentic way.
|
|
@@ -407,7 +451,7 @@ If your pipeline is not deployed yet, the Agent can autonomously validate it and
|
|
|
407
451
|
|
|
408
452
|
### deepset-mcp
|
|
409
453
|
|
|
410
|
-
The `deepset-mcp
|
|
454
|
+
The `deepset-mcp` command starts the Deepset MCP server to interact with the deepset AI platform.
|
|
411
455
|
|
|
412
456
|
You can run it in your terminal via `uvx deepset-mcp`.
|
|
413
457
|
|
|
@@ -417,14 +461,16 @@ If you want to run a specific version, you can run:
|
|
|
417
461
|
|
|
418
462
|
The following options are available:
|
|
419
463
|
|
|
420
|
-
| Option
|
|
421
|
-
|
|
422
|
-
| --api-key
|
|
423
|
-
| --workspace
|
|
424
|
-
| --workspace-mode
|
|
425
|
-
| --list-tools
|
|
426
|
-
| --tools
|
|
427
|
-
| --docs-share-url
|
|
464
|
+
| Option | Description |
|
|
465
|
+
|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
466
|
+
| --api-key | The deepset API key to use. Can also be set it via the "DEEPSET_API_KEY" environment variable. |
|
|
467
|
+
| --workspace | The deepset workspace to use. Can also be set via the "DEEPSET_WORKSPACE" environment variable. |
|
|
468
|
+
| --workspace-mode | If you want to allow an Agent to access multiple workspaces (Options: static, dynamic; default: static) |
|
|
469
|
+
| --list-tools | List all available tools (does not start the server). |
|
|
470
|
+
| --tools | Pass a space separated list of tool names that you want the server to register. |
|
|
471
|
+
| --docs-share-url | Pass a [shared prototype](https://docs.cloud.deepset.ai/docs/share-a-pipeline-prototype) URL to customize which pipeline the Agent uses for documentation search (default: official deepset documentation) |
|
|
472
|
+
| --api-key-from-auth-header | Get the deepset API key from the request's authorization header instead of using a static key. |
|
|
473
|
+
| --transport | The type of transport to use for running the MCP server (Options: stdio, streamable-http; default: stdio) |
|
|
428
474
|
|
|
429
475
|
|
|
430
476
|
### Tools
|
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
deepset_mcp/__init__.py,sha256=
|
|
2
|
-
deepset_mcp/config.py,sha256=
|
|
1
|
+
deepset_mcp/__init__.py,sha256=AP0SzhtVQxPhd3hwBadTlH7hNMrA9Mg7-EkKL9-p0gU,439
|
|
2
|
+
deepset_mcp/config.py,sha256=1pl_TbEmlYo_He-_h01haHdp1mTp2OsrnlOdhwIpK58,2085
|
|
3
3
|
deepset_mcp/initialize_embedding_model.py,sha256=5Zcccrw3ItHpt0rGgM-3WdqV-QQaiv79nxBHhDSwNwA,411
|
|
4
|
-
deepset_mcp/main.py,sha256=
|
|
5
|
-
deepset_mcp/
|
|
6
|
-
deepset_mcp/
|
|
4
|
+
deepset_mcp/main.py,sha256=ixcTgXcxoVlAQMPRGvYyQ2kzy8pMArsE2MEzZ1QeNPw,7308
|
|
5
|
+
deepset_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
deepset_mcp/server.py,sha256=jSXfQiF9aZ35_KT_qsg1nct2w9pKyrkQqbkEiTxnGFg,6712
|
|
7
|
+
deepset_mcp/store.py,sha256=OP-TkDei7Ppzntxp7ec385gqB9PRX7ot29ytiLw5DV0,1800
|
|
8
|
+
deepset_mcp/tool_factory.py,sha256=5kLoVsQeTs6zKxt4xH8nAAgEsKE710z5YtIsw3eV0_c,15483
|
|
9
|
+
deepset_mcp/tool_models.py,sha256=_ccYjYrBph7SkpiTN1iD3N5k9g1p-e7vJrHoIou2UNU,1076
|
|
10
|
+
deepset_mcp/tool_registry.py,sha256=BZEZcqH6woks_s136m-kg1aKMFi1As2OzIJGngCtFsY,8617
|
|
7
11
|
deepset_mcp/api/README.md,sha256=h3xj8G2x1f5Z5EA6fBtBfNeVtXNwYnr291yPMmr2fQo,15576
|
|
8
12
|
deepset_mcp/api/__init__.py,sha256=-32egOu1IHdVvJKcEEcbfVu4hqX1QGM8wePwThoMGBE,111
|
|
9
13
|
deepset_mcp/api/client.py,sha256=Lmf5skULQSiYZ-S81gbFUGfaC6f_E104fxQd4ENA4x4,9927
|
|
10
14
|
deepset_mcp/api/exceptions.py,sha256=QvkVYZteB07VjJpB2UX4lWgRK8KnS2AkeftI-MxYcvE,2545
|
|
11
15
|
deepset_mcp/api/protocols.py,sha256=4GIrP-hCvgPhkOWSbCuQlty8XKg-ThupWm21Ws-2HB0,4149
|
|
12
16
|
deepset_mcp/api/shared_models.py,sha256=dxQ384fNWiUP6DoFm50gsPxVorRjpwvrfISA4cUrgwM,522
|
|
13
|
-
deepset_mcp/api/transport.py,sha256=
|
|
17
|
+
deepset_mcp/api/transport.py,sha256=lxck7iuZvnrEgxDpbOT3aGkenRYRSspxYviZLeOS0Uk,10534
|
|
14
18
|
deepset_mcp/api/custom_components/__init__.py,sha256=-32egOu1IHdVvJKcEEcbfVu4hqX1QGM8wePwThoMGBE,111
|
|
15
19
|
deepset_mcp/api/custom_components/models.py,sha256=gjiKt8xn3dHHczmKAr28FSi23X1ZmN6WhXscqkX66QI,721
|
|
16
20
|
deepset_mcp/api/custom_components/protocols.py,sha256=72rm0Z9DHSfQoe4vPllFGf-FdlVR7tZ5cb4hORmFooQ,737
|
|
@@ -55,16 +59,17 @@ deepset_mcp/tools/haystack_service.py,sha256=0tNgEYj5NQE0CQY7vcf5btvIy-TlM1lAbcY
|
|
|
55
59
|
deepset_mcp/tools/haystack_service_models.py,sha256=7voNBIBTxFmYvpXmxon7cH1ZlpFjj4pxoeNymyuOIJs,2447
|
|
56
60
|
deepset_mcp/tools/indexes.py,sha256=4K2Any_7_GpMroOwPxEMO8tHDoSsKA91oj8ngIRQTNQ,5417
|
|
57
61
|
deepset_mcp/tools/model_protocol.py,sha256=k6xcnVYLqgXM8DX8SrA5ls3sbKBZC06XfO596KCSKQ4,529
|
|
62
|
+
deepset_mcp/tools/object_store.py,sha256=fgt4DrnYzTxd35iCT_jw4Mpx1TXKU-ZPvx-vecY8PxM,1964
|
|
58
63
|
deepset_mcp/tools/pipeline.py,sha256=Xt2K4i_1AK5gEYNV7xWCOsMQT_2umNDZRD1AIA7cfUE,14843
|
|
59
64
|
deepset_mcp/tools/pipeline_template.py,sha256=KC-PUbXMKpAv0Zdc64JMgV4pDYVtTCzQOWCbvEogP_w,5258
|
|
60
65
|
deepset_mcp/tools/secrets.py,sha256=qLPc6rrHC0-q6Jug6r-D1L4EluLSMsj9V25lJGjNgyU,3911
|
|
61
66
|
deepset_mcp/tools/workspace.py,sha256=iYUch2vk3N_4NLnofGQ_lfs4Gn9gmpWRVAYOSaJPh9k,2840
|
|
62
|
-
deepset_mcp/tools/tokonomics/__init__.py,sha256=
|
|
63
|
-
deepset_mcp/tools/tokonomics/decorators.py,sha256=
|
|
64
|
-
deepset_mcp/tools/tokonomics/explorer.py,sha256=
|
|
65
|
-
deepset_mcp/tools/tokonomics/object_store.py,sha256=
|
|
66
|
-
deepset_mcp-0.0.
|
|
67
|
-
deepset_mcp-0.0.
|
|
68
|
-
deepset_mcp-0.0.
|
|
69
|
-
deepset_mcp-0.0.
|
|
70
|
-
deepset_mcp-0.0.
|
|
67
|
+
deepset_mcp/tools/tokonomics/__init__.py,sha256=ATqcq_TluuARiwATYMunKasHs0IQNdBBdvqeSx7kYlA,469
|
|
68
|
+
deepset_mcp/tools/tokonomics/decorators.py,sha256=xPa8m5j0AoFecG5Z4q_i7cEroglp0r3U04gfwT9MNh4,13578
|
|
69
|
+
deepset_mcp/tools/tokonomics/explorer.py,sha256=y4PnvQZ_Y8f8C6vp5opVFj-Teax7la7aYFXVU1g6ECc,13618
|
|
70
|
+
deepset_mcp/tools/tokonomics/object_store.py,sha256=UW9g_NJ9Mw4-2HnhQye2hKyz3Pt_rYOgXL6gABtZwFE,4802
|
|
71
|
+
deepset_mcp-0.0.5rc1.dist-info/METADATA,sha256=BPIMXqhVBxES_K9Jvj1piQMCsHeHVYHDm3AOmL2HWtQ,42639
|
|
72
|
+
deepset_mcp-0.0.5rc1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
73
|
+
deepset_mcp-0.0.5rc1.dist-info/entry_points.txt,sha256=0X0vMrNLUbQYq02bA4DUgsFuEAbS2bAaGO4jrAMtRk0,53
|
|
74
|
+
deepset_mcp-0.0.5rc1.dist-info/licenses/LICENSE,sha256=k0H2cOtcgKczLsEN2Ju03DoAb8jhBSlp8WzWYlYlDvc,11342
|
|
75
|
+
deepset_mcp-0.0.5rc1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|