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>
12 KiB
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:
{
"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:
{
"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:
{
"propertyIds": ["prop-001", "prop-002", "prop-003"],
"metrics": ["price", "area", "price_per_sqm", "location_score", "agent_rating"]
}
Output Example:
{
"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:
{
"propertyId": "prop-001"
}
Output Example:
{
"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:
{
"district": "Quận 1",
"propertyType": "APARTMENT",
"period": "monthly"
}
Output Example:
{
"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:
{
"district": "Quận 1",
"propertyType": "APARTMENT",
"months": 12
}
Output Example:
{
"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:
{
"baseMonth": "January 2025"
}
Output Example:
{
"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:
{
"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:
{
"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:
{
"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:
{
"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:
{
"referencePropertyId": "prop-001",
"candidatePropertyIds": ["prop-002", "prop-003", "prop-004"]
}
Output Example:
{
"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
// 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
@Post('/mcp/tools/:toolName')
@Auth() // JWT required
async invokeTool(
@Param('toolName') toolName: string,
@Body() input: any
) {
return this.mcpRegistry.invoke(toolName, input);
}
Tool Pattern
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:
{
"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
pnpm test -- mcp/servers
Integration Tests
# 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/