import pytest import json from unittest.mock import MagicMock, patch from semantica.ingest import MCPIngestor, ingest_mcp, DBIngestor, FileIngestor from semantica.ingest.mcp_ingestor import MCPData pytestmark = pytest.mark.integration class TestCookbookIntegration: @pytest.fixture def mock_mcp_server(self): # We need to patch both httpx and requests because MCPClient tries httpx first with patch("httpx.post") as mock_httpx_post, \ patch("requests.post") as mock_requests_post: def side_effect(url, json=None, **kwargs): if not json: return MagicMock() method = json.get("method") response_mock = MagicMock() response_mock.status_code = 200 if method == "initialize": response_mock.json.return_value = { "jsonrpc": "2.0", "id": json.get("id"), "result": { "protocolVersion": "2024-11-05", "capabilities": {}, "serverInfo": {"name": "test_server", "version": "1.0"} } } elif method == "resources/list": response_mock.json.return_value = { "jsonrpc": "2.0", "id": json.get("id"), "result": { "resources": [ {"uri": "resource://test/1", "name": "Test Resource 1", "description": "Desc 1"}, {"uri": "resource://test/2", "name": "Test Resource 2", "description": "Desc 2"}, {"uri": "resource://inventory/database", "name": "Inventory DB", "description": "Inventory"} ] } } elif method == "tools/list": response_mock.json.return_value = { "jsonrpc": "2.0", "id": json.get("id"), "result": { "tools": [ {"name": "test_tool_1", "description": "Tool 1", "inputSchema": {}}, {"name": "test_tool_2", "description": "Tool 2", "inputSchema": {}}, {"name": "query_inventory", "description": "Query Inventory", "inputSchema": {}} ] } } elif method == "resources/read": response_mock.json.return_value = { "jsonrpc": "2.0", "id": json.get("id"), "result": { "contents": [ {"uri": json.get("params", {}).get("uri"), "text": "Sample content"} ] } } elif method == "tools/call": tool_name = json.get("params", {}).get("name") content = [{"type": "text", "text": "Tool Output"}] if tool_name == "query_inventory": content = [{"type": "text", "text": '{"warehouse_id": "WH001", "level": 100}'}] response_mock.json.return_value = { "jsonrpc": "2.0", "id": json.get("id"), "result": { "content": content } } else: response_mock.json.return_value = { "jsonrpc": "2.0", "id": json.get("id"), "result": {} } return response_mock mock_httpx_post.side_effect = side_effect mock_requests_post.side_effect = side_effect yield mock_httpx_post def test_financial_data_integration(self, mock_mcp_server): """ Validates the logic from cookbook/use_cases/finance/01_Financial_Data_Integration.ipynb """ # 1. Initialize MCP ingestor mcp_ingestor = MCPIngestor() # 2. Connect to financial data MCP server financial_mcp_url = "http://localhost:8000/mcp" # Patching progress tracker to avoid console output issues during testing if needed # But MCPIngestor now handles it gracefully or we can let it run. # We need to mock get_progress_tracker to avoid 'NoneType' errors if not initialized properly in some envs # although my previous fixes should handle it. Let's patch it to be safe and clean. with patch("semantica.ingest.mcp_ingestor.get_progress_tracker") as mock_tracker: tracker_instance = MagicMock() mock_tracker.return_value = tracker_instance mcp_ingestor.connect( "financial_server", url=financial_mcp_url, headers={"Authorization": "Bearer token"} ) # 3. List available resources resources = mcp_ingestor.list_available_resources("financial_server") assert len(resources) >= 2 assert resources[0].name == "Test Resource 1" # 4. List available tools tools = mcp_ingestor.list_available_tools("financial_server") assert len(tools) >= 2 assert tools[0].name == "test_tool_1" # 5. Ingest resources (simulating notebook logic) # The notebook likely calls ingest_resources ingested_data = mcp_ingestor.ingest_resources( "financial_server", resource_uris=["resource://test/1"] ) assert len(ingested_data) == 1 # content is the raw result from MCP read_resource assert ingested_data[0].content["contents"][0]["text"] == "Sample content" def test_supply_chain_data_integration(self, mock_mcp_server): """ Validates the logic from cookbook/use_cases/supply_chain/01_Supply_Chain_Data_Integration.ipynb """ mcp_ingestor = MCPIngestor() supply_chain_mcp_url = "http://localhost:8000/mcp" with patch("semantica.ingest.mcp_ingestor.get_progress_tracker") as mock_tracker: tracker_instance = MagicMock() mock_tracker.return_value = tracker_instance mcp_ingestor.connect( "supply_chain_server", url=supply_chain_mcp_url, headers={"Authorization": "Bearer token"} ) # Resource ingestion inventory_data = mcp_ingestor.ingest_resources( "supply_chain_server", resource_uris=["resource://inventory/database"] ) assert len(inventory_data) == 1 # Tool ingestion inventory_levels = mcp_ingestor.ingest_tool_output( "supply_chain_server", tool_name="query_inventory", arguments={"warehouse_id": "WH001"} ) assert inventory_levels is not None # Based on my mock, it returns a dict with 'content' if isinstance(inventory_levels, MCPData): assert inventory_levels.content is not None elif isinstance(inventory_levels, dict): assert "content" in inventory_levels else: # Should be list or MCPData assert isinstance(inventory_levels, list) def test_medical_database_integration(self, mock_mcp_server): """ Validates the logic from cookbook/use_cases/healthcare/05_Medical_Database_Integration.ipynb """ mcp_ingestor = MCPIngestor() medical_mcp_url = "http://localhost:8000/mcp" with patch("semantica.ingest.mcp_ingestor.get_progress_tracker") as mock_tracker: tracker_instance = MagicMock() mock_tracker.return_value = tracker_instance mcp_ingestor.connect( "medical_server", url=medical_mcp_url ) resources = mcp_ingestor.list_available_resources("medical_server") assert len(resources) > 0 def test_threat_intelligence_integration(self, mock_mcp_server): """ Validates the logic from cookbook/use_cases/cybersecurity/05_Threat_Intelligence_Integration.ipynb """ mcp_ingestor = MCPIngestor() threat_mcp_url = "http://localhost:8000/mcp" with patch("semantica.ingest.mcp_ingestor.get_progress_tracker") as mock_tracker: tracker_instance = MagicMock() mock_tracker.return_value = tracker_instance mcp_ingestor.connect( "threat_server", url=threat_mcp_url ) tools = mcp_ingestor.list_available_tools("threat_server") assert len(tools) > 0