# Testing the Skraak MCP Server
## Overview
The Skraak MCP Server provides 10 tools across three categories:
- **Read tools (2)**: `get_current_time`, `execute_sql`
- **Write tools (4)**: `create_or_update_dataset`, `create_or_update_location`, `create_or_update_cluster`, `create_or_update_pattern`
- **Import tools (2 MCP)**: `import_audio_files`, `import_ml_selections`
Plus resources (schema) and prompts (SQL workflow templates).
## Test Scripts
All scripts are in `shell_scripts/` and follow a consistent pattern.
### Read-Only Tests (No DB Modification)
```bash
cd shell_scripts
# Time tool (no database needed)
./test_time.sh
# SQL queries and security validation
./test_sql.sh
# Schema resources
./test_resources.sh
# All 6 MCP prompts
./test_prompts.sh
# Database integrity check
./test_db_state.sh
```
### Write Tests (Fresh DB Each Run)
These tests create a fresh copy of `skraak.duckdb` in `/tmp` and clean up automatically.
```bash
cd shell_scripts
# Create/update tools (dataset, location, cluster, pattern)
./test_write_tools.sh
# Import tools validation (error handling)
./test_import.sh
```
## Test Library
All tests source `test_lib.sh` for shared functionality:
```bash
source ./test_lib.sh
# Send MCP request
result=$(send_request "tools/call" '{"name":"execute_sql","arguments":{"query":"SELECT 1"}}')
# Run test with automatic tracking
run_test "Test name" "true" "$result" # true = expect success
# Print summary
print_summary
```
### Key Functions
| `send_request <method> <params> [db]` | Send single MCP request |
| `send_requests <db> <req1> <req2>...` | Send multiple requests in one session |
| `run_test <name> <expect_pass> <result>` | Track test pass/fail |
| `get_result <response>` | Extract result from response |
| `is_error <response>` | Check if response is error |
| `fresh_test_db` | Create fresh test DB in /tmp |
| `cleanup_test_db <path>` | Remove test DB and temp files |
| `print_summary` | Print test counts |
## Manual JSON-RPC Testing
You can test manually via stdin:
```bash
./skraak mcp --db ./db/test.duckdb
```
Then type JSON-RPC messages (one per line):
### Initialize
```json
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}
```
### List Tools
```json
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
```
### Execute SQL
```json
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"execute_sql","arguments":{"query":"SELECT COUNT(*) FROM dataset WHERE active = true"}}}
```
### Create Dataset
```json
{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"create_or_update_dataset","arguments":{"name":"Test Dataset","type":"test"}}}
```
### Get Schema Resource
```json
{"jsonrpc":"2.0","id":5,"method":"resources/read","params":{"uri":"schema://full"}}
```
### Get Prompt
```json
{"jsonrpc":"2.0","id":6,"method":"prompts/get","params":{"name":"query_active_datasets"}}
```
## SQL Query Examples
### Basic Queries
```sql
-- Active datasets
SELECT id, name, type FROM dataset WHERE active = true ORDER BY name
-- Parameterized query
SELECT id, name FROM location WHERE dataset_id = ? AND active = true
-- With limit
SELECT * FROM file WHERE active = true LIMIT 100
```
### JOINs
```sql
-- Dataset hierarchy with counts
SELECT d.name, COUNT(l.id) as locations, COUNT(f.id) as files
FROM dataset d
LEFT JOIN location l ON d.id = l.dataset_id
LEFT JOIN cluster c ON l.id = c.location_id
LEFT JOIN file f ON c.id = f.cluster_id
WHERE d.active = true
GROUP BY d.name
```
### Aggregates
```sql
-- Cluster statistics
SELECT COUNT(*) as files, SUM(duration) as total_seconds, AVG(duration) as avg_seconds
FROM file WHERE cluster_id = ? AND active = true
```
## Running Go Unit Tests
```bash
# All tests
go test ./...
# Specific package
go test ./utils/
# With coverage
go test -cover ./...
# Coverage report
go test -coverprofile=coverage.out ./utils/
go tool cover -html=coverage.out
```
**Test coverage**: 91.5% across 170+ tests
## Troubleshooting
| "skraak binary not found" | Run `go build` in project root |
| "Database not found" | Check path or use default |
| "Error: --db is required" | MCP command needs `--db path` |
| JSON parsing errors | Each message must be on one line |
| No response | Server outputs to stdout; check for errors in stderr |
| Test output too large | Tests print summary, not full output |
## Best Practices
1. **Run from shell_scripts directory**: Scripts use relative paths
2. **Use test.duckdb for manual testing**: Never use skraak.duckdb
3. **Write tests auto-clean**: They use /tmp and trap EXIT
4. **Check exit codes**: Tests return 0 on success, 1 on failure
5. **Run all tests before committing**: Ensures nothing is broken