A high-performance Model Context Protocol (MCP) server for analyzing Chrono series (Trigger, Cross, Radical Dreamers) ROMs.
This application is designed to run as a container on a NAS (Synology, Unraid) with external access provided via Cloudflare Tunnel or Tailscale as a secure reverse proxy. TLS termination is handled by the reverse proxy, not by this application.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ MCP Client │────▶│ Cloudflare/Tails │────▶│ crono-mcp │
│ (Claude AI) │ │ Tunnel │ │ Container │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ NAS Volume │
│ (roms/) │
└─────────────────┘
- ROM Analysis: Inspect SNES, NDS, and Switch ROM metadata
- Series Indexing: Exhaustive crawl of Chrono Trigger, Cross, and Radical Dreamers data
- MCP Protocol: Full JSON-RPC 2.0 implementation over SSE or stdio
- Graceful Shutdown: SIGTERM/SIGINT handling for container updates
- Health Checks:
/healthand/readyendpoints for container orchestration - 12-Factor App: Environment-based configuration
git clone https://github.com/ubermetroid/crono-mcp.git
cd crono-mcp
# Copy environment template
cp .env.example .env
# Edit .env with your settings (see Environment Variables below)# Build and start
docker-compose up -d
# View logs
docker-compose logs -f# Start crono-mcp in SSE mode
docker-compose up -d
# In another terminal, create tunnel
cloudflared tunnel --url http://localhost:1995
# Use the provided URL in your MCP client| Variable | Default | Description |
|---|---|---|
MODE |
sse |
Server mode: stdio (local) or sse (network) |
PORT |
1995 |
TCP port for SSE mode |
RUST_LOG |
info |
Log level: trace, debug, info, warn, error |
CORS_ALLOWED_ORIGINS |
http://localhost,http://127.0.0.1 |
Allowed CORS origins (comma-separated) |
PUID |
1000 |
User ID for container (prevents root-owned files) |
PGID |
1000 |
Group ID for container |
TZ |
UTC |
Timezone for log timestamps |
| Tool | Description |
|---|---|
inspect_rom |
Returns basic metadata from a SNES, NDS, or Switch ROM |
crawl_series_resources |
Exhaustive indexing of all series data |
get_item_info |
Instant lookup of item data from indexed database |
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Returns {"status": "ok"} - for container health checks |
/ready |
GET | Returns 503 if index not loaded, 200 if ready |
/sse |
GET | Server-Sent Events stream (keep-alive) |
/message |
POST | JSON-RPC 2.0 request handler |
# Build
cargo build --release
# Run tests
cargo test
# Run benchmarks
cargo bench
# Format and lint
cargo fmt
cargo clippy# SSE mode
cargo run -- --mode sse --port 1995
# Stdio mode (default)
cargo run- Runs as non-root user (
crono:crono, UID/GID 1000) - Drops all Linux capabilities (
cap_drop: - ALL) - Read-only ROM volume mount
- Resource limits: 1 CPU, 512MB RAM
- JSON-file logging with rotation (10MB max, 3 files)
# Check if server is responding
wget -qO- http://localhost:1995/health
# Check server logs
docker-compose logsRun crawl_series_resources first to build the index:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "crawl_series_resources",
"arguments": {
"ct_path": "roms/chrono_trigger.sfc",
"cc_path": "roms/chrono_cross.bin",
"rd_path": "roms/radical_dreamers.z64"
}
},
"id": 1
}GPL-3.0-only - See LICENSE for details.