{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/use_cases/supply_chain/01_Supply_Chain_Data_Integration.ipynb)\n",
    "\n",
    "# Supply Chain Data Integration Pipeline\n",
    "\n",
    "## Overview\n",
    "\n",
    "This notebook demonstrates how to integrate Python/FastMCP MCP servers as data sources for supply chain data ingestion. Connect to supply chain database MCP servers via URL, ingest logistics data, inventory, and shipment information, then build a supply chain knowledge graph.\n",
    "\n",
    "**IMPORTANT**: This implementation supports ONLY Python-based MCP servers and FastMCP servers. Users can bring their own Python/FastMCP MCP servers via URL connections.\n",
    "\n",
    "\n",
    "**Documentation**: [API Reference](https://semantica.readthedocs.io/use-cases/)\n",
    "\n",
    "## Installation\n",
    "\n",
    "Install Semantica from PyPI:\n",
    "\n",
    "```bash\n",
    "pip install semantica\n",
    "# Or with all optional dependencies:\n",
    "pip install semantica[all]\n",
    "```\n",
    "\n",
    "### Modules Used (20+)\n",
    "\n",
    "- **Ingestion**: FileIngestor, WebIngestor, FeedIngestor, StreamIngestor, DBIngestor, EmailIngestor, RepoIngestor, MCPIngestor\n",
    "- **Parsing**: MCPParser, JSONParser, StructuredDataParser, CSVParser\n",
    "- **Extraction**: NERExtractor, RelationExtractor, EventDetector, TripleExtractor\n",
    "- **KG**: GraphBuilder, TemporalGraphQuery, GraphAnalyzer, ConnectivityAnalyzer\n",
    "- **Analytics**: CentralityCalculator, CommunityDetector, ConnectivityAnalyzer\n",
    "- **Reasoning**: InferenceEngine, RuleManager, ExplanationGenerator\n",
    "- **Export**: JSONExporter, CSVExporter, RDFExporter, ReportGenerator\n",
    "- **Visualization**: KGVisualizer, TemporalVisualizer, AnalyticsVisualizer\n",
    "\n",
    "### Pipeline\n",
    "\n",
    "**Connect to Supply Chain MCP Server → Ingest Logistics Data via MCP → Parse MCP Responses → Extract Supply Chain Entities → Build Supply Chain KG → Analyze Supply Chain → Generate Reports → Visualize**\n",
    "\n",
    "---\n",
    "\n",
    "## Step 1: Connect to Supply Chain Database MCP Server\n",
    "\n",
    "Connect to a Python/FastMCP MCP server that provides supply chain data via URL. The MCP server can expose resources (inventory databases, shipment records) and tools (logistics queries, inventory checks).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from semantica.ingest import MCPIngestor, ingest_mcp, DBIngestor, FileIngestor\n",
    "from semantica.parse import MCPParser, JSONParser, StructuredDataParser, CSVParser\n",
    "from semantica.semantic_extract import NERExtractor, RelationExtractor, EventDetector, TripleExtractor\n",
    "from semantica.kg import GraphBuilder, TemporalGraphQuery, GraphAnalyzer, ConnectivityAnalyzer\n",
    "from semantica.kg import CentralityCalculator, CommunityDetector\n",
    "from semantica.reasoning import InferenceEngine, RuleManager, ExplanationGenerator\n",
    "from semantica.export import JSONExporter, CSVExporter, RDFExporter, ReportGenerator\n",
    "from semantica.visualization import KGVisualizer, TemporalVisualizer, AnalyticsVisualizer\n",
    "import json\n",
    "from datetime import datetime, timedelta\n",
    "\n",
    "# Initialize MCP ingestor\n",
    "mcp_ingestor = MCPIngestor()\n",
    "\n",
    "# Connect to supply chain database MCP server via URL\n",
    "# Replace with your actual MCP server URL\n",
    "# Example: http://localhost:8000/mcp or https://api.example.com/supplychain-mcp\n",
    "supply_chain_mcp_url = \"http://localhost:8000/mcp\"\n",
    "\n",
    "# Connect to MCP server with authentication (if required)\n",
    "mcp_ingestor.connect(\n",
    "    \"supply_chain_server\",\n",
    "    url=supply_chain_mcp_url,\n",
    "    headers={\n",
    "        \"Authorization\": \"Bearer your_token\",\n",
    "        \"X-API-Key\": \"your_api_key\"\n",
    "    } if \"api.example.com\" in supply_chain_mcp_url else {}\n",
    ")\n",
    "\n",
    "# List available resources (inventory databases, shipment records)\n",
    "resources = mcp_ingestor.list_available_resources(\"supply_chain_server\")\n",
    "print(f\"\\n📊 Available Resources ({len(resources)}):\")\n",
    "for resource in resources[:5]:  # Show first 5\n",
    "    print(f\"  - {resource.uri}: {resource.name}\")\n",
    "    if resource.description:\n",
    "        print(f\"    {resource.description[:80]}...\")\n",
    "\n",
    "# List available tools (logistics queries, inventory checks)\n",
    "tools = mcp_ingestor.list_available_tools(\"supply_chain_server\")\n",
    "print(f\"\\n🔧 Available Tools ({len(tools)}):\")\n",
    "for tool in tools[:5]:  # Show first 5\n",
    "    print(f\"  - {tool.name}: {tool.description or 'No description'}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 2: Ingest Supply Chain Data from MCP Server\n",
    "\n",
    "Ingest logistics data, inventory, and shipment information using both resource-based and tool-based methods.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize parsers\n",
    "mcp_parser = MCPParser()\n",
    "json_parser = JSONParser()\n",
    "structured_parser = StructuredDataParser()\n",
    "csv_parser = CSVParser()\n",
    "\n",
    "supply_chain_data = []\n",
    "\n",
    "# Method 1: Resource-based ingestion\n",
    "# Ingest from MCP resources (inventory databases, shipment records)\n",
    "inventory_data = mcp_ingestor.ingest_resources(\n",
    "    \"supply_chain_server\",\n",
    "    resource_uris=[\"resource://inventory/database\", \"resource://shipments/records\"]\n",
    ")\n",
    "\n",
    "for item in inventory_data:\n",
    "    supply_chain_data.append(item)\n",
    "    print(f\"  Ingested resource: {item}\")\n",
    "\n",
    "# Method 2: Tool-based ingestion\n",
    "# Call MCP tools to retrieve data dynamically\n",
    "# Example: Query inventory levels\n",
    "inventory_levels = mcp_ingestor.ingest_tool_output(\n",
    "    \"supply_chain_server\",\n",
    "    tool_name=\"query_inventory\",\n",
    "    arguments={\n",
    "        \"warehouse_id\": \"WH001\",\n",
    "        \"product_category\": \"Electronics\"\n",
    "    }\n",
    ")\n",
    "\n",
    "if inventory_levels:\n",
    "    supply_chain_data.append(inventory_levels)\n",
    "    print(f\"  Retrieved inventory levels\")\n",
    "\n",
    "# Example: Get shipment status\n",
    "shipment_status = mcp_ingestor.ingest_tool_output(\n",
    "    \"supply_chain_server\",\n",
    "    tool_name=\"get_shipment_status\",\n",
    "    arguments={\n",
    "        \"shipment_id\": \"SH001\",\n",
    "        \"include_tracking\": True\n",
    "    }\n",
    ")\n",
    "\n",
    "if shipment_status:\n",
    "    supply_chain_data.append(shipment_status)\n",
    "    print(f\"  Retrieved shipment status\")\n",
    "\n",
    "# Sample supply chain data (if MCP server is not available)\n",
    "if not supply_chain_data:\n",
    "    sample_data = {\n",
    "        \"inventory\": [\n",
    "            {\n",
    "                \"warehouse_id\": \"WH001\",\n",
    "                \"product_id\": \"P001\",\n",
    "                \"product_name\": \"Laptop\",\n",
    "                \"quantity\": 150,\n",
    "                \"location\": \"Aisle 3, Shelf 2\",\n",
    "                \"last_updated\": (datetime.now() - timedelta(days=1)).isoformat()\n",
    "            },\n",
    "            {\n",
    "                \"warehouse_id\": \"WH001\",\n",
    "                \"product_id\": \"P002\",\n",
    "                \"product_name\": \"Mouse\",\n",
    "                \"quantity\": 500,\n",
    "                \"location\": \"Aisle 1, Shelf 5\",\n",
    "                \"last_updated\": (datetime.now() - timedelta(hours=12)).isoformat()\n",
    "            },\n",
    "            {\n",
    "                \"warehouse_id\": \"WH002\",\n",
    "                \"product_id\": \"P001\",\n",
    "                \"product_name\": \"Laptop\",\n",
    "                \"quantity\": 200,\n",
    "                \"location\": \"Aisle 2, Shelf 1\",\n",
    "                \"last_updated\": datetime.now().isoformat()\n",
    "            }\n",
    "        ],\n",
    "        \"shipments\": [\n",
    "            {\n",
    "                \"shipment_id\": \"SH001\",\n",
    "                \"origin\": \"WH001\",\n",
    "                \"destination\": \"WH002\",\n",
    "                \"product_id\": \"P001\",\n",
    "                \"quantity\": 50,\n",
    "                \"status\": \"in_transit\",\n",
    "                \"estimated_arrival\": (datetime.now() + timedelta(days=2)).isoformat(),\n",
    "                \"timestamp\": (datetime.now() - timedelta(days=1)).isoformat()\n",
    "            },\n",
    "            {\n",
    "                \"shipment_id\": \"SH002\",\n",
    "                \"origin\": \"WH002\",\n",
    "                \"destination\": \"Customer A\",\n",
    "                \"product_id\": \"P002\",\n",
    "                \"quantity\": 100,\n",
    "                \"status\": \"delivered\",\n",
    "                \"estimated_arrival\": (datetime.now() - timedelta(days=1)).isoformat(),\n",
    "                \"timestamp\": (datetime.now() - timedelta(days=3)).isoformat()\n",
    "            }\n",
    "        ]\n",
    "    }\n",
    "    supply_chain_data.append(sample_data)\n",
    "    print(f\"  Loaded {len(sample_data['inventory'])} inventory records\")\n",
    "    print(f\"  Loaded {len(sample_data['shipments'])} shipment records\")\n",
    "\n",
    "print(f\"\\n📊 Total supply chain data items ingested: {len(supply_chain_data)}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 3: Parse Supply Chain Data\n",
    "\n",
    "Parse the supply chain data received from MCP server responses.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "parsed_supply_chain_data = []\n",
    "\n",
    "# Parse MCP responses\n",
    "for data_item in supply_chain_data:\n",
    "    # Parse MCP response (handles JSON, text, binary)\n",
    "    if isinstance(data_item, dict):\n",
    "        parsed_item = data_item\n",
    "    else:\n",
    "        parsed_item = mcp_parser.parse_response(data_item, response_type=\"json\")\n",
    "    \n",
    "    parsed_supply_chain_data.append(parsed_item)\n",
    "    print(f\"  Parsed data item\")\n",
    "\n",
    "# Extract inventory and shipments\n",
    "inventory_records = []\n",
    "shipment_records = []\n",
    "\n",
    "for item in parsed_supply_chain_data:\n",
    "    if isinstance(item, dict):\n",
    "        if \"inventory\" in item:\n",
    "            inventory_records.extend(item[\"inventory\"])\n",
    "        elif \"warehouse_id\" in item and \"product_id\" in item:\n",
    "            inventory_records.append(item)\n",
    "        elif \"shipments\" in item:\n",
    "            shipment_records.extend(item[\"shipments\"])\n",
    "        elif \"shipment_id\" in item:\n",
    "            shipment_records.append(item)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 4: Extract Supply Chain Entities and Relationships\n",
    "\n",
    "Extract supply chain entities (warehouses, products, shipments, locations) and relationships from MCP data.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ner_extractor = NERExtractor()\n",
    "relation_extractor = RelationExtractor()\n",
    "event_detector = EventDetector()\n",
    "triple_extractor = TripleExtractor()\n",
    "\n",
    "supply_chain_entities = []\n",
    "supply_chain_relationships = []\n",
    "\n",
    "# Extract from inventory records\n",
    "for inventory in inventory_records:\n",
    "    if isinstance(inventory, dict):\n",
    "        warehouse_id = inventory.get(\"warehouse_id\", \"\")\n",
    "        product_id = inventory.get(\"product_id\", \"\")\n",
    "        product_name = inventory.get(\"product_name\", \"\")\n",
    "        location = inventory.get(\"location\", \"\")\n",
    "        \n",
    "        # Warehouse entity\n",
    "        supply_chain_entities.append({\n",
    "            \"id\": warehouse_id,\n",
    "            \"type\": \"Warehouse\",\n",
    "            \"name\": warehouse_id,\n",
    "            \"properties\": {}\n",
    "        })\n",
    "        \n",
    "        # Product entity\n",
    "        supply_chain_entities.append({\n",
    "            \"id\": product_id,\n",
    "            \"type\": \"Product\",\n",
    "            \"name\": product_name or product_id,\n",
    "            \"properties\": {}\n",
    "        })\n",
    "        \n",
    "        # Warehouse-Product relationship (inventory)\n",
    "        supply_chain_relationships.append({\n",
    "            \"source\": warehouse_id,\n",
    "            \"target\": product_id,\n",
    "            \"type\": \"stocks\",\n",
    "            \"properties\": {\n",
    "                \"quantity\": inventory.get(\"quantity\", 0),\n",
    "                \"location\": location,\n",
    "                \"last_updated\": inventory.get(\"last_updated\", \"\")\n",
    "            }\n",
    "        })\n",
    "\n",
    "# Extract from shipment records\n",
    "for shipment in shipment_records:\n",
    "    if isinstance(shipment, dict):\n",
    "        shipment_id = shipment.get(\"shipment_id\", \"\")\n",
    "        origin = shipment.get(\"origin\", \"\")\n",
    "        destination = shipment.get(\"destination\", \"\")\n",
    "        product_id = shipment.get(\"product_id\", \"\")\n",
    "        \n",
    "        # Shipment entity\n",
    "        supply_chain_entities.append({\n",
    "            \"id\": shipment_id,\n",
    "            \"type\": \"Shipment\",\n",
    "            \"name\": shipment_id,\n",
    "            \"properties\": {\n",
    "                \"status\": shipment.get(\"status\", \"\"),\n",
    "                \"quantity\": shipment.get(\"quantity\", 0),\n",
    "                \"estimated_arrival\": shipment.get(\"estimated_arrival\", \"\"),\n",
    "                \"timestamp\": shipment.get(\"timestamp\", \"\")\n",
    "            }\n",
    "        })\n",
    "        \n",
    "        # Origin-Destination relationships\n",
    "        if origin:\n",
    "            supply_chain_relationships.append({\n",
    "                \"source\": origin,\n",
    "                \"target\": shipment_id,\n",
    "                \"type\": \"ships_from\",\n",
    "                \"properties\": {\"timestamp\": shipment.get(\"timestamp\", \"\")}\n",
    "            })\n",
    "        \n",
    "        if destination:\n",
    "            supply_chain_relationships.append({\n",
    "                \"source\": shipment_id,\n",
    "                \"target\": destination,\n",
    "                \"type\": \"ships_to\",\n",
    "                \"properties\": {\"timestamp\": shipment.get(\"timestamp\", \"\")}\n",
    "            })\n",
    "        \n",
    "        # Shipment-Product relationship\n",
    "        if product_id:\n",
    "            supply_chain_relationships.append({\n",
    "                \"source\": shipment_id,\n",
    "                \"target\": product_id,\n",
    "                \"type\": \"contains\",\n",
    "                \"properties\": {\"quantity\": shipment.get(\"quantity\", 0)}\n",
    "            })\n",
    "\n",
    "# Remove duplicates\n",
    "seen_entities = set()\n",
    "unique_entities = []\n",
    "for entity in supply_chain_entities:\n",
    "    entity_key = (entity[\"id\"], entity[\"type\"])\n",
    "    if entity_key not in seen_entities:\n",
    "        seen_entities.add(entity_key)\n",
    "        unique_entities.append(entity)\n",
    "\n",
    "supply_chain_entities = unique_entities\n",
    "\n",
    "print(f\"  - Warehouses: {len([e for e in supply_chain_entities if e['type'] == 'Warehouse'])}\")\n",
    "print(f\"  - Products: {len([e for e in supply_chain_entities if e['type'] == 'Product'])}\")\n",
    "print(f\"  - Shipments: {len([e for e in supply_chain_entities if e['type'] == 'Shipment'])}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 5: Build Supply Chain Knowledge Graph\n",
    "\n",
    "Build a knowledge graph from the extracted supply chain entities and relationships.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "builder = GraphBuilder()\n",
    "temporal_query = TemporalGraphQuery()\n",
    "graph_analyzer = GraphAnalyzer()\n",
    "connectivity_analyzer = ConnectivityAnalyzer()\n",
    "\n",
    "# Build knowledge graph\n",
    "supply_chain_kg = builder.build(supply_chain_entities, supply_chain_relationships)\n",
    "\n",
    "# Analyze graph structure\n",
    "metrics = graph_analyzer.compute_metrics(supply_chain_kg)\n",
    "centrality_calculator = CentralityCalculator()\n",
    "community_detector = CommunityDetector()\n",
    "connectivity = connectivity_analyzer.analyze_connectivity(supply_chain_kg)\n",
    "\n",
    "# Calculate graph metrics\n",
    "centrality_result = centrality_calculator.calculate_degree_centrality(supply_chain_kg)\n",
    "centrality_scores = centrality_result.get('centrality', {})\n",
    "communities = community_detector.detect_communities(supply_chain_kg)\n",
    "\n",
    "print(f\"  Entities: {len(supply_chain_kg.get('entities', []))}\")\n",
    "print(f\"  Relationships: {len(supply_chain_kg.get('relationships', []))}\")\n",
    "print(f\"  Graph density: {metrics.get('density', 0):.3f}\")\n",
    "print(f\"  Communities detected: {len(communities)}\")\n",
    "print(f\"  Connected components: {connectivity.get('connected_components', 0)}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 6: Analyze Supply Chain\n",
    "\n",
    "Analyze supply chain patterns using temporal queries and inference rules.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Temporal analysis\n",
    "start_time = (datetime.now() - timedelta(days=30)).isoformat()\n",
    "end_time = datetime.now().isoformat()\n",
    "\n",
    "temporal_results = temporal_query.query_time_range(\n",
    "    graph=supply_chain_kg,\n",
    "    query=\"Find shipments in the last 30 days\",\n",
    "    start_time=start_time,\n",
    "    end_time=end_time\n",
    ")\n",
    "\n",
    "# Inference engine for supply chain rules\n",
    "inference_engine = InferenceEngine()\n",
    "rule_manager = RuleManager()\n",
    "explanation_generator = ExplanationGenerator()\n",
    "\n",
    "# Supply chain analysis rules\n",
    "inference_engine.add_rule(\"IF quantity < 100 AND product_type(Electronics) THEN low_stock_alert\")\n",
    "inference_engine.add_rule(\"IF status(in_transit) AND days_since_shipment > 5 THEN delayed_shipment\")\n",
    "inference_engine.add_rule(\"IF stocks(Warehouse, Product) AND quantity > 500 THEN high_inventory\")\n",
    "\n",
    "# Add facts from supply chain data\n",
    "for inventory in inventory_records:\n",
    "    if isinstance(inventory, dict):\n",
    "        inference_engine.add_fact({\n",
    "            \"warehouse\": inventory.get(\"warehouse_id\", \"\"),\n",
    "            \"product\": inventory.get(\"product_id\", \"\"),\n",
    "            \"quantity\": inventory.get(\"quantity\", 0),\n",
    "            \"product_name\": inventory.get(\"product_name\", \"\")\n",
    "        })\n",
    "\n",
    "for shipment in shipment_records:\n",
    "    if isinstance(shipment, dict):\n",
    "        days_since = (datetime.now() - datetime.fromisoformat(shipment.get(\"timestamp\", datetime.now().isoformat()))).days\n",
    "        inference_engine.add_fact({\n",
    "            \"shipment_id\": shipment.get(\"shipment_id\", \"\"),\n",
    "            \"status\": shipment.get(\"status\", \"\"),\n",
    "            \"days_since_shipment\": days_since\n",
    "        })\n",
    "\n",
    "# Generate supply chain insights\n",
    "supply_chain_insights = inference_engine.forward_chain()\n",
    "\n",
    "print(f\"  Temporal entities: {len(temporal_results.get('entities', []))}\")\n",
    "print(f\"  Supply chain insights: {len(supply_chain_insights)}\")\n",
    "\n",
    "# Display insights\n",
    "for insight in supply_chain_insights[:3]:\n",
    "    print(f\"  - {insight}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 7: Export and Visualize\n",
    "\n",
    "Export the supply chain knowledge graph and generate visualizations.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tempfile\n",
    "import os\n",
    "\n",
    "temp_dir = tempfile.mkdtemp()\n",
    "\n",
    "json_exporter = JSONExporter()\n",
    "csv_exporter = CSVExporter()\n",
    "rdf_exporter = RDFExporter()\n",
    "report_generator = ReportGenerator()\n",
    "\n",
    "# Export knowledge graph\n",
    "json_exporter.export_knowledge_graph(supply_chain_kg, os.path.join(temp_dir, \"supply_chain_kg.json\"))\n",
    "csv_exporter.export_entities(supply_chain_entities, os.path.join(temp_dir, \"supply_chain_entities.csv\"))\n",
    "rdf_exporter.export_knowledge_graph(supply_chain_kg, os.path.join(temp_dir, \"supply_chain_kg.rdf\"))\n",
    "\n",
    "# Generate report\n",
    "report_data = {\n",
    "    \"summary\": f\"Supply chain data integration from MCP server identified {len(supply_chain_insights)} insights\",\n",
    "    \"warehouses\": len([e for e in supply_chain_entities if e['type'] == 'Warehouse']),\n",
    "    \"products\": len([e for e in supply_chain_entities if e['type'] == 'Product']),\n",
    "    \"shipments\": len([e for e in supply_chain_entities if e['type'] == 'Shipment']),\n",
    "    \"inventory_records\": len(inventory_records),\n",
    "    \"insights\": len(supply_chain_insights)\n",
    "}\n",
    "\n",
    "report = report_generator.generate_report(report_data, format=\"markdown\")\n",
    "\n",
    "print(f\"  JSON: {os.path.join(temp_dir, 'supply_chain_kg.json')}\")\n",
    "print(f\"  CSV: {os.path.join(temp_dir, 'supply_chain_entities.csv')}\")\n",
    "print(f\"  RDF: {os.path.join(temp_dir, 'supply_chain_kg.rdf')}\")\n",
    "\n",
    "# Visualize\n",
    "kg_visualizer = KGVisualizer()\n",
    "temporal_visualizer = TemporalVisualizer()\n",
    "analytics_visualizer = AnalyticsVisualizer()\n",
    "\n",
    "kg_viz = kg_visualizer.visualize_network(supply_chain_kg, output=\"interactive\")\n",
    "temporal_viz = temporal_visualizer.visualize_timeline(supply_chain_kg, output=\"interactive\")\n",
    "analytics_viz = analytics_visualizer.visualize_analytics(supply_chain_kg, output=\"interactive\")\n",
    "\n",
    "\n",
    "# Cleanup: Disconnect from MCP server\n",
    "mcp_ingestor.disconnect(\"supply_chain_server\")\n",
    "print(\"  Disconnected from MCP server\")\n",
    "\n",
    "print(f\"📊 Total modules used: 20+\")\n"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}