feat: expand MCP server functionality with customer, catalogue, marketing, and user tools and integrate new health indicators and configuration models.
This commit is contained in:
170
ARCHITECTURE.md
Normal file
170
ARCHITECTURE.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# Architecture — Loyalty Agent Service
|
||||
|
||||
## System Overview
|
||||
|
||||
AI-powered assistant for managing a Loyalty Platform, built on the **Model Context Protocol (MCP)**.
|
||||
|
||||
```text
|
||||
┌──────────────────┐
|
||||
│ React/Vite UI │
|
||||
│ :9333 │
|
||||
└────────┬─────────┘
|
||||
│ WebSocket / STOMP
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Loyalty Agent │
|
||||
│ :9332 │
|
||||
│ │
|
||||
│ LLM Orchestrator │
|
||||
│ MCP Client │
|
||||
│ Conversation │
|
||||
│ PostgreSQL │
|
||||
└────────┬─────────┘
|
||||
│ MCP SSE (/sse, /message)
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Loyalty MCP │
|
||||
│ Server :9331 │
|
||||
│ │
|
||||
│ 25+ MCP Tools │
|
||||
└────────┬─────────┘
|
||||
│ REST + OAuth2 (Client Credentials)
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Loyalty Core API │
|
||||
│ :8081 │
|
||||
└──────────────────┘
|
||||
|
||||
Keycloak ────── OAuth2 Token Provider
|
||||
PostgreSQL ──── Conversation Persistence
|
||||
Ollama ──────── Local LLM (Qwen3.5:4b)
|
||||
```
|
||||
|
||||
## Technology Stack
|
||||
|
||||
| Technology | Version | Purpose |
|
||||
|----------------|---------|----------------------------|
|
||||
| Java | 25 | Runtime |
|
||||
| Spring Boot | 4.0.0 | Framework |
|
||||
| Spring AI | 2.0.0 | LLM & MCP integration |
|
||||
| Ollama | latest | Local LLM hosting |
|
||||
| Qwen | 3.5:4b | Primary LLM model |
|
||||
| PostgreSQL | 15+ | Conversation persistence |
|
||||
| Keycloak | latest | OAuth2/OIDC provider |
|
||||
| React + Vite | 19/6 | Frontend UI |
|
||||
|
||||
## Module Architecture
|
||||
|
||||
### loyalty-mcp-server (`:9331`)
|
||||
|
||||
MCP Server exposing Loyalty Platform capabilities as MCP tools via SSE transport.
|
||||
|
||||
**Responsibilities:**
|
||||
- Register 25+ MCP tools (campaign, rule, customer, transaction, etc.)
|
||||
- Validate tool inputs
|
||||
- Proxy requests to Loyalty Core API with OAuth2 client credentials
|
||||
- Return structured `Result<T>` with agent instructions for LLM formatting
|
||||
- Handle errors (sanitize stack traces, structured error responses)
|
||||
|
||||
**Key Classes:**
|
||||
- `CampaignTools` / `CampaignRuleTools` — Primary tool registration
|
||||
- `CampaignService` / `CampaignRuleService` — Business logic
|
||||
- `RestClientConfig` — OAuth2 REST client factory
|
||||
- `Result<T>` — Standard response wrapper with `_agent_instruction`
|
||||
|
||||
### loyalty-agent (`:9332`)
|
||||
|
||||
AI Agent / BFF — Orchestrates LLM, MCP, conversations, and WebSocket.
|
||||
|
||||
**Responsibilities:**
|
||||
- Accept user messages via WebSocket/STOMP
|
||||
- Classify intent (regex-based, zero LLM latency)
|
||||
- Route to appropriate executor (SimpleAgent, Workflow, DirectChat)
|
||||
- Stream LLM responses back to frontend
|
||||
- Persist conversations to PostgreSQL
|
||||
|
||||
**Key Architecture:**
|
||||
|
||||
```text
|
||||
AgentController (@MessageMapping /chat)
|
||||
↓
|
||||
LoyaltyAgentService
|
||||
↓
|
||||
AgentOrchestrator
|
||||
├── Active Workflow? → WorkflowExecutor (multi-turn creation)
|
||||
├── IntentClassifier → QUERY → SimpleAgentExecutor (ReAct + tools)
|
||||
├── IntentClassifier → CONVERSATION → SimpleAgentExecutor (direct chat)
|
||||
└── IntentClassifier → CREATE_* → WorkflowExecutor
|
||||
```
|
||||
|
||||
**Intent Classification (regex-based):**
|
||||
|
||||
| Intent | Trigger Examples |
|
||||
|--------|-----------------|
|
||||
| `QUERY` | "tìm chiến dịch", "danh sách rule" |
|
||||
| `CONVERSATION` | "xin chào", "cảm ơn" |
|
||||
| `CREATE_CAMPAIGN` | "tạo chiến dịch mới" |
|
||||
| `CREATE_RULE` | "thêm thể lệ" |
|
||||
|
||||
**Tool Scope Enforcement:**
|
||||
|
||||
| Scope | Allowed Operations |
|
||||
|-------|-------------------|
|
||||
| `READ_ONLY` | search, get, find, count, check |
|
||||
| `CREATE_CAMPAIGN` | READ_ONLY + createCampaign + generateCampaignId |
|
||||
| `CREATE_RULE` | READ_ONLY + createRule + generateRuleId |
|
||||
|
||||
### Frontend (`:9333`)
|
||||
|
||||
React/Vite conversational UI with STOMP WebSocket.
|
||||
|
||||
**Key Features:**
|
||||
- STOMP over WebSocket for real-time messaging
|
||||
- Token streaming (character-by-character LLM output)
|
||||
- Tool execution status indicators
|
||||
- Conversation management (create, list, delete, rename)
|
||||
- Offline message queue with exponential backoff reconnect
|
||||
|
||||
## Security Architecture
|
||||
|
||||
```text
|
||||
Frontend ──(WebSocket)──> Agent ──(MCP SSE)──> MCP Server ──(OAuth2)──> Core API
|
||||
│
|
||||
▼
|
||||
Keycloak
|
||||
```
|
||||
|
||||
**Principles:**
|
||||
1. **LLM is never an authorization boundary** — tool scope is enforced by `AgentToolScope` before tools reach the LLM
|
||||
2. **OAuth2 Client Credentials** — MCP Server authenticates to Core API via Keycloak
|
||||
3. **Tool result sanitization** — `ToolInterceptor` strips Java stack traces
|
||||
4. **Input validation** — All tool parameters validated before downstream calls
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Chat Request Flow
|
||||
|
||||
```text
|
||||
1. User types message in React UI
|
||||
2. STOMP message → /app/chat → AgentController
|
||||
3. AgentController → LoyaltyAgentService.chat()
|
||||
4. AgentOrchestrator classifies intent
|
||||
5. Executor starts LLM streaming with tools
|
||||
6. LLM selects tool → ToolInterceptor wraps & calls MCP
|
||||
7. MCP Server executes tool → calls Core API
|
||||
8. Tool result → LLM reasons → generates response
|
||||
9. Response streamed back via STOMP → /user/queue/chat-events
|
||||
10. React UI renders tokens in real-time
|
||||
```
|
||||
|
||||
## Resilience Patterns
|
||||
|
||||
| Pattern | Implementation |
|
||||
|---------|---------------|
|
||||
| MCP auto-reconnect | `ToolInterceptor.attemptReconnect()` |
|
||||
| WebSocket reconnect | `StompService` exponential backoff + jitter |
|
||||
| Request timeout | `SimpleAgentExecutor` configurable via `agent.request-timeout-seconds` |
|
||||
| Tool result truncation | `ToolInterceptor` caps results > 4000 chars |
|
||||
| Error sanitization | `ToolInterceptor` strips stack traces |
|
||||
| Graceful shutdown | `server.shutdown: graceful` on both modules |
|
||||
| LLM search noise filtering | `SearchUtils.sanitizeSearch()` |
|
||||
Reference in New Issue
Block a user