Files
goodgo-platform/docs/mcp-servers.md
Ho Ngoc Hai e798468e4c 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>
2026-04-22 23:29:20 +07:00

601 lines
12 KiB
Markdown

# 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/`