Skip to main content
Glama
README.md
# DHL Ops Copilot - MCP + ADK Edition

A re-architected version of [DHL Ops Copilot](https://github.com/az-cod/DHL_OPS_COPILOT), migrating the original custom function-calling tool layer to the **Model Context Protocol (FastMCP)** and rebuilding multi-agent orchestration on Google's **Agent Development Kit (ADK)**.

---

## What Changed From The Original

| Component | Original Version | MCP + ADK Edition | Why It Matters |
|---|---|---|---|
| **Tool Layer** | Custom dict-based JSON schemas & manual dispatch function | Standardized Model Context Protocol (`FastMCP 4.0`) | Decouples tools from any single LLM or client; standard MCP clients (Claude Desktop, ADK, Cursor) can inspect & consume tools without custom code. |
| **Agent Orchestration** | Manual while-loop and chat completion message passing | Google ADK (`LlmAgent` + `SequentialAgent`) | Native pipeline orchestration with structured state passing and pipeline inspection. |
| **LLM Provider & Model** | Groq (`llama-3.3-70b-versatile`) | Google Gemini (`gemini-3.6-flash`) | Leverages Google AI Studio free-tier quotas and structured tool calling. |
| **Transport Protocol** | In-process Python imports | Dual-mode: Local `stdio` & Remote `streamable-http` | Runs locally via stdio with zero network overhead, and deploys to cloud hosting via Streamable HTTP. |

---

## What Stayed The Same (Core Provenance)

1. **Deterministic ID-Pattern Fallback**:
   - `SHP-xxxx`: Normalizes numeric inputs (e.g. `2044` -> `SHP-2044`) and matches shipment tracking records with hub status and ETA.
   - `SO-xxxxx`: Normalizes SAP order numbers (e.g. `88213` -> `SO-88213`) and reports sync status and errors (`MATERIAL_MASTER_NOT_FOUND`, `DUPLICATE_ORDER_REFERENCE`).
   - `INCxxxx`: Normalizes ServiceNow ticket IDs (e.g. `43` -> `INC0043`) or performs substring matching across issue descriptions.
   - Malformed/garbage IDs gracefully trigger deterministic fallback dictionaries without throwing unhandled exceptions.
2. **SQLite Audit Trail**:
   - Every tool execution logs an immutable record to `mcp_server/audit.db` (`id`, `ts`, `tool`, `query`, `result_status`).
   - Note on Render free tier: The free tier filesystem is ephemeral, meaning `audit.db` resets on container redeploy. For persistent enterprise audit logs, configure a managed SQLite/PostgreSQL mount.
3. **Investigator / Synthesis Hallucination-Constraint Pattern**:
   - **Investigator Agent**: Prohibited from answering the user directly; strictly tasked with calling tools and outputting evidence into `{evidence}`.
   - **Synthesizer Agent**: Strictly constrained to `{evidence}`, requiring inline citations and refusing ungrounded claims.

---

## MCP Tools Description and Details

The FastMCP server (`mcp_server/server.py`) standardizes operational data access across three core enterprise systems plus internal procedural runbooks.

### 1. Shipment Tracking Tool: `get_shipment_status`

Look up live shipment tracking details by tracking identifier.

- **Signature**: `get_shipment_status(tracking_id: str) -> Dict[str, Any]`
- **Input Parameters**:
  - `tracking_id` (string, required): Tracking code formatted as `SHP-xxxx` (e.g. `SHP-2044`, `SHP-3311`) or numeric digits (e.g. `2044`).
- **Return Shape**:
  ```json
  {
    "shipment_id": "SHP-2044",
    "found": true,
    "status": "In transit",
    "current_hub": "Frankfurt Hub",
    "eta": "2026-09-13",
    "note": "On schedule.",
    "source": "simulated shipment tracking system"
  }
  ```
- **Fallback Behavior**: Malformed IDs or missing records return `{"shipment_id": "...", "found": false, "status": "not_found", "fallback_applied": true}` without raising exceptions.
- **Audit Trace**: Logs tool name, tracking ID query, and status to `mcp_server/audit.db`.

---

### 2. SAP Order Backend Tool: `get_sap_order`

Retrieve enterprise sales order sync status and backend error codes from SAP.

- **Signature**: `get_sap_order(order_id: str) -> Dict[str, Any]`
- **Input Parameters**:
  - `order_id` (string, required): SAP order code formatted as `SO-xxxxx` (e.g. `SO-88213`, `SO-90144`) or numeric digits (e.g. `88213`).
- **Return Shape**:
  ```json
  {
    "order_id": "SO-88213",
    "found": true,
    "status": "Sync failed",
    "error_code": "MATERIAL_MASTER_NOT_FOUND",
    "order_value_usd": 4210.00,
    "note": "SKU replication pending.",
    "source": "simulated SAP backend"
  }
  ```
- **Fallback Behavior**: Malformed IDs return `{"order_id": "...", "found": false, "status": "not_found", "fallback_applied": true}`.
- **Audit Trace**: Logs tool name, order ID query, and status to `mcp_server/audit.db`.

---

### 3. ServiceNow Ticket Tool: `get_servicenow_ticket`

Look up IT support incident tickets by exact identifier or search by issue keyword.

- **Signature**: `get_servicenow_ticket(ticket_id: str) -> Dict[str, Any]`
- **Input Parameters**:
  - `ticket_id` (string, required): Ticket identifier (e.g. `INC0043`, `43`) or search query (e.g. `VPN`, `sync`).
- **Return Shape (Exact Match)**:
  ```json
  {
    "ticket_id": "INC0043",
    "found": true,
    "priority": "P2",
    "status": "In Progress",
    "description": "SAP order sync failures reported by 6 regional support agents, multiple orders showing MATERIAL_MASTER_NOT_FOUND.",
    "source": "simulated ServiceNow instance"
  }
  ```
- **Return Shape (Keyword Match)**:
  ```json
  {
    "query": "VPN",
    "found": true,
    "status": "matches_found",
    "matches": [
      {
        "ticket_id": "INC0091",
        "priority": "P3",
        "status": "Open",
        "description": "Single user unable to connect to VPN, certificate appears expired."
      }
    ],
    "source": "simulated ServiceNow instance"
  }
  ```
- **Audit Trace**: Logs tool name, ticket ID or query string, and status to `mcp_server/audit.db`.

---

### 4. Standard Operating Procedures Tool: `retrieve_sop`

Search internal knowledge base runbooks, escalation policies, and procedures.

- **Signature**: `retrieve_sop(query: str) -> Dict[str, Any]`
- **Input Parameters**:
  - `query` (string, required): Natural language search terms (e.g. `VPN expired certificate`, `SAP sync error`, `customs hold`).
- **Return Shape**:
  ```json
  {
    "query": "VPN expired certificate",
    "found": true,
    "status": "found",
    "results": [
      {
        "id": "SOP-VPN-01",
        "title": "VPN Access Troubleshooting",
        "text": "If user cannot connect to VPN: 1. Confirm AD account active. 2. Check VPN cert validity..."
      }
    ],
    "source": "internal knowledge base"
  }
  ```
- **Audit Trace**: Logs tool name, search query, and status to `mcp_server/audit.db`.

---

## How To Use In The Frontend

### Option A: Google ADK Web UI (Built-In Browser Interface)

The primary frontend interface is powered by Google ADK Web, providing a full chat window with real-time tool execution tracking.

#### Step 1: Start the Web UI Server

```bash
adk web agent --port 8085
```

#### Step 2: Open In Browser

Navigate to:
```
http://127.0.0.1:8085
```

#### Step 3: Select Agent & Start Session

1. On the left navigation pane, select **`agent`** (or the loaded application).
2. Click **New Session** to open a fresh chat workspace.

#### Step 4: Interact With Operational Queries

Type natural-language requests into the chat input:

- **Single System Query**:
  `What is the current status and location of shipment SHP-2044?`
  The `investigator` agent automatically calls `get_shipment_status("SHP-2044")`, and the `synthesizer` outputs the grounded status with inline citation `[get_shipment_status]`.

- **Multi-System Correlation**:
  `Check SAP order SO-88213 and ServiceNow ticket INC0043.`
  The pipeline executes parallel lookups for both systems, detects the `MATERIAL_MASTER_NOT_FOUND` error, automatically retrieves runbook `SOP-SAPSYNC-04`, and presents a structured incident brief.

- **Keyword Search**:
  `Are there any active tickets regarding VPN access issues?`
  The pipeline calls `get_servicenow_ticket("VPN")` and returns matching open incidents.

- **Runbook Procedures**:
  `What is our policy for shipments delayed on customs hold?`
  The pipeline queries `retrieve_sop("customs hold")` and summarizes `SOP-CUSTOMSHOLD-06`.

- **Malformed ID Handling**:
  `Look up shipment SHP-INVALID-999.`
  The pipeline gracefully reports that no records were found without crashing.

#### Step 5: Inspect Evidence & Tool Traces

In the ADK Web UI:
- Click on the intermediate execution steps to view raw JSON outputs returned by FastMCP tools.
- Expand the `{evidence}` dictionary to inspect the exact payload passed from the `investigator` to the `synthesizer`.

---

### Option B: Claude Desktop / Cursor (Standard MCP Client)

Because the tool layer uses standard FastMCP, any MCP-compliant frontend can connect to `mcp_server/server.py`.

#### Stdio Connection (Local)

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "dhl-ops-tools": {
      "command": "python",
      "args": ["/absolute/path/to/dhl-ops-mcp/mcp_server/server.py"]
    }
  }
}
```

#### Streamable HTTP Connection (Remote / Render)

When hosted on Render:

```json
{
  "mcpServers": {
    "dhl-ops-tools": {
      "url": "https://dhl-ops-mcp-server.onrender.com/mcp"
    }
  }
}
```

---

## Repository Structure

```
dhl-ops-mcp/
|-- mcp_server/
|   |-- __init__.py
|   |-- server.py
|   |-- audit.py
|   |-- fallback.py
|   \-- audit.db
|-- agent/
|   |-- __init__.py
|   |-- agent.py
|   |-- .env.example
|   \-- .env
|-- tests/
|   |-- __init__.py
|   |-- test_mcp_server.py
|   \-- test_e2e.py
|-- .env.example
|-- pyproject.toml
|-- requirements.txt
|-- render.yaml
\-- README.md
```

---

## Setup & Local Development

### 1. Installation

```bash
git clone https://github.com/az-cod/DHL_OPS_COPILOT.git dhl-ops-mcp
cd dhl-ops-mcp
git checkout mcp-adk-migration

