Add comprehensive testing and documentation
- Fix MCP server main() to use app.run() synchronously (FastMCP 2.x) - Add comprehensive test suite with 32+ test methods for all 13 tools - Add detailed installation guide (docs/INSTALLATION.md) - Add complete usage guide with examples (docs/USAGE.md) - Update README with production installation command - Add pytest configuration with beautiful HTML reports - Test caching, rate limiting, and error handling - Document the production command: claude mcp add mcrentcast -- uvx --from git+https://git.supported.systems/MCP/mcrentcast.git mcrentcast
This commit is contained in:
parent
228665ada1
commit
adce62fa95
269
README.md
269
README.md
@ -4,27 +4,27 @@ A Model Context Protocol (MCP) server that provides intelligent access to the Re
|
||||
|
||||
## 🌟 Features
|
||||
|
||||
- **🏠 Complete Rentcast API Integration**: Access all Rentcast endpoints for property data, valuations, listings, and market statistics
|
||||
- **💾 Intelligent Caching**: Automatic response caching with hit/miss tracking and configurable TTL
|
||||
- **🛡️ Rate Limiting**: Configurable daily/monthly/per-minute limits with exponential backoff
|
||||
- **💰 Cost Management**: Track API usage, estimate costs, and get confirmations before expensive operations
|
||||
- **🧪 Mock API for Testing**: Full mock implementation for development without consuming credits
|
||||
- **✨ MCP Integration**: Seamless integration with Claude and other MCP-compatible clients
|
||||
- **🐳 Docker Ready**: Complete Docker Compose setup for easy deployment
|
||||
- **📊 Usage Analytics**: Track API usage patterns, cache performance, and costs
|
||||
- **🏠 Complete Rentcast API Integration**: Access all major Rentcast endpoints for property data, valuations, listings, and market statistics
|
||||
- **💾 Intelligent Caching**: Automatic response caching with hit/miss tracking, 24-hour default TTL, and configurable cache management
|
||||
- **🛡️ Advanced Rate Limiting**: Multi-layer protection with daily/monthly/per-minute limits, exponential backoff, and automatic retry logic
|
||||
- **💰 Smart Cost Management**: Real-time usage tracking, cost estimation, and user confirmation for expensive operations
|
||||
- **🧪 Comprehensive Mock API**: Full-featured testing environment with multiple test keys and realistic data generation
|
||||
- **✨ Seamless MCP Integration**: Native Claude Desktop integration with 13 specialized tools for real estate analysis
|
||||
- **🐳 Production Ready**: Complete Docker setup with development/production modes and reverse proxy configuration
|
||||
- **📊 Advanced Analytics**: Detailed usage statistics, cache performance metrics, and cost tracking with historical data
|
||||
- **🔒 Security & Reliability**: Secure API key management, error handling, and graceful fallbacks to cached data
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Quick Start](#quick-start)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Installation](#installation)
|
||||
- [Configuration](#configuration)
|
||||
- [Usage](#usage)
|
||||
- [MCP Tools](#mcp-tools)
|
||||
- [Mock API](#mock-api)
|
||||
- [Documentation](#documentation)
|
||||
- [Development](#development)
|
||||
- [Testing](#testing)
|
||||
- [API Documentation](#api-documentation)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Support](#support)
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
@ -34,7 +34,28 @@ A Model Context Protocol (MCP) server that provides intelligent access to the Re
|
||||
- [uv](https://github.com/astral-sh/uv) package manager
|
||||
- Rentcast API key (or use mock mode for testing)
|
||||
|
||||
### Installation
|
||||
### Production Installation
|
||||
|
||||
The easiest way to install and use mcrentcast with Claude:
|
||||
|
||||
```bash
|
||||
# Install directly from git (recommended for production)
|
||||
claude mcp add mcrentcast -- uvx --from git+https://git.supported.systems/MCP/mcrentcast.git mcrentcast
|
||||
```
|
||||
|
||||
**Important**: After installation, you need to set your Rentcast API key in your environment or `.env` file:
|
||||
|
||||
```bash
|
||||
# Set your API key in your environment
|
||||
export RENTCAST_API_KEY=your_actual_api_key
|
||||
|
||||
# OR create a .env file in your current directory
|
||||
echo "RENTCAST_API_KEY=your_actual_api_key" > .env
|
||||
```
|
||||
|
||||
### Development Installation
|
||||
|
||||
For development or local installation:
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
@ -44,14 +65,11 @@ cd mcrentcast
|
||||
# Run the installation script
|
||||
./install.sh
|
||||
|
||||
# IMPORTANT: Set your API key in the .env file
|
||||
nano .env # Set RENTCAST_API_KEY=your_actual_api_key
|
||||
# Set your API key in the .env file
|
||||
echo "RENTCAST_API_KEY=your_actual_api_key" >> .env
|
||||
|
||||
# For development (from cloned repo)
|
||||
# Add to Claude for development
|
||||
claude mcp add mcrentcast -- uvx --from . mcrentcast
|
||||
|
||||
# For production (install from git)
|
||||
claude mcp add mcrentcast -- uvx --from git+https://git.supported.systems/MCP/mcrentcast.git mcrentcast
|
||||
```
|
||||
|
||||
## 📦 Installation
|
||||
@ -190,39 +208,67 @@ Note: The server uses the `mcp.json` file in the project root for configuration
|
||||
|
||||
## 🔧 Usage
|
||||
|
||||
### With Claude
|
||||
### Natural Language Interface with Claude
|
||||
|
||||
Once added to Claude, you can use natural language:
|
||||
Once installed, interact with the Rentcast API through natural language:
|
||||
|
||||
```
|
||||
User: Search for properties in Austin, Texas
|
||||
User: Find 5 properties for sale in Austin, Texas under $500,000
|
||||
|
||||
Claude: I'll search for properties in Austin, Texas.
|
||||
[Uses search_properties tool]
|
||||
Found 10 properties in Austin, TX...
|
||||
Claude: I'll search for properties for sale in Austin, Texas.
|
||||
[Uses search_sale_listings tool]
|
||||
|
||||
Found 8 sale listings (fresh data):
|
||||
- 123 Oak St: $450,000, 3BR/2BA, 1,800 sq ft
|
||||
- 456 Pine Ave: $485,000, 4BR/2.5BA, 2,100 sq ft
|
||||
- 789 Elm Dr: $425,000, 3BR/2BA, 1,650 sq ft
|
||||
...
|
||||
```
|
||||
|
||||
### Direct Python Usage
|
||||
```
|
||||
User: What's the estimated rental income for 123 Main St, Denver, CO?
|
||||
|
||||
```python
|
||||
from mcrentcast.rentcast_client import RentcastClient
|
||||
Claude: I'll get the rental estimate for that property.
|
||||
[Uses get_rent_estimate tool]
|
||||
|
||||
async def example():
|
||||
client = RentcastClient(api_key="your_key")
|
||||
|
||||
# Search properties
|
||||
properties, cached, age = await client.get_property_records(
|
||||
city="Austin",
|
||||
state="TX",
|
||||
limit=10
|
||||
)
|
||||
|
||||
# Get value estimate
|
||||
estimate, cached, age = await client.get_value_estimate(
|
||||
address="123 Main St, Austin, TX"
|
||||
)
|
||||
|
||||
await client.close()
|
||||
Rent estimate: $2,850/month (fresh data)
|
||||
- Estimated range: $2,565 - $3,135
|
||||
- Market comparison: 8% above area median
|
||||
- Based on 3 comparable rentals nearby
|
||||
```
|
||||
|
||||
```
|
||||
User: Show me the current real estate market statistics for Miami, FL
|
||||
|
||||
Claude: I'll get the current market statistics for Miami.
|
||||
[Uses get_market_statistics tool]
|
||||
|
||||
Miami, FL Market Statistics (from cache, age: 3.2 hours):
|
||||
- Median Sale Price: $485,000 (+7.2% YoY)
|
||||
- Median Rent: $2,650/month (+11.8% YoY)
|
||||
- Average Days on Market: 45 days
|
||||
- Active Inventory: 3,247 properties
|
||||
- Price per Square Foot: $285
|
||||
```
|
||||
|
||||
### Advanced Analysis Examples
|
||||
|
||||
```
|
||||
User: I'm considering an investment property in Nashville. Analyze the market and find potential deals.
|
||||
|
||||
Claude: I'll perform a comprehensive Nashville investment analysis.
|
||||
[Uses multiple tools: get_market_statistics, search_sale_listings, search_rental_listings]
|
||||
|
||||
Nashville Investment Analysis:
|
||||
✓ Market Growth: +8.2% annual appreciation
|
||||
✓ Rental Demand: Strong (+12.1% rent growth)
|
||||
✓ Investment Properties Found: 12 properties with 6%+ yield potential
|
||||
✓ Market Liquidity: Good (28 days average DOM)
|
||||
|
||||
Top Investment Opportunities:
|
||||
1. 234 Music Row: $385K, potential $2,400/month (7.5% yield)
|
||||
2. 567 Broadway St: $420K, potential $2,650/month (7.6% yield)
|
||||
...
|
||||
```
|
||||
|
||||
## 🛠️ MCP Tools
|
||||
@ -392,87 +438,59 @@ uv run pytest --cov=src --cov-report=html
|
||||
# View report at htmlcov/index.html
|
||||
```
|
||||
|
||||
## 📚 API Documentation
|
||||
## 📚 Documentation
|
||||
|
||||
### Rentcast API Endpoints
|
||||
### Comprehensive Guides
|
||||
|
||||
The server integrates with all major Rentcast endpoints:
|
||||
| Document | Description |
|
||||
|----------|-------------|
|
||||
| **[Installation Guide](docs/INSTALLATION.md)** | Detailed installation instructions for all scenarios |
|
||||
| **[Usage Guide](docs/USAGE.md)** | Complete examples for all 13 tools with best practices |
|
||||
| **[Mock API Guide](docs/mock-api.md)** | Testing without API credits using realistic mock data |
|
||||
| **[Claude Setup](docs/claude-setup.md)** | MCP integration and configuration |
|
||||
| **[API Reference](docs/api-reference.md)** | Technical API documentation |
|
||||
|
||||
- **Property Records**: Search and retrieve property information
|
||||
- **Value Estimates**: Get property valuations
|
||||
- **Rent Estimates**: Calculate rental prices
|
||||
- **Sale Listings**: Find properties for sale
|
||||
- **Rental Listings**: Find rental properties
|
||||
- **Market Statistics**: Access market trends and analytics
|
||||
### Quick Reference
|
||||
|
||||
### Response Caching
|
||||
|
||||
All API responses are automatically cached:
|
||||
- Default TTL: 24 hours (configurable)
|
||||
- Cache hit/miss tracking
|
||||
- Manual cache expiration available
|
||||
- Cache size management
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
Configurable rate limits:
|
||||
- Daily request limits
|
||||
- Monthly request limits
|
||||
- Per-minute rate limiting
|
||||
- Exponential backoff on failures
|
||||
|
||||
## 🔍 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Server won't start
|
||||
#### Essential Commands
|
||||
```bash
|
||||
# Check Python version
|
||||
python --version # Should be 3.13+
|
||||
# Production installation
|
||||
claude mcp add mcrentcast -- uvx --from git+https://git.supported.systems/MCP/mcrentcast.git mcrentcast
|
||||
|
||||
# Reinstall dependencies
|
||||
uv sync --reinstall
|
||||
# Test with mock API (no credits required)
|
||||
claude mcp add mcrentcast-test -- uvx --from git+https://git.supported.systems/MCP/mcrentcast.git mcrentcast \
|
||||
-e USE_MOCK_API=true -e RENTCAST_API_KEY=test_key_basic
|
||||
|
||||
# Check database
|
||||
rm -f data/mcrentcast.db
|
||||
uv run python -c "from mcrentcast.database import db_manager; db_manager.create_tables()"
|
||||
# Check installation
|
||||
claude mcp list | grep mcrentcast
|
||||
```
|
||||
|
||||
#### API Key Issues
|
||||
```bash
|
||||
# Test with mock API
|
||||
USE_MOCK_API=true uv run python scripts/test_mock_api.py
|
||||
#### Key Features
|
||||
- **13 MCP Tools**: Complete Rentcast API coverage
|
||||
- **Smart Caching**: 24-hour default TTL with intelligent cache management
|
||||
- **Cost Control**: Usage tracking, rate limiting, and user confirmations
|
||||
- **Testing Support**: Full mock API with realistic data
|
||||
- **Production Ready**: Docker support, security, and reliability features
|
||||
|
||||
# Verify API key
|
||||
curl -H "X-Api-Key: your_key" https://api.rentcast.io/v1/properties
|
||||
```
|
||||
### API Coverage
|
||||
|
||||
#### Cache Issues
|
||||
```bash
|
||||
# Clear cache
|
||||
rm -f data/mcrentcast.db
|
||||
The server provides complete access to Rentcast API endpoints:
|
||||
|
||||
# Expire specific cache
|
||||
uv run python -c "
|
||||
from mcrentcast.database import db_manager
|
||||
import asyncio
|
||||
asyncio.run(db_manager.expire_cache_entry('cache_key_here'))
|
||||
"
|
||||
```
|
||||
| Category | Endpoints | Tools |
|
||||
|----------|-----------|-------|
|
||||
| **Property Data** | Property records, specific properties | `search_properties`, `get_property` |
|
||||
| **Valuations** | Value and rent estimates | `get_value_estimate`, `get_rent_estimate` |
|
||||
| **Listings** | Sale and rental listings | `search_sale_listings`, `search_rental_listings` |
|
||||
| **Market Data** | Statistics and trends | `get_market_statistics` |
|
||||
| **Management** | Configuration and monitoring | 6 management tools |
|
||||
|
||||
### Debug Mode
|
||||
### Cost Management
|
||||
|
||||
Enable debug logging:
|
||||
```env
|
||||
DEBUG=true
|
||||
LOG_LEVEL=DEBUG
|
||||
```
|
||||
|
||||
### Getting Help
|
||||
|
||||
- Check `docs/` directory for detailed guides
|
||||
- Review `docs/mock-api.md` for testing documentation
|
||||
- Check `docs/claude-setup.md` for MCP integration help
|
||||
- **Automatic Cost Estimation**: Know before you spend
|
||||
- **User Confirmations**: Approve expensive operations
|
||||
- **Usage Tracking**: Monitor daily/monthly consumption
|
||||
- **Smart Caching**: Minimize redundant API calls
|
||||
- **Mock API**: Unlimited testing without credits
|
||||
|
||||
## 📄 License
|
||||
|
||||
@ -495,11 +513,30 @@ Contributions are welcome! Please:
|
||||
|
||||
## 📞 Support
|
||||
|
||||
- Documentation: See `/docs` directory
|
||||
- Issues: Create an issue on GitHub
|
||||
- Mock API Guide: See `docs/mock-api.md`
|
||||
- Claude Setup: See `docs/claude-setup.md`
|
||||
### Documentation Resources
|
||||
- **[Installation Guide](docs/INSTALLATION.md)**: Complete setup instructions
|
||||
- **[Usage Examples](docs/USAGE.md)**: All 13 tools with real-world examples
|
||||
- **[Mock API Testing](docs/mock-api.md)**: Test without consuming credits
|
||||
- **[Claude Integration](docs/claude-setup.md)**: MCP configuration help
|
||||
|
||||
### Getting Help
|
||||
- **Issues**: [Create an issue](https://git.supported.systems/MCP/mcrentcast/issues) on the repository
|
||||
- **Discussions**: Use GitHub discussions for questions and community support
|
||||
- **Documentation**: All guides available in the `/docs` directory
|
||||
|
||||
### Quick Troubleshooting
|
||||
```bash
|
||||
# Verify installation
|
||||
claude mcp list | grep mcrentcast
|
||||
|
||||
# Test with mock API (no API key needed)
|
||||
claude mcp add mcrentcast-test -- uvx --from git+https://git.supported.systems/MCP/mcrentcast.git mcrentcast \
|
||||
-e USE_MOCK_API=true -e RENTCAST_API_KEY=test_key_basic
|
||||
|
||||
# Enable debug logging
|
||||
DEBUG=true LOG_LEVEL=DEBUG
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Note**: This is an unofficial integration with the Rentcast API. Please ensure you comply with Rentcast's terms of service and API usage guidelines.
|
||||
**Important**: This is an unofficial integration with the Rentcast API. Please ensure you comply with [Rentcast's terms of service](https://rentcast.io/terms) and API usage guidelines. The mcrentcast server provides caching and rate limiting to help you stay within usage limits and manage costs effectively.
|
487
docs/INSTALLATION.md
Normal file
487
docs/INSTALLATION.md
Normal file
@ -0,0 +1,487 @@
|
||||
# mcrentcast Installation Guide
|
||||
|
||||
This guide provides detailed installation instructions for the mcrentcast MCP server for different use cases and environments.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before installing mcrentcast, ensure you have:
|
||||
|
||||
- **Python 3.13+** - Required for running the server
|
||||
- **Claude Desktop** - For MCP integration
|
||||
- **uv package manager** - For Python dependency management
|
||||
- **Rentcast API key** (optional for testing with mock API)
|
||||
|
||||
### Installing Prerequisites
|
||||
|
||||
#### Install uv (Python package manager)
|
||||
```bash
|
||||
# Install uv
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# Verify installation
|
||||
uv --version
|
||||
```
|
||||
|
||||
#### Get a Rentcast API Key
|
||||
1. Sign up at [Rentcast](https://rentcast.io/)
|
||||
2. Navigate to your API dashboard
|
||||
3. Generate an API key
|
||||
4. Note the key for later configuration
|
||||
|
||||
## Installation Methods
|
||||
|
||||
### Method 1: Production Installation (Recommended)
|
||||
|
||||
This method installs the latest stable version directly from the git repository.
|
||||
|
||||
#### Step 1: Install with Claude MCP
|
||||
```bash
|
||||
claude mcp add mcrentcast -- uvx --from git+https://git.supported.systems/MCP/mcrentcast.git mcrentcast
|
||||
```
|
||||
|
||||
#### Step 2: Configure API Key
|
||||
|
||||
Choose one of these methods to set your API key:
|
||||
|
||||
**Option A: Environment Variable**
|
||||
```bash
|
||||
export RENTCAST_API_KEY=your_actual_api_key
|
||||
```
|
||||
|
||||
**Option B: .env File (Recommended)**
|
||||
```bash
|
||||
# Create .env file in your preferred directory
|
||||
echo "RENTCAST_API_KEY=your_actual_api_key" > ~/.mcrentcast.env
|
||||
```
|
||||
|
||||
**Option C: Set via Claude**
|
||||
After installation, you can also set the API key through Claude:
|
||||
```
|
||||
User: Set my Rentcast API key to: your_actual_api_key
|
||||
|
||||
Claude: I'll set your Rentcast API key for this session.
|
||||
[Uses set_api_key tool]
|
||||
```
|
||||
|
||||
#### Step 3: Verify Installation
|
||||
|
||||
Test the installation by asking Claude to search for properties:
|
||||
```
|
||||
User: Search for properties in Austin, Texas
|
||||
|
||||
Claude: I'll search for properties in Austin, Texas using the Rentcast API.
|
||||
[If successful, you'll see property results]
|
||||
```
|
||||
|
||||
### Method 2: Development Installation
|
||||
|
||||
For development, testing, or customization:
|
||||
|
||||
#### Step 1: Clone Repository
|
||||
```bash
|
||||
git clone https://git.supported.systems/MCP/mcrentcast.git
|
||||
cd mcrentcast
|
||||
```
|
||||
|
||||
#### Step 2: Run Installation Script
|
||||
```bash
|
||||
# Make script executable
|
||||
chmod +x install.sh
|
||||
|
||||
# Run installation
|
||||
./install.sh
|
||||
```
|
||||
|
||||
The installation script will:
|
||||
- Install Python dependencies with uv
|
||||
- Create data directory
|
||||
- Initialize database
|
||||
- Create example .env file
|
||||
|
||||
#### Step 3: Configure Environment
|
||||
```bash
|
||||
# Copy example environment file
|
||||
cp .env.example .env
|
||||
|
||||
# Edit with your API key
|
||||
nano .env
|
||||
```
|
||||
|
||||
Set these essential variables in `.env`:
|
||||
```env
|
||||
RENTCAST_API_KEY=your_actual_api_key
|
||||
USE_MOCK_API=false
|
||||
CACHE_TTL_HOURS=24
|
||||
DAILY_API_LIMIT=100
|
||||
MONTHLY_API_LIMIT=1000
|
||||
```
|
||||
|
||||
#### Step 4: Add to Claude
|
||||
```bash
|
||||
# Add development version to Claude
|
||||
claude mcp add mcrentcast -- uvx --from . mcrentcast
|
||||
```
|
||||
|
||||
### Method 3: Testing with Mock API
|
||||
|
||||
To test without consuming API credits:
|
||||
|
||||
#### Step 1: Install (Production or Development)
|
||||
Follow either Method 1 or 2 above.
|
||||
|
||||
#### Step 2: Configure for Mock API
|
||||
```bash
|
||||
# Add to Claude with mock API configuration
|
||||
claude mcp add mcrentcast-test -- uvx --from git+https://git.supported.systems/MCP/mcrentcast.git mcrentcast \
|
||||
-e USE_MOCK_API=true \
|
||||
-e RENTCAST_API_KEY=test_key_basic
|
||||
```
|
||||
|
||||
#### Available Test Keys
|
||||
| Key | Daily Limit | Use Case |
|
||||
|-----|-------------|----------|
|
||||
| `test_key_basic` | 100 | Standard testing |
|
||||
| `test_key_free_tier` | 50 | Free tier simulation |
|
||||
| `test_key_pro` | 1,000 | High-volume testing |
|
||||
| `test_key_enterprise` | 10,000 | Unlimited testing |
|
||||
| `test_key_rate_limited` | 1 | Rate limit testing |
|
||||
|
||||
### Method 4: Docker Installation
|
||||
|
||||
For containerized deployment:
|
||||
|
||||
#### Step 1: Clone and Configure
|
||||
```bash
|
||||
git clone https://git.supported.systems/MCP/mcrentcast.git
|
||||
cd mcrentcast
|
||||
|
||||
# Configure environment
|
||||
cp .env.example .env
|
||||
nano .env # Set your API key
|
||||
```
|
||||
|
||||
#### Step 2: Start Services
|
||||
```bash
|
||||
# Development mode with hot-reload
|
||||
make dev
|
||||
|
||||
# Production mode
|
||||
make prod
|
||||
|
||||
# Mock API mode for testing
|
||||
make test-mock
|
||||
```
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
### Essential Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| `RENTCAST_API_KEY` | Yes* | - | Your Rentcast API key |
|
||||
| `USE_MOCK_API` | No | `false` | Use mock API for testing |
|
||||
| `CACHE_TTL_HOURS` | No | `24` | Cache expiration time |
|
||||
| `DAILY_API_LIMIT` | No | `100` | Daily request limit |
|
||||
| `MONTHLY_API_LIMIT` | No | `1000` | Monthly request limit |
|
||||
| `REQUESTS_PER_MINUTE` | No | `3` | Rate limit per minute |
|
||||
|
||||
*Not required when using mock API (`USE_MOCK_API=true`)
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
```env
|
||||
# Database settings
|
||||
DATABASE_URL=sqlite:///./data/mcrentcast.db
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=INFO
|
||||
DEBUG=false
|
||||
|
||||
# Mock API settings (for testing)
|
||||
USE_MOCK_API=false
|
||||
MOCK_API_URL=http://localhost:8001/v1
|
||||
|
||||
# Cache settings
|
||||
MAX_CACHE_SIZE_MB=100
|
||||
CACHE_CLEANUP_INTERVAL_HOURS=6
|
||||
|
||||
# Rate limiting
|
||||
EXPONENTIAL_BACKOFF_ENABLED=true
|
||||
MAX_RETRY_ATTEMPTS=3
|
||||
```
|
||||
|
||||
## Verification and Testing
|
||||
|
||||
### Verify Installation
|
||||
```bash
|
||||
# Check if server can start (development only)
|
||||
cd /path/to/mcrentcast
|
||||
uv run mcrentcast
|
||||
|
||||
# Test API connectivity
|
||||
uv run python -c "
|
||||
from src.mcrentcast.config import settings
|
||||
print('API Key configured:', bool(settings.rentcast_api_key))
|
||||
"
|
||||
```
|
||||
|
||||
### Test with Claude
|
||||
|
||||
1. **Basic Test**
|
||||
```
|
||||
User: What are the current API limits for mcrentcast?
|
||||
|
||||
Claude: I'll check the current API limits.
|
||||
[Shows daily/monthly limits and current usage]
|
||||
```
|
||||
|
||||
2. **Property Search Test**
|
||||
```
|
||||
User: Find 3 properties in San Francisco, CA
|
||||
|
||||
Claude: I'll search for properties in San Francisco.
|
||||
[Shows property listings with addresses, prices, details]
|
||||
```
|
||||
|
||||
3. **Value Estimation Test**
|
||||
```
|
||||
User: What's the estimated value of 123 Main St, Austin, TX?
|
||||
|
||||
Claude: I'll get a value estimate for that property.
|
||||
[Shows estimated price range and comparables]
|
||||
```
|
||||
|
||||
### Test Cache and Performance
|
||||
```
|
||||
User: Search for properties in Austin, TX (this should be cached on subsequent calls)
|
||||
|
||||
User: Get cache statistics to see hit/miss rates
|
||||
|
||||
User: Get usage statistics for the last 30 days
|
||||
```
|
||||
|
||||
## Troubleshooting Installation Issues
|
||||
|
||||
### Common Installation Problems
|
||||
|
||||
#### 1. Python Version Issues
|
||||
```bash
|
||||
# Check Python version
|
||||
python3 --version
|
||||
python3.13 --version
|
||||
|
||||
# If Python 3.13 not available, install it
|
||||
# Ubuntu/Debian:
|
||||
sudo apt update
|
||||
sudo apt install python3.13
|
||||
|
||||
# macOS with Homebrew:
|
||||
brew install python@3.13
|
||||
```
|
||||
|
||||
#### 2. uv Installation Issues
|
||||
```bash
|
||||
# Reinstall uv
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# Restart shell or reload PATH
|
||||
source ~/.bashrc # or ~/.zshrc
|
||||
```
|
||||
|
||||
#### 3. Permission Issues
|
||||
```bash
|
||||
# Fix directory permissions
|
||||
chmod -R 755 /path/to/mcrentcast
|
||||
|
||||
# Create data directory with correct permissions
|
||||
mkdir -p data
|
||||
chmod 755 data
|
||||
```
|
||||
|
||||
#### 4. Database Initialization Issues
|
||||
```bash
|
||||
# Remove existing database and recreate
|
||||
rm -f data/mcrentcast.db
|
||||
|
||||
# Reinitialize
|
||||
uv run python -c "
|
||||
from src.mcrentcast.database import db_manager
|
||||
db_manager.create_tables()
|
||||
print('Database initialized successfully')
|
||||
"
|
||||
```
|
||||
|
||||
#### 5. Claude MCP Integration Issues
|
||||
|
||||
**Server Not Found:**
|
||||
```bash
|
||||
# Check if server is registered
|
||||
claude mcp list
|
||||
|
||||
# Remove and re-add if needed
|
||||
claude mcp remove mcrentcast
|
||||
claude mcp add mcrentcast -- uvx --from git+https://git.supported.systems/MCP/mcrentcast.git mcrentcast
|
||||
```
|
||||
|
||||
**API Key Not Working:**
|
||||
```bash
|
||||
# Test API key directly
|
||||
curl -H "X-Api-Key: your_key" https://api.rentcast.io/v1/properties
|
||||
|
||||
# Use mock API for testing
|
||||
claude mcp add mcrentcast-test -- uvx --from git+https://git.supported.systems/MCP/mcrentcast.git mcrentcast \
|
||||
-e USE_MOCK_API=true \
|
||||
-e RENTCAST_API_KEY=test_key_basic
|
||||
```
|
||||
|
||||
### Debugging Steps
|
||||
|
||||
1. **Check Installation Status**
|
||||
```bash
|
||||
# Verify uv installation
|
||||
uv --version
|
||||
|
||||
# Check Python version
|
||||
uv run python --version
|
||||
|
||||
# Verify dependencies
|
||||
uv run python -c "import mcrentcast; print('Import successful')"
|
||||
```
|
||||
|
||||
2. **Test API Connectivity**
|
||||
```bash
|
||||
# Test with mock API
|
||||
USE_MOCK_API=true uv run python scripts/test_mock_api.py
|
||||
|
||||
# Test with real API (requires valid key)
|
||||
RENTCAST_API_KEY=your_key uv run python scripts/test_mock_api.py
|
||||
```
|
||||
|
||||
3. **Check Logs**
|
||||
```bash
|
||||
# Enable debug logging
|
||||
DEBUG=true LOG_LEVEL=DEBUG uv run mcrentcast
|
||||
```
|
||||
|
||||
4. **Database Verification**
|
||||
```bash
|
||||
# Check database file exists and is writable
|
||||
ls -la data/mcrentcast.db
|
||||
|
||||
# Test database connection
|
||||
uv run python -c "
|
||||
from src.mcrentcast.database import db_manager
|
||||
import asyncio
|
||||
async def test_db():
|
||||
stats = await db_manager.get_cache_stats()
|
||||
print('Database connection successful')
|
||||
asyncio.run(test_db())
|
||||
"
|
||||
```
|
||||
|
||||
## Environment-Specific Installation Notes
|
||||
|
||||
### Windows
|
||||
```powershell
|
||||
# Install uv for Windows
|
||||
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
|
||||
|
||||
# Use PowerShell for environment variables
|
||||
$env:RENTCAST_API_KEY = "your_actual_api_key"
|
||||
```
|
||||
|
||||
### macOS
|
||||
```bash
|
||||
# Install uv via Homebrew (alternative)
|
||||
brew install uv
|
||||
|
||||
# Set environment variable permanently
|
||||
echo 'export RENTCAST_API_KEY=your_actual_api_key' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
### Linux
|
||||
```bash
|
||||
# Install Python 3.13 on older distributions
|
||||
sudo add-apt-repository ppa:deadsnakes/ppa
|
||||
sudo apt update
|
||||
sudo apt install python3.13 python3.13-venv
|
||||
|
||||
# Set environment variable permanently
|
||||
echo 'export RENTCAST_API_KEY=your_actual_api_key' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
## Upgrading
|
||||
|
||||
### Upgrade Production Installation
|
||||
```bash
|
||||
# Remove old version
|
||||
claude mcp remove mcrentcast
|
||||
|
||||
# Install latest version
|
||||
claude mcp add mcrentcast -- uvx --from git+https://git.supported.systems/MCP/mcrentcast.git mcrentcast
|
||||
```
|
||||
|
||||
### Upgrade Development Installation
|
||||
```bash
|
||||
cd /path/to/mcrentcast
|
||||
|
||||
# Pull latest changes
|
||||
git pull origin main
|
||||
|
||||
# Update dependencies
|
||||
uv sync
|
||||
|
||||
# Reinitialize if needed
|
||||
./install.sh
|
||||
```
|
||||
|
||||
## Uninstallation
|
||||
|
||||
### Remove from Claude
|
||||
```bash
|
||||
# Remove MCP server
|
||||
claude mcp remove mcrentcast
|
||||
|
||||
# Also remove test server if installed
|
||||
claude mcp remove mcrentcast-test
|
||||
```
|
||||
|
||||
### Clean Development Installation
|
||||
```bash
|
||||
# Remove cloned repository
|
||||
rm -rf /path/to/mcrentcast
|
||||
|
||||
# Remove environment variables
|
||||
# Edit ~/.bashrc or ~/.zshrc to remove RENTCAST_API_KEY export
|
||||
```
|
||||
|
||||
## Getting Help
|
||||
|
||||
If you encounter issues during installation:
|
||||
|
||||
1. **Check the documentation**
|
||||
- [README.md](../README.md) - Overview and quick start
|
||||
- [USAGE.md](./USAGE.md) - Usage examples
|
||||
- [Mock API Guide](./mock-api.md) - Testing without credits
|
||||
|
||||
2. **Enable debug logging**
|
||||
```bash
|
||||
DEBUG=true LOG_LEVEL=DEBUG uv run mcrentcast
|
||||
```
|
||||
|
||||
3. **Test with mock API**
|
||||
```bash
|
||||
USE_MOCK_API=true uv run python scripts/test_mock_api.py
|
||||
```
|
||||
|
||||
4. **Create an issue**
|
||||
- Visit the [GitHub repository](https://git.supported.systems/MCP/mcrentcast)
|
||||
- Include error messages, environment details, and steps to reproduce
|
||||
|
||||
5. **Check system requirements**
|
||||
- Python 3.13+
|
||||
- Sufficient disk space (100MB minimum)
|
||||
- Internet connection for API calls
|
||||
- Write permissions for data directory
|
717
docs/USAGE.md
Normal file
717
docs/USAGE.md
Normal file
@ -0,0 +1,717 @@
|
||||
# mcrentcast Usage Guide
|
||||
|
||||
This guide provides comprehensive examples and best practices for using the mcrentcast MCP server with Claude.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Getting Started](#getting-started)
|
||||
- [Tool Reference](#tool-reference)
|
||||
- [Usage Examples](#usage-examples)
|
||||
- [Cost Management](#cost-management)
|
||||
- [Caching Best Practices](#caching-best-practices)
|
||||
- [Rate Limiting](#rate-limiting)
|
||||
- [Error Handling](#error-handling)
|
||||
- [Advanced Usage](#advanced-usage)
|
||||
|
||||
## Getting Started
|
||||
|
||||
Once mcrentcast is installed and configured with Claude, you can start using it through natural language conversations. All 13 tools are available and will be automatically selected by Claude based on your requests.
|
||||
|
||||
### First Steps
|
||||
|
||||
1. **Verify Installation**
|
||||
```
|
||||
User: What are my current API limits for Rentcast?
|
||||
|
||||
Claude: I'll check your current API limits.
|
||||
[Uses get_api_limits tool]
|
||||
|
||||
Shows: Daily: 0/100, Monthly: 0/1000, Rate limit: 3 requests/minute
|
||||
```
|
||||
|
||||
2. **Set API Key (if needed)**
|
||||
```
|
||||
User: Set my Rentcast API key to: sk_live_abcd1234...
|
||||
|
||||
Claude: I'll set your Rentcast API key for this session.
|
||||
[Uses set_api_key tool]
|
||||
|
||||
Response: API key updated successfully
|
||||
```
|
||||
|
||||
## Tool Reference
|
||||
|
||||
The mcrentcast server provides 13 MCP tools organized into categories:
|
||||
|
||||
### Property Data Tools (4 tools)
|
||||
| Tool | Description | Key Parameters |
|
||||
|------|-------------|----------------|
|
||||
| `search_properties` | Search for property records by location | `city`, `state`, `zipCode`, `limit`, `offset` |
|
||||
| `get_property` | Get detailed property information by ID | `property_id` |
|
||||
| `get_value_estimate` | Get property value estimate | `address` |
|
||||
| `get_rent_estimate` | Get rental price estimate | `address`, `bedrooms`, `bathrooms`, `squareFootage` |
|
||||
|
||||
### Listing Tools (3 tools)
|
||||
| Tool | Description | Key Parameters |
|
||||
|------|-------------|----------------|
|
||||
| `search_sale_listings` | Find properties currently for sale | `city`, `state`, `zipCode`, `limit` |
|
||||
| `search_rental_listings` | Find rental properties | `city`, `state`, `zipCode`, `limit` |
|
||||
| `get_market_statistics` | Get market trends and analytics | `city`, `state`, `zipCode` |
|
||||
|
||||
### Management Tools (6 tools)
|
||||
| Tool | Description | Key Parameters |
|
||||
|------|-------------|----------------|
|
||||
| `set_api_key` | Configure Rentcast API key | `api_key` |
|
||||
| `expire_cache` | Force refresh of cached data | `cache_key`, `endpoint`, `all` |
|
||||
| `get_cache_stats` | View cache performance metrics | - |
|
||||
| `get_usage_stats` | Track API usage and costs | `days` |
|
||||
| `set_api_limits` | Configure rate limits | `daily_limit`, `monthly_limit`, `requests_per_minute` |
|
||||
| `get_api_limits` | View current rate limits and usage | - |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### 1. Property Search
|
||||
|
||||
#### Basic Property Search
|
||||
```
|
||||
User: Find properties in Austin, Texas
|
||||
|
||||
Claude: I'll search for properties in Austin, Texas.
|
||||
[Uses search_properties with city="Austin", state="TX"]
|
||||
|
||||
Results: Found 10 properties (fresh data)
|
||||
- 123 Main St: $450,000, 3BR/2BA, 1,800 sq ft
|
||||
- 456 Oak Ave: $520,000, 4BR/3BA, 2,200 sq ft
|
||||
- ...
|
||||
```
|
||||
|
||||
#### Advanced Property Search
|
||||
```
|
||||
User: Show me the first 5 properties in ZIP code 78701, then get the next 5
|
||||
|
||||
Claude: I'll search for properties in ZIP code 78701.
|
||||
[Uses search_properties with zipCode="78701", limit=5, offset=0]
|
||||
|
||||
Then for the next batch:
|
||||
[Uses search_properties with zipCode="78701", limit=5, offset=5]
|
||||
```
|
||||
|
||||
#### Property Search with Force Refresh
|
||||
```
|
||||
User: Get fresh property data for downtown Seattle, ignore any cached results
|
||||
|
||||
Claude: I'll get fresh property data for downtown Seattle.
|
||||
[Uses search_properties with city="Seattle", state="WA", force_refresh=true]
|
||||
|
||||
Note: This will consume API credits for fresh data
|
||||
```
|
||||
|
||||
### 2. Property Details
|
||||
|
||||
#### Get Specific Property
|
||||
```
|
||||
User: Get details for property ID "prop_12345"
|
||||
|
||||
Claude: I'll get the detailed information for property ID prop_12345.
|
||||
[Uses get_property with property_id="prop_12345"]
|
||||
|
||||
Results: Property found (from cache, age: 2.3 hours)
|
||||
- Address: 789 Pine St, Denver, CO 80202
|
||||
- Property Type: Single Family
|
||||
- Bedrooms: 3, Bathrooms: 2.5
|
||||
- Square Footage: 2,100
|
||||
- Year Built: 1995
|
||||
- Last Sale: $475,000 (2023-08-15)
|
||||
```
|
||||
|
||||
### 3. Value Estimates
|
||||
|
||||
#### Property Value Estimate
|
||||
```
|
||||
User: What's the estimated value of 123 Main Street, Dallas, TX?
|
||||
|
||||
Claude: I'll get the value estimate for that property.
|
||||
[Uses get_value_estimate with address="123 Main Street, Dallas, TX"]
|
||||
|
||||
Results: Value estimate: $385,000 (fresh data)
|
||||
- Estimated range: $346,500 - $423,500
|
||||
- Confidence: High
|
||||
- Based on 3 comparable properties
|
||||
- Date: 2024-01-15
|
||||
```
|
||||
|
||||
#### Value Estimate with Property Details
|
||||
```
|
||||
User: I'm looking at a house at 456 Elm Ave, Portland, OR. What's it worth and what are similar properties selling for?
|
||||
|
||||
Claude: I'll get the value estimate and search for similar properties in Portland.
|
||||
[Uses get_value_estimate and search_sale_listings]
|
||||
|
||||
Value Estimate: $625,000 (range: $562,500 - $687,500)
|
||||
Similar properties for sale:
|
||||
- 444 Elm Ave: $599,000, 3BR/2BA
|
||||
- 468 Elm Ave: $649,000, 4BR/2.5BA
|
||||
```
|
||||
|
||||
### 4. Rent Estimates
|
||||
|
||||
#### Basic Rent Estimate
|
||||
```
|
||||
User: How much could I rent out my property at 789 Broadway, San Francisco, CA?
|
||||
|
||||
Claude: I'll get a rental estimate for that property.
|
||||
[Uses get_rent_estimate with address="789 Broadway, San Francisco, CA"]
|
||||
|
||||
Results: Rent estimate: $4,200/month (fresh data)
|
||||
- Estimated range: $3,780 - $4,620
|
||||
- Based on comparable rentals
|
||||
- Long-term rental estimate
|
||||
```
|
||||
|
||||
#### Detailed Rent Estimate
|
||||
```
|
||||
User: What's the rental potential for a 2-bedroom, 1.5-bathroom, 1200 sq ft condo at 555 Market St, San Francisco, CA?
|
||||
|
||||
Claude: I'll calculate the rental estimate with those specific details.
|
||||
[Uses get_rent_estimate with address, bedrooms=2, bathrooms=1.5, squareFootage=1200]
|
||||
|
||||
Results: Rent estimate: $3,850/month
|
||||
- Adjusted for: 2 bedrooms, 1.5 bathrooms, 1,200 sq ft
|
||||
- Comparable rentals:
|
||||
- 2BR/1BA, 1,100 sq ft: $3,600/month
|
||||
- 2BR/2BA, 1,300 sq ft: $4,100/month
|
||||
```
|
||||
|
||||
### 5. Sale Listings
|
||||
|
||||
#### Find Properties for Sale
|
||||
```
|
||||
User: What houses are currently for sale in Boulder, Colorado under $800,000?
|
||||
|
||||
Claude: I'll search for properties for sale in Boulder, Colorado.
|
||||
[Uses search_sale_listings with city="Boulder", state="CO"]
|
||||
|
||||
Found 8 sale listings (from cache, age: 1.2 hours)
|
||||
- 321 Mountain View Dr: $749,000, 3BR/2BA
|
||||
- 654 Forest Ave: $695,000, 2BR/2BA
|
||||
- 987 Creek Rd: $775,000, 4BR/3BA
|
||||
```
|
||||
|
||||
### 6. Rental Listings
|
||||
|
||||
#### Find Rental Properties
|
||||
```
|
||||
User: Show me rental properties available in Miami Beach, FL
|
||||
|
||||
Claude: I'll search for rental properties in Miami Beach.
|
||||
[Uses search_rental_listings with city="Miami Beach", state="FL"]
|
||||
|
||||
Found 12 rental listings (fresh data)
|
||||
- 111 Ocean Dr: $3,200/month, 2BR/2BA, Ocean view
|
||||
- 222 Collins Ave: $2,800/month, 1BR/1BA, Pool
|
||||
- 333 Washington Ave: $4,500/month, 3BR/2BA, Luxury
|
||||
```
|
||||
|
||||
### 7. Market Statistics
|
||||
|
||||
#### Market Analysis
|
||||
```
|
||||
User: What are the current market conditions in Nashville, Tennessee?
|
||||
|
||||
Claude: I'll get the market statistics for Nashville, Tennessee.
|
||||
[Uses get_market_statistics with city="Nashville", state="TN"]
|
||||
|
||||
Market Statistics for Nashville, TN (fresh data):
|
||||
- Median Sale Price: $425,000 (+8.2% YoY)
|
||||
- Median Rent: $1,850/month (+12.1% YoY)
|
||||
- Average Days on Market: 28 days
|
||||
- Active Inventory: 2,847 properties
|
||||
- Price per Square Foot: $185
|
||||
```
|
||||
|
||||
#### Comparative Market Analysis
|
||||
```
|
||||
User: Compare the real estate markets in Austin, TX and Denver, CO
|
||||
|
||||
Claude: I'll get market statistics for both Austin and Denver.
|
||||
[Uses get_market_statistics for both cities]
|
||||
|
||||
Austin, TX Market:
|
||||
- Median Sale Price: $485,000 (+5.8% YoY)
|
||||
- Median Rent: $2,100/month (+9.3% YoY)
|
||||
- Days on Market: 32 days
|
||||
|
||||
Denver, CO Market:
|
||||
- Median Sale Price: $525,000 (+3.2% YoY)
|
||||
- Median Rent: $2,350/month (+7.8% YoY)
|
||||
- Days on Market: 29 days
|
||||
|
||||
Analysis: Denver has higher prices but slower appreciation
|
||||
```
|
||||
|
||||
### 8. Cache Management
|
||||
|
||||
#### Check Cache Performance
|
||||
```
|
||||
User: How is the API cache performing?
|
||||
|
||||
Claude: I'll check the cache statistics.
|
||||
[Uses get_cache_stats]
|
||||
|
||||
Cache Statistics:
|
||||
- Total entries: 156
|
||||
- Cache hits: 89 (57.1% hit rate)
|
||||
- Cache misses: 67 (42.9% miss rate)
|
||||
- Storage used: 12.3 MB / 100 MB
|
||||
- Oldest entry: 18.2 hours ago
|
||||
```
|
||||
|
||||
#### Force Cache Refresh
|
||||
```
|
||||
User: Clear the cache for Austin property searches and get fresh data
|
||||
|
||||
Claude: I'll expire the cache for Austin property searches.
|
||||
[Uses expire_cache with endpoint="property-records" for Austin searches]
|
||||
|
||||
Cache entries expired: 8
|
||||
Fresh data will be fetched on next request.
|
||||
```
|
||||
|
||||
#### Clear All Cache
|
||||
```
|
||||
User: Clear all cached data
|
||||
|
||||
Claude: I'll clear all cached data.
|
||||
[Uses expire_cache with all=true]
|
||||
|
||||
Expired 156 cache entries
|
||||
All future requests will fetch fresh data from the API.
|
||||
```
|
||||
|
||||
### 9. Usage Tracking
|
||||
|
||||
#### Check API Usage
|
||||
```
|
||||
User: How much have I used the Rentcast API this month?
|
||||
|
||||
Claude: I'll check your API usage statistics.
|
||||
[Uses get_usage_stats with days=30]
|
||||
|
||||
Usage Statistics (Last 30 days):
|
||||
- Total Requests: 47 / 1000 monthly limit
|
||||
- Estimated Cost: $4.70
|
||||
- Most Used Endpoint: search_properties (28 requests)
|
||||
- Cache Hit Rate: 62%
|
||||
- Average Response Time: 245ms
|
||||
```
|
||||
|
||||
#### Weekly Usage Report
|
||||
```
|
||||
User: Show me my API usage for the past week
|
||||
|
||||
Claude: I'll get your usage statistics for the last 7 days.
|
||||
[Uses get_usage_stats with days=7]
|
||||
|
||||
Weekly Usage Report:
|
||||
- Total Requests: 12
|
||||
- Property Searches: 7 requests
|
||||
- Value Estimates: 3 requests
|
||||
- Rent Estimates: 2 requests
|
||||
- Estimated Cost: $1.20
|
||||
```
|
||||
|
||||
### 10. Rate Limit Management
|
||||
|
||||
#### Check Rate Limits
|
||||
```
|
||||
User: What are my current rate limits?
|
||||
|
||||
Claude: I'll check your current API limits and usage.
|
||||
[Uses get_api_limits]
|
||||
|
||||
API Limits:
|
||||
- Daily: 23/100 requests (23% used)
|
||||
- Monthly: 67/1000 requests (6.7% used)
|
||||
- Rate Limit: 3 requests per minute
|
||||
- Current status: Within limits
|
||||
```
|
||||
|
||||
#### Adjust Rate Limits
|
||||
```
|
||||
User: Increase my daily limit to 200 and monthly to 2000
|
||||
|
||||
Claude: I'll update your API limits.
|
||||
[Uses set_api_limits with daily_limit=200, monthly_limit=2000]
|
||||
|
||||
API Limits Updated:
|
||||
- Daily Limit: 100 → 200
|
||||
- Monthly Limit: 1000 → 2000
|
||||
- Rate Limit: 3 requests/minute (unchanged)
|
||||
```
|
||||
|
||||
## Cost Management
|
||||
|
||||
### Understanding API Costs
|
||||
|
||||
The mcrentcast server provides cost estimates and tracking:
|
||||
|
||||
- **Property Records Search**: ~$0.05-0.10 per request
|
||||
- **Value Estimates**: ~$0.15-0.25 per request
|
||||
- **Rent Estimates**: ~$0.15-0.25 per request
|
||||
- **Sale/Rental Listings**: ~$0.10-0.15 per request
|
||||
- **Market Statistics**: ~$0.20-0.30 per request
|
||||
|
||||
### Cost-Saving Strategies
|
||||
|
||||
1. **Use Caching Effectively**
|
||||
```
|
||||
User: I want to analyze Austin properties but minimize API costs
|
||||
|
||||
Claude: I'll help you minimize costs by using cached data where possible.
|
||||
|
||||
Strategy:
|
||||
- First search will be fresh (costs credits)
|
||||
- Subsequent related searches use cache
|
||||
- Market data cached for 24 hours by default
|
||||
```
|
||||
|
||||
2. **Batch Related Requests**
|
||||
```
|
||||
User: Get comprehensive data for ZIP code 90210 - properties, listings, and market stats
|
||||
|
||||
Claude: I'll get all the data for ZIP code 90210 in an efficient way.
|
||||
[Makes strategic API calls and leverages caching]
|
||||
```
|
||||
|
||||
3. **Use Mock API for Testing**
|
||||
```
|
||||
User: I want to test property searches without using API credits
|
||||
|
||||
Claude: You can use the mock API mode for testing.
|
||||
Configure with: USE_MOCK_API=true RENTCAST_API_KEY=test_key_basic
|
||||
```
|
||||
|
||||
### Cost Monitoring
|
||||
```
|
||||
User: Alert me if I'm approaching my monthly API limit
|
||||
|
||||
Claude: I'll check your current usage against limits.
|
||||
[Uses get_api_limits and get_usage_stats]
|
||||
|
||||
Current Usage: 850/1000 monthly requests (85% used)
|
||||
Warning: You're approaching your monthly limit. Consider:
|
||||
- Using cached data when possible
|
||||
- Setting force_refresh=false (default)
|
||||
- Monitoring with get_usage_stats regularly
|
||||
```
|
||||
|
||||
## Caching Best Practices
|
||||
|
||||
### Understanding Cache Behavior
|
||||
|
||||
1. **Automatic Caching**: All responses are cached by default
|
||||
2. **TTL (Time To Live)**: Default 24 hours, configurable
|
||||
3. **Cache Keys**: Based on endpoint + parameters
|
||||
4. **Force Refresh**: Use `force_refresh=true` to bypass cache
|
||||
|
||||
### Cache Strategy Examples
|
||||
|
||||
#### Smart Cache Usage
|
||||
```
|
||||
User: I'm doing market research on Austin. Get me property data efficiently.
|
||||
|
||||
Claude: I'll structure the requests to maximize cache efficiency.
|
||||
|
||||
1. Get market statistics (cached for 24h)
|
||||
2. Search properties (results cached)
|
||||
3. Get specific property details (uses cache if available)
|
||||
|
||||
This approach minimizes API calls while providing comprehensive data.
|
||||
```
|
||||
|
||||
#### Cache Warming
|
||||
```
|
||||
User: Prepare cached data for a client presentation on Denver real estate tomorrow
|
||||
|
||||
Claude: I'll pre-load cache with relevant Denver data.
|
||||
[Makes strategic API calls to cache:]
|
||||
- Market statistics
|
||||
- Property searches by key ZIP codes
|
||||
- Recent sale listings
|
||||
- Rental market data
|
||||
|
||||
Data will be cached and ready for your presentation.
|
||||
```
|
||||
|
||||
### Cache Maintenance
|
||||
```
|
||||
User: My cache seems stale. Refresh data for Seattle properties.
|
||||
|
||||
Claude: I'll refresh the Seattle property cache.
|
||||
[Uses expire_cache for Seattle-related entries, then searches with force_refresh]
|
||||
|
||||
Cache refreshed with fresh Seattle property data.
|
||||
```
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
### Understanding Rate Limits
|
||||
|
||||
The server implements multiple rate limiting layers:
|
||||
|
||||
1. **API-level**: Rentcast's limits (varies by plan)
|
||||
2. **Per-minute**: Default 3 requests/minute (configurable)
|
||||
3. **Daily/Monthly**: User-configurable quotas
|
||||
4. **Exponential Backoff**: Automatic retry with delays
|
||||
|
||||
### Working with Rate Limits
|
||||
|
||||
#### Handling Rate Limit Messages
|
||||
```
|
||||
User: Get data for 20 different ZIP codes quickly
|
||||
|
||||
Claude: I'll get data for multiple ZIP codes, but I need to respect rate limits.
|
||||
[Implements strategic delays between requests]
|
||||
|
||||
Note: Spacing requests to stay within 3 requests/minute limit.
|
||||
Processing ZIP codes in batches...
|
||||
```
|
||||
|
||||
#### Adjusting Rate Limits
|
||||
```
|
||||
User: I have a premium API plan. Increase my rate limits.
|
||||
|
||||
Claude: I'll update your rate limits for your premium plan.
|
||||
[Uses set_api_limits]
|
||||
|
||||
Updated for premium plan:
|
||||
- Daily: 500 requests
|
||||
- Monthly: 5000 requests
|
||||
- Rate: 10 requests/minute
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Error Scenarios
|
||||
|
||||
#### API Key Issues
|
||||
```
|
||||
User: Get properties in Chicago
|
||||
|
||||
Claude: I encountered an API key issue. Let me help resolve it.
|
||||
[Error: API key not configured]
|
||||
|
||||
Solution: Please set your API key using:
|
||||
"Set my Rentcast API key to: your_actual_key"
|
||||
```
|
||||
|
||||
#### Rate Limit Exceeded
|
||||
```
|
||||
User: [After many requests] Get more property data
|
||||
|
||||
Claude: I've hit the rate limit.
|
||||
[Error: Rate limit exceeded - retry after X seconds]
|
||||
|
||||
I'll wait and retry, or you can:
|
||||
- Use cached data with previous searches
|
||||
- Increase rate limits if you have a higher plan
|
||||
- Use mock API for testing
|
||||
```
|
||||
|
||||
#### Invalid Parameters
|
||||
```
|
||||
User: Get property data for "fake city, ZZ"
|
||||
|
||||
Claude: I'll search for properties in that location.
|
||||
[Error: Invalid location parameters]
|
||||
|
||||
The location "fake city, ZZ" wasn't found. Please try:
|
||||
- Valid city and state combinations
|
||||
- Existing ZIP codes
|
||||
- Check spelling of location names
|
||||
```
|
||||
|
||||
### Error Recovery Strategies
|
||||
|
||||
#### Automatic Retry with Cached Data
|
||||
```
|
||||
User: Get Austin property data
|
||||
|
||||
Claude: I'll try to get Austin property data.
|
||||
[API call fails, falls back to cache]
|
||||
|
||||
Using cached Austin data (age: 8.5 hours) due to API error.
|
||||
Would you like me to retry with fresh data?
|
||||
```
|
||||
|
||||
#### Graceful Degradation
|
||||
```
|
||||
User: Get comprehensive market report for Phoenix
|
||||
|
||||
Claude: I'll gather comprehensive Phoenix market data.
|
||||
[Some API calls succeed, others fail]
|
||||
|
||||
I was able to get:
|
||||
✓ Property listings (fresh)
|
||||
✓ Market statistics (cached, 4h old)
|
||||
✗ Value estimates (API error - using cached data)
|
||||
|
||||
The report is mostly complete with some cached data.
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Complex Analysis Workflows
|
||||
|
||||
#### Investment Property Analysis
|
||||
```
|
||||
User: Analyze 123 Oak St, Portland, OR as a potential rental investment
|
||||
|
||||
Claude: I'll perform a comprehensive investment analysis.
|
||||
[Uses multiple tools strategically:]
|
||||
|
||||
1. Property details and current value
|
||||
2. Rental estimate and comparable rentals
|
||||
3. Local market statistics and trends
|
||||
4. Sale listings for comparable properties
|
||||
|
||||
Investment Analysis for 123 Oak St, Portland, OR:
|
||||
- Current Value: $485,000 (±$25,000)
|
||||
- Rental Potential: $2,400/month
|
||||
- Gross Yield: 5.9% annually
|
||||
- Market Appreciation: +6.2% YoY
|
||||
- Days on Market: 34 days average
|
||||
- Recommendation: Positive cash flow potential
|
||||
```
|
||||
|
||||
#### Market Comparison Study
|
||||
```
|
||||
User: Compare investment opportunities between Austin, Nashville, and Raleigh
|
||||
|
||||
Claude: I'll compare real estate investment metrics across all three cities.
|
||||
[Systematic market analysis using cached data where possible]
|
||||
|
||||
Market Comparison Study:
|
||||
|
||||
Austin, TX:
|
||||
- Median Price: $485K, Rent: $2,100 (Yield: 5.2%)
|
||||
- Appreciation: +5.8% YoY, DOM: 32 days
|
||||
|
||||
Nashville, TN:
|
||||
- Median Price: $425K, Rent: $1,850 (Yield: 5.2%)
|
||||
- Appreciation: +8.2% YoY, DOM: 28 days
|
||||
|
||||
Raleigh, NC:
|
||||
- Median Price: $365K, Rent: $1,650 (Yield: 5.4%)
|
||||
- Appreciation: +7.1% YoY, DOM: 25 days
|
||||
|
||||
Best Value: Raleigh (lower entry cost, good yields)
|
||||
Best Growth: Nashville (highest appreciation)
|
||||
Most Liquid: Raleigh (fastest sales)
|
||||
```
|
||||
|
||||
### Automated Monitoring
|
||||
|
||||
#### Market Watch Setup
|
||||
```
|
||||
User: Set up automated monitoring for Phoenix real estate market changes
|
||||
|
||||
Claude: I'll help you track Phoenix market changes efficiently.
|
||||
|
||||
Strategy:
|
||||
1. Weekly market statistics checks
|
||||
2. Cache management to minimize costs
|
||||
3. Threshold alerts for significant changes
|
||||
4. Usage tracking to stay within limits
|
||||
|
||||
I'll check Phoenix market stats weekly and alert you to:
|
||||
- Price changes >5%
|
||||
- Inventory changes >20%
|
||||
- New rental/sale listings in target areas
|
||||
```
|
||||
|
||||
#### Portfolio Monitoring
|
||||
```
|
||||
User: Track value estimates for my 3 rental properties monthly
|
||||
|
||||
Properties:
|
||||
- 123 Main St, Austin, TX
|
||||
- 456 Oak Ave, Denver, CO
|
||||
- 789 Pine St, Atlanta, GA
|
||||
|
||||
Claude: I'll set up monthly value tracking for your portfolio.
|
||||
|
||||
Monthly Portfolio Report Strategy:
|
||||
- Value estimates for all 3 properties
|
||||
- Market statistics for each city
|
||||
- Rental market comparisons
|
||||
- Performance trends over time
|
||||
|
||||
I'll use caching efficiently and track API usage to minimize costs.
|
||||
```
|
||||
|
||||
### Integration Patterns
|
||||
|
||||
#### Real Estate CRM Integration
|
||||
```
|
||||
User: I have leads interested in Austin properties under $400K. Find suitable options and get market context.
|
||||
|
||||
Claude: I'll find suitable Austin properties and provide market context.
|
||||
[Strategic search and analysis]
|
||||
|
||||
Austin Properties Under $400K:
|
||||
- 5 properties found matching criteria
|
||||
- Market context: Prices 15% below median
|
||||
- Rental yields: 6.2-7.1% range
|
||||
- Market trend: +5.8% appreciation
|
||||
- Investment grade: Good entry opportunity
|
||||
|
||||
Ready for CRM integration with detailed property packets.
|
||||
```
|
||||
|
||||
#### Reporting and Analytics
|
||||
```
|
||||
User: Generate a quarterly market report for my real estate clients covering Dallas-Fort Worth
|
||||
|
||||
Claude: I'll create a comprehensive DFW quarterly market report.
|
||||
[Comprehensive data gathering using efficient API calls]
|
||||
|
||||
Q4 2024 Dallas-Fort Worth Market Report:
|
||||
|
||||
Executive Summary:
|
||||
- Median home price: $425K (+4.2% QoQ)
|
||||
- Average rent: $1,950/month (+8.1% QoQ)
|
||||
- Inventory levels: 3.2 months supply
|
||||
- Market velocity: 31 days average DOM
|
||||
|
||||
Detailed analysis with charts and comparable data ready for client presentation.
|
||||
```
|
||||
|
||||
## Best Practices Summary
|
||||
|
||||
### Cost Optimization
|
||||
1. **Leverage caching** - Don't force refresh unnecessarily
|
||||
2. **Batch related requests** - Get comprehensive data efficiently
|
||||
3. **Monitor usage** - Track costs with `get_usage_stats`
|
||||
4. **Use mock API** - For testing and development
|
||||
5. **Set appropriate limits** - Match your Rentcast plan
|
||||
|
||||
### Performance Optimization
|
||||
1. **Cache warming** - Pre-load frequently accessed data
|
||||
2. **Strategic timing** - Respect rate limits
|
||||
3. **Error handling** - Graceful fallbacks to cached data
|
||||
4. **Batch operations** - Combine related searches
|
||||
|
||||
### Data Management
|
||||
1. **Regular cache maintenance** - Clean expired entries
|
||||
2. **Monitor cache hit rates** - Optimize for efficiency
|
||||
3. **Track API patterns** - Understand usage trends
|
||||
4. **Validate data freshness** - Balance cost vs. accuracy
|
||||
|
||||
### Security and Reliability
|
||||
1. **Secure API key storage** - Use environment variables
|
||||
2. **Rate limit compliance** - Avoid API suspensions
|
||||
3. **Error monitoring** - Track and resolve issues
|
||||
4. **Backup strategies** - Cache provides resilience
|
||||
|
||||
This comprehensive usage guide should help you maximize the value of the mcrentcast MCP server while minimizing costs and maintaining optimal performance.
|
@ -768,10 +768,10 @@ else:
|
||||
|
||||
def main():
|
||||
"""Main entry point for the MCP server."""
|
||||
# Run the FastMCP server
|
||||
import asyncio
|
||||
# FastMCP handles everything when running as a script
|
||||
# The app.run() method in FastMCP 2.x runs synchronously
|
||||
try:
|
||||
asyncio.run(app.run())
|
||||
app.run()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except Exception as e:
|
||||
|
243
tests/README.md
Normal file
243
tests/README.md
Normal file
@ -0,0 +1,243 @@
|
||||
# MCRentCast MCP Server - Comprehensive Test Suite
|
||||
|
||||
This directory contains a comprehensive test suite for the mcrentcast MCP server, designed to thoroughly test all 13 MCP tools with various scenarios including caching, rate limiting, error handling, and both mock and real API modes.
|
||||
|
||||
## 📁 Test Structure
|
||||
|
||||
```
|
||||
tests/
|
||||
├── conftest.py # pytest configuration and shared fixtures
|
||||
├── test_mcp_server.py # Main comprehensive test suite (1,400+ lines)
|
||||
├── run_comprehensive_tests.py # Test runner script
|
||||
├── test_integration.py # Existing integration tests
|
||||
├── test_server.py # Basic server tests
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## 🧪 Test Coverage
|
||||
|
||||
### 13 MCP Tools Tested
|
||||
The test suite comprehensively tests all MCP tools defined in the server:
|
||||
|
||||
1. **`set_api_key`** - API key management and validation
|
||||
2. **`get_api_limits`** - Current API limits and usage retrieval
|
||||
3. **`set_api_limits`** - API rate limit configuration
|
||||
4. **`search_properties`** - Property record search with caching
|
||||
5. **`get_property`** - Individual property details retrieval
|
||||
6. **`get_value_estimate`** - Property value estimation
|
||||
7. **`get_rent_estimate`** - Property rent estimation
|
||||
8. **`search_sale_listings`** - Sale listing search
|
||||
9. **`search_rental_listings`** - Rental listing search
|
||||
10. **`get_market_statistics`** - Market statistics by location
|
||||
11. **`expire_cache`** - Cache management and expiration
|
||||
12. **`get_cache_stats`** - Cache performance statistics
|
||||
13. **`get_usage_stats`** - API usage tracking and reporting
|
||||
|
||||
### Test Categories
|
||||
|
||||
#### 🟢 **Smoke Tests** (`@pytest.mark.smoke`)
|
||||
- **`test_all_tools_exist`** - Verifies all 13 expected tools are registered
|
||||
- **`test_basic_server_functionality`** - Basic server setup validation
|
||||
|
||||
#### 🔵 **Unit Tests** (`@pytest.mark.unit`)
|
||||
- **API Key Management** - Set/validation with success and error cases
|
||||
- **Property Operations** - Individual tool functionality with mocking
|
||||
- **Cache Management** - Cache operations and statistics
|
||||
- **Usage & Limits** - API quota and rate limit management
|
||||
- **Error Handling** - Comprehensive error scenario testing
|
||||
|
||||
#### 🟣 **Integration Tests** (`@pytest.mark.integration`)
|
||||
- **Cache Hit/Miss Scenarios** - Full caching workflow testing
|
||||
- **Rate Limiting Behavior** - Exponential backoff and limit enforcement
|
||||
- **Mock API Integration** - Testing with mock Rentcast API
|
||||
- **Confirmation Flow** - User confirmation and elicitation testing
|
||||
|
||||
#### 🟠 **Performance Tests** (`@pytest.mark.performance`)
|
||||
- **Concurrent Request Handling** - Multiple simultaneous requests
|
||||
- **Rate Limit Stress Testing** - High-frequency request scenarios
|
||||
- **Cache Performance** - Cache efficiency under load
|
||||
|
||||
#### 🔴 **API Tests** (`@pytest.mark.api`)
|
||||
- **Real API Integration** - Tests against actual Rentcast API (when configured)
|
||||
- **Mock vs Real Comparison** - Behavior validation across modes
|
||||
|
||||
## 🚀 Enhanced Testing Framework
|
||||
|
||||
### TestReporter Class
|
||||
Custom test reporting with syntax highlighting and quality metrics:
|
||||
|
||||
```python
|
||||
reporter = TestReporter("test_name")
|
||||
reporter.log_input("request_data", data, "Test input description")
|
||||
reporter.log_processing_step("validation", "Validating API response", duration_ms=25.3)
|
||||
reporter.log_output("result", response, quality_score=9.5)
|
||||
reporter.log_quality_metric("accuracy", 0.95, threshold=0.90, passed=True)
|
||||
result = reporter.complete()
|
||||
```
|
||||
|
||||
### Beautiful HTML Reports
|
||||
- **Professional styling** with Inter fonts and gradient headers
|
||||
- **Quality scores** for each test with color-coded results
|
||||
- **Test categorization** with automatic marker detection
|
||||
- **Performance metrics** and timing information
|
||||
- **Interactive filtering** by test result and category
|
||||
|
||||
### Advanced Mocking
|
||||
- **Database manager mocking** for isolated testing
|
||||
- **Rentcast client mocking** with configurable responses
|
||||
- **Confirmation flow mocking** for user interaction testing
|
||||
- **Rate limiting simulation** for error condition testing
|
||||
|
||||
## 🎯 Key Testing Scenarios
|
||||
|
||||
### Caching Functionality
|
||||
```python
|
||||
# Cache hit scenario
|
||||
mock_db_manager.get_cache_entry.return_value = MagicMock() # Cache exists
|
||||
result = await app.tools["search_properties"](request)
|
||||
assert result["cached"] is True
|
||||
assert result["cache_age_hours"] > 0
|
||||
|
||||
# Cache miss with confirmation
|
||||
mock_db_manager.get_cache_entry.return_value = None # Cache miss
|
||||
mock_confirmation.return_value = True # User confirms
|
||||
result = await app.tools["search_properties"](request)
|
||||
assert result["cached"] is False
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
```python
|
||||
# Rate limit exceeded
|
||||
mock_client.get_property_records.side_effect = RateLimitExceeded("Rate limit exceeded")
|
||||
result = await app.tools["search_properties"](request)
|
||||
assert result["error"] == "Rate limit exceeded"
|
||||
assert "retry_after" in result
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
```python
|
||||
# API error handling
|
||||
mock_client.get_property_records.side_effect = RentcastAPIError("Invalid API key")
|
||||
result = await app.tools["search_properties"](request)
|
||||
assert result["error"] == "API error"
|
||||
assert "Invalid API key" in result["message"]
|
||||
```
|
||||
|
||||
## 📊 Running Tests
|
||||
|
||||
### Quick Start
|
||||
```bash
|
||||
# Run all smoke tests
|
||||
PYTHONPATH=src uv run pytest tests/test_mcp_server.py::TestSmokeTests -v
|
||||
|
||||
# Run comprehensive test suite
|
||||
python tests/run_comprehensive_tests.py
|
||||
|
||||
# Run specific test categories
|
||||
PYTHONPATH=src uv run pytest tests/test_mcp_server.py -m unit -v
|
||||
PYTHONPATH=src uv run pytest tests/test_mcp_server.py -m integration -v
|
||||
PYTHONPATH=src uv run pytest tests/test_mcp_server.py -m performance -v
|
||||
```
|
||||
|
||||
### Advanced Usage
|
||||
```bash
|
||||
# Generate HTML report
|
||||
PYTHONPATH=src uv run pytest tests/test_mcp_server.py --html=reports/test_report.html --self-contained-html
|
||||
|
||||
# Run with coverage
|
||||
PYTHONPATH=src uv run pytest tests/test_mcp_server.py --cov=src --cov-report=html --cov-report=term
|
||||
|
||||
# Run specific tests
|
||||
PYTHONPATH=src uv run pytest tests/test_mcp_server.py::TestPropertySearch::test_search_properties_cached_hit -v
|
||||
|
||||
# Collect tests without running
|
||||
PYTHONPATH=src uv run pytest tests/test_mcp_server.py --collect-only
|
||||
```
|
||||
|
||||
## 🔧 Test Configuration
|
||||
|
||||
### Fixtures Available
|
||||
- **`mock_db_manager`** - Mocked database operations
|
||||
- **`mock_rentcast_client`** - Mocked Rentcast API client
|
||||
- **`sample_property`** - Sample property record data
|
||||
- **`sample_cache_stats`** - Sample cache statistics
|
||||
- **`test_data_factory`** - Factory for creating test objects
|
||||
|
||||
### Environment Variables
|
||||
- **`PYTHONPATH=src`** - Required for imports
|
||||
- **`PYTEST_CURRENT_TEST`** - Auto-set by pytest
|
||||
- **`RENTCAST_API_KEY`** - For real API testing (optional)
|
||||
|
||||
## 📈 Test Metrics
|
||||
|
||||
### Coverage Targets
|
||||
- **Unit Tests**: 70-80% code coverage
|
||||
- **Critical Paths**: 90%+ coverage
|
||||
- **Integration Tests**: End-to-end workflow coverage
|
||||
- **Error Paths**: All error conditions tested
|
||||
|
||||
### Quality Metrics
|
||||
- **Response Time**: < 1000ms for mocked tests
|
||||
- **Accuracy**: 95%+ for data validation tests
|
||||
- **Reliability**: 0% flaky tests tolerance
|
||||
- **Maintainability**: Clear, descriptive test names and structure
|
||||
|
||||
## 🛠 Extending Tests
|
||||
|
||||
### Adding New Tests
|
||||
```python
|
||||
class TestNewFeature:
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
async def test_new_functionality(self, mock_db_manager):
|
||||
"""Test new feature functionality."""
|
||||
reporter = TestReporter("new_functionality")
|
||||
|
||||
# Test implementation
|
||||
result = await app.tools["new_tool"](request)
|
||||
|
||||
# Assertions
|
||||
assert result["success"] is True
|
||||
|
||||
reporter.complete()
|
||||
```
|
||||
|
||||
### Custom Fixtures
|
||||
```python
|
||||
@pytest.fixture
|
||||
def custom_test_data():
|
||||
"""Provide custom test data."""
|
||||
return {"custom": "data"}
|
||||
```
|
||||
|
||||
## 📋 Test Checklist
|
||||
|
||||
- [x] All 13 MCP tools have comprehensive tests
|
||||
- [x] Cache hit and miss scenarios covered
|
||||
- [x] Rate limiting behavior tested
|
||||
- [x] Error handling for all failure modes
|
||||
- [x] Mock API mode testing
|
||||
- [x] User confirmation flow testing
|
||||
- [x] Performance and concurrency testing
|
||||
- [x] Beautiful HTML reporting with quality metrics
|
||||
- [x] Professional test structure with fixtures
|
||||
- [x] Documentation and usage examples
|
||||
|
||||
## 🎨 Report Examples
|
||||
|
||||
The test suite generates beautiful HTML reports with:
|
||||
- **Custom styling** with professional gradients and typography
|
||||
- **Test categorization** (Unit, Integration, Smoke, Performance, API)
|
||||
- **Quality scores** (9.5/10 for passing tests, 3.0/10 for failures)
|
||||
- **Performance timing** for each test
|
||||
- **Interactive filtering** by result type and category
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
1. **Run the comprehensive test suite** to validate all functionality
|
||||
2. **Review HTML reports** for detailed test results and coverage
|
||||
3. **Add real API tests** when Rentcast API key is available
|
||||
4. **Extend performance tests** for production load scenarios
|
||||
5. **Integrate with CI/CD** pipeline for automated testing
|
||||
|
||||
This test suite follows FastMCP testing guidelines and provides comprehensive coverage of the mcrentcast MCP server functionality, ensuring reliability and maintainability of the codebase.
|
393
tests/conftest.py
Normal file
393
tests/conftest.py
Normal file
@ -0,0 +1,393 @@
|
||||
"""Pytest configuration and fixtures for mcrentcast MCP server tests.
|
||||
|
||||
Provides shared fixtures, test configuration, and enhanced HTML report styling
|
||||
following the project's testing framework requirements.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
|
||||
import pytest
|
||||
import structlog
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
# Add src directory to path for imports
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
||||
|
||||
# Configure test logging
|
||||
structlog.configure(
|
||||
processors=[
|
||||
structlog.stdlib.filter_by_level,
|
||||
structlog.stdlib.add_logger_name,
|
||||
structlog.stdlib.add_log_level,
|
||||
structlog.dev.ConsoleRenderer()
|
||||
],
|
||||
context_class=dict,
|
||||
logger_factory=structlog.stdlib.LoggerFactory(),
|
||||
cache_logger_on_first_use=True,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def event_loop():
|
||||
"""Create event loop for async tests."""
|
||||
loop = asyncio.new_event_loop()
|
||||
yield loop
|
||||
loop.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def clean_test_environment():
|
||||
"""Ensure clean test environment for each test."""
|
||||
# Reset any global state
|
||||
yield
|
||||
# Cleanup after test
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_settings():
|
||||
"""Mock application settings for testing."""
|
||||
from unittest.mock import patch
|
||||
|
||||
with patch("mcrentcast.server.settings") as mock_settings:
|
||||
# Configure default mock settings
|
||||
mock_settings.rentcast_api_key = "test_api_key_123"
|
||||
mock_settings.use_mock_api = False
|
||||
mock_settings.daily_api_limit = 100
|
||||
mock_settings.monthly_api_limit = 1000
|
||||
mock_settings.requests_per_minute = 3
|
||||
mock_settings.cache_ttl_hours = 24
|
||||
mock_settings.mode = "test"
|
||||
mock_settings.validate_api_key.return_value = True
|
||||
|
||||
yield mock_settings
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def test_database():
|
||||
"""Provide test database instance."""
|
||||
# For testing, we'll use in-memory SQLite
|
||||
from mcrentcast.database import DatabaseManager
|
||||
|
||||
test_db = DatabaseManager(database_url="sqlite:///:memory:")
|
||||
test_db.create_tables()
|
||||
|
||||
yield test_db
|
||||
|
||||
# Cleanup
|
||||
if hasattr(test_db, 'close'):
|
||||
await test_db.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_test_data():
|
||||
"""Provide sample test data for various test scenarios."""
|
||||
from mcrentcast.models import (
|
||||
PropertyRecord,
|
||||
ValueEstimate,
|
||||
RentEstimate,
|
||||
SaleListing,
|
||||
RentalListing,
|
||||
MarketStatistics
|
||||
)
|
||||
|
||||
return {
|
||||
"property_record": PropertyRecord(
|
||||
id="test_prop_001",
|
||||
address="123 Test Street",
|
||||
city="Test City",
|
||||
state="TX",
|
||||
zipCode="12345",
|
||||
propertyType="Single Family",
|
||||
bedrooms=3,
|
||||
bathrooms=2.0,
|
||||
squareFootage=1800,
|
||||
yearBuilt=2015,
|
||||
lastSalePrice=350000,
|
||||
zestimate=375000,
|
||||
rentestimate=2200
|
||||
),
|
||||
|
||||
"value_estimate": ValueEstimate(
|
||||
address="123 Test Street",
|
||||
price=375000,
|
||||
priceRangeLow=350000,
|
||||
priceRangeHigh=400000,
|
||||
confidence="High",
|
||||
lastSaleDate="2023-06-15",
|
||||
lastSalePrice=350000
|
||||
),
|
||||
|
||||
"rent_estimate": RentEstimate(
|
||||
address="123 Test Street",
|
||||
rent=2200,
|
||||
rentRangeLow=2000,
|
||||
rentRangeHigh=2400,
|
||||
confidence="Medium"
|
||||
),
|
||||
|
||||
"sale_listing": SaleListing(
|
||||
id="sale_test_001",
|
||||
address="456 Sale Avenue",
|
||||
city="Sale City",
|
||||
state="CA",
|
||||
zipCode="54321",
|
||||
price=525000,
|
||||
bedrooms=4,
|
||||
bathrooms=3.0,
|
||||
squareFootage=2400,
|
||||
propertyType="Single Family",
|
||||
listingDate="2024-08-01",
|
||||
daysOnMarket=30
|
||||
),
|
||||
|
||||
"rental_listing": RentalListing(
|
||||
id="rent_test_001",
|
||||
address="789 Rental Road",
|
||||
city="Rental City",
|
||||
state="NY",
|
||||
zipCode="67890",
|
||||
rent=3200,
|
||||
bedrooms=2,
|
||||
bathrooms=2.0,
|
||||
squareFootage=1400,
|
||||
propertyType="Condo",
|
||||
availableDate="2024-10-01",
|
||||
pets="Dogs allowed"
|
||||
),
|
||||
|
||||
"market_statistics": MarketStatistics(
|
||||
city="Test City",
|
||||
state="TX",
|
||||
medianSalePrice=425000,
|
||||
medianRent=2100,
|
||||
averageDaysOnMarket=32,
|
||||
inventoryCount=850,
|
||||
pricePerSquareFoot=245.50,
|
||||
rentPerSquareFoot=1.65,
|
||||
appreciation=6.8
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def pytest_html_report_title(report):
|
||||
"""Customize HTML report title."""
|
||||
report.title = "🏠 MCRentCast MCP Server - Comprehensive Test Results"
|
||||
|
||||
|
||||
def pytest_html_results_table_header(cells):
|
||||
"""Customize HTML report table headers."""
|
||||
cells.insert(2, '<th class="sortable" data-column-type="text">Test Category</th>')
|
||||
cells.insert(3, '<th class="sortable" data-column-type="text">Quality Score</th>')
|
||||
|
||||
|
||||
def pytest_html_results_table_row(report, cells):
|
||||
"""Customize HTML report table rows with enhanced information."""
|
||||
# Extract test category from markers
|
||||
test_categories = []
|
||||
if hasattr(report, 'keywords'):
|
||||
for marker in ['unit', 'integration', 'smoke', 'performance', 'api']:
|
||||
if marker in report.keywords:
|
||||
test_categories.append(marker.title())
|
||||
|
||||
category = ", ".join(test_categories) if test_categories else "General"
|
||||
|
||||
# Calculate quality score based on test outcome and performance
|
||||
if report.passed:
|
||||
quality_score = "9.5/10" if report.duration < 1.0 else "8.5/10"
|
||||
quality_color = "color: #28a745;"
|
||||
elif report.failed:
|
||||
quality_score = "3.0/10"
|
||||
quality_color = "color: #dc3545;"
|
||||
elif report.skipped:
|
||||
quality_score = "N/A"
|
||||
quality_color = "color: #6c757d;"
|
||||
else:
|
||||
quality_score = "Unknown"
|
||||
quality_color = "color: #17a2b8;"
|
||||
|
||||
# Insert custom columns
|
||||
cells.insert(2, f'<td>{category}</td>')
|
||||
cells.insert(3, f'<td style="{quality_color}"><strong>{quality_score}</strong></td>')
|
||||
|
||||
|
||||
def pytest_html_results_summary(prefix, session, postfix):
|
||||
"""Add custom summary information to the HTML report."""
|
||||
test_summary = f"""
|
||||
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; text-align: center;">
|
||||
<h2 style="margin: 0 0 10px 0; font-size: 24px;">🏠 MCRentCast MCP Server Test Suite</h2>
|
||||
<p style="margin: 5px 0; opacity: 0.9;">Comprehensive testing of 13 MCP tools with caching, rate limiting, and error handling</p>
|
||||
<p style="margin: 5px 0; opacity: 0.9;">Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} UTC</p>
|
||||
<p style="margin: 5px 0; opacity: 0.9;">Testing Framework: pytest + FastMCP + Enhanced Reporting</p>
|
||||
</div>
|
||||
"""
|
||||
prefix.extend([test_summary])
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def test_setup_and_teardown():
|
||||
"""Automatic setup and teardown for each test."""
|
||||
# Setup
|
||||
test_start_time = datetime.utcnow()
|
||||
|
||||
# Test execution happens here
|
||||
yield
|
||||
|
||||
# Teardown
|
||||
test_duration = (datetime.utcnow() - test_start_time).total_seconds()
|
||||
|
||||
# Log test completion (optional)
|
||||
if test_duration > 5.0: # Log slow tests
|
||||
logging.warning(f"Slow test detected: {test_duration:.2f}s")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_performance_tracker():
|
||||
"""Track test performance metrics."""
|
||||
class PerformanceTracker:
|
||||
def __init__(self):
|
||||
self.metrics = {}
|
||||
self.start_time = None
|
||||
|
||||
def start_tracking(self, operation: str):
|
||||
self.start_time = datetime.utcnow()
|
||||
|
||||
def end_tracking(self, operation: str):
|
||||
if self.start_time:
|
||||
duration = (datetime.utcnow() - self.start_time).total_seconds() * 1000
|
||||
self.metrics[operation] = duration
|
||||
self.start_time = None
|
||||
|
||||
def get_metrics(self) -> Dict[str, float]:
|
||||
return self.metrics.copy()
|
||||
|
||||
return PerformanceTracker()
|
||||
|
||||
|
||||
# Custom pytest markers
|
||||
def pytest_configure(config):
|
||||
"""Configure custom pytest markers."""
|
||||
config.addinivalue_line("markers", "unit: Unit tests that test individual functions")
|
||||
config.addinivalue_line("markers", "integration: Integration tests that test component interactions")
|
||||
config.addinivalue_line("markers", "smoke: Smoke tests for basic functionality verification")
|
||||
config.addinivalue_line("markers", "performance: Performance and benchmarking tests")
|
||||
config.addinivalue_line("markers", "api: Rentcast API integration tests")
|
||||
config.addinivalue_line("markers", "slow: Tests that are expected to take longer than usual")
|
||||
|
||||
|
||||
def pytest_collection_modifyitems(config, items):
|
||||
"""Modify test collection to add automatic markers."""
|
||||
for item in items:
|
||||
# Add slow marker to tests that might be slow
|
||||
if "integration" in item.keywords or "performance" in item.keywords:
|
||||
item.add_marker(pytest.mark.slow)
|
||||
|
||||
# Add markers based on test class names
|
||||
if "TestApiKeyManagement" in str(item.parent):
|
||||
item.add_marker(pytest.mark.unit)
|
||||
elif "TestPropertySearch" in str(item.parent):
|
||||
item.add_marker(pytest.mark.integration)
|
||||
elif "TestSmokeTests" in str(item.parent):
|
||||
item.add_marker(pytest.mark.smoke)
|
||||
elif "TestRateLimiting" in str(item.parent):
|
||||
item.add_marker(pytest.mark.performance)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_logger():
|
||||
"""Provide mock logger for testing."""
|
||||
return MagicMock(spec=structlog.BoundLogger)
|
||||
|
||||
|
||||
# Test data factories
|
||||
class TestDataFactory:
|
||||
"""Factory for creating test data objects."""
|
||||
|
||||
@staticmethod
|
||||
def create_property_record(**kwargs):
|
||||
"""Create a property record with default values."""
|
||||
from mcrentcast.models import PropertyRecord
|
||||
|
||||
defaults = {
|
||||
"id": "factory_prop_001",
|
||||
"address": "Factory Test Address",
|
||||
"city": "Factory City",
|
||||
"state": "TX",
|
||||
"zipCode": "00000",
|
||||
"propertyType": "Single Family",
|
||||
"bedrooms": 3,
|
||||
"bathrooms": 2.0,
|
||||
"squareFootage": 1500
|
||||
}
|
||||
defaults.update(kwargs)
|
||||
return PropertyRecord(**defaults)
|
||||
|
||||
@staticmethod
|
||||
def create_cache_stats(**kwargs):
|
||||
"""Create cache stats with default values."""
|
||||
from mcrentcast.models import CacheStats
|
||||
|
||||
defaults = {
|
||||
"total_entries": 100,
|
||||
"total_hits": 80,
|
||||
"total_misses": 20,
|
||||
"cache_size_mb": 5.0,
|
||||
"hit_rate": 80.0
|
||||
}
|
||||
defaults.update(kwargs)
|
||||
return CacheStats(**defaults)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_data_factory():
|
||||
"""Provide test data factory."""
|
||||
return TestDataFactory()
|
||||
|
||||
|
||||
# Async test utilities
|
||||
@pytest.fixture
|
||||
def async_test_utils():
|
||||
"""Provide utilities for async testing."""
|
||||
class AsyncTestUtils:
|
||||
@staticmethod
|
||||
async def wait_for_condition(condition_func, timeout=5.0, interval=0.1):
|
||||
"""Wait for a condition to become true."""
|
||||
import asyncio
|
||||
|
||||
end_time = asyncio.get_event_loop().time() + timeout
|
||||
while asyncio.get_event_loop().time() < end_time:
|
||||
if await condition_func():
|
||||
return True
|
||||
await asyncio.sleep(interval)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
async def run_with_timeout(coro, timeout=10.0):
|
||||
"""Run coroutine with timeout."""
|
||||
return await asyncio.wait_for(coro, timeout=timeout)
|
||||
|
||||
return AsyncTestUtils()
|
||||
|
||||
|
||||
# Environment setup for different test modes
|
||||
@pytest.fixture(params=["mock_api", "real_api"])
|
||||
def api_mode(request):
|
||||
"""Parameterized fixture for testing both mock and real API modes."""
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def configure_test_mode(api_mode):
|
||||
"""Configure test environment based on API mode."""
|
||||
from unittest.mock import patch
|
||||
|
||||
use_mock = api_mode == "mock_api"
|
||||
|
||||
with patch("mcrentcast.server.settings") as mock_settings:
|
||||
mock_settings.use_mock_api = use_mock
|
||||
mock_settings.mock_api_url = "http://localhost:8001/v1" if use_mock else None
|
||||
yield api_mode
|
173
tests/run_comprehensive_tests.py
Executable file
173
tests/run_comprehensive_tests.py
Executable file
@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Comprehensive test runner for mcrentcast MCP server.
|
||||
|
||||
This script provides various testing scenarios and configurations to thoroughly
|
||||
test the mcrentcast MCP server functionality.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add src directory to path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
||||
|
||||
|
||||
def run_command(cmd: list[str], description: str) -> bool:
|
||||
"""Run a command and return success status."""
|
||||
print(f"\n🧪 {description}")
|
||||
print(f" Command: {' '.join(cmd)}")
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=Path(__file__).parent.parent
|
||||
)
|
||||
print(f" ✅ Success ({result.returncode})")
|
||||
if result.stdout:
|
||||
# Show just the summary line
|
||||
lines = result.stdout.strip().split('\n')
|
||||
for line in lines[-10:]:
|
||||
if 'passed' in line or 'failed' in line or 'error' in line:
|
||||
print(f" 📊 {line}")
|
||||
break
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f" ❌ Failed ({e.returncode})")
|
||||
if e.stdout:
|
||||
print(f" 📝 Output: {e.stdout[-200:]}...") # Last 200 chars
|
||||
if e.stderr:
|
||||
print(f" 🚨 Error: {e.stderr[-200:]}...") # Last 200 chars
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
"""Run comprehensive test suite."""
|
||||
print("🏠 MCRentCast MCP Server - Comprehensive Test Suite")
|
||||
print("=" * 60)
|
||||
|
||||
# Set environment variables
|
||||
env = os.environ.copy()
|
||||
env["PYTHONPATH"] = "src"
|
||||
|
||||
base_cmd = ["uv", "run", "pytest"]
|
||||
test_file = "tests/test_mcp_server.py"
|
||||
|
||||
test_scenarios = [
|
||||
# Smoke tests - basic functionality
|
||||
{
|
||||
"cmd": base_cmd + [f"{test_file}::TestSmokeTests", "-v", "--tb=short"],
|
||||
"description": "Running smoke tests (basic functionality)",
|
||||
},
|
||||
|
||||
# API key management tests
|
||||
{
|
||||
"cmd": base_cmd + [f"{test_file}::TestApiKeyManagement", "-v", "--tb=short"],
|
||||
"description": "Testing API key management",
|
||||
},
|
||||
|
||||
# Property search tests (mocked)
|
||||
{
|
||||
"cmd": base_cmd + [f"{test_file}::TestPropertySearch::test_search_properties_no_api_key", "-v"],
|
||||
"description": "Testing property search error handling",
|
||||
},
|
||||
|
||||
# Cache management tests
|
||||
{
|
||||
"cmd": base_cmd + [f"{test_file}::TestCacheManagement", "-v", "--tb=short"],
|
||||
"description": "Testing cache management functionality",
|
||||
},
|
||||
|
||||
# Usage and limits tests
|
||||
{
|
||||
"cmd": base_cmd + [f"{test_file}::TestUsageAndLimits", "-v", "--tb=short"],
|
||||
"description": "Testing API usage and limits management",
|
||||
},
|
||||
|
||||
# Error handling tests
|
||||
{
|
||||
"cmd": base_cmd + [f"{test_file}::TestErrorHandling", "-v", "--tb=short"],
|
||||
"description": "Testing comprehensive error handling",
|
||||
},
|
||||
|
||||
# Run all tests with coverage
|
||||
{
|
||||
"cmd": base_cmd + [test_file, "--cov=src", "--cov-report=html", "--tb=short", "-q"],
|
||||
"description": "Full test suite with coverage report",
|
||||
},
|
||||
|
||||
# Generate final HTML report
|
||||
{
|
||||
"cmd": base_cmd + [test_file, "--html=reports/comprehensive_test_report.html", "--self-contained-html", "-q"],
|
||||
"description": "Generating comprehensive HTML test report",
|
||||
}
|
||||
]
|
||||
|
||||
# Track results
|
||||
passed = 0
|
||||
failed = 0
|
||||
|
||||
print("\n📋 Test Execution Plan:")
|
||||
for i, scenario in enumerate(test_scenarios, 1):
|
||||
print(f" {i}. {scenario['description']}")
|
||||
|
||||
print("\n🚀 Starting test execution...")
|
||||
|
||||
for i, scenario in enumerate(test_scenarios, 1):
|
||||
print(f"\n{'='*60}")
|
||||
print(f"Step {i}/{len(test_scenarios)}")
|
||||
|
||||
# Update environment for this command
|
||||
scenario_env = env.copy()
|
||||
|
||||
success = run_command(scenario["cmd"], scenario["description"])
|
||||
|
||||
if success:
|
||||
passed += 1
|
||||
else:
|
||||
failed += 1
|
||||
# For critical tests, we might want to stop
|
||||
if "smoke" in scenario["description"].lower():
|
||||
print(" 🛑 Smoke tests failed - stopping execution")
|
||||
break
|
||||
|
||||
# Final summary
|
||||
print(f"\n{'='*60}")
|
||||
print("🏁 TEST EXECUTION SUMMARY")
|
||||
print(f" ✅ Passed: {passed}")
|
||||
print(f" ❌ Failed: {failed}")
|
||||
print(f" 📊 Total: {passed + failed}")
|
||||
|
||||
if failed == 0:
|
||||
print(" 🎉 All test scenarios completed successfully!")
|
||||
print(" 📁 Check reports/ directory for detailed results")
|
||||
else:
|
||||
print(" ⚠️ Some test scenarios failed - review output above")
|
||||
|
||||
# Show useful commands
|
||||
print(f"\n📚 USEFUL COMMANDS:")
|
||||
print(f" # Run specific test categories:")
|
||||
print(f" PYTHONPATH=src uv run pytest {test_file} -m smoke -v")
|
||||
print(f" PYTHONPATH=src uv run pytest {test_file} -m unit -v")
|
||||
print(f" PYTHONPATH=src uv run pytest {test_file} -m integration -v")
|
||||
print(f" PYTHONPATH=src uv run pytest {test_file} -m performance -v")
|
||||
print(f" ")
|
||||
print(f" # Run with different output formats:")
|
||||
print(f" PYTHONPATH=src uv run pytest {test_file} --tb=line")
|
||||
print(f" PYTHONPATH=src uv run pytest {test_file} --tb=no -q")
|
||||
print(f" PYTHONPATH=src uv run pytest {test_file} --collect-only")
|
||||
print(f" ")
|
||||
print(f" # Generate reports:")
|
||||
print(f" PYTHONPATH=src uv run pytest {test_file} --html=reports/test_results.html --self-contained-html")
|
||||
print(f" PYTHONPATH=src uv run pytest {test_file} --cov=src --cov-report=html --cov-report=term")
|
||||
|
||||
return 0 if failed == 0 else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
1400
tests/test_mcp_server.py
Normal file
1400
tests/test_mcp_server.py
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user