docs(GOO-33): comprehensive documentation sprint
Create/update all Sprint 6 documentation: - CHANGELOG.md: document GOO-33 and recent audit findings - CONTRIBUTING.md: add branching, PR, commit conventions - docs/ci-cd.md: GitHub Actions pipeline documentation - docs/onboarding.md: developer setup & onboarding guide - docs/mcp-servers.md: MCP servers API documentation - docs/PROJECT_TRACKER.md: mark GOO-33 as in_progress - docs/QA_TRACKER.md: test status and verification plans Curate audit reports (reduce ~103 → 12 canonical files): - Keep canonical audit reports with descriptive index - Archive obsolete/duplicate audit exploration files Acceptance Criteria: - [x] QA_TRACKER.md exists with current test status - [x] CHANGELOG.md updated to today - [x] PROJECT_TRACKER.md reflects current sprint status - [x] CI/CD pipeline documented - [x] CONTRIBUTING.md has branching, PR, commit conventions - [x] docs/audits/ reduced to canonical reports Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
600
docs/mcp-servers.md
Normal file
600
docs/mcp-servers.md
Normal file
@@ -0,0 +1,600 @@
|
||||
# MCP Servers Documentation
|
||||
|
||||
GoodGo Platform sử dụng **Model Context Protocol (MCP)** để cấp quyền truy cập các công cụ chuyên dụng cho Claude AI. Ba MCP servers chính cung cấp khả năng **tìm kiếm bất động sản**, **phân tích thị trường**, và **định giá tự động (AVM)**.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
| Server | Port | Tools | Purpose |
|
||||
|--------|------|-------|---------|
|
||||
| **Property Search** | 3001 | `search_properties`, `compare_properties`, `get_property_details` | Tìm kiếm bất động sản, so sánh, chi tiết |
|
||||
| **Market Analytics** | 3001 | `get_market_report`, `analyze_trends`, `get_price_indices` | Phân tích thị trường, xu hướng giá |
|
||||
| **Valuation** | 3001 | `estimate_valuation`, `extract_features`, `compare_valuations` | Định giá BĐS, so sánh XGBoost |
|
||||
|
||||
**Architecture:**
|
||||
- All MCP servers are **in-process** (không tách microservice cho MVP)
|
||||
- Chạy cùng process NestJS API
|
||||
- HTTP transport dùng `/mcp/tools/*` endpoint
|
||||
- Claude API calls `POST /mcp/tools/{toolName}` để invoke tools
|
||||
|
||||
---
|
||||
|
||||
## 1. Property Search Server
|
||||
|
||||
### Purpose
|
||||
|
||||
Cung cấp công cụ tìm kiếm bất động sản với:
|
||||
- Full-text search (Typesense)
|
||||
- Geo-spatial search (PostGIS)
|
||||
- Faceted filtering (giá, loại, phòng ngủ, quận huyện)
|
||||
|
||||
### Tools
|
||||
|
||||
#### `search_properties`
|
||||
|
||||
Tìm kiếm bất động sản với nhiều tiêu chí.
|
||||
|
||||
**Input Schema:**
|
||||
```json
|
||||
{
|
||||
"query": "chung cư quận 1",
|
||||
"filters": {
|
||||
"priceMin": 1000000000,
|
||||
"priceMax": 5000000000,
|
||||
"bedrooms": 2,
|
||||
"district": "Quận 1",
|
||||
"propertyType": "APARTMENT"
|
||||
},
|
||||
"sort": "price_asc",
|
||||
"limit": 10,
|
||||
"offset": 0
|
||||
}
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
| Param | Type | Required | Default | Notes |
|
||||
|-------|------|----------|---------|-------|
|
||||
| `query` | string | Yes | - | Tìm kiếm từ khóa (tiêu đề, mô tả) |
|
||||
| `filters.priceMin` | number | No | 0 | Giá tối thiểu (VND) |
|
||||
| `filters.priceMax` | number | No | ∞ | Giá tối đa (VND) |
|
||||
| `filters.bedrooms` | number | No | - | Số phòng ngủ |
|
||||
| `filters.district` | string | No | - | Quận huyện |
|
||||
| `filters.propertyType` | enum | No | - | APARTMENT, HOUSE, LAND, ROOM_RENTAL |
|
||||
| `sort` | enum | No | `relevance` | `price_asc`, `price_desc`, `newest`, `relevance` |
|
||||
| `limit` | number | No | 20 | Số kết quả (1-100) |
|
||||
| `offset` | number | No | 0 | Phân trang offset |
|
||||
|
||||
**Output Example:**
|
||||
```json
|
||||
{
|
||||
"total": 245,
|
||||
"results": [
|
||||
{
|
||||
"id": "prop-001",
|
||||
"title": "Căn hộ 2PN view sông Sài Gòn",
|
||||
"type": "APARTMENT",
|
||||
"price": 3500000000,
|
||||
"bedrooms": 2,
|
||||
"bathrooms": 2,
|
||||
"area": 85,
|
||||
"district": "Quận 1",
|
||||
"ward": "Phường Bến Nghé",
|
||||
"address": "123 Tôn Đức Thắng, Q.1",
|
||||
"agentName": "Nguyễn Văn A",
|
||||
"agentPhone": "0987654321",
|
||||
"status": "ACTIVE",
|
||||
"createdAt": "2026-04-20T10:30:00Z"
|
||||
}
|
||||
],
|
||||
"facets": {
|
||||
"districts": [
|
||||
{ "name": "Quận 1", "count": 42 },
|
||||
{ "name": "Quận 3", "count": 38 }
|
||||
],
|
||||
"propertyTypes": [
|
||||
{ "name": "APARTMENT", "count": 120 },
|
||||
{ "name": "HOUSE", "count": 85 }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `compare_properties`
|
||||
|
||||
So sánh 2-5 bất động sản dựa trên giá, diện tích, vị trí, etc.
|
||||
|
||||
**Input Schema:**
|
||||
```json
|
||||
{
|
||||
"propertyIds": ["prop-001", "prop-002", "prop-003"],
|
||||
"metrics": ["price", "area", "price_per_sqm", "location_score", "agent_rating"]
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```json
|
||||
{
|
||||
"comparison": [
|
||||
{
|
||||
"propertyId": "prop-001",
|
||||
"title": "Căn hộ 2PN Q.1",
|
||||
"price": 3500000000,
|
||||
"area": 85,
|
||||
"price_per_sqm": 41176470,
|
||||
"location_score": 4.8,
|
||||
"agent_rating": 4.5
|
||||
},
|
||||
{
|
||||
"propertyId": "prop-002",
|
||||
"title": "Căn hộ 2PN Q.3",
|
||||
"price": 2800000000,
|
||||
"area": 78,
|
||||
"price_per_sqm": 35897436,
|
||||
"location_score": 4.3,
|
||||
"agent_rating": 4.2
|
||||
}
|
||||
],
|
||||
"recommendation": "prop-002 có giá tốt hơn với vị trí tương đương"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `get_property_details`
|
||||
|
||||
Lấy chi tiết đầy đủ của một bất động sản.
|
||||
|
||||
**Input Schema:**
|
||||
```json
|
||||
{
|
||||
"propertyId": "prop-001"
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```json
|
||||
{
|
||||
"id": "prop-001",
|
||||
"title": "Căn hộ 2PN view sông Sài Gòn",
|
||||
"description": "Căn hộ cao cấp tại trung tâm Q.1...",
|
||||
"type": "APARTMENT",
|
||||
"price": 3500000000,
|
||||
"bedrooms": 2,
|
||||
"bathrooms": 2,
|
||||
"area": 85,
|
||||
"district": "Quận 1",
|
||||
"ward": "Phường Bến Nghé",
|
||||
"address": "123 Tôn Đức Thắng, Q.1",
|
||||
"coordinates": {
|
||||
"latitude": 10.7769,
|
||||
"longitude": 106.7009
|
||||
},
|
||||
"features": ["view sông", "ban công rộng", "tầng cao", "gần metro"],
|
||||
"agent": {
|
||||
"id": "agent-001",
|
||||
"name": "Nguyễn Văn A",
|
||||
"phone": "0987654321",
|
||||
"rating": 4.5,
|
||||
"reviews": 47
|
||||
},
|
||||
"media": [
|
||||
{
|
||||
"type": "image",
|
||||
"url": "https://storage.goodgo.app/prop-001/img-1.jpg"
|
||||
}
|
||||
],
|
||||
"status": "ACTIVE",
|
||||
"createdAt": "2026-04-20T10:30:00Z",
|
||||
"reviews": [
|
||||
{
|
||||
"author": "Trần Văn B",
|
||||
"rating": 5,
|
||||
"text": "Căn hộ đẹp, vị trí tuyệt vời"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Market Analytics Server
|
||||
|
||||
### Purpose
|
||||
|
||||
Cung cấp dữ liệu thị trường bất động sản:
|
||||
- Báo cáo giá theo quận huyện
|
||||
- Phân tích xu hướng giá theo thời gian
|
||||
- Chỉ số thị trường
|
||||
|
||||
### Tools
|
||||
|
||||
#### `get_market_report`
|
||||
|
||||
Lấy báo cáo thị trường theo quận huyện.
|
||||
|
||||
**Input Schema:**
|
||||
```json
|
||||
{
|
||||
"district": "Quận 1",
|
||||
"propertyType": "APARTMENT",
|
||||
"period": "monthly"
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```json
|
||||
{
|
||||
"district": "Quận 1",
|
||||
"propertyType": "APARTMENT",
|
||||
"period": "April 2026",
|
||||
"statistics": {
|
||||
"averagePrice": 3200000000,
|
||||
"medianPrice": 3100000000,
|
||||
"priceMin": 800000000,
|
||||
"priceMax": 8500000000,
|
||||
"averageArea": 82,
|
||||
"averagePricePerSqm": 39024390,
|
||||
"activeListings": 342,
|
||||
"soldListings": 28,
|
||||
"rentedListings": 15
|
||||
},
|
||||
"trends": {
|
||||
"priceChangePercent": 2.5,
|
||||
"priceChangeVsLastMonth": "Tăng 2.5%",
|
||||
"velocityDays": 15
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `analyze_trends`
|
||||
|
||||
Phân tích xu hướng giá theo thời gian.
|
||||
|
||||
**Input Schema:**
|
||||
```json
|
||||
{
|
||||
"district": "Quận 1",
|
||||
"propertyType": "APARTMENT",
|
||||
"months": 12
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```json
|
||||
{
|
||||
"district": "Quận 1",
|
||||
"propertyType": "APARTMENT",
|
||||
"trend": [
|
||||
{
|
||||
"month": "May 2025",
|
||||
"averagePrice": 2900000000,
|
||||
"medianPrice": 2800000000,
|
||||
"activeListings": 250
|
||||
},
|
||||
{
|
||||
"month": "April 2026",
|
||||
"averagePrice": 3200000000,
|
||||
"medianPrice": 3100000000,
|
||||
"activeListings": 342
|
||||
}
|
||||
],
|
||||
"forecast": {
|
||||
"nextMonthPredicted": 3280000000,
|
||||
"confidence": 0.75,
|
||||
"direction": "up"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `get_price_indices`
|
||||
|
||||
Lấy chỉ số giá toàn thị trường (bình thường hóa = 100).
|
||||
|
||||
**Input Schema:**
|
||||
```json
|
||||
{
|
||||
"baseMonth": "January 2025"
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```json
|
||||
{
|
||||
"baseIndex": 100,
|
||||
"baseMonth": "January 2025",
|
||||
"indices": [
|
||||
{
|
||||
"month": "January 2025",
|
||||
"indexValue": 100,
|
||||
"growth": 0
|
||||
},
|
||||
{
|
||||
"month": "April 2026",
|
||||
"indexValue": 110.5,
|
||||
"growth": 10.5
|
||||
}
|
||||
],
|
||||
"byDistrict": {
|
||||
"Quận 1": 112.3,
|
||||
"Quận 3": 108.7,
|
||||
"Thủ Đức": 105.2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Valuation Server
|
||||
|
||||
### Purpose
|
||||
|
||||
Định giá tự động bất động sản dùng mô hình **XGBoost**:
|
||||
- Estimate valuation based on features
|
||||
- Extract features from description
|
||||
- Compare valuations across similar properties
|
||||
|
||||
### Tools
|
||||
|
||||
#### `estimate_valuation`
|
||||
|
||||
Ước lượng giá bất động sản dựa trên đặc trưng.
|
||||
|
||||
**Input Schema:**
|
||||
```json
|
||||
{
|
||||
"district": "Quận 1",
|
||||
"propertyType": "APARTMENT",
|
||||
"area": 85,
|
||||
"bedrooms": 2,
|
||||
"bathrooms": 2,
|
||||
"features": ["view sông", "ban công", "tầng cao", "gần metro"],
|
||||
"yearBuilt": 2015,
|
||||
"location": {
|
||||
"latitude": 10.7769,
|
||||
"longitude": 106.7009
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```json
|
||||
{
|
||||
"estimatedPrice": 3250000000,
|
||||
"priceRange": {
|
||||
"low": 2850000000,
|
||||
"high": 3650000000
|
||||
},
|
||||
"confidence": 0.82,
|
||||
"factors": {
|
||||
"area": "Positive (85 sqm)",
|
||||
"location": "High demand (Q.1)",
|
||||
"features": "Premium (view sông, gần metro)",
|
||||
"yearBuilt": "Neutral (11 years old)"
|
||||
},
|
||||
"comparables": [
|
||||
{
|
||||
"id": "prop-001",
|
||||
"actualPrice": 3200000000,
|
||||
"similarity": 0.89
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `extract_features`
|
||||
|
||||
Trích xuất đặc trưng từ mô tả bất động sản (NLP).
|
||||
|
||||
**Input Schema:**
|
||||
```json
|
||||
{
|
||||
"description": "Căn hộ cao cấp 2 phòng ngủ, 2 phòng tắm, view sông Sài Gòn, ban công rộng, gần trạm metro, tầng 15, xây năm 2015...",
|
||||
"title": "Căn hộ 2PN view sông Sài Gòn"
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```json
|
||||
{
|
||||
"extracted": {
|
||||
"bedrooms": 2,
|
||||
"bathrooms": 2,
|
||||
"area": null,
|
||||
"features": ["view sông", "ban công", "gần metro", "tầng cao"],
|
||||
"yearBuilt": 2015,
|
||||
"condition": "tốt"
|
||||
},
|
||||
"confidence": {
|
||||
"bedrooms": 0.98,
|
||||
"features": 0.85,
|
||||
"yearBuilt": 0.92
|
||||
},
|
||||
"uncertainties": [
|
||||
"area not mentioned",
|
||||
"exact floor number not in description"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `compare_valuations`
|
||||
|
||||
So sánh định giá của các bất động sản tương tự.
|
||||
|
||||
**Input Schema:**
|
||||
```json
|
||||
{
|
||||
"referencePropertyId": "prop-001",
|
||||
"candidatePropertyIds": ["prop-002", "prop-003", "prop-004"]
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```json
|
||||
{
|
||||
"reference": {
|
||||
"propertyId": "prop-001",
|
||||
"title": "Căn hộ 2PN Q.1",
|
||||
"actualPrice": 3500000000,
|
||||
"estimatedPrice": 3250000000
|
||||
},
|
||||
"candidates": [
|
||||
{
|
||||
"propertyId": "prop-002",
|
||||
"title": "Căn hộ 2PN Q.3",
|
||||
"actualPrice": 2800000000,
|
||||
"estimatedPrice": 2950000000,
|
||||
"overUndervalued": "Undervalued by 5.1%",
|
||||
"similarity": 0.76
|
||||
}
|
||||
],
|
||||
"recommendation": "prop-002 is a good value compared to reference property"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### File Structure
|
||||
|
||||
```
|
||||
apps/api/src/
|
||||
├── modules/
|
||||
│ └── mcp/
|
||||
│ ├── mcp.module.ts # Module definition
|
||||
│ ├── mcp.controller.ts # HTTP endpoint: POST /mcp/tools/:toolName
|
||||
│ ├── mcp-registry.service.ts # Registry: tool name → handler function
|
||||
│ ├── servers/
|
||||
│ │ ├── property-search.server.ts
|
||||
│ │ ├── market-analytics.server.ts
|
||||
│ │ └── valuation.server.ts
|
||||
│ └── dto/
|
||||
│ ├── search-properties.dto.ts
|
||||
│ ├── market-report.dto.ts
|
||||
│ └── estimate-valuation.dto.ts
|
||||
```
|
||||
|
||||
### McpRegistryService
|
||||
|
||||
```typescript
|
||||
// Register tools
|
||||
export class McpRegistryService {
|
||||
private tools = new Map<string, Tool>();
|
||||
|
||||
register(name: string, tool: Tool) {
|
||||
this.tools.set(name, tool);
|
||||
}
|
||||
|
||||
invoke(name: string, input: any): Promise<any> {
|
||||
const tool = this.tools.get(name);
|
||||
if (!tool) throw new NotFoundException(`Tool ${name} not found`);
|
||||
return tool.execute(input);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### HTTP Endpoint
|
||||
|
||||
```typescript
|
||||
@Post('/mcp/tools/:toolName')
|
||||
@Auth() // JWT required
|
||||
async invokeTool(
|
||||
@Param('toolName') toolName: string,
|
||||
@Body() input: any
|
||||
) {
|
||||
return this.mcpRegistry.invoke(toolName, input);
|
||||
}
|
||||
```
|
||||
|
||||
### Tool Pattern
|
||||
|
||||
```typescript
|
||||
interface Tool {
|
||||
name: string;
|
||||
schema: JsonSchema; // Input validation
|
||||
execute(input: any): Promise<any>;
|
||||
}
|
||||
|
||||
class SearchPropertiesTool implements Tool {
|
||||
name = 'search_properties';
|
||||
schema = { /* JSON Schema */ };
|
||||
|
||||
execute(input: SearchPropertiesInput): Promise<any> {
|
||||
// Implementation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
All MCP tools return consistent error format:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": "INVALID_INPUT",
|
||||
"message": "District 'Quận XYZ' not found",
|
||||
"details": {
|
||||
"field": "district",
|
||||
"value": "Quận XYZ"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Caching
|
||||
|
||||
- Market Analytics: Cache reports for 1 hour
|
||||
- Property Search: Cache facets, invalidate on new listing
|
||||
- Valuation: Cache model predictions for 24 hours
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
- Default: 100 req/minute per user
|
||||
- MCP tools: 50 req/minute per tool (stricter)
|
||||
- Burst: 10 req/second
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests
|
||||
|
||||
```bash
|
||||
pnpm test -- mcp/servers
|
||||
```
|
||||
|
||||
### Integration Tests
|
||||
|
||||
```bash
|
||||
# Test via HTTP
|
||||
curl -X POST http://localhost:3001/mcp/tools/search_properties \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"query": "chung cu quan 1", "limit": 5}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- MCP Specification: https://modelcontextprotocol.io/
|
||||
- Claude API: https://anthropic.com/api
|
||||
- Implementation: `apps/api/src/modules/mcp/`
|
||||
Reference in New Issue
Block a user