python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
```

### 2. Configure Environment

Create `agent/.env` (from `agent/.env.example`):

```ini
GOOGLE_API_KEY=your_gemini_api_key_from_ai_studio
GOOGLE_GENAI_USE_VERTEXAI=FALSE
ADK_DEFAULT_MODEL=gemini-3.6-flash
```

### 3. Test MCP Server in Isolation

Run the test suite or launch FastMCP inspector:

```bash
pytest tests/ -v
fastmcp dev mcp_server/server.py
```

### 4. Run ADK Agent Locally

Launch the ADK web chat interface:

```bash
adk web agent --port 8085
```

---

## Deployment (Render Free Tier)

Deploying as two independent microservices on Render:

1. **`dhl-ops-mcp-server`**:
   - Runtime: Python
   - Build command: `pip install -r requirements.txt`
   - Start command: `python mcp_server/server.py`
   - Env vars:
     - `PORT`: `8080`
     - `MCP_TRANSPORT`: `streamable-http`
2. **`dhl-ops-adk-agent`**:
   - Runtime: Python
   - Build command: `pip install -r requirements.txt`
   - Start command: `adk web agent --host 0.0.0.0 --port 10000`
   - Env vars:
     - `GOOGLE_API_KEY`: *(Set securely in Render Dashboard)*
     - `MCP_SERVER_URL`: `https://dhl-ops-mcp-server.onrender.com/mcp`

Both services are pre-configured in [`render.yaml`](render.yaml) for one-click deployment via Render Blueprints.

Maintenance

ActivityMaintained
ResponsivenessNo issues