# Harvest API Testing
Guide for running tests against the Harvest MCP server.
## Prerequisites
1. **Install dependencies:**
```bash
cd packages/mcp_tests
uv pip install -e .
cd ../apis/harvest
uv pip install -e ".[dev]"
```
2. **Configure credentials:**
Create a `.env` file in `packages/apis/harvest/`:
```bash
MCP_SERVER_URL=http://localhost:8080
HARVEST_ACCESS_TOKEN=your_harvest_token
HARVEST_ACCOUNT_ID=your_account_id
```
## Running Tests
### Using Just (Recommended)
The `justfile` provides convenient recipes for running tests:
#### Local Testing (using .env file)
```bash
cd packages/apis/harvest
just smoke-test
```
This runs tests against the URL configured in your `.env` file.
#### Testing Deployed Stack
```bash
just smoke-test HarvestAPIStack
```
This automatically:
1. Fetches the API URL from CloudFormation stack outputs
2. Sets `MCP_SERVER_URL` environment variable
3. Runs tests against the deployed API
### Using pytest Directly
You can also run tests directly with pytest:
```bash
# From repository root
cd packages/apis/harvest
source ../../../.venv/bin/activate
python -m pytest test_harvest_mcp.py -v -s
```
**Options:**
- `-v`: Verbose output
- `-s`: Show print statements
- `-k test_list_tools`: Run specific test
## Test Structure
### Test Files
- `test_harvest_mcp.py` - Main integration tests for Harvest API
- `test_list_tools` - Verifies tools are available
- `test_get_current_user` - Tests user retrieval endpoint
### Test Architecture
Tests use the `mcp_tests` package which provides:
- **MCP SDK Integration**: Official MCP Python SDK with SSE transport
- **Given-When-Then**: Clear test structure
- **Async/Await**: Modern async patterns with `pytest-asyncio`
- **Type Safety**: Full type hints using MCP types
### Example Test
```python
@pytest.mark.asyncio
async def test_list_tools(authenticated_url):
# Given: An authenticated MCP server URL
async with create_mcp_session(authenticated_url) as session:
# When: Requesting the list of available tools
tools_response = await session.list_tools()
# Then: The response contains a valid list of tools
assert len(tools_response.tools) > 0
```
## CI/CD Integration
The `smoke-test` recipe is designed for CI/CD pipelines:
```yaml
# Example GitHub Actions
- name: Run Harvest Tests
env:
HARVEST_ACCESS_TOKEN: ${{ secrets.HARVEST_ACCESS_TOKEN }}
HARVEST_ACCOUNT_ID: ${{ secrets.HARVEST_ACCOUNT_ID }}
run: |
just smoke-test HarvestAPIStack
```
## Troubleshooting
### Connection Refused
```
httpcore.ConnectError: [Errno 61] Connection refused
```
**Solution**: Ensure the MCP server is running at the URL in `MCP_SERVER_URL`.
### Missing Credentials
```
pytest.fail: HARVEST_ACCESS_TOKEN environment variable not set
```
**Solution**: Configure credentials in `.env` file or set environment variables.
### Import Errors
```
ModuleNotFoundError: No module named 'mcp_tests'
```
**Solution**: Install the `mcp_tests` package:
```bash
cd packages/mcp_tests && uv pip install -e .
```
## Writing New Tests
When adding new tests for Harvest API:
1. Use the `mcp_tests` package helpers
2. Follow Given-When-Then pattern
3. Mark tests as `@pytest.mark.asyncio`
4. Use descriptive assertion messages
Example:
```python
from mcp_tests import create_mcp_session, find_tool_by_name
@pytest.mark.asyncio
async def test_my_feature(authenticated_url):
# Given: An authenticated session
async with create_mcp_session(authenticated_url) as session:
# When: Calling my tool
tools = await session.list_tools()
my_tool = find_tool_by_name(tools.tools, "my_tool_name")
result = await session.call_tool(my_tool.name, {"arg": "value"})
# Then: The result is valid
assert len(result.content) > 0
```
## Related Documentation
- [MCP Tests Package README](../../mcp_tests/README.md)
- [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)
- [Main Project README](../../../README.md)