mcp-haystack 1.5.0__tar.gz → 1.5.2__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.
Files changed (29) hide show
  1. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/CHANGELOG.md +22 -1
  2. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/PKG-INFO +1 -1
  3. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/src/haystack_integrations/tools/mcp/mcp_tool.py +4 -1
  4. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/src/haystack_integrations/tools/mcp/mcp_toolset.py +5 -1
  5. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/tests/test_mcp_tool.py +15 -0
  6. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/tests/test_mcp_toolset.py +20 -0
  7. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/.gitignore +0 -0
  8. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/LICENSE.txt +0 -0
  9. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/README.md +0 -0
  10. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/examples/mcp_client.py +0 -0
  11. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/examples/mcp_filtered_tools.py +0 -0
  12. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/examples/mcp_server.py +0 -0
  13. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/examples/mcp_stdio_client.py +0 -0
  14. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/examples/mcp_stdio_toolset.py +0 -0
  15. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/examples/time_pipeline.py +0 -0
  16. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/examples/time_pipeline_toolset.py +0 -0
  17. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/pydoc/config_docusaurus.yml +0 -0
  18. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/pyproject.toml +0 -0
  19. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/src/haystack_integrations/tools/mcp/__init__.py +0 -0
  20. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/src/haystack_integrations/tools/mcp/compatibility_layer.py +0 -0
  21. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/src/haystack_integrations/tools/py.typed +0 -0
  22. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/tests/__init__.py +0 -0
  23. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/tests/conftest.py +0 -0
  24. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/tests/mcp_memory_transport.py +0 -0
  25. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/tests/mcp_servers_fixtures.py +0 -0
  26. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/tests/test_compatibility_layer.py +0 -0
  27. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/tests/test_mcp_integration.py +0 -0
  28. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/tests/test_mcp_server_info.py +0 -0
  29. {mcp_haystack-1.5.0 → mcp_haystack-1.5.2}/tests/test_mcp_timeout_reconnection.py +0 -0
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [integrations/mcp-v1.5.1] - 2026-09-01
4
+
5
+ ### 🚀 Features
6
+
7
+ - Support MCP Python SDK v2 - compatibility mode (#3878)
8
+
9
+ ### 🐛 Bug Fixes
10
+
11
+ - Standardize license files (#3771)
12
+
13
+ ### 🧪 Testing
14
+
15
+ - MCP - refactor test_toolset_combination for Toolset.__add__ removal (#3877)
16
+
17
+ ### 🧹 Chores
18
+
19
+ - Re-standardize READMEs (#3768)
20
+
21
+
3
22
  ## [integrations/mcp-v1.4.1] - 2026-07-29
4
23
 
5
24
  ### 🐛 Bug Fixes
@@ -103,7 +122,7 @@
103
122
 
104
123
  - Add MCPTool/MCPToolset warm_up (#2384)
105
124
 
106
- ## [integrations/mcp-v0.8.0] - 2025-10-14
125
+ ## [integrations/mcp-v0.0.8] - 2025-10-14
107
126
 
108
127
  ### 🐛 Bug Fixes
109
128
 
@@ -160,6 +179,8 @@
160
179
 
161
180
  - Align core-integrations Hatch scripts (#1898)
162
181
 
182
+ ## [integrations/mcp-v0.3.1] - 2025-05-28
183
+
163
184
  ### 🌀 Miscellaneous
164
185
 
165
186
  - App pins for MCP (#1845)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: mcp-haystack
3
- Version: 1.5.0
3
+ Version: 1.5.2
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
@@ -1155,7 +1155,7 @@ class MCPTool(Tool):
1155
1155
  return set(properties.keys())
1156
1156
 
1157
1157
  def warm_up(self) -> None:
1158
- """Connect and fetch the tool schema if eager_connect is turned off."""
1158
+ """Connect and fetch the tool schema unless already connected."""
1159
1159
  with self._lock:
1160
1160
  if self._client is not None:
1161
1161
  return
@@ -1266,6 +1266,9 @@ class MCPTool(Tool):
1266
1266
  self._worker.stop()
1267
1267
  except Exception as e:
1268
1268
  logger.debug(f"TOOL: Error during synchronous worker stop: {e!s}")
1269
+ finally:
1270
+ self._client = None
1271
+ self._worker = None
1269
1272
 
1270
1273
  def __del__(self) -> None:
1271
1274
  """Cleanup resources when the tool is garbage collected."""
@@ -244,6 +244,7 @@ class MCPToolset(Toolset):
244
244
  self.outputs_to_state = outputs_to_state or {}
245
245
  self.outputs_to_string = outputs_to_string or {}
246
246
  self._warmup_called = False
247
+ self._worker: _MCPClientSessionManager | None = None
247
248
 
248
249
  if not eager_connect:
249
250
  # Do not connect during validation; expose a toolset with one fake tool to pass validation
@@ -261,7 +262,7 @@ class MCPToolset(Toolset):
261
262
 
262
263
  def warm_up(self) -> None:
263
264
  """
264
- Connect and load tools when eager_connect is turned off.
265
+ Connect and load tools unless already connected.
265
266
 
266
267
  This method is automatically called by `Agent.warm_up()` and `Pipeline.warm_up()`.
267
268
  You can also call it directly before using the toolset to ensure all tool schemas
@@ -511,6 +512,9 @@ class MCPToolset(Toolset):
511
512
  self._worker.stop()
512
513
  except Exception as e:
513
514
  logger.debug(f"TOOLSET: error during worker stop: {e!s}")
515
+ finally:
516
+ self._worker = None
517
+ self._warmup_called = False
514
518
 
515
519
  def __del__(self) -> None:
516
520
  self.close()
@@ -17,6 +17,7 @@ from haystack.tools.from_function import tool
17
17
  from haystack_integrations.tools.mcp import (
18
18
  MCPTool,
19
19
  MCPToolNotFoundError,
20
+ SSEServerInfo,
20
21
  StdioServerInfo,
21
22
  )
22
23
  from haystack_integrations.tools.mcp.mcp_tool import (
@@ -365,6 +366,20 @@ class TestMCPTool:
365
366
  assert "b" in tool.parameters["properties"]
366
367
  assert mock_connect.call_count == 1
367
368
 
369
+ @pytest.mark.parametrize("eager_connect", [False, True])
370
+ def test_mcp_tool_reopens_after_close(self, eager_connect, mcp_calculator_server, mcp_tool_cleanup):
371
+ port = mcp_calculator_server("sse")
372
+ server_info = SSEServerInfo(url=f"http://127.0.0.1:{port}/sse", max_retries=0)
373
+ tool = mcp_tool_cleanup(MCPTool(name="add", server_info=server_info, eager_connect=eager_connect))
374
+
375
+ tool.warm_up()
376
+ assert json.loads(tool.invoke(a=2, b=3))["content"][0]["text"] == "5"
377
+
378
+ tool.close()
379
+
380
+ tool.warm_up()
381
+ assert json.loads(tool.invoke(a=2, b=3))["content"][0]["text"] == "5"
382
+
368
383
  @pytest.mark.asyncio
369
384
  async def test_mcp_tool_ainvoke_matches_invoke_with_outputs_to_state(self, mcp_tool_cleanup):
370
385
  """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