mcp-haystack 1.5.1__tar.gz → 2.0.0__tar.gz
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.
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/CHANGELOG.md +33 -1
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/PKG-INFO +3 -4
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/pyproject.toml +2 -4
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/src/haystack_integrations/tools/mcp/mcp_tool.py +5 -3
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/src/haystack_integrations/tools/mcp/mcp_toolset.py +5 -2
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/tests/test_mcp_tool.py +15 -1
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/tests/test_mcp_toolset.py +20 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/.gitignore +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/LICENSE.txt +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/README.md +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/examples/mcp_client.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/examples/mcp_filtered_tools.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/examples/mcp_server.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/examples/mcp_stdio_client.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/examples/mcp_stdio_toolset.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/examples/time_pipeline.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/examples/time_pipeline_toolset.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/pydoc/config_docusaurus.yml +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/src/haystack_integrations/tools/mcp/__init__.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/src/haystack_integrations/tools/mcp/compatibility_layer.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/src/haystack_integrations/tools/py.typed +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/tests/__init__.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/tests/conftest.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/tests/mcp_memory_transport.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/tests/mcp_servers_fixtures.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/tests/test_compatibility_layer.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/tests/test_mcp_integration.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/tests/test_mcp_server_info.py +0 -0
- {mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/tests/test_mcp_timeout_reconnection.py +0 -0
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [integrations/mcp-v1.5.2] - 2026-10-07
|
|
4
|
+
|
|
5
|
+
### 🐛 Bug Fixes
|
|
6
|
+
|
|
7
|
+
- MCP - warm_up must reopen connections after close (#4065)
|
|
8
|
+
|
|
9
|
+
### ⚙️ CI
|
|
10
|
+
|
|
11
|
+
- Improve changelog generation; fix existing changelogs (#3883)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [integrations/mcp-v1.5.1] - 2026-09-01
|
|
15
|
+
|
|
16
|
+
### 🚀 Features
|
|
17
|
+
|
|
18
|
+
- Support MCP Python SDK v2 - compatibility mode (#3878)
|
|
19
|
+
|
|
20
|
+
### 🐛 Bug Fixes
|
|
21
|
+
|
|
22
|
+
- Standardize license files (#3771)
|
|
23
|
+
|
|
24
|
+
### 🧪 Testing
|
|
25
|
+
|
|
26
|
+
- MCP - refactor test_toolset_combination for Toolset.__add__ removal (#3877)
|
|
27
|
+
|
|
28
|
+
### 🧹 Chores
|
|
29
|
+
|
|
30
|
+
- Re-standardize READMEs (#3768)
|
|
31
|
+
|
|
32
|
+
|
|
3
33
|
## [integrations/mcp-v1.4.1] - 2026-07-29
|
|
4
34
|
|
|
5
35
|
### 🐛 Bug Fixes
|
|
@@ -103,7 +133,7 @@
|
|
|
103
133
|
|
|
104
134
|
- Add MCPTool/MCPToolset warm_up (#2384)
|
|
105
135
|
|
|
106
|
-
## [integrations/mcp-v0.8
|
|
136
|
+
## [integrations/mcp-v0.0.8] - 2025-10-14
|
|
107
137
|
|
|
108
138
|
### 🐛 Bug Fixes
|
|
109
139
|
|
|
@@ -160,6 +190,8 @@
|
|
|
160
190
|
|
|
161
191
|
- Align core-integrations Hatch scripts (#1898)
|
|
162
192
|
|
|
193
|
+
## [integrations/mcp-v0.3.1] - 2025-05-28
|
|
194
|
+
|
|
163
195
|
### 🌀 Miscellaneous
|
|
164
196
|
|
|
165
197
|
- App pins for MCP (#1845)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mcp-haystack
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Haystack integration for Model Context Protocol (MCP)
|
|
5
5
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/mcp#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/deepset-ai/haystack-core-integrations/issues
|
|
@@ -12,14 +12,13 @@ Keywords: Haystack,MCP,Model Context Protocol
|
|
|
12
12
|
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
14
|
Classifier: Programming Language :: Python
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
20
20
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
21
|
-
Requires-Python: >=3.
|
|
22
|
-
Requires-Dist: exceptiongroup
|
|
21
|
+
Requires-Python: >=3.11
|
|
23
22
|
Requires-Dist: haystack-ai>=2.23.0
|
|
24
23
|
Requires-Dist: mcp>=1.24.0
|
|
25
24
|
Description-Content-Type: text/markdown
|
|
@@ -7,7 +7,7 @@ name = "mcp-haystack"
|
|
|
7
7
|
dynamic = ["version"]
|
|
8
8
|
description = "Haystack integration for Model Context Protocol (MCP)"
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
keywords = [
|
|
13
13
|
"MCP",
|
|
@@ -21,17 +21,16 @@ classifiers = [
|
|
|
21
21
|
"License :: OSI Approved :: Apache Software License",
|
|
22
22
|
"Development Status :: 4 - Beta",
|
|
23
23
|
"Programming Language :: Python",
|
|
24
|
-
"Programming Language :: Python :: 3.10",
|
|
25
24
|
"Programming Language :: Python :: 3.11",
|
|
26
25
|
"Programming Language :: Python :: 3.12",
|
|
27
26
|
"Programming Language :: Python :: 3.13",
|
|
28
27
|
"Programming Language :: Python :: 3.14",
|
|
28
|
+
"Programming Language :: Python :: 3.15",
|
|
29
29
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
30
30
|
]
|
|
31
31
|
dependencies = [
|
|
32
32
|
"mcp>=1.24.0",
|
|
33
33
|
"haystack-ai>=2.23.0",
|
|
34
|
-
"exceptiongroup", # Backport of ExceptionGroup for Python < 3.11
|
|
35
34
|
]
|
|
36
35
|
|
|
37
36
|
[project.urls]
|
|
@@ -88,7 +87,6 @@ disallow_incomplete_defs = true
|
|
|
88
87
|
|
|
89
88
|
|
|
90
89
|
[tool.ruff]
|
|
91
|
-
target-version = "py310"
|
|
92
90
|
line-length = 120
|
|
93
91
|
|
|
94
92
|
[tool.ruff.lint]
|
|
@@ -17,7 +17,6 @@ from contextlib import AsyncExitStack
|
|
|
17
17
|
from dataclasses import dataclass, fields
|
|
18
18
|
from typing import Any, cast
|
|
19
19
|
|
|
20
|
-
from exceptiongroup import ExceptionGroup
|
|
21
20
|
from haystack import logging
|
|
22
21
|
from haystack.core.serialization import generate_qualified_class_name, import_class_by_name
|
|
23
22
|
from haystack.tools import Tool
|
|
@@ -1121,7 +1120,7 @@ class MCPTool(Tool):
|
|
|
1121
1120
|
return _extract_first_text_element(result)
|
|
1122
1121
|
|
|
1123
1122
|
return result
|
|
1124
|
-
except
|
|
1123
|
+
except TimeoutError as e:
|
|
1125
1124
|
message = f"Tool invocation timed out after {self._invocation_timeout} seconds"
|
|
1126
1125
|
raise TimeoutError(message) from e
|
|
1127
1126
|
except Exception as e:
|
|
@@ -1155,7 +1154,7 @@ class MCPTool(Tool):
|
|
|
1155
1154
|
return set(properties.keys())
|
|
1156
1155
|
|
|
1157
1156
|
def warm_up(self) -> None:
|
|
1158
|
-
"""Connect and fetch the tool schema
|
|
1157
|
+
"""Connect and fetch the tool schema unless already connected."""
|
|
1159
1158
|
with self._lock:
|
|
1160
1159
|
if self._client is not None:
|
|
1161
1160
|
return
|
|
@@ -1266,6 +1265,9 @@ class MCPTool(Tool):
|
|
|
1266
1265
|
self._worker.stop()
|
|
1267
1266
|
except Exception as e:
|
|
1268
1267
|
logger.debug(f"TOOL: Error during synchronous worker stop: {e!s}")
|
|
1268
|
+
finally:
|
|
1269
|
+
self._client = None
|
|
1270
|
+
self._worker = None
|
|
1269
1271
|
|
|
1270
1272
|
def __del__(self) -> None:
|
|
1271
1273
|
"""Cleanup resources when the tool is garbage collected."""
|
{mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/src/haystack_integrations/tools/mcp/mcp_toolset.py
RENAMED
|
@@ -7,7 +7,6 @@ from collections.abc import Callable
|
|
|
7
7
|
from typing import Any, cast
|
|
8
8
|
from urllib.parse import urlparse
|
|
9
9
|
|
|
10
|
-
from exceptiongroup import ExceptionGroup
|
|
11
10
|
from haystack import logging
|
|
12
11
|
from haystack.core.serialization import generate_qualified_class_name, import_class_by_name
|
|
13
12
|
from haystack.tools import Tool, Toolset
|
|
@@ -244,6 +243,7 @@ class MCPToolset(Toolset):
|
|
|
244
243
|
self.outputs_to_state = outputs_to_state or {}
|
|
245
244
|
self.outputs_to_string = outputs_to_string or {}
|
|
246
245
|
self._warmup_called = False
|
|
246
|
+
self._worker: _MCPClientSessionManager | None = None
|
|
247
247
|
|
|
248
248
|
if not eager_connect:
|
|
249
249
|
# Do not connect during validation; expose a toolset with one fake tool to pass validation
|
|
@@ -261,7 +261,7 @@ class MCPToolset(Toolset):
|
|
|
261
261
|
|
|
262
262
|
def warm_up(self) -> None:
|
|
263
263
|
"""
|
|
264
|
-
Connect and load tools
|
|
264
|
+
Connect and load tools unless already connected.
|
|
265
265
|
|
|
266
266
|
This method is automatically called by `Agent.warm_up()` and `Pipeline.warm_up()`.
|
|
267
267
|
You can also call it directly before using the toolset to ensure all tool schemas
|
|
@@ -511,6 +511,9 @@ class MCPToolset(Toolset):
|
|
|
511
511
|
self._worker.stop()
|
|
512
512
|
except Exception as e:
|
|
513
513
|
logger.debug(f"TOOLSET: error during worker stop: {e!s}")
|
|
514
|
+
finally:
|
|
515
|
+
self._worker = None
|
|
516
|
+
self._warmup_called = False
|
|
514
517
|
|
|
515
518
|
def __del__(self) -> None:
|
|
516
519
|
self.close()
|
|
@@ -6,7 +6,6 @@ from types import SimpleNamespace
|
|
|
6
6
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
|
-
from exceptiongroup import ExceptionGroup
|
|
10
9
|
from haystack.components.agents import Agent
|
|
11
10
|
from haystack.components.generators.chat import OpenAIChatGenerator
|
|
12
11
|
from haystack.core.pipeline import Pipeline
|
|
@@ -17,6 +16,7 @@ from haystack.tools.from_function import tool
|
|
|
17
16
|
from haystack_integrations.tools.mcp import (
|
|
18
17
|
MCPTool,
|
|
19
18
|
MCPToolNotFoundError,
|
|
19
|
+
SSEServerInfo,
|
|
20
20
|
StdioServerInfo,
|
|
21
21
|
)
|
|
22
22
|
from haystack_integrations.tools.mcp.mcp_tool import (
|
|
@@ -365,6 +365,20 @@ class TestMCPTool:
|
|
|
365
365
|
assert "b" in tool.parameters["properties"]
|
|
366
366
|
assert mock_connect.call_count == 1
|
|
367
367
|
|
|
368
|
+
@pytest.mark.parametrize("eager_connect", [False, True])
|
|
369
|
+
def test_mcp_tool_reopens_after_close(self, eager_connect, mcp_calculator_server, mcp_tool_cleanup):
|
|
370
|
+
port = mcp_calculator_server("sse")
|
|
371
|
+
server_info = SSEServerInfo(url=f"http://127.0.0.1:{port}/sse", max_retries=0)
|
|
372
|
+
tool = mcp_tool_cleanup(MCPTool(name="add", server_info=server_info, eager_connect=eager_connect))
|
|
373
|
+
|
|
374
|
+
tool.warm_up()
|
|
375
|
+
assert json.loads(tool.invoke(a=2, b=3))["content"][0]["text"] == "5"
|
|
376
|
+
|
|
377
|
+
tool.close()
|
|
378
|
+
|
|
379
|
+
tool.warm_up()
|
|
380
|
+
assert json.loads(tool.invoke(a=2, b=3))["content"][0]["text"] == "5"
|
|
381
|
+
|
|
368
382
|
@pytest.mark.asyncio
|
|
369
383
|
async def test_mcp_tool_ainvoke_matches_invoke_with_outputs_to_state(self, mcp_tool_cleanup):
|
|
370
384
|
"""Test that sync and async invocation paths return the same parsed state output."""
|
|
@@ -195,6 +195,26 @@ class TestMCPToolset:
|
|
|
195
195
|
toolset.warm_up()
|
|
196
196
|
assert [tool.name for tool in toolset.tools] == warmed_tool_names
|
|
197
197
|
|
|
198
|
+
@pytest.mark.parametrize("eager_connect", [False, True])
|
|
199
|
+
async def test_mcp_toolset_reopens_after_close(self, eager_connect, mcp_calculator_server, mcp_tool_cleanup):
|
|
200
|
+
port = mcp_calculator_server("sse")
|
|
201
|
+
server_info = SSEServerInfo(url=f"http://127.0.0.1:{port}/sse", max_retries=0)
|
|
202
|
+
toolset = mcp_tool_cleanup(MCPToolset(server_info=server_info, eager_connect=eager_connect))
|
|
203
|
+
|
|
204
|
+
toolset.warm_up()
|
|
205
|
+
assert sorted(tool.name for tool in toolset.tools) == ["add", "subtract"]
|
|
206
|
+
for tool in toolset.tools:
|
|
207
|
+
expected = "5" if tool.name == "add" else "-1"
|
|
208
|
+
assert json.loads(tool.invoke(a=2, b=3))["content"][0]["text"] == expected
|
|
209
|
+
|
|
210
|
+
toolset.close()
|
|
211
|
+
|
|
212
|
+
toolset.warm_up()
|
|
213
|
+
assert sorted(tool.name for tool in toolset.tools) == ["add", "subtract"]
|
|
214
|
+
for tool in toolset.tools:
|
|
215
|
+
expected = "5" if tool.name == "add" else "-1"
|
|
216
|
+
assert json.loads(tool.invoke(a=2, b=3))["content"][0]["text"] == expected
|
|
217
|
+
|
|
198
218
|
async def test_toolset_serde(self, calculator_toolset):
|
|
199
219
|
"""Test serialization and deserialization of MCPToolset."""
|
|
200
220
|
toolset = calculator_toolset
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_haystack-1.5.1 → mcp_haystack-2.0.0}/src/haystack_integrations/tools/mcp/compatibility_layer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|